diff --git a/Documentation/DocBook/Makefile b/Documentation/DocBook/Makefile index 9b1f6ca100d1de96e9071193f90a3cbf6d81e34c..0a08126d30942bad2f59d11e09c9c651c8f5e63b 100644 --- a/Documentation/DocBook/Makefile +++ b/Documentation/DocBook/Makefile @@ -6,7 +6,7 @@ # To add a new book the only step required is to add the book to the # list of DOCBOOKS. -DOCBOOKS := wanbook.xml z8530book.xml mcabook.xml \ +DOCBOOKS := z8530book.xml mcabook.xml \ kernel-hacking.xml kernel-locking.xml deviceiobook.xml \ procfs-guide.xml writing_usb_driver.xml networking.xml \ kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \ diff --git a/Documentation/DocBook/networking.tmpl b/Documentation/DocBook/networking.tmpl index f24f9e85e4aeba788d7b4557bf19d93efaa7dc99..627707a3cb9d66406ba40a356cf000772de97701 100644 --- a/Documentation/DocBook/networking.tmpl +++ b/Documentation/DocBook/networking.tmpl @@ -98,9 +98,6 @@ X!Enet/core/wireless.c --> - Synchronous PPP -!Edrivers/net/wan/syncppp.c - diff --git a/Documentation/DocBook/wanbook.tmpl b/Documentation/DocBook/wanbook.tmpl deleted file mode 100644 index 8c93db122f049a13177b5d5f612d8da3f12aeaad..0000000000000000000000000000000000000000 --- a/Documentation/DocBook/wanbook.tmpl +++ /dev/null @@ -1,99 +0,0 @@ - - - - - - Synchronous PPP and Cisco HDLC Programming Guide - - - - Alan - Cox - -
- alan@lxorguk.ukuu.org.uk -
-
-
-
- - - 2000 - Alan Cox - - - - - This documentation 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 - - - - For more details see the file COPYING in the source - distribution of Linux. - - -
- - - - - Introduction - - The syncppp drivers in Linux provide a fairly complete - implementation of Cisco HDLC and a minimal implementation of - PPP. The longer term goal is to switch the PPP layer to the - generic PPP interface that is new in Linux 2.3.x. The API should - remain unchanged when this is done, but support will then be - available for IPX, compression and other PPP features - - - - Known Bugs And Assumptions - - - PPP is minimal - - - The current PPP implementation is very basic, although sufficient - for most wan usages. - - - - Cisco HDLC Quirks - - - Currently we do not end all packets with the correct Cisco multicast - or unicast flags. Nothing appears to mind too much but this should - be corrected. - - - - - - - - - Public Functions Provided -!Edrivers/net/wan/syncppp.c - - -
diff --git a/Documentation/RCU/rculist_nulls.txt b/Documentation/RCU/rculist_nulls.txt new file mode 100644 index 0000000000000000000000000000000000000000..239f542d48baa9425f29a54b6b43f00468d986c2 --- /dev/null +++ b/Documentation/RCU/rculist_nulls.txt @@ -0,0 +1,167 @@ +Using hlist_nulls to protect read-mostly linked lists and +objects using SLAB_DESTROY_BY_RCU allocations. + +Please read the basics in Documentation/RCU/listRCU.txt + +Using special makers (called 'nulls') is a convenient way +to solve following problem : + +A typical RCU linked list managing objects which are +allocated with SLAB_DESTROY_BY_RCU kmem_cache can +use following algos : + +1) Lookup algo +-------------- +rcu_read_lock() +begin: +obj = lockless_lookup(key); +if (obj) { + if (!try_get_ref(obj)) // might fail for free objects + goto begin; + /* + * Because a writer could delete object, and a writer could + * reuse these object before the RCU grace period, we + * must check key after geting the reference on object + */ + if (obj->key != key) { // not the object we expected + put_ref(obj); + goto begin; + } +} +rcu_read_unlock(); + +Beware that lockless_lookup(key) cannot use traditional hlist_for_each_entry_rcu() +but a version with an additional memory barrier (smp_rmb()) + +lockless_lookup(key) +{ + struct hlist_node *node, *next; + for (pos = rcu_dereference((head)->first); + pos && ({ next = pos->next; smp_rmb(); prefetch(next); 1; }) && + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); + pos = rcu_dereference(next)) + if (obj->key == key) + return obj; + return NULL; + +And note the traditional hlist_for_each_entry_rcu() misses this smp_rmb() : + + struct hlist_node *node; + for (pos = rcu_dereference((head)->first); + pos && ({ prefetch(pos->next); 1; }) && + ({ tpos = hlist_entry(pos, typeof(*tpos), member); 1; }); + pos = rcu_dereference(pos->next)) + if (obj->key == key) + return obj; + return NULL; +} + +Quoting Corey Minyard : + +"If the object is moved from one list to another list in-between the + time the hash is calculated and the next field is accessed, and the + object has moved to the end of a new list, the traversal will not + complete properly on the list it should have, since the object will + be on the end of the new list and there's not a way to tell it's on a + new list and restart the list traversal. I think that this can be + solved by pre-fetching the "next" field (with proper barriers) before + checking the key." + +2) Insert algo : +---------------- + +We need to make sure a reader cannot read the new 'obj->obj_next' value +and previous value of 'obj->key'. Or else, an item could be deleted +from a chain, and inserted into another chain. If new chain was empty +before the move, 'next' pointer is NULL, and lockless reader can +not detect it missed following items in original chain. + +/* + * Please note that new inserts are done at the head of list, + * not in the middle or end. + */ +obj = kmem_cache_alloc(...); +lock_chain(); // typically a spin_lock() +obj->key = key; +atomic_inc(&obj->refcnt); +/* + * we need to make sure obj->key is updated before obj->next + */ +smp_wmb(); +hlist_add_head_rcu(&obj->obj_node, list); +unlock_chain(); // typically a spin_unlock() + + +3) Remove algo +-------------- +Nothing special here, we can use a standard RCU hlist deletion. +But thanks to SLAB_DESTROY_BY_RCU, beware a deleted object can be reused +very very fast (before the end of RCU grace period) + +if (put_last_reference_on(obj) { + lock_chain(); // typically a spin_lock() + hlist_del_init_rcu(&obj->obj_node); + unlock_chain(); // typically a spin_unlock() + kmem_cache_free(cachep, obj); +} + + + +-------------------------------------------------------------------------- +With hlist_nulls we can avoid extra smp_rmb() in lockless_lookup() +and extra smp_wmb() in insert function. + +For example, if we choose to store the slot number as the 'nulls' +end-of-list marker for each slot of the hash table, we can detect +a race (some writer did a delete and/or a move of an object +to another chain) checking the final 'nulls' value if +the lookup met the end of chain. If final 'nulls' value +is not the slot number, then we must restart the lookup at +the begining. If the object was moved to same chain, +then the reader doesnt care : It might eventually +scan the list again without harm. + + +1) lookup algo + + head = &table[slot]; + rcu_read_lock(); +begin: + hlist_nulls_for_each_entry_rcu(obj, node, head, member) { + if (obj->key == key) { + if (!try_get_ref(obj)) // might fail for free objects + goto begin; + if (obj->key != key) { // not the object we expected + put_ref(obj); + goto begin; + } + goto out; + } +/* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (get_nulls_value(node) != slot) + goto begin; + obj = NULL; + +out: + rcu_read_unlock(); + +2) Insert function : +-------------------- + +/* + * Please note that new inserts are done at the head of list, + * not in the middle or end. + */ +obj = kmem_cache_alloc(cachep); +lock_chain(); // typically a spin_lock() +obj->key = key; +atomic_set(&obj->refcnt, 1); +/* + * insert obj in RCU way (readers might be traversing chain) + */ +hlist_nulls_add_head_rcu(&obj->obj_node, list); +unlock_chain(); // typically a spin_unlock() diff --git a/Documentation/feature-removal-schedule.txt b/Documentation/feature-removal-schedule.txt index 1a8af7354e799843721c3fb7ac40ab2df9352671..dc7c681e532cacf9fbf9ec0f692e9fb2bd5740e7 100644 --- a/Documentation/feature-removal-schedule.txt +++ b/Documentation/feature-removal-schedule.txt @@ -120,13 +120,6 @@ Who: Christoph Hellwig --------------------------- -What: eepro100 network driver -When: January 2007 -Why: replaced by the e100 driver -Who: Adrian Bunk - ---------------------------- - What: Unused EXPORT_SYMBOL/EXPORT_SYMBOL_GPL exports (temporary transition config option provided until then) The transition config option will also be removed at the same time. diff --git a/Documentation/networking/README.ipw2200 b/Documentation/networking/README.ipw2200 index 4f2a40f1dbc629837463a96695759e3848f41c68..80c728522c4c7a0482d1804689f87869d9c404c0 100644 --- a/Documentation/networking/README.ipw2200 +++ b/Documentation/networking/README.ipw2200 @@ -147,7 +147,7 @@ Where the supported parameter are: driver. If disabled, the driver will not attempt to scan for and associate to a network until it has been configured with one or more properties for the target network, for example configuring - the network SSID. Default is 1 (auto-associate) + the network SSID. Default is 0 (do not auto-associate) Example: % modprobe ipw2200 associate=0 diff --git a/Documentation/networking/bonding.txt b/Documentation/networking/bonding.txt index 688dfe1e6b70f75a36d84f30dda2234c53664be0..5ede7473b4251e43e53c5053e144cf12f3d6032a 100644 --- a/Documentation/networking/bonding.txt +++ b/Documentation/networking/bonding.txt @@ -194,6 +194,48 @@ or, for backwards compatibility, the option value. E.g., The parameters are as follows: +ad_select + + Specifies the 802.3ad aggregation selection logic to use. The + possible values and their effects are: + + stable or 0 + + The active aggregator is chosen by largest aggregate + bandwidth. + + Reselection of the active aggregator occurs only when all + slaves of the active aggregator are down or the active + aggregator has no slaves. + + This is the default value. + + bandwidth or 1 + + The active aggregator is chosen by largest aggregate + bandwidth. Reselection occurs if: + + - A slave is added to or removed from the bond + + - Any slave's link state changes + + - Any slave's 802.3ad association state changes + + - The bond's adminstrative state changes to up + + count or 2 + + The active aggregator is chosen by the largest number of + ports (slaves). Reselection occurs as described under the + "bandwidth" setting, above. + + The bandwidth and count selection policies permit failover of + 802.3ad aggregations when partial failure of the active aggregator + occurs. This keeps the aggregator with the highest availability + (either in bandwidth or in number of ports) active at all times. + + This option was added in bonding version 3.4.0. + arp_interval Specifies the ARP link monitoring frequency in milliseconds. @@ -551,6 +593,16 @@ num_grat_arp affects only the active-backup mode. This option was added for bonding version 3.3.0. +num_unsol_na + + Specifies the number of unsolicited IPv6 Neighbor Advertisements + to be issued after a failover event. One unsolicited NA is issued + immediately after the failover. + + The valid range is 0 - 255; the default value is 1. This option + affects only the active-backup mode. This option was added for + bonding version 3.4.0. + primary A string (eth0, eth2, etc) specifying which slave is the @@ -922,17 +974,19 @@ USERCTL=no NETMASK, NETWORK and BROADCAST) to match your network configuration. For later versions of initscripts, such as that found with Fedora -7 and Red Hat Enterprise Linux version 5 (or later), it is possible, and, -indeed, preferable, to specify the bonding options in the ifcfg-bond0 +7 (or later) and Red Hat Enterprise Linux version 5 (or later), it is possible, +and, indeed, preferable, to specify the bonding options in the ifcfg-bond0 file, e.g. a line of the format: -BONDING_OPTS="mode=active-backup arp_interval=60 arp_ip_target=+192.168.1.254" +BONDING_OPTS="mode=active-backup arp_interval=60 arp_ip_target=192.168.1.254" will configure the bond with the specified options. The options specified in BONDING_OPTS are identical to the bonding module parameters -except for the arp_ip_target field. Each target should be included as a -separate option and should be preceded by a '+' to indicate it should be -added to the list of queried targets, e.g., +except for the arp_ip_target field when using versions of initscripts older +than and 8.57 (Fedora 8) and 8.45.19 (Red Hat Enterprise Linux 5.2). When +using older versions each target should be included as a separate option and +should be preceded by a '+' to indicate it should be added to the list of +queried targets, e.g., arp_ip_target=+192.168.1.1 arp_ip_target=+192.168.1.2 @@ -940,7 +994,7 @@ added to the list of queried targets, e.g., options via BONDING_OPTS, it is not necessary to edit /etc/modules.conf or /etc/modprobe.conf. - For older versions of initscripts that do not support + For even older versions of initscripts that do not support BONDING_OPTS, it is necessary to edit /etc/modules.conf (or /etc/modprobe.conf, depending upon your distro) to load the bonding module with your desired options when the bond0 interface is brought up. The diff --git a/Documentation/networking/dccp.txt b/Documentation/networking/dccp.txt index 39131a3c78f8826bb9949ddf25ff50e591904028..7a3bb1abb8304a1fe7222e354e43164a7a7635bb 100644 --- a/Documentation/networking/dccp.txt +++ b/Documentation/networking/dccp.txt @@ -57,6 +57,24 @@ can be set before calling bind(). DCCP_SOCKOPT_GET_CUR_MPS is read-only and retrieves the current maximum packet size (application payload size) in bytes, see RFC 4340, section 14. +DCCP_SOCKOPT_AVAILABLE_CCIDS is also read-only and returns the list of CCIDs +supported by the endpoint (see include/linux/dccp.h for symbolic constants). +The caller needs to provide a sufficiently large (> 2) array of type uint8_t. + +DCCP_SOCKOPT_CCID is write-only and sets both the TX and RX CCIDs at the same +time, combining the operation of the next two socket options. This option is +preferrable over the latter two, since often applications will use the same +type of CCID for both directions; and mixed use of CCIDs is not currently well +understood. This socket option takes as argument at least one uint8_t value, or +an array of uint8_t values, which must match available CCIDS (see above). CCIDs +must be registered on the socket before calling connect() or listen(). + +DCCP_SOCKOPT_TX_CCID is read/write. It returns the current CCID (if set) or sets +the preference list for the TX CCID, using the same format as DCCP_SOCKOPT_CCID. +Please note that the getsockopt argument type here is `int', not uint8_t. + +DCCP_SOCKOPT_RX_CCID is analogous to DCCP_SOCKOPT_TX_CCID, but for the RX CCID. + DCCP_SOCKOPT_SERVER_TIMEWAIT enables the server (listening socket) to hold timewait state when closing the connection (RFC 4340, 8.3). The usual case is that the closing server sends a CloseReq, whereupon the client holds timewait @@ -115,20 +133,12 @@ retries2 importance for retransmitted acknowledgments and feature negotiation, data packets are never retransmitted. Analogue of tcp_retries2. -send_ndp = 1 - Whether or not to send NDP count options (sec. 7.7.2). - -send_ackvec = 1 - Whether or not to send Ack Vector options (sec. 11.5). - -ack_ratio = 2 - The default Ack Ratio (sec. 11.3) to use. - tx_ccid = 2 - Default CCID for the sender-receiver half-connection. + Default CCID for the sender-receiver half-connection. Depending on the + choice of CCID, the Send Ack Vector feature is enabled automatically. rx_ccid = 2 - Default CCID for the receiver-sender half-connection. + Default CCID for the receiver-sender half-connection; see tx_ccid. seq_window = 100 The initial sequence window (sec. 7.5.2). diff --git a/Documentation/networking/driver.txt b/Documentation/networking/driver.txt index ea72d2e66ca81a62fa493b695ed0e5cf94fc92a4..03283daa64fef72360667fb979a256aa10a3bb91 100644 --- a/Documentation/networking/driver.txt +++ b/Documentation/networking/driver.txt @@ -13,7 +13,7 @@ Transmit path guidelines: static int drv_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct drv *dp = dev->priv; + struct drv *dp = netdev_priv(dev); lock_tx(dp); ... diff --git a/Documentation/networking/generic-hdlc.txt b/Documentation/networking/generic-hdlc.txt index 31bc8b759b755e03875426f3678e92e86a022b33..4eb3cc40b702e33d7fa6f059555a2d7876c7a981 100644 --- a/Documentation/networking/generic-hdlc.txt +++ b/Documentation/networking/generic-hdlc.txt @@ -3,15 +3,15 @@ Krzysztof Halasa Generic HDLC layer currently supports: -1. Frame Relay (ANSI, CCITT, Cisco and no LMI). +1. Frame Relay (ANSI, CCITT, Cisco and no LMI) - Normal (routed) and Ethernet-bridged (Ethernet device emulation) interfaces can share a single PVC. - ARP support (no InARP support in the kernel - there is an experimental InARP user-space daemon available on: http://www.kernel.org/pub/linux/utils/net/hdlc/). -2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation. -3. Cisco HDLC. -4. PPP (uses syncppp.c). +2. raw HDLC - either IP (IPv4) interface or Ethernet device emulation +3. Cisco HDLC +4. PPP 5. X.25 (uses X.25 routines). Generic HDLC is a protocol driver only - it needs a low-level driver diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt index d84932650fd3e926cc11d5fa0bcaee6cc8a8cd33..c7712787933c1734c98a0191db23d9cb2886d0f8 100644 --- a/Documentation/networking/ip-sysctl.txt +++ b/Documentation/networking/ip-sysctl.txt @@ -27,6 +27,12 @@ min_adv_mss - INTEGER The advertised MSS depends on the first hop route MTU, but will never be lower than this setting. +rt_cache_rebuild_count - INTEGER + The per net-namespace route cache emergency rebuild threshold. + Any net-namespace having its route cache rebuilt due to + a hash bucket chain being too long more than this many times + will have its route caching disabled + IP Fragmentation: ipfrag_high_thresh - INTEGER diff --git a/Documentation/networking/mac80211_hwsim/README b/Documentation/networking/mac80211_hwsim/README index 2ff8ccb8dc3715dd343c5229b8c6ded98dde7d03..24ac91d56698d626fb266556c5b0c3b9fd212fa9 100644 --- a/Documentation/networking/mac80211_hwsim/README +++ b/Documentation/networking/mac80211_hwsim/README @@ -50,10 +50,6 @@ associates with the AP. hostapd and wpa_supplicant are used to take care of WPA2-PSK authentication. In addition, hostapd is also processing access point side of association. -Please note that the current Linux kernel does not enable AP mode, so a -simple patch is needed to enable AP mode selection: -http://johannes.sipsolutions.net/patches/kernel/all/LATEST/006-allow-ap-vlan-modes.patch - # Build mac80211_hwsim as part of kernel configuration @@ -65,3 +61,8 @@ hostapd hostapd.conf # Run wpa_supplicant (station) for wlan1 wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf + + +More test cases are available in hostap.git: +git://w1.fi/srv/git/hostap.git and mac80211_hwsim/tests subdirectory +(http://w1.fi/gitweb/gitweb.cgi?p=hostap.git;a=tree;f=mac80211_hwsim/tests) diff --git a/Documentation/networking/netdevices.txt b/Documentation/networking/netdevices.txt index d0f71fc7f7829b1dfb9dfc689afe0978bec53c76..a2ab6a0b116d96ff8e6198154d5f455cac2fec5e 100644 --- a/Documentation/networking/netdevices.txt +++ b/Documentation/networking/netdevices.txt @@ -18,7 +18,7 @@ There are routines in net_init.c to handle the common cases of alloc_etherdev, alloc_netdev. These reserve extra space for driver private data which gets freed when the network device is freed. If separately allocated data is attached to the network device -(dev->priv) then it is up to the module exit handler to free that. +(netdev_priv(dev)) then it is up to the module exit handler to free that. MTU === diff --git a/Documentation/networking/regulatory.txt b/Documentation/networking/regulatory.txt index a96989a8ff351c0a409187819175461cfa44f456..dcf31648414ad8423e934851bea5ee38b0d09f2f 100644 --- a/Documentation/networking/regulatory.txt +++ b/Documentation/networking/regulatory.txt @@ -131,11 +131,13 @@ are expected to do this during initialization. r = zd_reg2alpha2(mac->regdomain, alpha2); if (!r) - regulatory_hint(hw->wiphy, alpha2, NULL); + regulatory_hint(hw->wiphy, alpha2); Example code - drivers providing a built in regulatory domain: -------------------------------------------------------------- +[NOTE: This API is not currently available, it can be added when required] + If you have regulatory information you can obtain from your driver and you *need* to use this we let you build a regulatory domain structure and pass it to the wireless core. To do this you should @@ -167,7 +169,6 @@ struct ieee80211_regdomain mydriver_jp_regdom = { Then in some part of your code after your wiphy has been registered: - int r; struct ieee80211_regdomain *rd; int size_of_regd; int num_rules = mydriver_jp_regdom.n_reg_rules; @@ -178,17 +179,12 @@ Then in some part of your code after your wiphy has been registered: rd = kzalloc(size_of_regd, GFP_KERNEL); if (!rd) - return -ENOMEM; + return -ENOMEM; memcpy(rd, &mydriver_jp_regdom, sizeof(struct ieee80211_regdomain)); - for (i=0; i < num_rules; i++) { - memcpy(&rd->reg_rules[i], &mydriver_jp_regdom.reg_rules[i], - sizeof(struct ieee80211_reg_rule)); - } - r = regulatory_hint(hw->wiphy, NULL, rd); - if (r) { - kfree(rd); - return r; - } - + for (i=0; i < num_rules; i++) + memcpy(&rd->reg_rules[i], + &mydriver_jp_regdom.reg_rules[i], + sizeof(struct ieee80211_reg_rule)); + regulatory_struct_hint(rd); diff --git a/Documentation/powerpc/dts-bindings/fsl/tsec.txt b/Documentation/powerpc/dts-bindings/fsl/tsec.txt index cf55fa4112d2736de01e0989c5f11d417346326a..7fa4b27574b5f54aabb1c9839e61fcf9f053c0ad 100644 --- a/Documentation/powerpc/dts-bindings/fsl/tsec.txt +++ b/Documentation/powerpc/dts-bindings/fsl/tsec.txt @@ -2,8 +2,8 @@ The MDIO is a bus to which the PHY devices are connected. For each device that exists on this bus, a child node should be created. See -the definition of the PHY node below for an example of how to define -a PHY. +the definition of the PHY node in booting-without-of.txt for an example +of how to define a PHY. Required properties: - reg : Offset and length of the register set for the device @@ -21,6 +21,14 @@ Example: }; }; +* TBI Internal MDIO bus + +As of this writing, every tsec is associated with an internal TBI PHY. +This PHY is accessed through the local MDIO bus. These buses are defined +similarly to the mdio buses, except they are compatible with "fsl,gianfar-tbi". +The TBI PHYs underneath them are similar to normal PHYs, but the reg property +is considered instructive, rather than descriptive. The reg property should +be chosen so it doesn't interfere with other PHYs on the bus. * Gianfar-compatible ethernet nodes diff --git a/Documentation/rfkill.txt b/Documentation/rfkill.txt index b65f0799df485dfea9d0346a3d3ede5c7fc5afba..4d3ee317a4a3e84181047ab417a3e2a88c4995bc 100644 --- a/Documentation/rfkill.txt +++ b/Documentation/rfkill.txt @@ -191,12 +191,20 @@ Userspace input handlers (uevents) or kernel input handlers (rfkill-input): to tell the devices registered with the rfkill class to change their state (i.e. translates the input layer event into real action). + * rfkill-input implements EPO by handling EV_SW SW_RFKILL_ALL 0 (power off all transmitters) in a special way: it ignores any overrides and local state cache and forces all transmitters to the RFKILL_STATE_SOFT_BLOCKED state (including those which are already - supposed to be BLOCKED). Note that the opposite event (power on all - transmitters) is handled normally. + supposed to be BLOCKED). + * rfkill EPO will remain active until rfkill-input receives an + EV_SW SW_RFKILL_ALL 1 event. While the EPO is active, transmitters + are locked in the blocked state (rfkill will refuse to unblock them). + * rfkill-input implements different policies that the user can + select for handling EV_SW SW_RFKILL_ALL 1. It will unlock rfkill, + and either do nothing (leave transmitters blocked, but now unlocked), + restore the transmitters to their state before the EPO, or unblock + them all. Userspace uevent handler or kernel platform-specific drivers hooked to the rfkill notifier chain: @@ -331,11 +339,9 @@ class to get a sysfs interface :-) correct event for your switch/button. These events are emergency power-off events when they are trying to turn the transmitters off. An example of an input device which SHOULD generate *_RFKILL_ALL events is the wireless-kill -switch in a laptop which is NOT a hotkey, but a real switch that kills radios -in hardware, even if the O.S. has gone to lunch. An example of an input device -which SHOULD NOT generate *_RFKILL_ALL events by default, is any sort of hot -key that does nothing by itself, as well as any hot key that is type-specific -(e.g. the one for WLAN). +switch in a laptop which is NOT a hotkey, but a real sliding/rocker switch. +An example of an input device which SHOULD NOT generate *_RFKILL_ALL events by +default, is any sort of hot key that is type-specific (e.g. the one for WLAN). 3.1 Guidelines for wireless device drivers diff --git a/MAINTAINERS b/MAINTAINERS index 701025701514db7f85478f8711285d8d1768dce3..08d0ab7fa1615b093864bf30444a4427109b6d00 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -742,7 +742,7 @@ M: jirislaby@gmail.com P: Nick Kossifidis M: mickflemm@gmail.com P: Luis R. Rodriguez -M: mcgrof@gmail.com +M: lrodriguez@atheros.com P: Bob Copeland M: me@bobcopeland.com L: linux-wireless@vger.kernel.org @@ -1607,11 +1607,6 @@ L: acpi4asus-user@lists.sourceforge.net W: http://sourceforge.net/projects/acpi4asus S: Maintained -EEPRO100 NETWORK DRIVER -P: Andrey V. Savochkin -M: saw@saw.sw.com.sg -S: Maintained - EFS FILESYSTEM W: http://aeschi.ch.eu.org/efs/ S: Orphan @@ -1849,7 +1844,7 @@ P: Haavard Skinnemoen M: hskinnemoen@atmel.com S: Supported -GENERIC HDLC DRIVER, N2, C101, PCI200SYN and WANXL DRIVERS +GENERIC HDLC (WAN) DRIVERS P: Krzysztof Halasa M: khc@pm.waw.pl W: http://www.kernel.org/pub/linux/utils/net/hdlc/ @@ -2248,6 +2243,11 @@ M: dan.j.williams@intel.com L: linux-kernel@vger.kernel.org S: Supported +INTEL IXP4XX QMGR, NPE, ETHERNET and HSS SUPPORT +P: Krzysztof Halasa +M: khc@pm.waw.pl +S: Maintained + INTEL IXP4XX RANDOM NUMBER GENERATOR SUPPORT P: Deepak Saxena M: dsaxena@plexity.net @@ -3614,16 +3614,26 @@ L: linux-hams@vger.kernel.org W: http://www.linux-ax25.org/ S: Maintained -RTL818X WIRELESS DRIVER -P: Michael Wu -M: flamingice@sourmilk.net -P: Andrea Merello -M: andreamrl@tiscali.it +RTL8180 WIRELESS DRIVER +P: John W. Linville +M: linville@tuxdriver.com L: linux-wireless@vger.kernel.org W: http://linuxwireless.org/ -T: git kernel.org:/pub/scm/linux/kernel/git/mwu/mac80211-drivers.git +T: git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-testing.git S: Maintained +RTL8187 WIRELESS DRIVER +P: Herton Ronaldo Krzesinski +M: herton@mandriva.com.br +P: Hin-Tak Leung +M htl10@users.sourceforge.net +P: Larry Finger +M: Larry.Finger@lwfinger.net +L: linux-wireless@vger.kernel.org +W: http://linuxwireless.org/ +T: git kernel.org:/pub/scm/linux/kernel/git/linville/wireless-testing.git +S: Maintained + S3 SAVAGE FRAMEBUFFER DRIVER P: Antonino Daplas M: adaplas@gmail.com @@ -3913,6 +3923,18 @@ M: mhoffman@lightlink.com L: lm-sensors@lm-sensors.org S: Maintained +SMSC911x ETHERNET DRIVER +P: Steve Glendinning +M: steve.glendinning@smsc.com +L: netdev@vger.kernel.org +S: Supported + +SMSC9420 PCI ETHERNET DRIVER +P: Steve Glendinning +M: steve.glendinning@smsc.com +L: netdev@vger.kernel.org +S: Supported + SMX UIO Interface P: Ben Nizette M: bn@niasdigital.com diff --git a/arch/arm/mach-ixp4xx/fsg-setup.c b/arch/arm/mach-ixp4xx/fsg-setup.c index e7c6386782ede189976cb4cb6b59fa2b7af97497..5add22fc98999ac57b0da0f688926b4f65c0dcfc 100644 --- a/arch/arm/mach-ixp4xx/fsg-setup.c +++ b/arch/arm/mach-ixp4xx/fsg-setup.c @@ -177,7 +177,6 @@ static irqreturn_t fsg_reset_handler(int irq, void *dev_id) static void __init fsg_init(void) { - DECLARE_MAC_BUF(mac_buf); uint8_t __iomem *f; ixp4xx_sys_init(); @@ -256,10 +255,10 @@ static void __init fsg_init(void) #endif iounmap(f); } - printk(KERN_INFO "FSG: Using MAC address %s for port 0\n", - print_mac(mac_buf, fsg_plat_eth[0].hwaddr)); - printk(KERN_INFO "FSG: Using MAC address %s for port 1\n", - print_mac(mac_buf, fsg_plat_eth[1].hwaddr)); + printk(KERN_INFO "FSG: Using MAC address %pM for port 0\n", + fsg_plat_eth[0].hwaddr); + printk(KERN_INFO "FSG: Using MAC address %pM for port 1\n", + fsg_plat_eth[1].hwaddr); } diff --git a/arch/arm/mach-ixp4xx/include/mach/qmgr.h b/arch/arm/mach-ixp4xx/include/mach/qmgr.h index 1e52b95cede5518db0b73630cf65d2bc46f82315..0cbe6ceb67c5a012837221f8e9a95509689dea94 100644 --- a/arch/arm/mach-ixp4xx/include/mach/qmgr.h +++ b/arch/arm/mach-ixp4xx/include/mach/qmgr.h @@ -12,6 +12,8 @@ #include #include +#define DEBUG_QMGR 0 + #define HALF_QUEUES 32 #define QUEUES 64 /* only 32 lower queues currently supported */ #define MAX_QUEUE_LENGTH 4 /* in dwords */ @@ -61,22 +63,51 @@ void qmgr_enable_irq(unsigned int queue); void qmgr_disable_irq(unsigned int queue); /* request_ and release_queue() must be called from non-IRQ context */ + +#if DEBUG_QMGR +extern char qmgr_queue_descs[QUEUES][32]; + int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, - unsigned int nearly_full_watermark); + unsigned int nearly_full_watermark, + const char *desc_format, const char* name); +#else +int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, + unsigned int nearly_empty_watermark, + unsigned int nearly_full_watermark); +#define qmgr_request_queue(queue, len, nearly_empty_watermark, \ + nearly_full_watermark, desc_format, name) \ + __qmgr_request_queue(queue, len, nearly_empty_watermark, \ + nearly_full_watermark) +#endif + void qmgr_release_queue(unsigned int queue); static inline void qmgr_put_entry(unsigned int queue, u32 val) { extern struct qmgr_regs __iomem *qmgr_regs; +#if DEBUG_QMGR + BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */ + + printk(KERN_DEBUG "Queue %s(%i) put %X\n", + qmgr_queue_descs[queue], queue, val); +#endif __raw_writel(val, &qmgr_regs->acc[queue][0]); } static inline u32 qmgr_get_entry(unsigned int queue) { + u32 val; extern struct qmgr_regs __iomem *qmgr_regs; - return __raw_readl(&qmgr_regs->acc[queue][0]); + val = __raw_readl(&qmgr_regs->acc[queue][0]); +#if DEBUG_QMGR + BUG_ON(!qmgr_queue_descs[queue]); /* not yet requested */ + + printk(KERN_DEBUG "Queue %s(%i) get %X\n", + qmgr_queue_descs[queue], queue, val); +#endif + return val; } static inline int qmgr_get_stat1(unsigned int queue) diff --git a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c index c6cb069a5a83cea283e94dfc906f1ae81558a320..bfddc73d0a200b358b80761891106e5237b22799 100644 --- a/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c +++ b/arch/arm/mach-ixp4xx/ixp4xx_qmgr.c @@ -14,8 +14,6 @@ #include #include -#define DEBUG 0 - struct qmgr_regs __iomem *qmgr_regs; static struct resource *mem_res; static spinlock_t qmgr_lock; @@ -23,6 +21,10 @@ static u32 used_sram_bitmap[4]; /* 128 16-dword pages */ static void (*irq_handlers[HALF_QUEUES])(void *pdev); static void *irq_pdevs[HALF_QUEUES]; +#if DEBUG_QMGR +char qmgr_queue_descs[QUEUES][32]; +#endif + void qmgr_set_irq(unsigned int queue, int src, void (*handler)(void *pdev), void *pdev) { @@ -70,6 +72,7 @@ void qmgr_disable_irq(unsigned int queue) spin_lock_irqsave(&qmgr_lock, flags); __raw_writel(__raw_readl(&qmgr_regs->irqen[0]) & ~(1 << queue), &qmgr_regs->irqen[0]); + __raw_writel(1 << queue, &qmgr_regs->irqstat[0]); /* clear */ spin_unlock_irqrestore(&qmgr_lock, flags); } @@ -81,9 +84,16 @@ static inline void shift_mask(u32 *mask) mask[0] <<= 1; } +#if DEBUG_QMGR int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, unsigned int nearly_empty_watermark, - unsigned int nearly_full_watermark) + unsigned int nearly_full_watermark, + const char *desc_format, const char* name) +#else +int __qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, + unsigned int nearly_empty_watermark, + unsigned int nearly_full_watermark) +#endif { u32 cfg, addr = 0, mask[4]; /* in 16-dwords */ int err; @@ -151,12 +161,13 @@ int qmgr_request_queue(unsigned int queue, unsigned int len /* dwords */, used_sram_bitmap[2] |= mask[2]; used_sram_bitmap[3] |= mask[3]; __raw_writel(cfg | (addr << 14), &qmgr_regs->sram[queue]); - spin_unlock_irq(&qmgr_lock); - -#if DEBUG - printk(KERN_DEBUG "qmgr: requested queue %i, addr = 0x%02X\n", - queue, addr); +#if DEBUG_QMGR + snprintf(qmgr_queue_descs[queue], sizeof(qmgr_queue_descs[0]), + desc_format, name); + printk(KERN_DEBUG "qmgr: requested queue %s(%i) addr = 0x%02X\n", + qmgr_queue_descs[queue], queue, addr); #endif + spin_unlock_irq(&qmgr_lock); return 0; err: @@ -189,6 +200,11 @@ void qmgr_release_queue(unsigned int queue) while (addr--) shift_mask(mask); +#if DEBUG_QMGR + printk(KERN_DEBUG "qmgr: releasing queue %s(%i)\n", + qmgr_queue_descs[queue], queue); + qmgr_queue_descs[queue][0] = '\x0'; +#endif __raw_writel(0, &qmgr_regs->sram[queue]); used_sram_bitmap[0] &= ~mask[0]; @@ -199,9 +215,10 @@ void qmgr_release_queue(unsigned int queue) spin_unlock_irq(&qmgr_lock); module_put(THIS_MODULE); -#if DEBUG - printk(KERN_DEBUG "qmgr: released queue %i\n", queue); -#endif + + while ((addr = qmgr_get_entry(queue))) + printk(KERN_ERR "qmgr: released queue %i not empty: 0x%08X\n", + queue, addr); } static int qmgr_init(void) @@ -272,5 +289,10 @@ EXPORT_SYMBOL(qmgr_regs); EXPORT_SYMBOL(qmgr_set_irq); EXPORT_SYMBOL(qmgr_enable_irq); EXPORT_SYMBOL(qmgr_disable_irq); +#if DEBUG_QMGR +EXPORT_SYMBOL(qmgr_queue_descs); EXPORT_SYMBOL(qmgr_request_queue); +#else +EXPORT_SYMBOL(__qmgr_request_queue); +#endif EXPORT_SYMBOL(qmgr_release_queue); diff --git a/arch/arm/mach-ixp4xx/nas100d-setup.c b/arch/arm/mach-ixp4xx/nas100d-setup.c index 0acd95ecf27ef39e716a2c27cf470e30c666c640..921c947b5b6b33f170f279525cf8e87dfc0697a4 100644 --- a/arch/arm/mach-ixp4xx/nas100d-setup.c +++ b/arch/arm/mach-ixp4xx/nas100d-setup.c @@ -231,7 +231,6 @@ static irqreturn_t nas100d_reset_handler(int irq, void *dev_id) static void __init nas100d_init(void) { - DECLARE_MAC_BUF(mac_buf); uint8_t __iomem *f; int i; @@ -294,8 +293,8 @@ static void __init nas100d_init(void) #endif iounmap(f); } - printk(KERN_INFO "NAS100D: Using MAC address %s for port 0\n", - print_mac(mac_buf, nas100d_plat_eth[0].hwaddr)); + printk(KERN_INFO "NAS100D: Using MAC address %pM for port 0\n", + nas100d_plat_eth[0].hwaddr); } diff --git a/arch/arm/mach-ixp4xx/nslu2-setup.c b/arch/arm/mach-ixp4xx/nslu2-setup.c index bc9d920ae54f0f28a58597682abcc0e9c0c99c5e..ff6a08d02cc42e8b050c3c91eced3b490ec92877 100644 --- a/arch/arm/mach-ixp4xx/nslu2-setup.c +++ b/arch/arm/mach-ixp4xx/nslu2-setup.c @@ -220,7 +220,6 @@ static struct sys_timer nslu2_timer = { static void __init nslu2_init(void) { - DECLARE_MAC_BUF(mac_buf); uint8_t __iomem *f; int i; @@ -275,8 +274,8 @@ static void __init nslu2_init(void) #endif iounmap(f); } - printk(KERN_INFO "NSLU2: Using MAC address %s for port 0\n", - print_mac(mac_buf, nslu2_plat_eth[0].hwaddr)); + printk(KERN_INFO "NSLU2: Using MAC address %pM for port 0\n", + nslu2_plat_eth[0].hwaddr); } diff --git a/arch/ia64/hp/sim/simeth.c b/arch/ia64/hp/sim/simeth.c index 3d47839a0c488c5625bb6903b68e74d31b0489e8..e4d8fde68103b84a18492b1a0d1a9a47c8fd9011 100644 --- a/arch/ia64/hp/sim/simeth.c +++ b/arch/ia64/hp/sim/simeth.c @@ -167,6 +167,15 @@ netdev_read(int fd, unsigned char *buf, unsigned int len) return ia64_ssc(fd, __pa(buf), len, 0, SSC_NETDEV_RECV); } +static const struct net_device_ops simeth_netdev_ops = { + .ndo_open = simeth_open, + .ndo_stop = simeth_close, + .ndo_start_xmit = simeth_tx, + .ndo_get_stats = simeth_get_stats, + .ndo_set_multicast_list = set_multicast_list, /* not yet used */ + +}; + /* * Function shared with module code, so cannot be in init section * @@ -206,14 +215,10 @@ simeth_probe1(void) memcpy(dev->dev_addr, mac_addr, sizeof(mac_addr)); - local = dev->priv; + local = netdev_priv(dev); local->simfd = fd; /* keep track of underlying file descriptor */ - dev->open = simeth_open; - dev->stop = simeth_close; - dev->hard_start_xmit = simeth_tx; - dev->get_stats = simeth_get_stats; - dev->set_multicast_list = set_multicast_list; /* no yet used */ + dev->netdev_ops = &simeth_netdev_ops; err = register_netdev(dev); if (err) { @@ -325,7 +330,7 @@ simeth_device_event(struct notifier_block *this,unsigned long event, void *ptr) * we get DOWN then UP. */ - local = dev->priv; + local = netdev_priv(dev); /* now do it for real */ r = event == NETDEV_UP ? netdev_attach(local->simfd, dev->irq, ntohl(ifa->ifa_local)): @@ -380,7 +385,7 @@ frame_print(unsigned char *from, unsigned char *frame, int len) static int simeth_tx(struct sk_buff *skb, struct net_device *dev) { - struct simeth_local *local = dev->priv; + struct simeth_local *local = netdev_priv(dev); #if 0 /* ensure we have at least ETH_ZLEN bytes (min frame size) */ @@ -443,7 +448,7 @@ simeth_rx(struct net_device *dev) int len; int rcv_count = SIMETH_RECV_MAX; - local = dev->priv; + local = netdev_priv(dev); /* * the loop concept has been borrowed from other drivers * looks to me like it's a throttling thing to avoid pushing to many @@ -507,7 +512,7 @@ simeth_interrupt(int irq, void *dev_id) static struct net_device_stats * simeth_get_stats(struct net_device *dev) { - struct simeth_local *local = dev->priv; + struct simeth_local *local = netdev_priv(dev); return &local->stats; } diff --git a/arch/powerpc/boot/dts/asp834x-redboot.dts b/arch/powerpc/boot/dts/asp834x-redboot.dts index 6235fca445de43ec0418cc2beb8c0bf91919bff3..524af7ef9f26742e388aa7b6f21adbe75df2b8e5 100644 --- a/arch/powerpc/boot/dts/asp834x-redboot.dts +++ b/arch/powerpc/boot/dts/asp834x-redboot.dts @@ -199,8 +199,26 @@ reg = <0x2>; device_type = "ethernet-phy"; }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -210,6 +228,7 @@ local-mac-address = [ 00 08 e5 11 32 33 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; linux,network-index = <0>; }; @@ -223,6 +242,7 @@ local-mac-address = [ 00 08 e5 11 32 34 ]; interrupts = <35 0x8 36 0x8 37 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; linux,network-index = <1>; }; diff --git a/arch/powerpc/boot/dts/ksi8560.dts b/arch/powerpc/boot/dts/ksi8560.dts index 49737589ffc81f65778a2dbf4a8476427ab49e09..3bfff47418db434c1520637b557d7812ad62b9ae 100644 --- a/arch/powerpc/boot/dts/ksi8560.dts +++ b/arch/powerpc/boot/dts/ksi8560.dts @@ -141,8 +141,26 @@ reg = <0x2>; device_type = "ethernet-phy"; }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + enet0: ethernet@24000 { device_type = "network"; model = "TSEC"; @@ -152,6 +170,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&PHY1>; }; @@ -164,6 +183,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&PHY2>; }; diff --git a/arch/powerpc/boot/dts/mpc8313erdb.dts b/arch/powerpc/boot/dts/mpc8313erdb.dts index 503031766825362e63a2691e0d98df1cd4611405..d4df8b6857a447c790a2f0f3e508bae22ca3e5ae 100644 --- a/arch/powerpc/boot/dts/mpc8313erdb.dts +++ b/arch/powerpc/boot/dts/mpc8313erdb.dts @@ -190,6 +190,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 0x8 36 0x8 35 0x8>; interrupt-parent = <&ipic>; + tbi-handle = < &tbi0 >; phy-handle = < &phy1 >; fsl,magic-packet; @@ -210,6 +211,10 @@ reg = <0x4>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; }; @@ -222,9 +227,24 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <34 0x8 33 0x8 32 0x8>; interrupt-parent = <&ipic>; + tbi-handle = < &tbi1 >; phy-handle = < &phy4 >; sleep = <&pmc 0x10000000>; fsl,magic-packet; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + }; serial0: serial@4500 { diff --git a/arch/powerpc/boot/dts/mpc8315erdb.dts b/arch/powerpc/boot/dts/mpc8315erdb.dts index 6b850670de1df9da01b043dac83dea9c3afa550d..d2cdd47a246d5a94e112ac4888f0896b24fe0c6b 100644 --- a/arch/powerpc/boot/dts/mpc8315erdb.dts +++ b/arch/powerpc/boot/dts/mpc8315erdb.dts @@ -206,8 +206,25 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -217,6 +234,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = < &phy0 >; }; @@ -229,6 +247,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 0x8 36 0x8 37 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = < &phy1 >; }; diff --git a/arch/powerpc/boot/dts/mpc8349emitx.dts b/arch/powerpc/boot/dts/mpc8349emitx.dts index 4bdbaf4993a185c176000890f1c999108f6b2f11..712783d0707ecf0dc8d12c5e6006e3005486508f 100644 --- a/arch/powerpc/boot/dts/mpc8349emitx.dts +++ b/arch/powerpc/boot/dts/mpc8349emitx.dts @@ -184,6 +184,22 @@ reg = <0x1c>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -195,6 +211,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy1c>; linux,network-index = <0>; }; @@ -211,6 +228,7 @@ /* Vitesse 7385 isn't on the MDIO bus */ fixed-link = <1 1 1000 0 0>; linux,network-index = <1>; + tbi-handle = <&tbi1>; }; serial0: serial@4500 { diff --git a/arch/powerpc/boot/dts/mpc8349emitxgp.dts b/arch/powerpc/boot/dts/mpc8349emitxgp.dts index fa40647ee62e9bb74ef363ff6c2c9962b8a6dac2..3e918af41fb137215dc0b85971ea6e6990c7f2b8 100644 --- a/arch/powerpc/boot/dts/mpc8349emitxgp.dts +++ b/arch/powerpc/boot/dts/mpc8349emitxgp.dts @@ -163,6 +163,10 @@ reg = <0x1c>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -174,6 +178,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy1c>; linux,network-index = <0>; }; diff --git a/arch/powerpc/boot/dts/mpc834x_mds.dts b/arch/powerpc/boot/dts/mpc834x_mds.dts index c986c541e9bba8b9d013ede8db8e2017dc9ee6ee..d9adba01c09c7564898dca8bd5a2f3fd9e1e9c26 100644 --- a/arch/powerpc/boot/dts/mpc834x_mds.dts +++ b/arch/powerpc/boot/dts/mpc834x_mds.dts @@ -185,8 +185,25 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -196,6 +213,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; linux,network-index = <0>; }; @@ -209,6 +227,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 0x8 36 0x8 37 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; linux,network-index = <1>; }; diff --git a/arch/powerpc/boot/dts/mpc8377_mds.dts b/arch/powerpc/boot/dts/mpc8377_mds.dts index 0484561bd2c022aab258f40a2ea523144c663339..1d14d7052e6d534711ae067fe3dee07b89f6ed84 100644 --- a/arch/powerpc/boot/dts/mpc8377_mds.dts +++ b/arch/powerpc/boot/dts/mpc8377_mds.dts @@ -193,8 +193,25 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -205,6 +222,7 @@ interrupts = <32 0x8 33 0x8 34 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -218,6 +236,7 @@ interrupts = <35 0x8 36 0x8 37 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy3>; }; diff --git a/arch/powerpc/boot/dts/mpc8377_rdb.dts b/arch/powerpc/boot/dts/mpc8377_rdb.dts index 435ef3dd022d0f3614f85e7bbcffced5c0102cd7..31f348fdfe148d5ff35acf920e8e5766bf0ab0c2 100644 --- a/arch/powerpc/boot/dts/mpc8377_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8377_rdb.dts @@ -211,8 +211,25 @@ reg = <0x2>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -223,6 +240,7 @@ interrupts = <32 0x8 33 0x8 34 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -237,6 +255,7 @@ phy-connection-type = "mii"; interrupt-parent = <&ipic>; fixed-link = <1 1 1000 0 0>; + tbi-handle = <&tbi1>; }; serial0: serial@4500 { diff --git a/arch/powerpc/boot/dts/mpc8378_mds.dts b/arch/powerpc/boot/dts/mpc8378_mds.dts index 67a08d2e2ff254fff684ecfc550cd73e680f0318..b85fc02682d250991d3af01c3966dcd859704901 100644 --- a/arch/powerpc/boot/dts/mpc8378_mds.dts +++ b/arch/powerpc/boot/dts/mpc8378_mds.dts @@ -232,8 +232,25 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -244,6 +261,7 @@ interrupts = <32 0x8 33 0x8 34 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -257,6 +275,7 @@ interrupts = <35 0x8 36 0x8 37 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy3>; }; diff --git a/arch/powerpc/boot/dts/mpc8378_rdb.dts b/arch/powerpc/boot/dts/mpc8378_rdb.dts index b11e68f56a0612d302ce61bee6d2c56f03f01f3b..7a2bad038bd611926b1acdf48b5820ef203bd782 100644 --- a/arch/powerpc/boot/dts/mpc8378_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8378_rdb.dts @@ -211,8 +211,25 @@ reg = <0x2>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; diff --git a/arch/powerpc/boot/dts/mpc8379_mds.dts b/arch/powerpc/boot/dts/mpc8379_mds.dts index 323370a2b5ff6fa38266e593b66110f8230fc33c..acf06c438dbf60bc5beb736a373ec7b24ce5a0af 100644 --- a/arch/powerpc/boot/dts/mpc8379_mds.dts +++ b/arch/powerpc/boot/dts/mpc8379_mds.dts @@ -232,6 +232,22 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -244,6 +260,7 @@ interrupts = <32 0x8 33 0x8 34 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -257,6 +274,7 @@ interrupts = <35 0x8 36 0x8 37 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy3>; }; diff --git a/arch/powerpc/boot/dts/mpc8379_rdb.dts b/arch/powerpc/boot/dts/mpc8379_rdb.dts index 337af6ea26d3817247543fa94ddddba9ee135ee9..e067616f3f42ed69995ac7ec9f682669e218b6e7 100644 --- a/arch/powerpc/boot/dts/mpc8379_rdb.dts +++ b/arch/powerpc/boot/dts/mpc8379_rdb.dts @@ -211,6 +211,22 @@ reg = <0x2>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -223,6 +239,7 @@ interrupts = <32 0x8 33 0x8 34 0x8>; phy-connection-type = "mii"; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -237,6 +254,7 @@ phy-connection-type = "mii"; interrupt-parent = <&ipic>; fixed-link = <1 1 1000 0 0>; + tbi-handle = <&tbi1>; }; serial0: serial@4500 { diff --git a/arch/powerpc/boot/dts/mpc8536ds.dts b/arch/powerpc/boot/dts/mpc8536ds.dts index 35db1e5440c7631928562337ac2f043f82e6f55a..3c905df1812ca1d50844e50f857d974505f12618 100644 --- a/arch/powerpc/boot/dts/mpc8536ds.dts +++ b/arch/powerpc/boot/dts/mpc8536ds.dts @@ -155,6 +155,22 @@ reg = <1>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; usb@22000 { @@ -186,6 +202,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; @@ -199,6 +216,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy0>; phy-connection-type = "rgmii-id"; }; diff --git a/arch/powerpc/boot/dts/mpc8540ads.dts b/arch/powerpc/boot/dts/mpc8540ads.dts index 9568bfaff8f74aab49f18c3526edbfa5655b9a13..79570ffe41b9e46179779044b8df213ed195cc34 100644 --- a/arch/powerpc/boot/dts/mpc8540ads.dts +++ b/arch/powerpc/boot/dts/mpc8540ads.dts @@ -150,6 +150,34 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -161,6 +189,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -173,6 +202,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; @@ -185,6 +215,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <41 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy3>; }; diff --git a/arch/powerpc/boot/dts/mpc8541cds.dts b/arch/powerpc/boot/dts/mpc8541cds.dts index 6480f4fd96e09f3d7f7a7cab0a5b0daa0c68c6b5..221036a8ce236ca1a808274a0a9c874ba8cfb703 100644 --- a/arch/powerpc/boot/dts/mpc8541cds.dts +++ b/arch/powerpc/boot/dts/mpc8541cds.dts @@ -144,6 +144,22 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -155,6 +171,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -167,6 +184,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/mpc8544ds.dts b/arch/powerpc/boot/dts/mpc8544ds.dts index f1fb20737e3ef35db6bfb247e7953cce2dbb6ca2..b9da42105066d37bd7a9432d530127a1d8aa100b 100644 --- a/arch/powerpc/boot/dts/mpc8544ds.dts +++ b/arch/powerpc/boot/dts/mpc8544ds.dts @@ -116,8 +116,26 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + dma@21300 { #address-cells = <1>; #size-cells = <1>; @@ -169,6 +187,7 @@ interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; phy-handle = <&phy0>; + tbi-handle = <&tbi0>; phy-connection-type = "rgmii-id"; }; @@ -182,6 +201,7 @@ interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; phy-handle = <&phy1>; + tbi-handle = <&tbi1>; phy-connection-type = "rgmii-id"; }; diff --git a/arch/powerpc/boot/dts/mpc8548cds.dts b/arch/powerpc/boot/dts/mpc8548cds.dts index 431b496270dc47359e323f79e6e36e1049e9599f..df774a7088ffd409d8f3e3e921bbdab2d8287ee3 100644 --- a/arch/powerpc/boot/dts/mpc8548cds.dts +++ b/arch/powerpc/boot/dts/mpc8548cds.dts @@ -172,6 +172,46 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -183,6 +223,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -195,6 +236,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; @@ -208,6 +250,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy2>; }; @@ -220,6 +263,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy3>; }; */ diff --git a/arch/powerpc/boot/dts/mpc8555cds.dts b/arch/powerpc/boot/dts/mpc8555cds.dts index d833a5c4f4766508988d716b6426eff4677c8049..053b01e1c93bf4d5603098a1d61098b1c225322c 100644 --- a/arch/powerpc/boot/dts/mpc8555cds.dts +++ b/arch/powerpc/boot/dts/mpc8555cds.dts @@ -144,6 +144,22 @@ reg = <0x1>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -155,6 +171,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -167,6 +184,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/mpc8560ads.dts b/arch/powerpc/boot/dts/mpc8560ads.dts index 4d1f2f28409439d118a552f97103bb861bc55946..11b1bcbe14cedaf47e297265bde1230fbcb84a1c 100644 --- a/arch/powerpc/boot/dts/mpc8560ads.dts +++ b/arch/powerpc/boot/dts/mpc8560ads.dts @@ -145,6 +145,22 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -156,6 +172,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -168,6 +185,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/mpc8568mds.dts b/arch/powerpc/boot/dts/mpc8568mds.dts index c80158f7741db22f93c3f969492c10c706e18bb1..1955bd9e113d9d605d7264f790f669197a715074 100644 --- a/arch/powerpc/boot/dts/mpc8568mds.dts +++ b/arch/powerpc/boot/dts/mpc8568mds.dts @@ -179,6 +179,22 @@ reg = <0x3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -190,6 +206,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -202,6 +219,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy3>; }; diff --git a/arch/powerpc/boot/dts/mpc8572ds.dts b/arch/powerpc/boot/dts/mpc8572ds.dts index 5c69b2fafd32c588e64b0bb1ec1f257010477b18..05f67253b49fcf54e18d2a848c8bdf2ee71e6e7c 100644 --- a/arch/powerpc/boot/dts/mpc8572ds.dts +++ b/arch/powerpc/boot/dts/mpc8572ds.dts @@ -225,6 +225,47 @@ interrupts = <10 1>; reg = <0x3>; }; + + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -236,6 +277,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; phy-connection-type = "rgmii-id"; }; @@ -249,6 +291,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; @@ -262,6 +305,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy2>; phy-connection-type = "rgmii-id"; }; @@ -275,6 +319,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy3>; phy-connection-type = "rgmii-id"; }; diff --git a/arch/powerpc/boot/dts/mpc8641_hpcn.dts b/arch/powerpc/boot/dts/mpc8641_hpcn.dts index d665e767822a8cfcd2d8371721f5c320c6325034..35d5e248ccd7939768ce2bd14e8a54cc5101353f 100644 --- a/arch/powerpc/boot/dts/mpc8641_hpcn.dts +++ b/arch/powerpc/boot/dts/mpc8641_hpcn.dts @@ -205,8 +205,49 @@ reg = <3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; + enet0: ethernet@24000 { cell-index = <0>; device_type = "network"; @@ -216,6 +257,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; phy-connection-type = "rgmii-id"; }; @@ -229,6 +271,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; @@ -242,6 +285,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy2>; phy-connection-type = "rgmii-id"; }; @@ -255,6 +299,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy3>; phy-connection-type = "rgmii-id"; }; diff --git a/arch/powerpc/boot/dts/sbc8349.dts b/arch/powerpc/boot/dts/sbc8349.dts index 0f941f310e444ae2d209f8195b7f71525cb07ad4..8d365a57ebc122bbc4aefce181a30c1ae638daa7 100644 --- a/arch/powerpc/boot/dts/sbc8349.dts +++ b/arch/powerpc/boot/dts/sbc8349.dts @@ -177,6 +177,22 @@ reg = <0x1a>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -188,6 +204,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <32 0x8 33 0x8 34 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; linux,network-index = <0>; }; @@ -201,6 +218,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 0x8 36 0x8 37 0x8>; interrupt-parent = <&ipic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; linux,network-index = <1>; }; diff --git a/arch/powerpc/boot/dts/sbc8548.dts b/arch/powerpc/boot/dts/sbc8548.dts index 333552b4e90dd1d417ebe31cbf3c5ef0d248aab2..2baf4a51f224a9c7a63792182a0d837d6fad4624 100644 --- a/arch/powerpc/boot/dts/sbc8548.dts +++ b/arch/powerpc/boot/dts/sbc8548.dts @@ -252,6 +252,22 @@ reg = <0x1a>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -263,6 +279,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -275,6 +292,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/sbc8560.dts b/arch/powerpc/boot/dts/sbc8560.dts index db3632ef9888f3270a4885ba647f88bceb9c8ac8..01542f7062abf7d6cb428ac9eadefbd8e117adab 100644 --- a/arch/powerpc/boot/dts/sbc8560.dts +++ b/arch/powerpc/boot/dts/sbc8560.dts @@ -168,6 +168,22 @@ reg = <0x1c>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -179,6 +195,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x1d 0x2 0x1e 0x2 0x22 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; }; @@ -191,6 +208,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <0x23 0x2 0x24 0x2 0x28 0x2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/sbc8641d.dts b/arch/powerpc/boot/dts/sbc8641d.dts index 9652456158fbac84db0da31f7e7825e61bcabd9f..36db981548e4754768ecbc4c69f780d4a7b46381 100644 --- a/arch/powerpc/boot/dts/sbc8641d.dts +++ b/arch/powerpc/boot/dts/sbc8641d.dts @@ -222,6 +222,46 @@ reg = <2>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -233,6 +273,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy0>; phy-connection-type = "rgmii-id"; }; @@ -246,6 +287,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; phy-connection-type = "rgmii-id"; }; @@ -259,6 +301,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy2>; phy-connection-type = "rgmii-id"; }; @@ -272,6 +315,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy3>; phy-connection-type = "rgmii-id"; }; diff --git a/arch/powerpc/boot/dts/stx_gp3_8560.dts b/arch/powerpc/boot/dts/stx_gp3_8560.dts index fcd1db6ca0a8e10ea0860c349e75882ac9c473fb..fff33fe6efc61211449673e24f9fc85f4a21d7b8 100644 --- a/arch/powerpc/boot/dts/stx_gp3_8560.dts +++ b/arch/powerpc/boot/dts/stx_gp3_8560.dts @@ -142,6 +142,22 @@ reg = <4>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -153,6 +169,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -165,6 +182,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy4>; }; diff --git a/arch/powerpc/boot/dts/tqm8540.dts b/arch/powerpc/boot/dts/tqm8540.dts index e1d260b9085eeaaf8a3b3e0620a2a6408d5a145f..a693f01c21aa6874f0688437425da6622094522b 100644 --- a/arch/powerpc/boot/dts/tqm8540.dts +++ b/arch/powerpc/boot/dts/tqm8540.dts @@ -155,6 +155,34 @@ reg = <3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { diff --git a/arch/powerpc/boot/dts/tqm8541.dts b/arch/powerpc/boot/dts/tqm8541.dts index d76441ec5dc72f1599ced341d2356062538da9b5..9e3f5f0dde2002049b531600c52a48f61a53f4a9 100644 --- a/arch/powerpc/boot/dts/tqm8541.dts +++ b/arch/powerpc/boot/dts/tqm8541.dts @@ -154,6 +154,22 @@ reg = <3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -165,6 +181,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -177,6 +194,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/tqm8548-bigflash.dts b/arch/powerpc/boot/dts/tqm8548-bigflash.dts index 4199e89b4e50cdf871ca2ff51f74f3e7be7ba541..15086eb65c507cf039c920ee91d84117b189bb75 100644 --- a/arch/powerpc/boot/dts/tqm8548-bigflash.dts +++ b/arch/powerpc/boot/dts/tqm8548-bigflash.dts @@ -179,6 +179,46 @@ reg = <5>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -190,6 +230,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -202,6 +243,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; @@ -214,6 +256,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy3>; }; @@ -226,6 +269,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy4>; }; diff --git a/arch/powerpc/boot/dts/tqm8548.dts b/arch/powerpc/boot/dts/tqm8548.dts index 58ee4185454b233f32f3bca4195303d7ddd5e20f..b7b65f5e79b654a024c1b1cff191b28d01c65bfb 100644 --- a/arch/powerpc/boot/dts/tqm8548.dts +++ b/arch/powerpc/boot/dts/tqm8548.dts @@ -179,6 +179,46 @@ reg = <5>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@26520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x26520 0x20>; + + tbi2: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@27520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x27520 0x20>; + + tbi3: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -190,6 +230,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -202,6 +243,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; @@ -214,6 +256,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <31 2 32 2 33 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi2>; phy-handle = <&phy3>; }; @@ -226,6 +269,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <37 2 38 2 39 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi3>; phy-handle = <&phy4>; }; diff --git a/arch/powerpc/boot/dts/tqm8555.dts b/arch/powerpc/boot/dts/tqm8555.dts index 6f7ea59c4846e05c783b4076349cc29cb6c09185..cf92b4e7945e3d6fa61b57907929692ac48b29d0 100644 --- a/arch/powerpc/boot/dts/tqm8555.dts +++ b/arch/powerpc/boot/dts/tqm8555.dts @@ -154,6 +154,22 @@ reg = <3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -165,6 +181,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -177,6 +194,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/boot/dts/tqm8560.dts b/arch/powerpc/boot/dts/tqm8560.dts index 3fe35208907b9cfe317d64642223fba9ed8467b5..9e1ab2d2f669b003d7b676a312aac96a0b8bfbe3 100644 --- a/arch/powerpc/boot/dts/tqm8560.dts +++ b/arch/powerpc/boot/dts/tqm8560.dts @@ -156,6 +156,22 @@ reg = <3>; device_type = "ethernet-phy"; }; + tbi0: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; + }; + + mdio@25520 { + #address-cells = <1>; + #size-cells = <0>; + compatible = "fsl,gianfar-tbi"; + reg = <0x25520 0x20>; + + tbi1: tbi-phy@11 { + reg = <0x11>; + device_type = "tbi-phy"; + }; }; enet0: ethernet@24000 { @@ -167,6 +183,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <29 2 30 2 34 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi0>; phy-handle = <&phy2>; }; @@ -179,6 +196,7 @@ local-mac-address = [ 00 00 00 00 00 00 ]; interrupts = <35 2 36 2 40 2>; interrupt-parent = <&mpic>; + tbi-handle = <&tbi1>; phy-handle = <&phy1>; }; diff --git a/arch/powerpc/sysdev/fsl_soc.c b/arch/powerpc/sysdev/fsl_soc.c index 26ecb96f9731dec733b23e6368fb3e0f6cf6d629..115cb16351fd97b3dfcac78fca07634f0f0ba8eb 100644 --- a/arch/powerpc/sysdev/fsl_soc.c +++ b/arch/powerpc/sysdev/fsl_soc.c @@ -207,236 +207,51 @@ static int __init of_add_fixed_phys(void) arch_initcall(of_add_fixed_phys); #endif /* CONFIG_FIXED_PHY */ -static int gfar_mdio_of_init_one(struct device_node *np) -{ - int k; - struct device_node *child = NULL; - struct gianfar_mdio_data mdio_data; - struct platform_device *mdio_dev; - struct resource res; - int ret; - - memset(&res, 0, sizeof(res)); - memset(&mdio_data, 0, sizeof(mdio_data)); - - ret = of_address_to_resource(np, 0, &res); - if (ret) - return ret; - - /* The gianfar device will try to use the same ID created below to find - * this bus, to coordinate register access (since they share). */ - mdio_dev = platform_device_register_simple("fsl-gianfar_mdio", - res.start&0xfffff, &res, 1); - if (IS_ERR(mdio_dev)) - return PTR_ERR(mdio_dev); - - for (k = 0; k < 32; k++) - mdio_data.irq[k] = PHY_POLL; - - while ((child = of_get_next_child(np, child)) != NULL) { - int irq = irq_of_parse_and_map(child, 0); - if (irq != NO_IRQ) { - const u32 *id = of_get_property(child, "reg", NULL); - mdio_data.irq[*id] = irq; - } - } - - ret = platform_device_add_data(mdio_dev, &mdio_data, - sizeof(struct gianfar_mdio_data)); - if (ret) - platform_device_unregister(mdio_dev); - - return ret; -} - -static int __init gfar_mdio_of_init(void) -{ - struct device_node *np = NULL; - - for_each_compatible_node(np, NULL, "fsl,gianfar-mdio") - gfar_mdio_of_init_one(np); - - /* try the deprecated version */ - for_each_compatible_node(np, "mdio", "gianfar"); - gfar_mdio_of_init_one(np); - - return 0; -} - -arch_initcall(gfar_mdio_of_init); - -static const char *gfar_tx_intr = "tx"; -static const char *gfar_rx_intr = "rx"; -static const char *gfar_err_intr = "error"; - -static int __init gfar_of_init(void) +#ifdef CONFIG_PPC_83xx +static int __init mpc83xx_wdt_init(void) { + struct resource r; struct device_node *np; - unsigned int i; - struct platform_device *gfar_dev; - struct resource res; + struct platform_device *dev; + u32 freq = fsl_get_sys_freq(); int ret; - for (np = NULL, i = 0; - (np = of_find_compatible_node(np, "network", "gianfar")) != NULL; - i++) { - struct resource r[4]; - struct device_node *phy, *mdio; - struct gianfar_platform_data gfar_data; - const unsigned int *id; - const char *model; - const char *ctype; - const void *mac_addr; - const phandle *ph; - int n_res = 2; - - if (!of_device_is_available(np)) - continue; - - memset(r, 0, sizeof(r)); - memset(&gfar_data, 0, sizeof(gfar_data)); - - ret = of_address_to_resource(np, 0, &r[0]); - if (ret) - goto err; - - of_irq_to_resource(np, 0, &r[1]); - - model = of_get_property(np, "model", NULL); - - /* If we aren't the FEC we have multiple interrupts */ - if (model && strcasecmp(model, "FEC")) { - r[1].name = gfar_tx_intr; - - r[2].name = gfar_rx_intr; - of_irq_to_resource(np, 1, &r[2]); + np = of_find_compatible_node(NULL, "watchdog", "mpc83xx_wdt"); - r[3].name = gfar_err_intr; - of_irq_to_resource(np, 2, &r[3]); - - n_res += 2; - } - - gfar_dev = - platform_device_register_simple("fsl-gianfar", i, &r[0], - n_res); - - if (IS_ERR(gfar_dev)) { - ret = PTR_ERR(gfar_dev); - goto err; - } - - mac_addr = of_get_mac_address(np); - if (mac_addr) - memcpy(gfar_data.mac_addr, mac_addr, 6); - - if (model && !strcasecmp(model, "TSEC")) - gfar_data.device_flags = - FSL_GIANFAR_DEV_HAS_GIGABIT | - FSL_GIANFAR_DEV_HAS_COALESCE | - FSL_GIANFAR_DEV_HAS_RMON | - FSL_GIANFAR_DEV_HAS_MULTI_INTR; - if (model && !strcasecmp(model, "eTSEC")) - gfar_data.device_flags = - FSL_GIANFAR_DEV_HAS_GIGABIT | - FSL_GIANFAR_DEV_HAS_COALESCE | - FSL_GIANFAR_DEV_HAS_RMON | - FSL_GIANFAR_DEV_HAS_MULTI_INTR | - FSL_GIANFAR_DEV_HAS_CSUM | - FSL_GIANFAR_DEV_HAS_VLAN | - FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; - - ctype = of_get_property(np, "phy-connection-type", NULL); - - /* We only care about rgmii-id. The rest are autodetected */ - if (ctype && !strcmp(ctype, "rgmii-id")) - gfar_data.interface = PHY_INTERFACE_MODE_RGMII_ID; - else - gfar_data.interface = PHY_INTERFACE_MODE_MII; - - if (of_get_property(np, "fsl,magic-packet", NULL)) - gfar_data.device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET; - - ph = of_get_property(np, "phy-handle", NULL); - if (ph == NULL) { - u32 *fixed_link; - - fixed_link = (u32 *)of_get_property(np, "fixed-link", - NULL); - if (!fixed_link) { - ret = -ENODEV; - goto unreg; - } - - snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "0"); - gfar_data.phy_id = fixed_link[0]; - } else { - phy = of_find_node_by_phandle(*ph); - - if (phy == NULL) { - ret = -ENODEV; - goto unreg; - } - - mdio = of_get_parent(phy); - - id = of_get_property(phy, "reg", NULL); - ret = of_address_to_resource(mdio, 0, &res); - if (ret) { - of_node_put(phy); - of_node_put(mdio); - goto unreg; - } - - gfar_data.phy_id = *id; - snprintf(gfar_data.bus_id, MII_BUS_ID_SIZE, "%llx", - (unsigned long long)res.start&0xfffff); + if (!np) { + ret = -ENODEV; + goto nodev; + } - of_node_put(phy); - of_node_put(mdio); - } + memset(&r, 0, sizeof(r)); - /* Get MDIO bus controlled by this eTSEC, if any. Normally only - * eTSEC 1 will control an MDIO bus, not necessarily the same - * bus that its PHY is on ('mdio' above), so we can't just use - * that. What we do is look for a gianfar mdio device that has - * overlapping registers with this device. That's really the - * whole point, to find the device sharing our registers to - * coordinate access with it. - */ - for_each_compatible_node(mdio, NULL, "fsl,gianfar-mdio") { - if (of_address_to_resource(mdio, 0, &res)) - continue; - - if (res.start >= r[0].start && res.end <= r[0].end) { - /* Get the ID the mdio bus platform device was - * registered with. gfar_data.bus_id is - * different because it's for finding a PHY, - * while this is for finding a MII bus. - */ - gfar_data.mdio_bus = res.start&0xfffff; - of_node_put(mdio); - break; - } - } + ret = of_address_to_resource(np, 0, &r); + if (ret) + goto err; - ret = - platform_device_add_data(gfar_dev, &gfar_data, - sizeof(struct - gianfar_platform_data)); - if (ret) - goto unreg; + dev = platform_device_register_simple("mpc83xx_wdt", 0, &r, 1); + if (IS_ERR(dev)) { + ret = PTR_ERR(dev); + goto err; } + ret = platform_device_add_data(dev, &freq, sizeof(freq)); + if (ret) + goto unreg; + + of_node_put(np); return 0; unreg: - platform_device_unregister(gfar_dev); + platform_device_unregister(dev); err: + of_node_put(np); +nodev: return ret; } -arch_initcall(gfar_of_init); +arch_initcall(mpc83xx_wdt_init); +#endif static enum fsl_usb2_phy_modes determine_usb_phy(const char *phy_type) { diff --git a/arch/s390/appldata/appldata_net_sum.c b/arch/s390/appldata/appldata_net_sum.c index 3b746556e1a39ddce7dcac254538c521b3e835a1..fa741f84c5b9b639b5bbadc1adf4893daa50d6e4 100644 --- a/arch/s390/appldata/appldata_net_sum.c +++ b/arch/s390/appldata/appldata_net_sum.c @@ -67,7 +67,6 @@ static void appldata_get_net_sum_data(void *data) int i; struct appldata_net_sum_data *net_data; struct net_device *dev; - struct net_device_stats *stats; unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes, rx_errors, tx_errors, rx_dropped, tx_dropped, collisions; @@ -86,7 +85,8 @@ static void appldata_get_net_sum_data(void *data) collisions = 0; read_lock(&dev_base_lock); for_each_netdev(&init_net, dev) { - stats = dev->get_stats(dev); + const struct net_device_stats *stats = dev_get_stats(dev); + rx_packets += stats->rx_packets; tx_packets += stats->tx_packets; rx_bytes += stats->rx_bytes; diff --git a/arch/sparc64/kernel/idprom.c b/arch/sparc64/kernel/idprom.c index 5b45a808c621da79fcb7211796277c763bbbee5c..a62ff83337cdc16bf9e83ec0d7013de556ab1351 100644 --- a/arch/sparc64/kernel/idprom.c +++ b/arch/sparc64/kernel/idprom.c @@ -42,8 +42,5 @@ void __init idprom_init(void) idprom->id_cksum, calc_idprom_cksum(idprom)); } - printk("Ethernet address: %02x:%02x:%02x:%02x:%02x:%02x\n", - idprom->id_ethaddr[0], idprom->id_ethaddr[1], - idprom->id_ethaddr[2], idprom->id_ethaddr[3], - idprom->id_ethaddr[4], idprom->id_ethaddr[5]); + printk("Ethernet address: %pM\n", idprom->id_ethaddr); } diff --git a/arch/um/drivers/daemon_kern.c b/arch/um/drivers/daemon_kern.c index d53ff52bb40447942cff82fd93d001cfcc7200e1..b4a1522f21575bbdc1142e0c8653edf999f6c651 100644 --- a/arch/um/drivers/daemon_kern.c +++ b/arch/um/drivers/daemon_kern.c @@ -22,7 +22,7 @@ static void daemon_init(struct net_device *dev, void *data) struct daemon_data *dpri; struct daemon_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); dpri = (struct daemon_data *) pri->user; dpri->sock_type = init->sock_type; dpri->ctl_sock = init->ctl_sock; diff --git a/arch/um/drivers/mcast_kern.c b/arch/um/drivers/mcast_kern.c index 8c4378a76d6333d88d14537ae1c9a3b42b099537..ffc6416d5ed7f9af80a2490133050098fb8083aa 100644 --- a/arch/um/drivers/mcast_kern.c +++ b/arch/um/drivers/mcast_kern.c @@ -28,7 +28,7 @@ static void mcast_init(struct net_device *dev, void *data) struct mcast_data *dpri; struct mcast_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); dpri = (struct mcast_data *) pri->user; dpri->addr = init->addr; dpri->port = init->port; diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c index 5b4ca8d93682cf70fe191c16c0c1180d872c8c78..fde510b664d34db07ecab00ea48d285adefd2703 100644 --- a/arch/um/drivers/net_kern.c +++ b/arch/um/drivers/net_kern.c @@ -76,7 +76,7 @@ out: static int uml_net_rx(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int pkt_len; struct sk_buff *skb; @@ -119,7 +119,7 @@ static void uml_dev_close(struct work_struct *work) static irqreturn_t uml_net_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int err; if (!netif_running(dev)) @@ -150,7 +150,7 @@ out: static int uml_net_open(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); int err; if (lp->fd >= 0) { @@ -195,7 +195,7 @@ out: static int uml_net_close(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); netif_stop_queue(dev); @@ -213,7 +213,7 @@ static int uml_net_close(struct net_device *dev) static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); unsigned long flags; int len; @@ -250,7 +250,7 @@ static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *uml_net_get_stats(struct net_device *dev) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); return &lp->stats; } @@ -267,7 +267,7 @@ static void uml_net_tx_timeout(struct net_device *dev) static int uml_net_set_mac(struct net_device *dev, void *addr) { - struct uml_net_private *lp = dev->priv; + struct uml_net_private *lp = netdev_priv(dev); struct sockaddr *hwaddr = addr; spin_lock_irq(&lp->lock); @@ -368,7 +368,7 @@ static void net_device_release(struct device *dev) { struct uml_net *device = dev->driver_data; struct net_device *netdev = device->dev; - struct uml_net_private *lp = netdev->priv; + struct uml_net_private *lp = netdev_priv(netdev); if (lp->remove != NULL) (*lp->remove)(&lp->user); @@ -418,14 +418,9 @@ static void eth_configure(int n, void *init, char *mac, setup_etheraddr(mac, device->mac, dev->name); - printk(KERN_INFO "Netdevice %d ", n); - printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", - device->mac[0], device->mac[1], - device->mac[2], device->mac[3], - device->mac[4], device->mac[5]); - printk(": "); + printk(KERN_INFO "Netdevice %d (%pM) : ", n, device->mac); - lp = dev->priv; + lp = netdev_priv(dev); /* This points to the transport private data. It's still clear, but we * must memset it to 0 *now*. Let's help the drivers. */ memset(lp, 0, size); @@ -735,7 +730,7 @@ static int net_remove(int n, char **error_out) return -ENODEV; dev = device->dev; - lp = dev->priv; + lp = netdev_priv(dev); if (lp->fd > 0) return -EBUSY; unregister_netdev(dev); @@ -766,7 +761,7 @@ static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, if (dev->open != uml_net_open) return NOTIFY_DONE; - lp = dev->priv; + lp = netdev_priv(dev); proc = NULL; switch (event) { diff --git a/arch/um/drivers/pcap_kern.c b/arch/um/drivers/pcap_kern.c index 3a750dd39be12083935c5cdbb9633f9a3b786cfd..2860525f8ff6d56219e81dd2fe7afa8f3c627c35 100644 --- a/arch/um/drivers/pcap_kern.c +++ b/arch/um/drivers/pcap_kern.c @@ -21,7 +21,7 @@ void pcap_init(struct net_device *dev, void *data) struct pcap_data *ppri; struct pcap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); ppri = (struct pcap_data *) pri->user; ppri->host_if = init->host_if; ppri->promisc = init->promisc; diff --git a/arch/um/drivers/slip_kern.c b/arch/um/drivers/slip_kern.c index d19faec7046e5cdb05eba59ff32c1c1beb477beb..5ec17563142e22cc6f6ff1e3ec76db23666d3ec9 100644 --- a/arch/um/drivers/slip_kern.c +++ b/arch/um/drivers/slip_kern.c @@ -19,7 +19,7 @@ static void slip_init(struct net_device *dev, void *data) struct slip_data *spri; struct slip_init *init = data; - private = dev->priv; + private = netdev_priv(dev); spri = (struct slip_data *) private->user; memset(spri->name, 0, sizeof(spri->name)); diff --git a/arch/um/drivers/slirp_kern.c b/arch/um/drivers/slirp_kern.c index d987af277db9d8f1cc943aa72ab46201e57cbb58..f15a6e7654f36fdf17af6388172d8273ebb11f71 100644 --- a/arch/um/drivers/slirp_kern.c +++ b/arch/um/drivers/slirp_kern.c @@ -22,7 +22,7 @@ void slirp_init(struct net_device *dev, void *data) struct slirp_init *init = data; int i; - private = dev->priv; + private = netdev_priv(dev); spri = (struct slirp_data *) private->user; spri->argw = init->argw; diff --git a/arch/um/drivers/vde_kern.c b/arch/um/drivers/vde_kern.c index add7e722defb3a8b331a38d11302b6e290e64d9d..1b852bffdebcf019d61c66dda7f4da77e4e1ff1f 100644 --- a/arch/um/drivers/vde_kern.c +++ b/arch/um/drivers/vde_kern.c @@ -19,7 +19,7 @@ static void vde_init(struct net_device *dev, void *data) struct uml_net_private *pri; struct vde_data *vpri; - pri = dev->priv; + pri = netdev_priv(dev); vpri = (struct vde_data *) pri->user; vpri->vde_switch = init->vde_switch; diff --git a/arch/um/os-Linux/drivers/ethertap_kern.c b/arch/um/os-Linux/drivers/ethertap_kern.c index 046a131f61046260c293e12111f30a53266084fd..7f6f9a71aae40e04db6ff38f901589e38aa54906 100644 --- a/arch/um/os-Linux/drivers/ethertap_kern.c +++ b/arch/um/os-Linux/drivers/ethertap_kern.c @@ -22,7 +22,7 @@ static void etap_init(struct net_device *dev, void *data) struct ethertap_data *epri; struct ethertap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); epri = (struct ethertap_data *) pri->user; epri->dev_name = init->dev_name; epri->gate_addr = init->gate_addr; diff --git a/arch/um/os-Linux/drivers/tuntap_kern.c b/arch/um/os-Linux/drivers/tuntap_kern.c index 6b9e33d5de20688d639ace827c57013e76b970ff..4048800e4696a97612b3b2d282a024b3cbd86a96 100644 --- a/arch/um/os-Linux/drivers/tuntap_kern.c +++ b/arch/um/os-Linux/drivers/tuntap_kern.c @@ -21,7 +21,7 @@ static void tuntap_init(struct net_device *dev, void *data) struct tuntap_data *tpri; struct tuntap_init *init = data; - pri = dev->priv; + pri = netdev_priv(dev); tpri = (struct tuntap_data *) pri->user; tpri->dev_name = init->dev_name; tpri->fixed_config = (init->dev_name != NULL); diff --git a/arch/xtensa/platforms/iss/network.c b/arch/xtensa/platforms/iss/network.c index 11a20adc140999b96b5b76f844c9e8fedd00c9f0..64f057d89e7302f929e535d9ca3bbcea7867d91d 100644 --- a/arch/xtensa/platforms/iss/network.c +++ b/arch/xtensa/platforms/iss/network.c @@ -365,7 +365,7 @@ static int tuntap_probe(struct iss_net_private *lp, int index, char *init) static int iss_net_rx(struct net_device *dev) { - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); int pkt_len; struct sk_buff *skb; @@ -456,7 +456,7 @@ static void iss_net_timer(unsigned long priv) static int iss_net_open(struct net_device *dev) { - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); char addr[sizeof "255.255.255.255\0"]; int err; @@ -496,7 +496,7 @@ out: static int iss_net_close(struct net_device *dev) { - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); printk("iss_net_close!\n"); netif_stop_queue(dev); spin_lock(&lp->lock); @@ -515,7 +515,7 @@ printk("iss_net_close!\n"); static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); unsigned long flags; int len; @@ -551,7 +551,7 @@ static int iss_net_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *iss_net_get_stats(struct net_device *dev) { - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); return &lp->stats; } @@ -578,7 +578,7 @@ static void iss_net_tx_timeout(struct net_device *dev) static int iss_net_set_mac(struct net_device *dev, void *addr) { #if 0 - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); struct sockaddr *hwaddr = addr; spin_lock(&lp->lock); @@ -592,7 +592,7 @@ static int iss_net_set_mac(struct net_device *dev, void *addr) static int iss_net_change_mtu(struct net_device *dev, int new_mtu) { #if 0 - struct iss_net_private *lp = dev->priv; + struct iss_net_private *lp = netdev_priv(dev); int err = 0; spin_lock(&lp->lock); @@ -636,7 +636,7 @@ static int iss_net_configure(int index, char *init) /* Initialize private element. */ - lp = dev->priv; + lp = netdev_priv(dev); *lp = ((struct iss_net_private) { .device_list = LIST_HEAD_INIT(lp->device_list), .opened_list = LIST_HEAD_INIT(lp->opened_list), @@ -660,10 +660,7 @@ static int iss_net_configure(int index, char *init) printk(KERN_INFO "Netdevice %d ", index); if (lp->have_mac) - printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", - lp->mac[0], lp->mac[1], - lp->mac[2], lp->mac[3], - lp->mac[4], lp->mac[5]); + printk("(%pM) ", lp->mac); printk(": "); /* sysfs register */ diff --git a/drivers/atm/Kconfig b/drivers/atm/Kconfig index f197a193633aebd3f1f8964c34cbf4c9bffd72b3..191b85e857e0a3f0ef9055c27dd2408812ad1268 100644 --- a/drivers/atm/Kconfig +++ b/drivers/atm/Kconfig @@ -391,4 +391,10 @@ config ATM_HE_USE_SUNI Support for the S/UNI-Ultra and S/UNI-622 found in the ForeRunner HE cards. This driver provides carrier detection some statistics. +config ATM_SOLOS + tristate "Solos ADSL2+ PCI Multiport card driver" + depends on PCI + help + Support for the Solos multiport ADSL2+ card. + endif # ATM diff --git a/drivers/atm/Makefile b/drivers/atm/Makefile index 0bfb31748ecf8495185888789e5009945bc9051f..62c3cc1075ae9239349652d53c114d404e282347 100644 --- a/drivers/atm/Makefile +++ b/drivers/atm/Makefile @@ -12,6 +12,7 @@ obj-$(CONFIG_ATM_IA) += iphase.o suni.o obj-$(CONFIG_ATM_FORE200E) += fore_200e.o obj-$(CONFIG_ATM_ENI) += eni.o suni.o obj-$(CONFIG_ATM_IDT77252) += idt77252.o +obj-$(CONFIG_ATM_SOLOS) += solos-pci.o ifeq ($(CONFIG_ATM_NICSTAR_USE_SUNI),y) obj-$(CONFIG_ATM_NICSTAR) += suni.o diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c new file mode 100644 index 0000000000000000000000000000000000000000..72fc0f799a64e55d81365dba9dd78acca1e86f1d --- /dev/null +++ b/drivers/atm/solos-pci.c @@ -0,0 +1,790 @@ +/* + * Driver for the Solos PCI ADSL2+ card, designed to support Linux by + * Traverse Technologies -- http://www.traverse.com.au/ + * Xrio Limited -- http://www.xrio.com/ + * + * + * Copyright © 2008 Traverse Technologies + * Copyright © 2008 Intel Corporation + * + * Authors: Nathan Williams + * David Woodhouse + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#define DEBUG +#define VERBOSE_DEBUG + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define VERSION "0.04" +#define PTAG "solos-pci" + +#define CONFIG_RAM_SIZE 128 +#define FLAGS_ADDR 0x7C +#define IRQ_EN_ADDR 0x78 +#define FPGA_VER 0x74 +#define IRQ_CLEAR 0x70 +#define BUG_FLAG 0x6C + +#define DATA_RAM_SIZE 32768 +#define BUF_SIZE 4096 + +#define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2) +#define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE) + +static int debug = 0; +static int atmdebug = 0; + +struct pkt_hdr { + __le16 size; + __le16 vpi; + __le16 vci; + __le16 type; +}; + +#define PKT_DATA 0 +#define PKT_COMMAND 1 +#define PKT_POPEN 3 +#define PKT_PCLOSE 4 + +struct solos_card { + void __iomem *config_regs; + void __iomem *buffers; + int nr_ports; + struct pci_dev *dev; + struct atm_dev *atmdev[4]; + struct tasklet_struct tlet; + spinlock_t tx_lock; + spinlock_t tx_queue_lock; + spinlock_t cli_queue_lock; + struct sk_buff_head tx_queue[4]; + struct sk_buff_head cli_queue[4]; +}; + +#define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data) + +MODULE_AUTHOR("Traverse Technologies "); +MODULE_DESCRIPTION("Solos PCI driver"); +MODULE_VERSION(VERSION); +MODULE_LICENSE("GPL"); +MODULE_PARM_DESC(debug, "Enable Loopback"); +MODULE_PARM_DESC(atmdebug, "Print ATM data"); +module_param(debug, int, 0444); +module_param(atmdebug, int, 0444); + +static int opens; + +static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, + struct atm_vcc *vcc); +static int fpga_tx(struct solos_card *); +static irqreturn_t solos_irq(int irq, void *dev_id); +static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci); +static int list_vccs(int vci); +static int atm_init(struct solos_card *); +static void atm_remove(struct solos_card *); +static int send_command(struct solos_card *card, int dev, const char *buf, size_t size); +static void solos_bh(unsigned long); +static int print_buffer(struct sk_buff *buf); + +static inline void solos_pop(struct atm_vcc *vcc, struct sk_buff *skb) +{ + if (vcc->pop) + vcc->pop(vcc, skb); + else + dev_kfree_skb_any(skb); +} + +static ssize_t console_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); + struct solos_card *card = atmdev->dev_data; + struct sk_buff *skb; + + spin_lock(&card->cli_queue_lock); + skb = skb_dequeue(&card->cli_queue[SOLOS_CHAN(atmdev)]); + spin_unlock(&card->cli_queue_lock); + if(skb == NULL) + return sprintf(buf, "No data.\n"); + + memcpy(buf, skb->data, skb->len); + dev_dbg(&card->dev->dev, "len: %d\n", skb->len); + + kfree_skb(skb); + return skb->len; +} + +static int send_command(struct solos_card *card, int dev, const char *buf, size_t size) +{ + struct sk_buff *skb; + struct pkt_hdr *header; + +// dev_dbg(&card->dev->dev, "size: %d\n", size); + + if (size > (BUF_SIZE - sizeof(*header))) { + dev_dbg(&card->dev->dev, "Command is too big. Dropping request\n"); + return 0; + } + skb = alloc_skb(size + sizeof(*header), GFP_ATOMIC); + if (!skb) { + dev_warn(&card->dev->dev, "Failed to allocate sk_buff in send_command()\n"); + return 0; + } + + header = (void *)skb_put(skb, sizeof(*header)); + + header->size = cpu_to_le16(size); + header->vpi = cpu_to_le16(0); + header->vci = cpu_to_le16(0); + header->type = cpu_to_le16(PKT_COMMAND); + + memcpy(skb_put(skb, size), buf, size); + + fpga_queue(card, dev, skb, NULL); + + return 0; +} + +static ssize_t console_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev); + struct solos_card *card = atmdev->dev_data; + int err; + + err = send_command(card, SOLOS_CHAN(atmdev), buf, count); + + return err?:count; +} + +static DEVICE_ATTR(console, 0644, console_show, console_store); + +static irqreturn_t solos_irq(int irq, void *dev_id) +{ + struct solos_card *card = dev_id; + int handled = 1; + + //ACK IRQ + iowrite32(0, card->config_regs + IRQ_CLEAR); + //Disable IRQs from FPGA + iowrite32(0, card->config_regs + IRQ_EN_ADDR); + + /* If we only do it when the device is open, we lose console + messages */ + if (1 || opens) + tasklet_schedule(&card->tlet); + + //Enable IRQs from FPGA + iowrite32(1, card->config_regs + IRQ_EN_ADDR); + return IRQ_RETVAL(handled); +} + +void solos_bh(unsigned long card_arg) +{ + struct solos_card *card = (void *)card_arg; + int port; + uint32_t card_flags; + uint32_t tx_mask; + uint32_t rx_done = 0; + + card_flags = ioread32(card->config_regs + FLAGS_ADDR); + + /* The TX bits are set if the channel is busy; clear if not. We want to + invoke fpga_tx() unless _all_ the bits for active channels are set */ + tx_mask = (1 << card->nr_ports) - 1; + if ((card_flags & tx_mask) != tx_mask) + fpga_tx(card); + + for (port = 0; port < card->nr_ports; port++) { + if (card_flags & (0x10 << port)) { + struct pkt_hdr header; + struct sk_buff *skb; + struct atm_vcc *vcc; + int size; + + rx_done |= 0x10 << port; + + memcpy_fromio(&header, RX_BUF(card, port), sizeof(header)); + + size = le16_to_cpu(header.size); + + skb = alloc_skb(size, GFP_ATOMIC); + if (!skb) { + if (net_ratelimit()) + dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n"); + continue; + } + + memcpy_fromio(skb_put(skb, size), + RX_BUF(card, port) + sizeof(header), + size); + + if (atmdebug) { + dev_info(&card->dev->dev, "Received: device %d\n", port); + dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n", + size, le16_to_cpu(header.vpi), + le16_to_cpu(header.vci)); + print_buffer(skb); + } + + switch (le16_to_cpu(header.type)) { + case PKT_DATA: + vcc = find_vcc(card->atmdev[port], le16_to_cpu(header.vpi), + le16_to_cpu(header.vci)); + if (!vcc) { + if (net_ratelimit()) + dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n", + le16_to_cpu(header.vci), le16_to_cpu(header.vpi), + port); + continue; + } + atm_charge(vcc, skb->truesize); + vcc->push(vcc, skb); + atomic_inc(&vcc->stats->rx); + break; + + case PKT_COMMAND: + default: /* FIXME: Not really, surely? */ + spin_lock(&card->cli_queue_lock); + if (skb_queue_len(&card->cli_queue[port]) > 10) { + if (net_ratelimit()) + dev_warn(&card->dev->dev, "Dropping console response on port %d\n", + port); + } else + skb_queue_tail(&card->cli_queue[port], skb); + spin_unlock(&card->cli_queue_lock); + break; + } + } + } + if (rx_done) + iowrite32(rx_done, card->config_regs + FLAGS_ADDR); + + return; +} + +static struct atm_vcc *find_vcc(struct atm_dev *dev, short vpi, int vci) +{ + struct hlist_head *head; + struct atm_vcc *vcc = NULL; + struct hlist_node *node; + struct sock *s; + + read_lock(&vcc_sklist_lock); + head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; + sk_for_each(s, node, head) { + vcc = atm_sk(s); + if (vcc->dev == dev && vcc->vci == vci && + vcc->vpi == vpi && vcc->qos.rxtp.traffic_class != ATM_NONE) + goto out; + } + vcc = NULL; + out: + read_unlock(&vcc_sklist_lock); + return vcc; +} + +static int list_vccs(int vci) +{ + struct hlist_head *head; + struct atm_vcc *vcc; + struct hlist_node *node; + struct sock *s; + int num_found = 0; + int i; + + read_lock(&vcc_sklist_lock); + if (vci != 0){ + head = &vcc_hash[vci & (VCC_HTABLE_SIZE -1)]; + sk_for_each(s, node, head) { + num_found ++; + vcc = atm_sk(s); + printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", + vcc->dev->number, + vcc->vpi, + vcc->vci); + } + } else { + for(i=0; i<32; i++){ + head = &vcc_hash[i]; + sk_for_each(s, node, head) { + num_found ++; + vcc = atm_sk(s); + printk(KERN_DEBUG "Device: %d Vpi: %d Vci: %d\n", + vcc->dev->number, + vcc->vpi, + vcc->vci); + } + } + } + read_unlock(&vcc_sklist_lock); + return num_found; +} + + +static int popen(struct atm_vcc *vcc) +{ + struct solos_card *card = vcc->dev->dev_data; + struct sk_buff *skb; + struct pkt_hdr *header; + + skb = alloc_skb(sizeof(*header), GFP_ATOMIC); + if (!skb && net_ratelimit()) { + dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n"); + return -ENOMEM; + } + header = (void *)skb_put(skb, sizeof(*header)); + + header->size = cpu_to_le16(sizeof(*header)); + header->vpi = cpu_to_le16(vcc->vpi); + header->vci = cpu_to_le16(vcc->vci); + header->type = cpu_to_le16(PKT_POPEN); + + fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); + +// dev_dbg(&card->dev->dev, "Open for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev)); + set_bit(ATM_VF_ADDR, &vcc->flags); // accept the vpi / vci + set_bit(ATM_VF_READY, &vcc->flags); + list_vccs(0); + + if (!opens) + iowrite32(1, card->config_regs + IRQ_EN_ADDR); + + opens++; //count open PVCs + + return 0; +} + +static void pclose(struct atm_vcc *vcc) +{ + struct solos_card *card = vcc->dev->dev_data; + struct sk_buff *skb; + struct pkt_hdr *header; + + skb = alloc_skb(sizeof(*header), GFP_ATOMIC); + if (!skb) { + dev_warn(&card->dev->dev, "Failed to allocate sk_buff in pclose()\n"); + return; + } + header = (void *)skb_put(skb, sizeof(*header)); + + header->size = cpu_to_le16(sizeof(*header)); + header->vpi = cpu_to_le16(vcc->vpi); + header->vci = cpu_to_le16(vcc->vci); + header->type = cpu_to_le16(PKT_PCLOSE); + + fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL); + +// dev_dbg(&card->dev->dev, "Close for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev)); + if (!--opens) + iowrite32(0, card->config_regs + IRQ_EN_ADDR); + + clear_bit(ATM_VF_ADDR, &vcc->flags); + clear_bit(ATM_VF_READY, &vcc->flags); + + return; +} + +static int print_buffer(struct sk_buff *buf) +{ + int len,i; + char msg[500]; + char item[10]; + + len = buf->len; + for (i = 0; i < len; i++){ + if(i % 8 == 0) + sprintf(msg, "%02X: ", i); + + sprintf(item,"%02X ",*(buf->data + i)); + strcat(msg, item); + if(i % 8 == 7) { + sprintf(item, "\n"); + strcat(msg, item); + printk(KERN_DEBUG "%s", msg); + } + } + if (i % 8 != 0) { + sprintf(item, "\n"); + strcat(msg, item); + printk(KERN_DEBUG "%s", msg); + } + printk(KERN_DEBUG "\n"); + + return 0; +} + +static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb, + struct atm_vcc *vcc) +{ + int old_len; + + *(void **)skb->cb = vcc; + + spin_lock(&card->tx_queue_lock); + old_len = skb_queue_len(&card->tx_queue[port]); + skb_queue_tail(&card->tx_queue[port], skb); + spin_unlock(&card->tx_queue_lock); + + /* If TX might need to be started, do so */ + if (!old_len) + fpga_tx(card); +} + +static int fpga_tx(struct solos_card *card) +{ + uint32_t tx_pending; + uint32_t tx_started = 0; + struct sk_buff *skb; + struct atm_vcc *vcc; + unsigned char port; + unsigned long flags; + + spin_lock_irqsave(&card->tx_lock, flags); + + tx_pending = ioread32(card->config_regs + FLAGS_ADDR); + + dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending); + + for (port = 0; port < card->nr_ports; port++) { + if (!(tx_pending & (1 << port))) { + + spin_lock(&card->tx_queue_lock); + skb = skb_dequeue(&card->tx_queue[port]); + spin_unlock(&card->tx_queue_lock); + + if (!skb) + continue; + + if (atmdebug) { + dev_info(&card->dev->dev, "Transmitted: port %d\n", + port); + print_buffer(skb); + } + memcpy_toio(TX_BUF(card, port), skb->data, skb->len); + + vcc = *(void **)skb->cb; + + if (vcc) { + atomic_inc(&vcc->stats->tx); + solos_pop(vcc, skb); + } else + dev_kfree_skb_irq(skb); + + tx_started |= 1 << port; //Set TX full flag + } + } + if (tx_started) + iowrite32(tx_started, card->config_regs + FLAGS_ADDR); + + spin_unlock_irqrestore(&card->tx_lock, flags); + return 0; +} + +static int psend(struct atm_vcc *vcc, struct sk_buff *skb) +{ + struct solos_card *card = vcc->dev->dev_data; + struct sk_buff *skb2 = NULL; + struct pkt_hdr *header; + + //dev_dbg(&card->dev->dev, "psend called.\n"); + //dev_dbg(&card->dev->dev, "dev,vpi,vci = %d,%d,%d\n",SOLOS_CHAN(vcc->dev),vcc->vpi,vcc->vci); + + if (debug) { + skb2 = atm_alloc_charge(vcc, skb->len, GFP_ATOMIC); + if (skb2) { + memcpy(skb2->data, skb->data, skb->len); + skb_put(skb2, skb->len); + vcc->push(vcc, skb2); + atomic_inc(&vcc->stats->rx); + } + atomic_inc(&vcc->stats->tx); + solos_pop(vcc, skb); + return 0; + } + + if (skb->len > (BUF_SIZE - sizeof(*header))) { + dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n"); + solos_pop(vcc, skb); + return 0; + } + + if (!skb_clone_writable(skb, sizeof(*header))) { + int expand_by = 0; + int ret; + + if (skb_headroom(skb) < sizeof(*header)) + expand_by = sizeof(*header) - skb_headroom(skb); + + ret = pskb_expand_head(skb, expand_by, 0, GFP_ATOMIC); + if (ret) { + solos_pop(vcc, skb); + return ret; + } + } + + header = (void *)skb_push(skb, sizeof(*header)); + + header->size = cpu_to_le16(skb->len); + header->vpi = cpu_to_le16(vcc->vpi); + header->vci = cpu_to_le16(vcc->vci); + header->type = cpu_to_le16(PKT_DATA); + + fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, vcc); + + return 0; +} + +static struct atmdev_ops fpga_ops = { + .open = popen, + .close = pclose, + .ioctl = NULL, + .getsockopt = NULL, + .setsockopt = NULL, + .send = psend, + .send_oam = NULL, + .phy_put = NULL, + .phy_get = NULL, + .change_qos = NULL, + .proc_read = NULL, + .owner = THIS_MODULE +}; + +static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id) +{ + int err, i; + uint16_t fpga_ver; + uint8_t major_ver, minor_ver; + uint32_t data32; + struct solos_card *card; + + if (debug) + return 0; + + card = kzalloc(sizeof(*card), GFP_KERNEL); + if (!card) + return -ENOMEM; + + card->dev = dev; + + err = pci_enable_device(dev); + if (err) { + dev_warn(&dev->dev, "Failed to enable PCI device\n"); + goto out; + } + + err = pci_request_regions(dev, "solos"); + if (err) { + dev_warn(&dev->dev, "Failed to request regions\n"); + goto out; + } + + card->config_regs = pci_iomap(dev, 0, CONFIG_RAM_SIZE); + if (!card->config_regs) { + dev_warn(&dev->dev, "Failed to ioremap config registers\n"); + goto out_release_regions; + } + card->buffers = pci_iomap(dev, 1, DATA_RAM_SIZE); + if (!card->buffers) { + dev_warn(&dev->dev, "Failed to ioremap data buffers\n"); + goto out_unmap_config; + } + +// for(i=0;i<64 ;i+=4){ +// data32=ioread32(card->buffers + i); +// dev_dbg(&card->dev->dev, "%08lX\n",(unsigned long)data32); +// } + + //Fill Config Mem with zeros + for(i = 0; i < 128; i += 4) + iowrite32(0, card->config_regs + i); + + //Set RX empty flags + iowrite32(0xF0, card->config_regs + FLAGS_ADDR); + + data32 = ioread32(card->config_regs + FPGA_VER); + fpga_ver = (data32 & 0x0000FFFF); + major_ver = ((data32 & 0xFF000000) >> 24); + minor_ver = ((data32 & 0x00FF0000) >> 16); + dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n", + major_ver, minor_ver, fpga_ver); + + card->nr_ports = 2; /* FIXME: Detect daughterboard */ + + err = atm_init(card); + if (err) + goto out_unmap_both; + + pci_set_drvdata(dev, card); + tasklet_init(&card->tlet, solos_bh, (unsigned long)card); + spin_lock_init(&card->tx_lock); + spin_lock_init(&card->tx_queue_lock); + spin_lock_init(&card->cli_queue_lock); +/* + // Set Loopback mode + data32 = 0x00010000; + iowrite32(data32,card->config_regs + FLAGS_ADDR); +*/ +/* + // Fill Buffers with zeros + for (i = 0; i < BUF_SIZE * 8; i += 4) + iowrite32(0, card->buffers + i); +*/ +/* + for(i = 0; i < (BUF_SIZE * 1); i += 4) + iowrite32(0x12345678, card->buffers + i + (0*BUF_SIZE)); + for(i = 0; i < (BUF_SIZE * 1); i += 4) + iowrite32(0xabcdef98, card->buffers + i + (1*BUF_SIZE)); + + // Read Config Memory + printk(KERN_DEBUG "Reading Config MEM\n"); + i = 0; + for(i = 0; i < 16; i++) { + data32=ioread32(card->buffers + i*(BUF_SIZE/2)); + printk(KERN_ALERT "Addr: %lX Data: %08lX\n", + (unsigned long)(addr_start + i*(BUF_SIZE/2)), + (unsigned long)data32); + } +*/ + //dev_dbg(&card->dev->dev, "Requesting IRQ: %d\n",dev->irq); + err = request_irq(dev->irq, solos_irq, IRQF_DISABLED|IRQF_SHARED, + "solos-pci", card); + if (err) + dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq); + + // Enable IRQs + iowrite32(1, card->config_regs + IRQ_EN_ADDR); + + return 0; + + out_unmap_both: + pci_iounmap(dev, card->config_regs); + out_unmap_config: + pci_iounmap(dev, card->buffers); + out_release_regions: + pci_release_regions(dev); + out: + return err; +} + +static int atm_init(struct solos_card *card) +{ + int i; + + opens = 0; + + for (i = 0; i < card->nr_ports; i++) { + skb_queue_head_init(&card->tx_queue[i]); + skb_queue_head_init(&card->cli_queue[i]); + + card->atmdev[i] = atm_dev_register("solos-pci", &fpga_ops, -1, NULL); + if (!card->atmdev[i]) { + dev_err(&card->dev->dev, "Could not register ATM device %d\n", i); + atm_remove(card); + return -ENODEV; + } + if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_console)) + dev_err(&card->dev->dev, "Could not register console for ATM device %d\n", i); + + dev_info(&card->dev->dev, "Registered ATM device %d\n", card->atmdev[i]->number); + + card->atmdev[i]->ci_range.vpi_bits = 8; + card->atmdev[i]->ci_range.vci_bits = 16; + card->atmdev[i]->dev_data = card; + card->atmdev[i]->phy_data = (void *)(unsigned long)i; + } + return 0; +} + +static void atm_remove(struct solos_card *card) +{ + int i; + + for (i = 0; i < card->nr_ports; i++) { + if (card->atmdev[i]) { + dev_info(&card->dev->dev, "Unregistering ATM device %d\n", card->atmdev[i]->number); + atm_dev_deregister(card->atmdev[i]); + } + } +} + +static void fpga_remove(struct pci_dev *dev) +{ + struct solos_card *card = pci_get_drvdata(dev); + + if (debug) + return; + + atm_remove(card); + + dev_vdbg(&dev->dev, "Freeing IRQ\n"); + // Disable IRQs from FPGA + iowrite32(0, card->config_regs + IRQ_EN_ADDR); + free_irq(dev->irq, card); + tasklet_kill(&card->tlet); + + // iowrite32(0x01,pciregs); + dev_vdbg(&dev->dev, "Unmapping PCI resource\n"); + pci_iounmap(dev, card->buffers); + pci_iounmap(dev, card->config_regs); + + dev_vdbg(&dev->dev, "Releasing PCI Region\n"); + pci_release_regions(dev); + pci_disable_device(dev); + + pci_set_drvdata(dev, NULL); + kfree(card); +// dev_dbg(&card->dev->dev, "fpga_remove\n"); + return; +} + +static struct pci_device_id fpga_pci_tbl[] __devinitdata = { + { 0x10ee, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci,fpga_pci_tbl); + +static struct pci_driver fpga_driver = { + .name = "solos", + .id_table = fpga_pci_tbl, + .probe = fpga_probe, + .remove = fpga_remove, +}; + + +static int __init solos_pci_init(void) +{ + printk(KERN_INFO "Solos PCI Driver Version %s\n", VERSION); + return pci_register_driver(&fpga_driver); +} + +static void __exit solos_pci_exit(void) +{ + pci_unregister_driver(&fpga_driver); + printk(KERN_INFO "Solos PCI Driver %s Unloaded\n", VERSION); +} + +module_init(solos_pci_init); +module_exit(solos_pci_exit); diff --git a/drivers/block/aoe/aoe.h b/drivers/block/aoe/aoe.h index 93f3690396a5176de5cec3fb3151ef9e1670299d..c237527b1aa59880b272a13bc8d0a17d6206ca2a 100644 --- a/drivers/block/aoe/aoe.h +++ b/drivers/block/aoe/aoe.h @@ -200,4 +200,3 @@ void aoenet_xmit(struct sk_buff_head *); int is_aoe_netif(struct net_device *ifp); int set_aoe_iflist(const char __user *str, size_t size); -unsigned long long mac_addr(char addr[6]); diff --git a/drivers/block/aoe/aoeblk.c b/drivers/block/aoe/aoeblk.c index 1747dd272cd476bd1c14b03be0ee0c8f5faf17dd..2307a271bdc99e91b5c410083383a0595c4c08d0 100644 --- a/drivers/block/aoe/aoeblk.c +++ b/drivers/block/aoe/aoeblk.c @@ -37,7 +37,7 @@ static ssize_t aoedisk_show_mac(struct device *dev, if (t == NULL) return snprintf(page, PAGE_SIZE, "none\n"); - return snprintf(page, PAGE_SIZE, "%012llx\n", mac_addr(t->addr)); + return snprintf(page, PAGE_SIZE, "%pm\n", t->addr); } static ssize_t aoedisk_show_netif(struct device *dev, struct device_attribute *attr, char *page) diff --git a/drivers/block/aoe/aoecmd.c b/drivers/block/aoe/aoecmd.c index 71ff78c9e4d6c24a3d752cc35956645aa752eb34..45c5a33daf498d623e9749bd75e8f4bf94a9e49e 100644 --- a/drivers/block/aoe/aoecmd.c +++ b/drivers/block/aoe/aoecmd.c @@ -349,11 +349,9 @@ resend(struct aoedev *d, struct aoetgt *t, struct frame *f) ah = (struct aoe_atahdr *) (h+1); snprintf(buf, sizeof buf, - "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x " - "s=%012llx d=%012llx nout=%d\n", + "%15s e%ld.%d oldtag=%08x@%08lx newtag=%08x s=%pm d=%pm nout=%d\n", "retransmit", d->aoemajor, d->aoeminor, f->tag, jiffies, n, - mac_addr(h->src), - mac_addr(h->dst), t->nout); + h->src, h->dst, t->nout); aoechr_error(buf); f->tag = n; @@ -544,10 +542,10 @@ rexmit_timer(ulong vp) printk(KERN_INFO "aoe: e%ld.%d: " "too many lost jumbo on " - "%s:%012llx - " + "%s:%pm - " "falling back to %d frames.\n", d->aoemajor, d->aoeminor, - ifp->nd->name, mac_addr(t->addr), + ifp->nd->name, t->addr, DEFAULTBCNT); ifp->maxbcnt = 0; } @@ -672,8 +670,8 @@ ataid_complete(struct aoedev *d, struct aoetgt *t, unsigned char *id) if (d->ssize != ssize) printk(KERN_INFO - "aoe: %012llx e%ld.%d v%04x has %llu sectors\n", - mac_addr(t->addr), + "aoe: %pm e%ld.%d v%04x has %llu sectors\n", + t->addr, d->aoemajor, d->aoeminor, d->fw_ver, (long long)ssize); d->ssize = ssize; @@ -775,8 +773,8 @@ aoecmd_ata_rsp(struct sk_buff *skb) n = get_unaligned_be32(&hin->tag); t = gettgt(d, hin->src); if (t == NULL) { - printk(KERN_INFO "aoe: can't find target e%ld.%d:%012llx\n", - d->aoemajor, d->aoeminor, mac_addr(hin->src)); + printk(KERN_INFO "aoe: can't find target e%ld.%d:%pm\n", + d->aoemajor, d->aoeminor, hin->src); spin_unlock_irqrestore(&d->lock, flags); return; } @@ -1036,10 +1034,10 @@ aoecmd_cfg_rsp(struct sk_buff *skb) n = n ? n * 512 : DEFAULTBCNT; if (n != ifp->maxbcnt) { printk(KERN_INFO - "aoe: e%ld.%d: setting %d%s%s:%012llx\n", + "aoe: e%ld.%d: setting %d%s%s:%pm\n", d->aoemajor, d->aoeminor, n, " byte data frames on ", ifp->nd->name, - mac_addr(t->addr)); + t->addr); ifp->maxbcnt = n; } } diff --git a/drivers/block/aoe/aoenet.c b/drivers/block/aoe/aoenet.c index 9157d64270cb041ba8b92bc462913439b12018e0..30de5b1c647e80b05007a22f1a4e0b79a38dcad4 100644 --- a/drivers/block/aoe/aoenet.c +++ b/drivers/block/aoe/aoenet.c @@ -83,17 +83,6 @@ set_aoe_iflist(const char __user *user_str, size_t size) return 0; } -unsigned long long -mac_addr(char addr[6]) -{ - __be64 n = 0; - char *p = (char *) &n; - - memcpy(p + 2, addr, 6); /* (sizeof addr != 6) */ - - return (unsigned long long) __be64_to_cpu(n); -} - void aoenet_xmit(struct sk_buff_head *queue) { diff --git a/drivers/bluetooth/Kconfig b/drivers/bluetooth/Kconfig index 7cb4029a5375a774ed9c0cc888284d37330b1b17..1164837bb781470730768c37f466a17f091095d3 100644 --- a/drivers/bluetooth/Kconfig +++ b/drivers/bluetooth/Kconfig @@ -2,26 +2,6 @@ menu "Bluetooth device drivers" depends on BT -config BT_HCIUSB - tristate "HCI USB driver (old version)" - depends on USB && BT_HCIBTUSB=n - help - Bluetooth HCI USB driver. - This driver is required if you want to use Bluetooth devices with - USB interface. - - Say Y here to compile support for Bluetooth USB devices into the - kernel or say M to compile it as module (hci_usb). - -config BT_HCIUSB_SCO - bool "SCO (voice) support" - depends on BT_HCIUSB - help - This option enables the SCO support in the HCI USB driver. You need this - to transmit voice data with your Bluetooth USB device. - - Say Y here to compile support for SCO over HCI USB. - config BT_HCIBTUSB tristate "HCI USB driver" depends on USB diff --git a/drivers/bluetooth/Makefile b/drivers/bluetooth/Makefile index 77444afbf107281de422a950d1e0a4ac63469cc0..16930f93d1ca4db6ffaf08df3e2f5fb4132ea076 100644 --- a/drivers/bluetooth/Makefile +++ b/drivers/bluetooth/Makefile @@ -2,7 +2,6 @@ # Makefile for the Linux Bluetooth HCI device drivers. # -obj-$(CONFIG_BT_HCIUSB) += hci_usb.o obj-$(CONFIG_BT_HCIVHCI) += hci_vhci.o obj-$(CONFIG_BT_HCIUART) += hci_uart.o obj-$(CONFIG_BT_HCIBCM203X) += bcm203x.o diff --git a/drivers/bluetooth/bcm203x.c b/drivers/bluetooth/bcm203x.c index ee40201c7278ad94aadf43ac220c1cedfd67c49e..eafd4af0746e7bb2a6004e48604cf86e6ab1c109 100644 --- a/drivers/bluetooth/bcm203x.c +++ b/drivers/bluetooth/bcm203x.c @@ -37,11 +37,6 @@ #include -#ifndef CONFIG_BT_HCIBCM203X_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "1.2" static struct usb_device_id bcm203x_table[] = { @@ -199,7 +194,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id return -EIO; } - BT_DBG("minidrv data %p size %d", firmware->data, firmware->size); + BT_DBG("minidrv data %p size %zu", firmware->data, firmware->size); size = max_t(uint, firmware->size, 4096); @@ -227,7 +222,7 @@ static int bcm203x_probe(struct usb_interface *intf, const struct usb_device_id return -EIO; } - BT_DBG("firmware data %p size %d", firmware->data, firmware->size); + BT_DBG("firmware data %p size %zu", firmware->data, firmware->size); data->fw_data = kmalloc(firmware->size, GFP_KERNEL); if (!data->fw_data) { diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c index 90a0946346303c4d654afd215bfbcda2c9e66f1b..d3f14bee0f1939fcb1ff0261e6018b0f99e1689e 100644 --- a/drivers/bluetooth/bfusb.c +++ b/drivers/bluetooth/bfusb.c @@ -38,11 +38,6 @@ #include #include -#ifndef CONFIG_BT_HCIBFUSB_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "1.2" static struct usb_driver bfusb_driver; @@ -221,7 +216,7 @@ static int bfusb_rx_submit(struct bfusb_data *data, struct urb *urb) struct sk_buff *skb; int err, pipe, size = HCI_MAX_FRAME_SIZE + 32; - BT_DBG("bfusb %p urb %p", bfusb, urb); + BT_DBG("bfusb %p urb %p", data, urb); if (!urb && !(urb = usb_alloc_urb(0, GFP_ATOMIC))) return -ENOMEM; @@ -354,7 +349,7 @@ static void bfusb_rx_complete(struct urb *urb) int count = urb->actual_length; int err, hdr, len; - BT_DBG("bfusb %p urb %p skb %p len %d", bfusb, urb, skb, skb->len); + BT_DBG("bfusb %p urb %p skb %p len %d", data, urb, skb, skb->len); read_lock(&data->lock); @@ -691,7 +686,7 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i goto error; } - BT_DBG("firmware data %p size %d", firmware->data, firmware->size); + BT_DBG("firmware data %p size %zu", firmware->data, firmware->size); if (bfusb_load_firmware(data, firmware->data, firmware->size) < 0) { BT_ERR("Firmware loading failed"); diff --git a/drivers/bluetooth/bpa10x.c b/drivers/bluetooth/bpa10x.c index b936d8ce2728836c2ba3c214a2cf93960886187f..c115285867c3010495b74da4b7eccfd910e518cb 100644 --- a/drivers/bluetooth/bpa10x.c +++ b/drivers/bluetooth/bpa10x.c @@ -35,11 +35,6 @@ #include #include -#ifndef CONFIG_BT_HCIBPA10X_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "0.10" static struct usb_device_id bpa10x_table[] = { @@ -489,6 +484,8 @@ static int bpa10x_probe(struct usb_interface *intf, const struct usb_device_id * hdev->owner = THIS_MODULE; + set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + err = hci_register_dev(hdev); if (err < 0) { hci_free_dev(hdev); diff --git a/drivers/bluetooth/bt3c_cs.c b/drivers/bluetooth/bt3c_cs.c index b3e4d07a4ac2b75bd73a1caf3c91be36c8124a62..ff195c23082587e03a957043cb48dd009984d745 100644 --- a/drivers/bluetooth/bt3c_cs.c +++ b/drivers/bluetooth/bt3c_cs.c @@ -502,15 +502,15 @@ static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware, memset(b, 0, sizeof(b)); memcpy(b, ptr + 2, 2); - size = simple_strtol(b, NULL, 16); + size = simple_strtoul(b, NULL, 16); memset(b, 0, sizeof(b)); memcpy(b, ptr + 4, 8); - addr = simple_strtol(b, NULL, 16); + addr = simple_strtoul(b, NULL, 16); memset(b, 0, sizeof(b)); memcpy(b, ptr + (size * 2) + 2, 2); - fcs = simple_strtol(b, NULL, 16); + fcs = simple_strtoul(b, NULL, 16); memset(b, 0, sizeof(b)); for (tmp = 0, i = 0; i < size; i++) { @@ -530,7 +530,7 @@ static int bt3c_load_firmware(bt3c_info_t *info, const unsigned char *firmware, memset(b, 0, sizeof(b)); for (i = 0; i < (size - 4) / 2; i++) { memcpy(b, ptr + (i * 4) + 12, 4); - tmp = simple_strtol(b, NULL, 16); + tmp = simple_strtoul(b, NULL, 16); bt3c_put(iobase, tmp); } } diff --git a/drivers/bluetooth/btsdio.c b/drivers/bluetooth/btsdio.c index cda6c7cc944b1470a00ab1bafc8942236417b30a..7e298275c8f663b45fc04f57e5499c9f372b62d5 100644 --- a/drivers/bluetooth/btsdio.c +++ b/drivers/bluetooth/btsdio.c @@ -37,11 +37,6 @@ #include #include -#ifndef CONFIG_BT_HCIBTSDIO_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "0.1" static const struct sdio_device_id btsdio_table[] = { @@ -91,6 +86,7 @@ static int btsdio_tx_packet(struct btsdio_data *data, struct sk_buff *skb) err = sdio_writesb(data->func, REG_TDAT, skb->data, skb->len); if (err < 0) { + skb_pull(skb, 4); sdio_writeb(data->func, 0x01, REG_PC_WRT, NULL); return err; } diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c index af472e05273296e664e8ddcb7fa443f4bc0e60e8..b5fbda6d490a4a142e5a11936b3e14260a09d3de 100644 --- a/drivers/bluetooth/btusb.c +++ b/drivers/bluetooth/btusb.c @@ -35,31 +35,25 @@ #include #include -//#define CONFIG_BT_HCIBTUSB_DEBUG -#ifndef CONFIG_BT_HCIBTUSB_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - -#define VERSION "0.3" +#define VERSION "0.4" static int ignore_dga; static int ignore_csr; static int ignore_sniffer; static int disable_scofix; static int force_scofix; -static int reset; + +static int reset = 1; static struct usb_driver btusb_driver; #define BTUSB_IGNORE 0x01 -#define BTUSB_RESET 0x02 -#define BTUSB_DIGIANSWER 0x04 -#define BTUSB_CSR 0x08 -#define BTUSB_SNIFFER 0x10 -#define BTUSB_BCM92035 0x20 -#define BTUSB_BROKEN_ISOC 0x40 -#define BTUSB_WRONG_SCO_MTU 0x80 +#define BTUSB_DIGIANSWER 0x02 +#define BTUSB_CSR 0x04 +#define BTUSB_SNIFFER 0x08 +#define BTUSB_BCM92035 0x10 +#define BTUSB_BROKEN_ISOC 0x20 +#define BTUSB_WRONG_SCO_MTU 0x40 static struct usb_device_id btusb_table[] = { /* Generic Bluetooth USB device */ @@ -79,7 +73,7 @@ static struct usb_device_id btusb_table[] = { { USB_DEVICE(0x0bdb, 0x1002) }, /* Canyon CN-BTU1 with HID interfaces */ - { USB_DEVICE(0x0c10, 0x0000), .driver_info = BTUSB_RESET }, + { USB_DEVICE(0x0c10, 0x0000) }, { } /* Terminating entry */ }; @@ -94,52 +88,37 @@ static struct usb_device_id blacklist_table[] = { { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE }, /* Broadcom BCM2035 */ - { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2009), .driver_info = BTUSB_BCM92035 }, /* Broadcom BCM2045 */ - { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - - /* Broadcom BCM2046 */ - { USB_DEVICE(0x0a5c, 0x2146), .driver_info = BTUSB_RESET }, - { USB_DEVICE(0x0a5c, 0x2151), .driver_info = BTUSB_RESET }, - - /* Apple MacBook Pro with Broadcom chip */ - { USB_DEVICE(0x05ac, 0x820f), .driver_info = BTUSB_RESET }, + { USB_DEVICE(0x0a5c, 0x2039), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2101), .driver_info = BTUSB_WRONG_SCO_MTU }, /* IBM/Lenovo ThinkPad with Broadcom chip */ - { USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - - /* Targus ACB10US */ - { USB_DEVICE(0x0a5c, 0x2100), .driver_info = BTUSB_RESET }, - { USB_DEVICE(0x0a5c, 0x2154), .driver_info = BTUSB_RESET }, - - /* ANYCOM Bluetooth USB-200 and USB-250 */ - { USB_DEVICE(0x0a5c, 0x2111), .driver_info = BTUSB_RESET }, + { USB_DEVICE(0x0a5c, 0x201e), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x0a5c, 0x2110), .driver_info = BTUSB_WRONG_SCO_MTU }, /* HP laptop with Broadcom chip */ - { USB_DEVICE(0x03f0, 0x171d), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x03f0, 0x171d), .driver_info = BTUSB_WRONG_SCO_MTU }, /* Dell laptop with Broadcom chip */ - { USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x413c, 0x8126), .driver_info = BTUSB_WRONG_SCO_MTU }, - /* Dell Wireless 370 */ - { USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, + /* Dell Wireless 370 and 410 devices */ + { USB_DEVICE(0x413c, 0x8152), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x413c, 0x8156), .driver_info = BTUSB_WRONG_SCO_MTU }, - /* Dell Wireless 410 */ - { USB_DEVICE(0x413c, 0x8152), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, + /* Belkin F8T012 and F8T013 devices */ + { USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_WRONG_SCO_MTU }, + { USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_WRONG_SCO_MTU }, - /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ - { USB_DEVICE(0x045e, 0x009c), .driver_info = BTUSB_RESET }, + /* Asus WL-BTD202 device */ + { USB_DEVICE(0x0b05, 0x1715), .driver_info = BTUSB_WRONG_SCO_MTU }, /* Kensington Bluetooth USB adapter */ - { USB_DEVICE(0x047d, 0x105d), .driver_info = BTUSB_RESET }, - { USB_DEVICE(0x047d, 0x105e), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - - /* ISSC Bluetooth Adapter v3.1 */ - { USB_DEVICE(0x1131, 0x1001), .driver_info = BTUSB_RESET }, + { USB_DEVICE(0x047d, 0x105e), .driver_info = BTUSB_WRONG_SCO_MTU }, /* RTX Telecom based adapters with buggy SCO support */ { USB_DEVICE(0x0400, 0x0807), .driver_info = BTUSB_BROKEN_ISOC }, @@ -148,13 +127,6 @@ static struct usb_device_id blacklist_table[] = { /* CONWISE Technology based adapters with buggy SCO support */ { USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC }, - /* Belkin F8T012 and F8T013 devices */ - { USB_DEVICE(0x050d, 0x0012), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - { USB_DEVICE(0x050d, 0x0013), .driver_info = BTUSB_RESET | BTUSB_WRONG_SCO_MTU }, - - /* Belkin F8T016 device */ - { USB_DEVICE(0x050d, 0x016a), .driver_info = BTUSB_RESET }, - /* Digianswer devices */ { USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER }, { USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE }, @@ -197,7 +169,10 @@ struct btusb_data { struct usb_endpoint_descriptor *isoc_tx_ep; struct usb_endpoint_descriptor *isoc_rx_ep; + __u8 cmdreq_type; + int isoc_altsetting; + int suspend_count; }; static void btusb_intr_complete(struct urb *urb) @@ -236,7 +211,7 @@ static void btusb_intr_complete(struct urb *urb) } } -static int btusb_submit_intr_urb(struct hci_dev *hdev) +static int btusb_submit_intr_urb(struct hci_dev *hdev, gfp_t mem_flags) { struct btusb_data *data = hdev->driver_data; struct urb *urb; @@ -249,13 +224,13 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev) if (!data->intr_ep) return -ENODEV; - urb = usb_alloc_urb(0, GFP_ATOMIC); + urb = usb_alloc_urb(0, mem_flags); if (!urb) return -ENOMEM; size = le16_to_cpu(data->intr_ep->wMaxPacketSize); - buf = kmalloc(size, GFP_ATOMIC); + buf = kmalloc(size, mem_flags); if (!buf) { usb_free_urb(urb); return -ENOMEM; @@ -271,7 +246,7 @@ static int btusb_submit_intr_urb(struct hci_dev *hdev) usb_anchor_urb(urb, &data->intr_anchor); - err = usb_submit_urb(urb, GFP_ATOMIC); + err = usb_submit_urb(urb, mem_flags); if (err < 0) { BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); @@ -319,7 +294,7 @@ static void btusb_bulk_complete(struct urb *urb) } } -static int btusb_submit_bulk_urb(struct hci_dev *hdev) +static int btusb_submit_bulk_urb(struct hci_dev *hdev, gfp_t mem_flags) { struct btusb_data *data = hdev->driver_data; struct urb *urb; @@ -332,13 +307,13 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev) if (!data->bulk_rx_ep) return -ENODEV; - urb = usb_alloc_urb(0, GFP_KERNEL); + urb = usb_alloc_urb(0, mem_flags); if (!urb) return -ENOMEM; size = le16_to_cpu(data->bulk_rx_ep->wMaxPacketSize); - buf = kmalloc(size, GFP_KERNEL); + buf = kmalloc(size, mem_flags); if (!buf) { usb_free_urb(urb); return -ENOMEM; @@ -353,7 +328,7 @@ static int btusb_submit_bulk_urb(struct hci_dev *hdev) usb_anchor_urb(urb, &data->bulk_anchor); - err = usb_submit_urb(urb, GFP_KERNEL); + err = usb_submit_urb(urb, mem_flags); if (err < 0) { BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); @@ -430,7 +405,7 @@ static void inline __fill_isoc_descriptor(struct urb *urb, int len, int mtu) urb->number_of_packets = i; } -static int btusb_submit_isoc_urb(struct hci_dev *hdev) +static int btusb_submit_isoc_urb(struct hci_dev *hdev, gfp_t mem_flags) { struct btusb_data *data = hdev->driver_data; struct urb *urb; @@ -443,14 +418,14 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev) if (!data->isoc_rx_ep) return -ENODEV; - urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, GFP_KERNEL); + urb = usb_alloc_urb(BTUSB_MAX_ISOC_FRAMES, mem_flags); if (!urb) return -ENOMEM; size = le16_to_cpu(data->isoc_rx_ep->wMaxPacketSize) * BTUSB_MAX_ISOC_FRAMES; - buf = kmalloc(size, GFP_KERNEL); + buf = kmalloc(size, mem_flags); if (!buf) { usb_free_urb(urb); return -ENOMEM; @@ -473,7 +448,7 @@ static int btusb_submit_isoc_urb(struct hci_dev *hdev) usb_anchor_urb(urb, &data->isoc_anchor); - err = usb_submit_urb(urb, GFP_KERNEL); + err = usb_submit_urb(urb, mem_flags); if (err < 0) { BT_ERR("%s urb %p submission failed (%d)", hdev->name, urb, -err); @@ -520,7 +495,7 @@ static int btusb_open(struct hci_dev *hdev) if (test_and_set_bit(BTUSB_INTR_RUNNING, &data->flags)) return 0; - err = btusb_submit_intr_urb(hdev); + err = btusb_submit_intr_urb(hdev, GFP_KERNEL); if (err < 0) { clear_bit(BTUSB_INTR_RUNNING, &data->flags); clear_bit(HCI_RUNNING, &hdev->flags); @@ -589,7 +564,7 @@ static int btusb_send_frame(struct sk_buff *skb) return -ENOMEM; } - dr->bRequestType = USB_TYPE_CLASS; + dr->bRequestType = data->cmdreq_type; dr->bRequest = 0; dr->wIndex = 0; dr->wValue = 0; @@ -680,8 +655,19 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt) BT_DBG("%s evt %d", hdev->name, evt); - if (evt == HCI_NOTIFY_CONN_ADD || evt == HCI_NOTIFY_CONN_DEL) - schedule_work(&data->work); + if (hdev->conn_hash.acl_num > 0) { + if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) { + if (btusb_submit_bulk_urb(hdev, GFP_ATOMIC) < 0) + clear_bit(BTUSB_BULK_RUNNING, &data->flags); + else + btusb_submit_bulk_urb(hdev, GFP_ATOMIC); + } + } else { + clear_bit(BTUSB_BULK_RUNNING, &data->flags); + usb_unlink_anchored_urbs(&data->bulk_anchor); + } + + schedule_work(&data->work); } static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting) @@ -732,18 +718,6 @@ static void btusb_work(struct work_struct *work) struct btusb_data *data = container_of(work, struct btusb_data, work); struct hci_dev *hdev = data->hdev; - if (hdev->conn_hash.acl_num > 0) { - if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) { - if (btusb_submit_bulk_urb(hdev) < 0) - clear_bit(BTUSB_BULK_RUNNING, &data->flags); - else - btusb_submit_bulk_urb(hdev); - } - } else { - clear_bit(BTUSB_BULK_RUNNING, &data->flags); - usb_kill_anchored_urbs(&data->bulk_anchor); - } - if (hdev->conn_hash.sco_num > 0) { if (data->isoc_altsetting != 2) { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); @@ -754,10 +728,10 @@ static void btusb_work(struct work_struct *work) } if (!test_and_set_bit(BTUSB_ISOC_RUNNING, &data->flags)) { - if (btusb_submit_isoc_urb(hdev) < 0) + if (btusb_submit_isoc_urb(hdev, GFP_KERNEL) < 0) clear_bit(BTUSB_ISOC_RUNNING, &data->flags); else - btusb_submit_isoc_urb(hdev); + btusb_submit_isoc_urb(hdev, GFP_KERNEL); } } else { clear_bit(BTUSB_ISOC_RUNNING, &data->flags); @@ -828,6 +802,8 @@ static int btusb_probe(struct usb_interface *intf, return -ENODEV; } + data->cmdreq_type = USB_TYPE_CLASS; + data->udev = interface_to_usbdev(intf); data->intf = intf; @@ -862,11 +838,11 @@ static int btusb_probe(struct usb_interface *intf, hdev->owner = THIS_MODULE; - /* interface numbers are hardcoded in the spec */ + /* Interface numbers are hardcoded in the specification */ data->isoc = usb_ifnum_to_if(data->udev, 1); - if (reset || id->driver_info & BTUSB_RESET) - set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); + if (!reset) + set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); if (force_scofix || id->driver_info & BTUSB_WRONG_SCO_MTU) { if (!disable_scofix) @@ -876,9 +852,23 @@ static int btusb_probe(struct usb_interface *intf, if (id->driver_info & BTUSB_BROKEN_ISOC) data->isoc = NULL; + if (id->driver_info & BTUSB_DIGIANSWER) { + data->cmdreq_type = USB_TYPE_VENDOR; + set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + } + + if (id->driver_info & BTUSB_CSR) { + struct usb_device *udev = data->udev; + + /* Old firmware would otherwise execute USB reset */ + if (le16_to_cpu(udev->descriptor.bcdDevice) < 0x117) + set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); + } + if (id->driver_info & BTUSB_SNIFFER) { struct usb_device *udev = data->udev; + /* New sniffer firmware has crippled HCI interface */ if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); @@ -949,10 +939,71 @@ static void btusb_disconnect(struct usb_interface *intf) hci_free_dev(hdev); } +static int btusb_suspend(struct usb_interface *intf, pm_message_t message) +{ + struct btusb_data *data = usb_get_intfdata(intf); + + BT_DBG("intf %p", intf); + + if (data->suspend_count++) + return 0; + + cancel_work_sync(&data->work); + + usb_kill_anchored_urbs(&data->tx_anchor); + + usb_kill_anchored_urbs(&data->isoc_anchor); + usb_kill_anchored_urbs(&data->bulk_anchor); + usb_kill_anchored_urbs(&data->intr_anchor); + + return 0; +} + +static int btusb_resume(struct usb_interface *intf) +{ + struct btusb_data *data = usb_get_intfdata(intf); + struct hci_dev *hdev = data->hdev; + int err; + + BT_DBG("intf %p", intf); + + if (--data->suspend_count) + return 0; + + if (!test_bit(HCI_RUNNING, &hdev->flags)) + return 0; + + if (test_bit(BTUSB_INTR_RUNNING, &data->flags)) { + err = btusb_submit_intr_urb(hdev, GFP_NOIO); + if (err < 0) { + clear_bit(BTUSB_INTR_RUNNING, &data->flags); + return err; + } + } + + if (test_bit(BTUSB_BULK_RUNNING, &data->flags)) { + if (btusb_submit_bulk_urb(hdev, GFP_NOIO) < 0) + clear_bit(BTUSB_BULK_RUNNING, &data->flags); + else + btusb_submit_bulk_urb(hdev, GFP_NOIO); + } + + if (test_bit(BTUSB_ISOC_RUNNING, &data->flags)) { + if (btusb_submit_isoc_urb(hdev, GFP_NOIO) < 0) + clear_bit(BTUSB_ISOC_RUNNING, &data->flags); + else + btusb_submit_isoc_urb(hdev, GFP_NOIO); + } + + return 0; +} + static struct usb_driver btusb_driver = { .name = "btusb", .probe = btusb_probe, .disconnect = btusb_disconnect, + .suspend = btusb_suspend, + .resume = btusb_resume, .id_table = btusb_table, }; diff --git a/drivers/bluetooth/hci_bcsp.c b/drivers/bluetooth/hci_bcsp.c index 7938062c1cc7a13daf1306baa659c6cf477782be..894b2cb11ea6caf808ff55b6c3135d42e9ad33b5 100644 --- a/drivers/bluetooth/hci_bcsp.c +++ b/drivers/bluetooth/hci_bcsp.c @@ -47,11 +47,6 @@ #include "hci_uart.h" -#ifndef CONFIG_BT_HCIUART_DEBUG -#undef BT_DBG -#define BT_DBG( A... ) -#endif - #define VERSION "0.3" static int txcrc = 1; diff --git a/drivers/bluetooth/hci_h4.c b/drivers/bluetooth/hci_h4.c index bfbae14cf93d0fe388fc879ff5ca5ed69b99a5f9..b0fafb0559964762ee7db79a32dd336d34e2017b 100644 --- a/drivers/bluetooth/hci_h4.c +++ b/drivers/bluetooth/hci_h4.c @@ -46,11 +46,6 @@ #include "hci_uart.h" -#ifndef CONFIG_BT_HCIUART_DEBUG -#undef BT_DBG -#define BT_DBG( A... ) -#endif - #define VERSION "1.2" struct h4_struct { diff --git a/drivers/bluetooth/hci_ldisc.c b/drivers/bluetooth/hci_ldisc.c index 4426bb552bd90849b8df4e06c1a8e03f2a4af12f..af761dc434f638e9ab869a8e8d8508a98adbd175 100644 --- a/drivers/bluetooth/hci_ldisc.c +++ b/drivers/bluetooth/hci_ldisc.c @@ -46,11 +46,6 @@ #include "hci_uart.h" -#ifndef CONFIG_BT_HCIUART_DEBUG -#undef BT_DBG -#define BT_DBG( A... ) -#endif - #define VERSION "2.2" static int reset = 0; @@ -399,8 +394,8 @@ static int hci_uart_register_dev(struct hci_uart *hu) hdev->owner = THIS_MODULE; - if (reset) - set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); + if (!reset) + set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks); if (hci_register_dev(hdev) < 0) { BT_ERR("Can't register HCI device"); diff --git a/drivers/bluetooth/hci_usb.c b/drivers/bluetooth/hci_usb.c deleted file mode 100644 index 3c453924f8386c9b92050ae978967d188ec3b4da..0000000000000000000000000000000000000000 --- a/drivers/bluetooth/hci_usb.c +++ /dev/null @@ -1,1136 +0,0 @@ -/* - HCI USB driver for Linux Bluetooth protocol stack (BlueZ) - Copyright (C) 2000-2001 Qualcomm Incorporated - Written 2000,2001 by Maxim Krasnyansky - - Copyright (C) 2003 Maxim Krasnyansky - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* - * Bluetooth HCI USB driver. - * Based on original USB Bluetooth driver for Linux kernel - * Copyright (c) 2000 Greg Kroah-Hartman - * Copyright (c) 2000 Mark Douglas Corner - * - */ - -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include - -#include "hci_usb.h" - -#ifndef CONFIG_BT_HCIUSB_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - -#ifndef CONFIG_BT_HCIUSB_ZERO_PACKET -#undef URB_ZERO_PACKET -#define URB_ZERO_PACKET 0 -#endif - -static int ignore_dga; -static int ignore_csr; -static int ignore_sniffer; -static int disable_scofix; -static int force_scofix; -static int reset; - -#ifdef CONFIG_BT_HCIUSB_SCO -static int isoc = 2; -#endif - -#define VERSION "2.10" - -static struct usb_driver hci_usb_driver; - -static struct usb_device_id bluetooth_ids[] = { - /* Generic Bluetooth USB device */ - { USB_DEVICE_INFO(HCI_DEV_CLASS, HCI_DEV_SUBCLASS, HCI_DEV_PROTOCOL) }, - - /* AVM BlueFRITZ! USB v2.0 */ - { USB_DEVICE(0x057c, 0x3800) }, - - /* Bluetooth Ultraport Module from IBM */ - { USB_DEVICE(0x04bf, 0x030a) }, - - /* ALPS Modules with non-standard id */ - { USB_DEVICE(0x044e, 0x3001) }, - { USB_DEVICE(0x044e, 0x3002) }, - - /* Ericsson with non-standard id */ - { USB_DEVICE(0x0bdb, 0x1002) }, - - /* Canyon CN-BTU1 with HID interfaces */ - { USB_DEVICE(0x0c10, 0x0000), .driver_info = HCI_RESET }, - - { } /* Terminating entry */ -}; - -MODULE_DEVICE_TABLE (usb, bluetooth_ids); - -static struct usb_device_id blacklist_ids[] = { - /* CSR BlueCore devices */ - { USB_DEVICE(0x0a12, 0x0001), .driver_info = HCI_CSR }, - - /* Broadcom BCM2033 without firmware */ - { USB_DEVICE(0x0a5c, 0x2033), .driver_info = HCI_IGNORE }, - - /* Broadcom BCM2035 */ - { USB_DEVICE(0x0a5c, 0x2035), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x200a), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x2009), .driver_info = HCI_BCM92035 }, - - /* Broadcom BCM2045 */ - { USB_DEVICE(0x0a5c, 0x2039), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x2101), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* IBM/Lenovo ThinkPad with Broadcom chip */ - { USB_DEVICE(0x0a5c, 0x201e), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - { USB_DEVICE(0x0a5c, 0x2110), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* Targus ACB10US */ - { USB_DEVICE(0x0a5c, 0x2100), .driver_info = HCI_RESET }, - - /* ANYCOM Bluetooth USB-200 and USB-250 */ - { USB_DEVICE(0x0a5c, 0x2111), .driver_info = HCI_RESET }, - - /* HP laptop with Broadcom chip */ - { USB_DEVICE(0x03f0, 0x171d), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* Dell laptop with Broadcom chip */ - { USB_DEVICE(0x413c, 0x8126), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - /* Dell Wireless 370 */ - { USB_DEVICE(0x413c, 0x8156), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - /* Dell Wireless 410 */ - { USB_DEVICE(0x413c, 0x8152), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* Broadcom 2046 */ - { USB_DEVICE(0x0a5c, 0x2151), .driver_info = HCI_RESET }, - - /* Microsoft Wireless Transceiver for Bluetooth 2.0 */ - { USB_DEVICE(0x045e, 0x009c), .driver_info = HCI_RESET }, - - /* Kensington Bluetooth USB adapter */ - { USB_DEVICE(0x047d, 0x105d), .driver_info = HCI_RESET }, - { USB_DEVICE(0x047d, 0x105e), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* ISSC Bluetooth Adapter v3.1 */ - { USB_DEVICE(0x1131, 0x1001), .driver_info = HCI_RESET }, - - /* RTX Telecom based adapters with buggy SCO support */ - { USB_DEVICE(0x0400, 0x0807), .driver_info = HCI_BROKEN_ISOC }, - { USB_DEVICE(0x0400, 0x080a), .driver_info = HCI_BROKEN_ISOC }, - - /* CONWISE Technology based adapters with buggy SCO support */ - { USB_DEVICE(0x0e5e, 0x6622), .driver_info = HCI_BROKEN_ISOC }, - - /* Belkin F8T012 and F8T013 devices */ - { USB_DEVICE(0x050d, 0x0012), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - { USB_DEVICE(0x050d, 0x0013), .driver_info = HCI_RESET | HCI_WRONG_SCO_MTU }, - - /* Digianswer devices */ - { USB_DEVICE(0x08fd, 0x0001), .driver_info = HCI_DIGIANSWER }, - { USB_DEVICE(0x08fd, 0x0002), .driver_info = HCI_IGNORE }, - - /* CSR BlueCore Bluetooth Sniffer */ - { USB_DEVICE(0x0a12, 0x0002), .driver_info = HCI_SNIFFER }, - - /* Frontline ComProbe Bluetooth Sniffer */ - { USB_DEVICE(0x16d3, 0x0002), .driver_info = HCI_SNIFFER }, - - { } /* Terminating entry */ -}; - -static struct _urb *_urb_alloc(int isoc, gfp_t gfp) -{ - struct _urb *_urb = kmalloc(sizeof(struct _urb) + - sizeof(struct usb_iso_packet_descriptor) * isoc, gfp); - if (_urb) { - memset(_urb, 0, sizeof(*_urb)); - usb_init_urb(&_urb->urb); - } - return _urb; -} - -static struct _urb *_urb_dequeue(struct _urb_queue *q) -{ - struct _urb *_urb = NULL; - unsigned long flags; - spin_lock_irqsave(&q->lock, flags); - { - struct list_head *head = &q->head; - struct list_head *next = head->next; - if (next != head) { - _urb = list_entry(next, struct _urb, list); - list_del(next); _urb->queue = NULL; - } - } - spin_unlock_irqrestore(&q->lock, flags); - return _urb; -} - -static void hci_usb_rx_complete(struct urb *urb); -static void hci_usb_tx_complete(struct urb *urb); - -#define __pending_tx(husb, type) (&husb->pending_tx[type-1]) -#define __pending_q(husb, type) (&husb->pending_q[type-1]) -#define __completed_q(husb, type) (&husb->completed_q[type-1]) -#define __transmit_q(husb, type) (&husb->transmit_q[type-1]) - -static inline struct _urb *__get_completed(struct hci_usb *husb, int type) -{ - return _urb_dequeue(__completed_q(husb, type)); -} - -#ifdef CONFIG_BT_HCIUSB_SCO -static void __fill_isoc_desc(struct urb *urb, int len, int mtu) -{ - int offset = 0, i; - - BT_DBG("len %d mtu %d", len, mtu); - - for (i=0; i < HCI_MAX_ISOC_FRAMES && len >= mtu; i++, offset += mtu, len -= mtu) { - urb->iso_frame_desc[i].offset = offset; - urb->iso_frame_desc[i].length = mtu; - BT_DBG("desc %d offset %d len %d", i, offset, mtu); - } - if (len && i < HCI_MAX_ISOC_FRAMES) { - urb->iso_frame_desc[i].offset = offset; - urb->iso_frame_desc[i].length = len; - BT_DBG("desc %d offset %d len %d", i, offset, len); - i++; - } - urb->number_of_packets = i; -} -#endif - -static int hci_usb_intr_rx_submit(struct hci_usb *husb) -{ - struct _urb *_urb; - struct urb *urb; - int err, pipe, interval, size; - void *buf; - - BT_DBG("%s", husb->hdev->name); - - size = le16_to_cpu(husb->intr_in_ep->desc.wMaxPacketSize); - - buf = kmalloc(size, GFP_ATOMIC); - if (!buf) - return -ENOMEM; - - _urb = _urb_alloc(0, GFP_ATOMIC); - if (!_urb) { - kfree(buf); - return -ENOMEM; - } - _urb->type = HCI_EVENT_PKT; - _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - - urb = &_urb->urb; - pipe = usb_rcvintpipe(husb->udev, husb->intr_in_ep->desc.bEndpointAddress); - interval = husb->intr_in_ep->desc.bInterval; - usb_fill_int_urb(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb, interval); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - BT_ERR("%s intr rx submit failed urb %p err %d", - husb->hdev->name, urb, err); - _urb_unlink(_urb); - kfree(_urb); - kfree(buf); - } - return err; -} - -static int hci_usb_bulk_rx_submit(struct hci_usb *husb) -{ - struct _urb *_urb; - struct urb *urb; - int err, pipe, size = HCI_MAX_FRAME_SIZE; - void *buf; - - buf = kmalloc(size, GFP_ATOMIC); - if (!buf) - return -ENOMEM; - - _urb = _urb_alloc(0, GFP_ATOMIC); - if (!_urb) { - kfree(buf); - return -ENOMEM; - } - _urb->type = HCI_ACLDATA_PKT; - _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - - urb = &_urb->urb; - pipe = usb_rcvbulkpipe(husb->udev, husb->bulk_in_ep->desc.bEndpointAddress); - usb_fill_bulk_urb(urb, husb->udev, pipe, buf, size, hci_usb_rx_complete, husb); - urb->transfer_flags = 0; - - BT_DBG("%s urb %p", husb->hdev->name, urb); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - BT_ERR("%s bulk rx submit failed urb %p err %d", - husb->hdev->name, urb, err); - _urb_unlink(_urb); - kfree(_urb); - kfree(buf); - } - return err; -} - -#ifdef CONFIG_BT_HCIUSB_SCO -static int hci_usb_isoc_rx_submit(struct hci_usb *husb) -{ - struct _urb *_urb; - struct urb *urb; - int err, mtu, size; - void *buf; - - mtu = le16_to_cpu(husb->isoc_in_ep->desc.wMaxPacketSize); - size = mtu * HCI_MAX_ISOC_FRAMES; - - buf = kmalloc(size, GFP_ATOMIC); - if (!buf) - return -ENOMEM; - - _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); - if (!_urb) { - kfree(buf); - return -ENOMEM; - } - _urb->type = HCI_SCODATA_PKT; - _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - - urb = &_urb->urb; - - urb->context = husb; - urb->dev = husb->udev; - urb->pipe = usb_rcvisocpipe(husb->udev, husb->isoc_in_ep->desc.bEndpointAddress); - urb->complete = hci_usb_rx_complete; - - urb->interval = husb->isoc_in_ep->desc.bInterval; - - urb->transfer_buffer_length = size; - urb->transfer_buffer = buf; - urb->transfer_flags = URB_ISO_ASAP; - - __fill_isoc_desc(urb, size, mtu); - - BT_DBG("%s urb %p", husb->hdev->name, urb); - - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - BT_ERR("%s isoc rx submit failed urb %p err %d", - husb->hdev->name, urb, err); - _urb_unlink(_urb); - kfree(_urb); - kfree(buf); - } - return err; -} -#endif - -/* Initialize device */ -static int hci_usb_open(struct hci_dev *hdev) -{ - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - int i, err; - unsigned long flags; - - BT_DBG("%s", hdev->name); - - if (test_and_set_bit(HCI_RUNNING, &hdev->flags)) - return 0; - - write_lock_irqsave(&husb->completion_lock, flags); - - err = hci_usb_intr_rx_submit(husb); - if (!err) { - for (i = 0; i < HCI_MAX_BULK_RX; i++) - hci_usb_bulk_rx_submit(husb); - -#ifdef CONFIG_BT_HCIUSB_SCO - if (husb->isoc_iface) - for (i = 0; i < HCI_MAX_ISOC_RX; i++) - hci_usb_isoc_rx_submit(husb); -#endif - } else { - clear_bit(HCI_RUNNING, &hdev->flags); - } - - write_unlock_irqrestore(&husb->completion_lock, flags); - return err; -} - -/* Reset device */ -static int hci_usb_flush(struct hci_dev *hdev) -{ - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - int i; - - BT_DBG("%s", hdev->name); - - for (i = 0; i < 4; i++) - skb_queue_purge(&husb->transmit_q[i]); - return 0; -} - -static void hci_usb_unlink_urbs(struct hci_usb *husb) -{ - int i; - - BT_DBG("%s", husb->hdev->name); - - for (i = 0; i < 4; i++) { - struct _urb *_urb; - struct urb *urb; - - /* Kill pending requests */ - while ((_urb = _urb_dequeue(&husb->pending_q[i]))) { - urb = &_urb->urb; - BT_DBG("%s unlinking _urb %p type %d urb %p", - husb->hdev->name, _urb, _urb->type, urb); - usb_kill_urb(urb); - _urb_queue_tail(__completed_q(husb, _urb->type), _urb); - } - - /* Release completed requests */ - while ((_urb = _urb_dequeue(&husb->completed_q[i]))) { - urb = &_urb->urb; - BT_DBG("%s freeing _urb %p type %d urb %p", - husb->hdev->name, _urb, _urb->type, urb); - kfree(urb->setup_packet); - kfree(urb->transfer_buffer); - kfree(_urb); - } - } -} - -/* Close device */ -static int hci_usb_close(struct hci_dev *hdev) -{ - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - unsigned long flags; - - if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) - return 0; - - BT_DBG("%s", hdev->name); - - /* Synchronize with completion handlers */ - write_lock_irqsave(&husb->completion_lock, flags); - write_unlock_irqrestore(&husb->completion_lock, flags); - - hci_usb_unlink_urbs(husb); - hci_usb_flush(hdev); - return 0; -} - -static int __tx_submit(struct hci_usb *husb, struct _urb *_urb) -{ - struct urb *urb = &_urb->urb; - int err; - - BT_DBG("%s urb %p type %d", husb->hdev->name, urb, _urb->type); - - _urb_queue_tail(__pending_q(husb, _urb->type), _urb); - err = usb_submit_urb(urb, GFP_ATOMIC); - if (err) { - BT_ERR("%s tx submit failed urb %p type %d err %d", - husb->hdev->name, urb, _urb->type, err); - _urb_unlink(_urb); - _urb_queue_tail(__completed_q(husb, _urb->type), _urb); - } else - atomic_inc(__pending_tx(husb, _urb->type)); - - return err; -} - -static inline int hci_usb_send_ctrl(struct hci_usb *husb, struct sk_buff *skb) -{ - struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type); - struct usb_ctrlrequest *dr; - struct urb *urb; - - if (!_urb) { - _urb = _urb_alloc(0, GFP_ATOMIC); - if (!_urb) - return -ENOMEM; - _urb->type = bt_cb(skb)->pkt_type; - - dr = kmalloc(sizeof(*dr), GFP_ATOMIC); - if (!dr) { - kfree(_urb); - return -ENOMEM; - } - } else - dr = (void *) _urb->urb.setup_packet; - - dr->bRequestType = husb->ctrl_req; - dr->bRequest = 0; - dr->wIndex = 0; - dr->wValue = 0; - dr->wLength = __cpu_to_le16(skb->len); - - urb = &_urb->urb; - usb_fill_control_urb(urb, husb->udev, usb_sndctrlpipe(husb->udev, 0), - (void *) dr, skb->data, skb->len, hci_usb_tx_complete, husb); - - BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len); - - _urb->priv = skb; - return __tx_submit(husb, _urb); -} - -static inline int hci_usb_send_bulk(struct hci_usb *husb, struct sk_buff *skb) -{ - struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type); - struct urb *urb; - int pipe; - - if (!_urb) { - _urb = _urb_alloc(0, GFP_ATOMIC); - if (!_urb) - return -ENOMEM; - _urb->type = bt_cb(skb)->pkt_type; - } - - urb = &_urb->urb; - pipe = usb_sndbulkpipe(husb->udev, husb->bulk_out_ep->desc.bEndpointAddress); - usb_fill_bulk_urb(urb, husb->udev, pipe, skb->data, skb->len, - hci_usb_tx_complete, husb); - urb->transfer_flags = URB_ZERO_PACKET; - - BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len); - - _urb->priv = skb; - return __tx_submit(husb, _urb); -} - -#ifdef CONFIG_BT_HCIUSB_SCO -static inline int hci_usb_send_isoc(struct hci_usb *husb, struct sk_buff *skb) -{ - struct _urb *_urb = __get_completed(husb, bt_cb(skb)->pkt_type); - struct urb *urb; - - if (!_urb) { - _urb = _urb_alloc(HCI_MAX_ISOC_FRAMES, GFP_ATOMIC); - if (!_urb) - return -ENOMEM; - _urb->type = bt_cb(skb)->pkt_type; - } - - BT_DBG("%s skb %p len %d", husb->hdev->name, skb, skb->len); - - urb = &_urb->urb; - - urb->context = husb; - urb->dev = husb->udev; - urb->pipe = usb_sndisocpipe(husb->udev, husb->isoc_out_ep->desc.bEndpointAddress); - urb->complete = hci_usb_tx_complete; - urb->transfer_flags = URB_ISO_ASAP; - - urb->interval = husb->isoc_out_ep->desc.bInterval; - - urb->transfer_buffer = skb->data; - urb->transfer_buffer_length = skb->len; - - __fill_isoc_desc(urb, skb->len, le16_to_cpu(husb->isoc_out_ep->desc.wMaxPacketSize)); - - _urb->priv = skb; - return __tx_submit(husb, _urb); -} -#endif - -static void hci_usb_tx_process(struct hci_usb *husb) -{ - struct sk_buff_head *q; - struct sk_buff *skb; - - BT_DBG("%s", husb->hdev->name); - - do { - clear_bit(HCI_USB_TX_WAKEUP, &husb->state); - - /* Process command queue */ - q = __transmit_q(husb, HCI_COMMAND_PKT); - if (!atomic_read(__pending_tx(husb, HCI_COMMAND_PKT)) && - (skb = skb_dequeue(q))) { - if (hci_usb_send_ctrl(husb, skb) < 0) - skb_queue_head(q, skb); - } - -#ifdef CONFIG_BT_HCIUSB_SCO - /* Process SCO queue */ - q = __transmit_q(husb, HCI_SCODATA_PKT); - if (atomic_read(__pending_tx(husb, HCI_SCODATA_PKT)) < HCI_MAX_ISOC_TX && - (skb = skb_dequeue(q))) { - if (hci_usb_send_isoc(husb, skb) < 0) - skb_queue_head(q, skb); - } -#endif - - /* Process ACL queue */ - q = __transmit_q(husb, HCI_ACLDATA_PKT); - while (atomic_read(__pending_tx(husb, HCI_ACLDATA_PKT)) < HCI_MAX_BULK_TX && - (skb = skb_dequeue(q))) { - if (hci_usb_send_bulk(husb, skb) < 0) { - skb_queue_head(q, skb); - break; - } - } - } while(test_bit(HCI_USB_TX_WAKEUP, &husb->state)); -} - -static inline void hci_usb_tx_wakeup(struct hci_usb *husb) -{ - /* Serialize TX queue processing to avoid data reordering */ - if (!test_and_set_bit(HCI_USB_TX_PROCESS, &husb->state)) { - hci_usb_tx_process(husb); - clear_bit(HCI_USB_TX_PROCESS, &husb->state); - } else - set_bit(HCI_USB_TX_WAKEUP, &husb->state); -} - -/* Send frames from HCI layer */ -static int hci_usb_send_frame(struct sk_buff *skb) -{ - struct hci_dev *hdev = (struct hci_dev *) skb->dev; - struct hci_usb *husb; - - if (!hdev) { - BT_ERR("frame for uknown device (hdev=NULL)"); - return -ENODEV; - } - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return -EBUSY; - - BT_DBG("%s type %d len %d", hdev->name, bt_cb(skb)->pkt_type, skb->len); - - husb = (struct hci_usb *) hdev->driver_data; - - switch (bt_cb(skb)->pkt_type) { - case HCI_COMMAND_PKT: - hdev->stat.cmd_tx++; - break; - - case HCI_ACLDATA_PKT: - hdev->stat.acl_tx++; - break; - -#ifdef CONFIG_BT_HCIUSB_SCO - case HCI_SCODATA_PKT: - hdev->stat.sco_tx++; - break; -#endif - - default: - kfree_skb(skb); - return 0; - } - - read_lock(&husb->completion_lock); - - skb_queue_tail(__transmit_q(husb, bt_cb(skb)->pkt_type), skb); - hci_usb_tx_wakeup(husb); - - read_unlock(&husb->completion_lock); - return 0; -} - -static void hci_usb_rx_complete(struct urb *urb) -{ - struct _urb *_urb = container_of(urb, struct _urb, urb); - struct hci_usb *husb = (void *) urb->context; - struct hci_dev *hdev = husb->hdev; - int err, count = urb->actual_length; - - BT_DBG("%s urb %p type %d status %d count %d flags %x", hdev->name, urb, - _urb->type, urb->status, count, urb->transfer_flags); - - read_lock(&husb->completion_lock); - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - goto unlock; - - if (urb->status || !count) - goto resubmit; - - if (_urb->type == HCI_SCODATA_PKT) { -#ifdef CONFIG_BT_HCIUSB_SCO - int i; - for (i=0; i < urb->number_of_packets; i++) { - BT_DBG("desc %d status %d offset %d len %d", i, - urb->iso_frame_desc[i].status, - urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - - if (!urb->iso_frame_desc[i].status) { - husb->hdev->stat.byte_rx += urb->iso_frame_desc[i].actual_length; - hci_recv_fragment(husb->hdev, _urb->type, - urb->transfer_buffer + urb->iso_frame_desc[i].offset, - urb->iso_frame_desc[i].actual_length); - } - } -#else - ; -#endif - } else { - husb->hdev->stat.byte_rx += count; - err = hci_recv_fragment(husb->hdev, _urb->type, urb->transfer_buffer, count); - if (err < 0) { - BT_ERR("%s corrupted packet: type %d count %d", - husb->hdev->name, _urb->type, count); - hdev->stat.err_rx++; - } - } - -resubmit: - urb->dev = husb->udev; - err = usb_submit_urb(urb, GFP_ATOMIC); - BT_DBG("%s urb %p type %d resubmit status %d", hdev->name, urb, - _urb->type, err); - -unlock: - read_unlock(&husb->completion_lock); -} - -static void hci_usb_tx_complete(struct urb *urb) -{ - struct _urb *_urb = container_of(urb, struct _urb, urb); - struct hci_usb *husb = (void *) urb->context; - struct hci_dev *hdev = husb->hdev; - - BT_DBG("%s urb %p status %d flags %x", hdev->name, urb, - urb->status, urb->transfer_flags); - - atomic_dec(__pending_tx(husb, _urb->type)); - - urb->transfer_buffer = NULL; - kfree_skb((struct sk_buff *) _urb->priv); - - if (!test_bit(HCI_RUNNING, &hdev->flags)) - return; - - if (!urb->status) - hdev->stat.byte_tx += urb->transfer_buffer_length; - else - hdev->stat.err_tx++; - - read_lock(&husb->completion_lock); - - _urb_unlink(_urb); - _urb_queue_tail(__completed_q(husb, _urb->type), _urb); - - hci_usb_tx_wakeup(husb); - - read_unlock(&husb->completion_lock); -} - -static void hci_usb_destruct(struct hci_dev *hdev) -{ - struct hci_usb *husb = (struct hci_usb *) hdev->driver_data; - - BT_DBG("%s", hdev->name); - - kfree(husb); -} - -static void hci_usb_notify(struct hci_dev *hdev, unsigned int evt) -{ - BT_DBG("%s evt %d", hdev->name, evt); -} - -static int hci_usb_probe(struct usb_interface *intf, const struct usb_device_id *id) -{ - struct usb_device *udev = interface_to_usbdev(intf); - struct usb_host_endpoint *bulk_out_ep = NULL; - struct usb_host_endpoint *bulk_in_ep = NULL; - struct usb_host_endpoint *intr_in_ep = NULL; - struct usb_host_endpoint *ep; - struct usb_host_interface *uif; - struct usb_interface *isoc_iface; - struct hci_usb *husb; - struct hci_dev *hdev; - int i, e, size, isoc_ifnum, isoc_alts; - - BT_DBG("udev %p intf %p", udev, intf); - - if (!id->driver_info) { - const struct usb_device_id *match; - match = usb_match_id(intf, blacklist_ids); - if (match) - id = match; - } - - if (id->driver_info & HCI_IGNORE) - return -ENODEV; - - if (ignore_dga && id->driver_info & HCI_DIGIANSWER) - return -ENODEV; - - if (ignore_csr && id->driver_info & HCI_CSR) - return -ENODEV; - - if (ignore_sniffer && id->driver_info & HCI_SNIFFER) - return -ENODEV; - - if (intf->cur_altsetting->desc.bInterfaceNumber > 0) - return -ENODEV; - - /* Find endpoints that we need */ - uif = intf->cur_altsetting; - for (e = 0; e < uif->desc.bNumEndpoints; e++) { - ep = &uif->endpoint[e]; - - switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_INT: - if (ep->desc.bEndpointAddress & USB_DIR_IN) - intr_in_ep = ep; - break; - - case USB_ENDPOINT_XFER_BULK: - if (ep->desc.bEndpointAddress & USB_DIR_IN) - bulk_in_ep = ep; - else - bulk_out_ep = ep; - break; - } - } - - if (!bulk_in_ep || !bulk_out_ep || !intr_in_ep) { - BT_DBG("Bulk endpoints not found"); - goto done; - } - - if (!(husb = kzalloc(sizeof(struct hci_usb), GFP_KERNEL))) { - BT_ERR("Can't allocate: control structure"); - goto done; - } - - husb->udev = udev; - husb->bulk_out_ep = bulk_out_ep; - husb->bulk_in_ep = bulk_in_ep; - husb->intr_in_ep = intr_in_ep; - - if (id->driver_info & HCI_DIGIANSWER) - husb->ctrl_req = USB_TYPE_VENDOR; - else - husb->ctrl_req = USB_TYPE_CLASS; - - /* Find isochronous endpoints that we can use */ - size = 0; - isoc_iface = NULL; - isoc_alts = 0; - isoc_ifnum = 1; - -#ifdef CONFIG_BT_HCIUSB_SCO - if (isoc && !(id->driver_info & (HCI_BROKEN_ISOC | HCI_SNIFFER))) - isoc_iface = usb_ifnum_to_if(udev, isoc_ifnum); - - if (isoc_iface) { - int a; - struct usb_host_endpoint *isoc_out_ep = NULL; - struct usb_host_endpoint *isoc_in_ep = NULL; - - for (a = 0; a < isoc_iface->num_altsetting; a++) { - uif = &isoc_iface->altsetting[a]; - for (e = 0; e < uif->desc.bNumEndpoints; e++) { - ep = &uif->endpoint[e]; - - switch (ep->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) { - case USB_ENDPOINT_XFER_ISOC: - if (le16_to_cpu(ep->desc.wMaxPacketSize) < size || - uif->desc.bAlternateSetting != isoc) - break; - size = le16_to_cpu(ep->desc.wMaxPacketSize); - - isoc_alts = uif->desc.bAlternateSetting; - - if (ep->desc.bEndpointAddress & USB_DIR_IN) - isoc_in_ep = ep; - else - isoc_out_ep = ep; - break; - } - } - } - - if (!isoc_in_ep || !isoc_out_ep) - BT_DBG("Isoc endpoints not found"); - else { - BT_DBG("isoc ifnum %d alts %d", isoc_ifnum, isoc_alts); - if (usb_driver_claim_interface(&hci_usb_driver, isoc_iface, husb) != 0) - BT_ERR("Can't claim isoc interface"); - else if (usb_set_interface(udev, isoc_ifnum, isoc_alts)) { - BT_ERR("Can't set isoc interface settings"); - husb->isoc_iface = isoc_iface; - usb_driver_release_interface(&hci_usb_driver, isoc_iface); - husb->isoc_iface = NULL; - } else { - husb->isoc_iface = isoc_iface; - husb->isoc_in_ep = isoc_in_ep; - husb->isoc_out_ep = isoc_out_ep; - } - } - } -#endif - - rwlock_init(&husb->completion_lock); - - for (i = 0; i < 4; i++) { - skb_queue_head_init(&husb->transmit_q[i]); - _urb_queue_init(&husb->pending_q[i]); - _urb_queue_init(&husb->completed_q[i]); - } - - /* Initialize and register HCI device */ - hdev = hci_alloc_dev(); - if (!hdev) { - BT_ERR("Can't allocate HCI device"); - goto probe_error; - } - - husb->hdev = hdev; - - hdev->type = HCI_USB; - hdev->driver_data = husb; - SET_HCIDEV_DEV(hdev, &intf->dev); - - hdev->open = hci_usb_open; - hdev->close = hci_usb_close; - hdev->flush = hci_usb_flush; - hdev->send = hci_usb_send_frame; - hdev->destruct = hci_usb_destruct; - hdev->notify = hci_usb_notify; - - hdev->owner = THIS_MODULE; - - if (reset || id->driver_info & HCI_RESET) - set_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks); - - if (force_scofix || id->driver_info & HCI_WRONG_SCO_MTU) { - if (!disable_scofix) - set_bit(HCI_QUIRK_FIXUP_BUFFER_SIZE, &hdev->quirks); - } - - if (id->driver_info & HCI_SNIFFER) { - if (le16_to_cpu(udev->descriptor.bcdDevice) > 0x997) - set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks); - } - - if (id->driver_info & HCI_BCM92035) { - unsigned char cmd[] = { 0x3b, 0xfc, 0x01, 0x00 }; - struct sk_buff *skb; - - skb = bt_skb_alloc(sizeof(cmd), GFP_KERNEL); - if (skb) { - memcpy(skb_put(skb, sizeof(cmd)), cmd, sizeof(cmd)); - skb_queue_tail(&hdev->driver_init, skb); - } - } - - if (hci_register_dev(hdev) < 0) { - BT_ERR("Can't register HCI device"); - hci_free_dev(hdev); - goto probe_error; - } - - usb_set_intfdata(intf, husb); - return 0; - -probe_error: - if (husb->isoc_iface) - usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface); - kfree(husb); - -done: - return -EIO; -} - -static void hci_usb_disconnect(struct usb_interface *intf) -{ - struct hci_usb *husb = usb_get_intfdata(intf); - struct hci_dev *hdev; - - if (!husb || intf == husb->isoc_iface) - return; - - usb_set_intfdata(intf, NULL); - hdev = husb->hdev; - - BT_DBG("%s", hdev->name); - - hci_usb_close(hdev); - - if (husb->isoc_iface) - usb_driver_release_interface(&hci_usb_driver, husb->isoc_iface); - - if (hci_unregister_dev(hdev) < 0) - BT_ERR("Can't unregister HCI device %s", hdev->name); - - hci_free_dev(hdev); -} - -static int hci_usb_suspend(struct usb_interface *intf, pm_message_t message) -{ - struct hci_usb *husb = usb_get_intfdata(intf); - struct list_head killed; - unsigned long flags; - int i; - - if (!husb || intf == husb->isoc_iface) - return 0; - - hci_suspend_dev(husb->hdev); - - INIT_LIST_HEAD(&killed); - - for (i = 0; i < 4; i++) { - struct _urb_queue *q = &husb->pending_q[i]; - struct _urb *_urb, *_tmp; - - while ((_urb = _urb_dequeue(q))) { - /* reset queue since _urb_dequeue sets it to NULL */ - _urb->queue = q; - usb_kill_urb(&_urb->urb); - list_add(&_urb->list, &killed); - } - - spin_lock_irqsave(&q->lock, flags); - - list_for_each_entry_safe(_urb, _tmp, &killed, list) { - list_move_tail(&_urb->list, &q->head); - } - - spin_unlock_irqrestore(&q->lock, flags); - } - - return 0; -} - -static int hci_usb_resume(struct usb_interface *intf) -{ - struct hci_usb *husb = usb_get_intfdata(intf); - unsigned long flags; - int i, err = 0; - - if (!husb || intf == husb->isoc_iface) - return 0; - - for (i = 0; i < 4; i++) { - struct _urb_queue *q = &husb->pending_q[i]; - struct _urb *_urb; - - spin_lock_irqsave(&q->lock, flags); - - list_for_each_entry(_urb, &q->head, list) { - err = usb_submit_urb(&_urb->urb, GFP_ATOMIC); - if (err) - break; - } - - spin_unlock_irqrestore(&q->lock, flags); - - if (err) - return -EIO; - } - - hci_resume_dev(husb->hdev); - - return 0; -} - -static struct usb_driver hci_usb_driver = { - .name = "hci_usb", - .probe = hci_usb_probe, - .disconnect = hci_usb_disconnect, - .suspend = hci_usb_suspend, - .resume = hci_usb_resume, - .id_table = bluetooth_ids, -}; - -static int __init hci_usb_init(void) -{ - int err; - - BT_INFO("HCI USB driver ver %s", VERSION); - - if ((err = usb_register(&hci_usb_driver)) < 0) - BT_ERR("Failed to register HCI USB driver"); - - return err; -} - -static void __exit hci_usb_exit(void) -{ - usb_deregister(&hci_usb_driver); -} - -module_init(hci_usb_init); -module_exit(hci_usb_exit); - -module_param(ignore_dga, bool, 0644); -MODULE_PARM_DESC(ignore_dga, "Ignore devices with id 08fd:0001"); - -module_param(ignore_csr, bool, 0644); -MODULE_PARM_DESC(ignore_csr, "Ignore devices with id 0a12:0001"); - -module_param(ignore_sniffer, bool, 0644); -MODULE_PARM_DESC(ignore_sniffer, "Ignore devices with id 0a12:0002"); - -module_param(disable_scofix, bool, 0644); -MODULE_PARM_DESC(disable_scofix, "Disable fixup of wrong SCO buffer size"); - -module_param(force_scofix, bool, 0644); -MODULE_PARM_DESC(force_scofix, "Force fixup of wrong SCO buffers size"); - -module_param(reset, bool, 0644); -MODULE_PARM_DESC(reset, "Send HCI reset command on initialization"); - -#ifdef CONFIG_BT_HCIUSB_SCO -module_param(isoc, int, 0644); -MODULE_PARM_DESC(isoc, "Set isochronous transfers for SCO over HCI support"); -#endif - -MODULE_AUTHOR("Marcel Holtmann "); -MODULE_DESCRIPTION("Bluetooth HCI USB driver ver " VERSION); -MODULE_VERSION(VERSION); -MODULE_LICENSE("GPL"); diff --git a/drivers/bluetooth/hci_usb.h b/drivers/bluetooth/hci_usb.h deleted file mode 100644 index 8e659914523f76990e1e736201044771531b02eb..0000000000000000000000000000000000000000 --- a/drivers/bluetooth/hci_usb.h +++ /dev/null @@ -1,129 +0,0 @@ -/* - HCI USB driver for Linux Bluetooth protocol stack (BlueZ) - Copyright (C) 2000-2001 Qualcomm Incorporated - Written 2000,2001 by Maxim Krasnyansky - - Copyright (C) 2003 Maxim Krasnyansky - - 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; - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. - IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY - CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - - ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS, - COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS - SOFTWARE IS DISCLAIMED. -*/ - -/* Class, SubClass, and Protocol codes that describe a Bluetooth device */ -#define HCI_DEV_CLASS 0xe0 /* Wireless class */ -#define HCI_DEV_SUBCLASS 0x01 /* RF subclass */ -#define HCI_DEV_PROTOCOL 0x01 /* Bluetooth programming protocol */ - -#define HCI_IGNORE 0x01 -#define HCI_RESET 0x02 -#define HCI_DIGIANSWER 0x04 -#define HCI_CSR 0x08 -#define HCI_SNIFFER 0x10 -#define HCI_BCM92035 0x20 -#define HCI_BROKEN_ISOC 0x40 -#define HCI_WRONG_SCO_MTU 0x80 - -#define HCI_MAX_IFACE_NUM 3 - -#define HCI_MAX_BULK_TX 4 -#define HCI_MAX_BULK_RX 1 - -#define HCI_MAX_ISOC_RX 2 -#define HCI_MAX_ISOC_TX 2 - -#define HCI_MAX_ISOC_FRAMES 10 - -struct _urb_queue { - struct list_head head; - spinlock_t lock; -}; - -struct _urb { - struct list_head list; - struct _urb_queue *queue; - int type; - void *priv; - struct urb urb; -}; - -static inline void _urb_queue_init(struct _urb_queue *q) -{ - INIT_LIST_HEAD(&q->head); - spin_lock_init(&q->lock); -} - -static inline void _urb_queue_head(struct _urb_queue *q, struct _urb *_urb) -{ - unsigned long flags; - spin_lock_irqsave(&q->lock, flags); - /* _urb_unlink needs to know which spinlock to use, thus smp_mb(). */ - _urb->queue = q; smp_mb(); list_add(&_urb->list, &q->head); - spin_unlock_irqrestore(&q->lock, flags); -} - -static inline void _urb_queue_tail(struct _urb_queue *q, struct _urb *_urb) -{ - unsigned long flags; - spin_lock_irqsave(&q->lock, flags); - /* _urb_unlink needs to know which spinlock to use, thus smp_mb(). */ - _urb->queue = q; smp_mb(); list_add_tail(&_urb->list, &q->head); - spin_unlock_irqrestore(&q->lock, flags); -} - -static inline void _urb_unlink(struct _urb *_urb) -{ - struct _urb_queue *q; - unsigned long flags; - - smp_mb(); - q = _urb->queue; - /* If q is NULL, it will die at easy-to-debug NULL pointer dereference. - No need to BUG(). */ - spin_lock_irqsave(&q->lock, flags); - list_del(&_urb->list); _urb->queue = NULL; - spin_unlock_irqrestore(&q->lock, flags); -} - -struct hci_usb { - struct hci_dev *hdev; - - unsigned long state; - - struct usb_device *udev; - - struct usb_host_endpoint *bulk_in_ep; - struct usb_host_endpoint *bulk_out_ep; - struct usb_host_endpoint *intr_in_ep; - - struct usb_interface *isoc_iface; - struct usb_host_endpoint *isoc_out_ep; - struct usb_host_endpoint *isoc_in_ep; - - __u8 ctrl_req; - - struct sk_buff_head transmit_q[4]; - - rwlock_t completion_lock; - - atomic_t pending_tx[4]; /* Number of pending requests */ - struct _urb_queue pending_q[4]; /* Pending requests */ - struct _urb_queue completed_q[4]; /* Completed requests */ -}; - -/* States */ -#define HCI_USB_TX_PROCESS 1 -#define HCI_USB_TX_WAKEUP 2 diff --git a/drivers/bluetooth/hci_vhci.c b/drivers/bluetooth/hci_vhci.c index 7320a71b63685403c9972766c4eb716ba9b05791..0bbefba6469cee659e7b114e961a677e3fa65fa0 100644 --- a/drivers/bluetooth/hci_vhci.c +++ b/drivers/bluetooth/hci_vhci.c @@ -40,11 +40,6 @@ #include #include -#ifndef CONFIG_BT_HCIVHCI_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "1.2" static int minor = MISC_DYNAMIC_MINOR; diff --git a/drivers/firmware/iscsi_ibft.c b/drivers/firmware/iscsi_ibft.c index 4353414a0b770c368b938760e8630f50bd065346..3ab3e4a41d670f48af0583c841dae8a6d040748f 100644 --- a/drivers/firmware/iscsi_ibft.c +++ b/drivers/firmware/iscsi_ibft.c @@ -284,15 +284,12 @@ static ssize_t sprintf_ipaddr(char *buf, u8 *ip) /* * IPV4 */ - str += sprintf(buf, NIPQUAD_FMT, ip[12], - ip[13], ip[14], ip[15]); + str += sprintf(buf, "%pI4", ip + 12); } else { /* * IPv6 */ - str += sprintf(str, NIP6_FMT, ntohs(ip[0]), ntohs(ip[1]), - ntohs(ip[2]), ntohs(ip[3]), ntohs(ip[4]), - ntohs(ip[5]), ntohs(ip[6]), ntohs(ip[7])); + str += sprintf(str, "%pI6", ip); } str += sprintf(str, "\n"); return str - buf; diff --git a/drivers/infiniband/core/sysfs.c b/drivers/infiniband/core/sysfs.c index 4d1042115598d39b95ccc76b12b80da0cbdf89c6..4f4d1bb9f069fa6a8f61c0027eb1f07c377d3664 100644 --- a/drivers/infiniband/core/sysfs.c +++ b/drivers/infiniband/core/sysfs.c @@ -262,15 +262,7 @@ static ssize_t show_port_gid(struct ib_port *p, struct port_attribute *attr, if (ret) return ret; - return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - be16_to_cpu(((__be16 *) gid.raw)[0]), - be16_to_cpu(((__be16 *) gid.raw)[1]), - be16_to_cpu(((__be16 *) gid.raw)[2]), - be16_to_cpu(((__be16 *) gid.raw)[3]), - be16_to_cpu(((__be16 *) gid.raw)[4]), - be16_to_cpu(((__be16 *) gid.raw)[5]), - be16_to_cpu(((__be16 *) gid.raw)[6]), - be16_to_cpu(((__be16 *) gid.raw)[7])); + return sprintf(buf, "%pI6\n", gid.raw); } static ssize_t show_port_pkey(struct ib_port *p, struct port_attribute *attr, diff --git a/drivers/infiniband/hw/amso1100/c2_provider.c b/drivers/infiniband/hw/amso1100/c2_provider.c index 69580e282af012a918fb6bf258333a34f258a584..5119d6508181633bf2ace7886bc0034afd74bcf8 100644 --- a/drivers/infiniband/hw/amso1100/c2_provider.c +++ b/drivers/infiniband/hw/amso1100/c2_provider.c @@ -653,7 +653,7 @@ static int c2_service_destroy(struct iw_cm_id *cm_id) static int c2_pseudo_up(struct net_device *netdev) { struct in_device *ind; - struct c2_dev *c2dev = netdev->priv; + struct c2_dev *c2dev = netdev->ml_priv; ind = in_dev_get(netdev); if (!ind) @@ -678,7 +678,7 @@ static int c2_pseudo_up(struct net_device *netdev) static int c2_pseudo_down(struct net_device *netdev) { struct in_device *ind; - struct c2_dev *c2dev = netdev->priv; + struct c2_dev *c2dev = netdev->ml_priv; ind = in_dev_get(netdev); if (!ind) @@ -746,14 +746,14 @@ static struct net_device *c2_pseudo_netdev_init(struct c2_dev *c2dev) /* change ethxxx to iwxxx */ strcpy(name, "iw"); strcat(name, &c2dev->netdev->name[3]); - netdev = alloc_netdev(sizeof(*netdev), name, setup); + netdev = alloc_netdev(0, name, setup); if (!netdev) { printk(KERN_ERR PFX "%s - etherdev alloc failed", __func__); return NULL; } - netdev->priv = c2dev; + netdev->ml_priv = c2dev; SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev); diff --git a/drivers/infiniband/hw/mthca/mthca_mcg.c b/drivers/infiniband/hw/mthca/mthca_mcg.c index 3f5f948792089a3bf33440794f263bf35dc33d6e..d4c81053e439fe0fa46bae57e42e92738792b9e6 100644 --- a/drivers/infiniband/hw/mthca/mthca_mcg.c +++ b/drivers/infiniband/hw/mthca/mthca_mcg.c @@ -87,17 +87,7 @@ static int find_mgm(struct mthca_dev *dev, } if (0) - mthca_dbg(dev, "Hash for %04x:%04x:%04x:%04x:" - "%04x:%04x:%04x:%04x is %04x\n", - be16_to_cpu(((__be16 *) gid)[0]), - be16_to_cpu(((__be16 *) gid)[1]), - be16_to_cpu(((__be16 *) gid)[2]), - be16_to_cpu(((__be16 *) gid)[3]), - be16_to_cpu(((__be16 *) gid)[4]), - be16_to_cpu(((__be16 *) gid)[5]), - be16_to_cpu(((__be16 *) gid)[6]), - be16_to_cpu(((__be16 *) gid)[7]), - *hash); + mthca_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash); *index = *hash; *prev = -1; @@ -264,16 +254,7 @@ int mthca_multicast_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid) goto out; if (index == -1) { - mthca_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " - "not found\n", - be16_to_cpu(((__be16 *) gid->raw)[0]), - be16_to_cpu(((__be16 *) gid->raw)[1]), - be16_to_cpu(((__be16 *) gid->raw)[2]), - be16_to_cpu(((__be16 *) gid->raw)[3]), - be16_to_cpu(((__be16 *) gid->raw)[4]), - be16_to_cpu(((__be16 *) gid->raw)[5]), - be16_to_cpu(((__be16 *) gid->raw)[6]), - be16_to_cpu(((__be16 *) gid->raw)[7])); + mthca_err(dev, "MGID %pI6 not found\n", gid->raw); err = -EINVAL; goto out; } diff --git a/drivers/infiniband/hw/nes/nes.c b/drivers/infiniband/hw/nes/nes.c index aa1dc41f04c8fae5a8765bc9eb6853d9c28f4bf0..b9611ade9eab1aa917fcac20f0ef639404773981 100644 --- a/drivers/infiniband/hw/nes/nes.c +++ b/drivers/infiniband/hw/nes/nes.c @@ -142,14 +142,9 @@ static int nes_inetaddr_event(struct notifier_block *notifier, struct nes_device *nesdev; struct net_device *netdev; struct nes_vnic *nesvnic; - unsigned int addr; - unsigned int mask; - - addr = ntohl(ifa->ifa_address); - mask = ntohl(ifa->ifa_mask); - nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address " NIPQUAD_FMT - ", netmask " NIPQUAD_FMT ".\n", - HIPQUAD(addr), HIPQUAD(mask)); + + nes_debug(NES_DBG_NETDEV, "nes_inetaddr_event: ip address %pI4, netmask %pI4.\n", + &ifa->ifa_address, &ifa->ifa_mask); list_for_each_entry(nesdev, &nes_dev_list, list) { nes_debug(NES_DBG_NETDEV, "Nesdev list entry = 0x%p. (%s)\n", nesdev, nesdev->netdev[0]->name); @@ -360,10 +355,8 @@ struct ib_qp *nes_get_qp(struct ib_device *device, int qpn) */ static void nes_print_macaddr(struct net_device *netdev) { - DECLARE_MAC_BUF(mac); - - nes_debug(NES_DBG_INIT, "%s: %s, IRQ %u\n", - netdev->name, print_mac(mac, netdev->dev_addr), netdev->irq); + nes_debug(NES_DBG_INIT, "%s: %pM, IRQ %u\n", + netdev->name, netdev->dev_addr, netdev->irq); } /** diff --git a/drivers/infiniband/hw/nes/nes_cm.c b/drivers/infiniband/hw/nes/nes_cm.c index cb48041bed694857a8bc4757f1ad854e93deed0f..a812db24347756a2e755988e590c416bc12dab60 100644 --- a/drivers/infiniband/hw/nes/nes_cm.c +++ b/drivers/infiniband/hw/nes/nes_cm.c @@ -782,8 +782,8 @@ static struct nes_cm_node *find_node(struct nes_cm_core *cm_core, /* get a handle on the hte */ hte = &cm_core->connected_nodes; - nes_debug(NES_DBG_CM, "Searching for an owner node: " NIPQUAD_FMT ":%x from core %p->%p\n", - HIPQUAD(loc_addr), loc_port, cm_core, hte); + nes_debug(NES_DBG_CM, "Searching for an owner node: %pI4:%x from core %p->%p\n", + &loc_addr, loc_port, cm_core, hte); /* walk list and find cm_node associated with this session ID */ spin_lock_irqsave(&cm_core->ht_lock, flags); @@ -832,8 +832,8 @@ static struct nes_cm_listener *find_listener(struct nes_cm_core *cm_core, } spin_unlock_irqrestore(&cm_core->listen_list_lock, flags); - nes_debug(NES_DBG_CM, "Unable to find listener for " NIPQUAD_FMT ":%x\n", - HIPQUAD(dst_addr), dst_port); + nes_debug(NES_DBG_CM, "Unable to find listener for %pI4:%x\n", + &dst_addr, dst_port); /* no listener */ return NULL; @@ -988,7 +988,6 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip) struct flowi fl; struct neighbour *neigh; int rc = -1; - DECLARE_MAC_BUF(mac); memset(&fl, 0, sizeof fl); fl.nl_u.ip4_u.daddr = htonl(dst_ip); @@ -1002,8 +1001,8 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip) if (neigh) { if (neigh->nud_state & NUD_VALID) { nes_debug(NES_DBG_CM, "Neighbor MAC address for 0x%08X" - " is %s, Gateway is 0x%08X \n", dst_ip, - print_mac(mac, neigh->ha), ntohl(rt->rt_gateway)); + " is %pM, Gateway is 0x%08X \n", dst_ip, + neigh->ha, ntohl(rt->rt_gateway)); nes_manage_arp_cache(nesvnic->netdev, neigh->ha, dst_ip, NES_ARP_ADD); rc = nes_arp_table(nesvnic->nesdev, dst_ip, NULL, @@ -1032,7 +1031,6 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, int arpindex = 0; struct nes_device *nesdev; struct nes_adapter *nesadapter; - DECLARE_MAC_BUF(mac); /* create an hte and cm_node for this instance */ cm_node = kzalloc(sizeof(*cm_node), GFP_ATOMIC); @@ -1045,10 +1043,9 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, cm_node->loc_port = cm_info->loc_port; cm_node->rem_port = cm_info->rem_port; cm_node->send_write0 = send_first; - nes_debug(NES_DBG_CM, "Make node addresses : loc = " NIPQUAD_FMT - ":%x, rem = " NIPQUAD_FMT ":%x\n", - HIPQUAD(cm_node->loc_addr), cm_node->loc_port, - HIPQUAD(cm_node->rem_addr), cm_node->rem_port); + nes_debug(NES_DBG_CM, "Make node addresses : loc = %pI4:%x, rem = %pI4:%x\n", + &cm_node->loc_addr, cm_node->loc_port, + &cm_node->rem_addr, cm_node->rem_port); cm_node->listener = listener; cm_node->netdev = nesvnic->netdev; cm_node->cm_id = cm_info->cm_id; @@ -1101,8 +1098,8 @@ static struct nes_cm_node *make_cm_node(struct nes_cm_core *cm_core, /* copy the mac addr to node context */ memcpy(cm_node->rem_mac, nesadapter->arp_table[arpindex].mac_addr, ETH_ALEN); - nes_debug(NES_DBG_CM, "Remote mac addr from arp table: %s\n", - print_mac(mac, cm_node->rem_mac)); + nes_debug(NES_DBG_CM, "Remote mac addr from arp table: %pM\n", + cm_node->rem_mac); add_hte_node(cm_core, cm_node); atomic_inc(&cm_nodes_created); @@ -2077,10 +2074,8 @@ static int mini_cm_recv_pkt(struct nes_cm_core *cm_core, nfo.rem_addr = ntohl(iph->saddr); nfo.rem_port = ntohs(tcph->source); - nes_debug(NES_DBG_CM, "Received packet: dest=" NIPQUAD_FMT - ":0x%04X src=" NIPQUAD_FMT ":0x%04X\n", - NIPQUAD(iph->daddr), tcph->dest, - NIPQUAD(iph->saddr), tcph->source); + nes_debug(NES_DBG_CM, "Received packet: dest=%pI4:0x%04X src=%pI4:0x%04X\n", + &iph->daddr, tcph->dest, &iph->saddr, tcph->source); do { cm_node = find_node(cm_core, diff --git a/drivers/infiniband/hw/nes/nes_hw.c b/drivers/infiniband/hw/nes/nes_hw.c index 8f70ff2dcc5855b3d8e69e3772f6f9bac260d2fd..5d139db1b771e745e9c248df0536c3bbdbc5d01e 100644 --- a/drivers/infiniband/hw/nes/nes_hw.c +++ b/drivers/infiniband/hw/nes/nes_hw.c @@ -2541,7 +2541,7 @@ static void nes_nic_napi_ce_handler(struct nes_device *nesdev, struct nes_hw_nic { struct nes_vnic *nesvnic = container_of(cq, struct nes_vnic, nic_cq); - netif_rx_schedule(nesdev->netdev[nesvnic->netdev_index], &nesvnic->napi); + netif_rx_schedule(&nesvnic->napi); } diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c index 730358637bb62603111e936f02ac1ad5c336e780..57a47cf7e513ca60d86a1a108454f36248bcd16a 100644 --- a/drivers/infiniband/hw/nes/nes_nic.c +++ b/drivers/infiniband/hw/nes/nes_nic.c @@ -99,7 +99,6 @@ static int nics_per_function = 1; static int nes_netdev_poll(struct napi_struct *napi, int budget) { struct nes_vnic *nesvnic = container_of(napi, struct nes_vnic, napi); - struct net_device *netdev = nesvnic->netdev; struct nes_device *nesdev = nesvnic->nesdev; struct nes_hw_nic_cq *nescq = &nesvnic->nic_cq; @@ -112,7 +111,7 @@ static int nes_netdev_poll(struct napi_struct *napi, int budget) nes_nic_ce_handler(nesdev, nescq); if (nescq->cqes_pending == 0) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); /* clear out completed cqes and arm */ nes_write32(nesdev->regs+NES_CQE_ALLOC, NES_CQE_ALLOC_NOTIFY_NEXT | nescq->cq_number | (nescq->cqe_allocs_pending << 16)); @@ -797,14 +796,13 @@ static int nes_netdev_set_mac_address(struct net_device *netdev, void *p) int i; u32 macaddr_low; u16 macaddr_high; - DECLARE_MAC_BUF(mac); if (!is_valid_ether_addr(mac_addr->sa_data)) return -EADDRNOTAVAIL; memcpy(netdev->dev_addr, mac_addr->sa_data, netdev->addr_len); - printk(PFX "%s: Address length = %d, Address = %s\n", - __func__, netdev->addr_len, print_mac(mac, mac_addr->sa_data)); + printk(PFX "%s: Address length = %d, Address = %pM\n", + __func__, netdev->addr_len, mac_addr->sa_data); macaddr_high = ((u16)netdev->dev_addr[0]) << 8; macaddr_high += (u16)netdev->dev_addr[1]; macaddr_low = ((u32)netdev->dev_addr[2]) << 24; @@ -909,9 +907,8 @@ static void nes_netdev_set_multicast_list(struct net_device *netdev) if (mc_index >= max_pft_entries_avaiable) break; if (multicast_addr) { - DECLARE_MAC_BUF(mac); - nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %s to register 0x%04X nic_idx=%d\n", - print_mac(mac, multicast_addr->dmi_addr), + nes_debug(NES_DBG_NIC_RX, "Assigning MC Address %pM to register 0x%04X nic_idx=%d\n", + multicast_addr->dmi_addr, perfect_filter_register_address+(mc_index * 8), mc_nic_index); macaddr_high = ((u16)multicast_addr->dmi_addr[0]) << 8; diff --git a/drivers/infiniband/hw/nes/nes_utils.c b/drivers/infiniband/hw/nes/nes_utils.c index 5611a73d5831395f61e57559cd972f9949b726c0..aa9b7348c7285a026a7e8831b1ad97f2ed7a00eb 100644 --- a/drivers/infiniband/hw/nes/nes_utils.c +++ b/drivers/infiniband/hw/nes/nes_utils.c @@ -682,9 +682,8 @@ int nes_arp_table(struct nes_device *nesdev, u32 ip_addr, u8 *mac_addr, u32 acti /* DELETE or RESOLVE */ if (arp_index == nesadapter->arp_table_size) { - nes_debug(NES_DBG_NETDEV, "MAC for " NIPQUAD_FMT " not in ARP table - cannot %s\n", - HIPQUAD(ip_addr), - action == NES_ARP_RESOLVE ? "resolve" : "delete"); + nes_debug(NES_DBG_NETDEV, "MAC for %pI4 not in ARP table - cannot %s\n", + &ip_addr, action == NES_ARP_RESOLVE ? "resolve" : "delete"); return -1; } diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h index e0c7dfabf2b4e6d6f13abab65ffcc4d11dffefcb..753a983a5fdc8c85d6467e430f27bef4afc716b1 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib.h +++ b/drivers/infiniband/ulp/ipoib/ipoib.h @@ -732,29 +732,6 @@ extern int ipoib_debug_level; do { (void) (priv); } while (0) #endif /* CONFIG_INFINIBAND_IPOIB_DEBUG_DATA */ - -#define IPOIB_GID_FMT "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:" \ - "%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x:%2.2x%2.2x" - -#define IPOIB_GID_RAW_ARG(gid) ((u8 *)(gid))[0], \ - ((u8 *)(gid))[1], \ - ((u8 *)(gid))[2], \ - ((u8 *)(gid))[3], \ - ((u8 *)(gid))[4], \ - ((u8 *)(gid))[5], \ - ((u8 *)(gid))[6], \ - ((u8 *)(gid))[7], \ - ((u8 *)(gid))[8], \ - ((u8 *)(gid))[9], \ - ((u8 *)(gid))[10],\ - ((u8 *)(gid))[11],\ - ((u8 *)(gid))[12],\ - ((u8 *)(gid))[13],\ - ((u8 *)(gid))[14],\ - ((u8 *)(gid))[15] - -#define IPOIB_GID_ARG(gid) IPOIB_GID_RAW_ARG((gid).raw) - #define IPOIB_QPN(ha) (be32_to_cpup((__be32 *) ha) & 0xffffff) #endif /* _IPOIB_H */ diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c index 7b14c2c395008fc2acc3b38505c81cbeb3111929..47d588ba2a7f73e830c249b7546c441c93e26fcf 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c @@ -1128,8 +1128,8 @@ static int ipoib_cm_tx_init(struct ipoib_cm_tx *p, u32 qpn, goto err_send_cm; } - ipoib_dbg(priv, "Request connection 0x%x for gid " IPOIB_GID_FMT " qpn 0x%x\n", - p->qp->qp_num, IPOIB_GID_ARG(pathrec->dgid), qpn); + ipoib_dbg(priv, "Request connection 0x%x for gid %pI6 qpn 0x%x\n", + p->qp->qp_num, pathrec->dgid.raw, qpn); return 0; @@ -1276,8 +1276,8 @@ void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx) if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) { list_move(&tx->list, &priv->cm.reap_list); queue_work(ipoib_workqueue, &priv->cm.reap_task); - ipoib_dbg(priv, "Reap connection for gid " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(tx->neigh->dgid)); + ipoib_dbg(priv, "Reap connection for gid %pI6\n", + tx->neigh->dgid.raw); tx->neigh = NULL; } } diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c index 28eb6f03c588987c1c417377205e53b34b2f5058..a1925810be3cb23f8e768b030c60d68944267b5f 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c @@ -446,11 +446,11 @@ poll_more: if (dev->features & NETIF_F_LRO) lro_flush_all(&priv->lro.lro_mgr); - netif_rx_complete(dev, napi); + netif_rx_complete(napi); if (unlikely(ib_req_notify_cq(priv->recv_cq, IB_CQ_NEXT_COMP | IB_CQ_REPORT_MISSED_EVENTS)) && - netif_rx_reschedule(dev, napi)) + netif_rx_reschedule(napi)) goto poll_more; } @@ -462,7 +462,7 @@ void ipoib_ib_completion(struct ib_cq *cq, void *dev_ptr) struct net_device *dev = dev_ptr; struct ipoib_dev_priv *priv = netdev_priv(dev); - netif_rx_schedule(dev, &priv->napi); + netif_rx_schedule(&priv->napi); } static void drain_tx_cq(struct net_device *dev) diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c index 85257f6b9576f77b6a5e24820ad895267d65e50c..19e06bc38b39e88c877aa9d29e49c85bfde9c84e 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_main.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c @@ -360,9 +360,9 @@ void ipoib_mark_paths_invalid(struct net_device *dev) spin_lock_irq(&priv->lock); list_for_each_entry_safe(path, tp, &priv->path_list, list) { - ipoib_dbg(priv, "mark path LID 0x%04x GID " IPOIB_GID_FMT " invalid\n", + ipoib_dbg(priv, "mark path LID 0x%04x GID %pI6 invalid\n", be16_to_cpu(path->pathrec.dlid), - IPOIB_GID_ARG(path->pathrec.dgid)); + path->pathrec.dgid.raw); path->valid = 0; } @@ -414,11 +414,11 @@ static void path_rec_completion(int status, unsigned long flags; if (!status) - ipoib_dbg(priv, "PathRec LID 0x%04x for GID " IPOIB_GID_FMT "\n", - be16_to_cpu(pathrec->dlid), IPOIB_GID_ARG(pathrec->dgid)); + ipoib_dbg(priv, "PathRec LID 0x%04x for GID %pI6\n", + be16_to_cpu(pathrec->dlid), pathrec->dgid.raw); else - ipoib_dbg(priv, "PathRec status %d for GID " IPOIB_GID_FMT "\n", - status, IPOIB_GID_ARG(path->pathrec.dgid)); + ipoib_dbg(priv, "PathRec status %d for GID %pI6\n", + status, path->pathrec.dgid.raw); skb_queue_head_init(&skqueue); @@ -528,8 +528,8 @@ static int path_rec_start(struct net_device *dev, { struct ipoib_dev_priv *priv = netdev_priv(dev); - ipoib_dbg(priv, "Start path record lookup for " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(path->pathrec.dgid)); + ipoib_dbg(priv, "Start path record lookup for %pI6\n", + path->pathrec.dgid.raw); init_completion(&path->done); @@ -766,12 +766,11 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev) if ((be16_to_cpup((__be16 *) skb->data) != ETH_P_ARP) && (be16_to_cpup((__be16 *) skb->data) != ETH_P_RARP)) { - ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x " - IPOIB_GID_FMT "\n", + ipoib_warn(priv, "Unicast, no %s: type %04x, QPN %06x %pI6\n", skb->dst ? "neigh" : "dst", be16_to_cpup((__be16 *) skb->data), IPOIB_QPN(phdr->hwaddr), - IPOIB_GID_RAW_ARG(phdr->hwaddr + 4)); + phdr->hwaddr + 4); dev_kfree_skb_any(skb); ++dev->stats.tx_dropped; return NETDEV_TX_OK; @@ -847,9 +846,9 @@ static void ipoib_neigh_cleanup(struct neighbour *n) else return; ipoib_dbg(priv, - "neigh_cleanup for %06x " IPOIB_GID_FMT "\n", + "neigh_cleanup for %06x %pI6\n", IPOIB_QPN(n->ha), - IPOIB_GID_RAW_ARG(n->ha + 4)); + n->ha + 4); spin_lock_irqsave(&priv->lock, flags); diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c index d9d1223c3fd5f7dc1609764c9a1db16e3a20018f..a2eb3b9789ebabb08f69f3b0421128900db22bd6 100644 --- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c +++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c @@ -71,9 +71,8 @@ static void ipoib_mcast_free(struct ipoib_mcast *mcast) struct ipoib_neigh *neigh, *tmp; int tx_dropped = 0; - ipoib_dbg_mcast(netdev_priv(dev), - "deleting multicast group " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_dbg_mcast(netdev_priv(dev), "deleting multicast group %pI6\n", + mcast->mcmember.mgid.raw); spin_lock_irq(&priv->lock); @@ -205,9 +204,8 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { if (test_and_set_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { - ipoib_warn(priv, "multicast group " IPOIB_GID_FMT - " already attached\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_warn(priv, "multicast group %pI6 already attached\n", + mcast->mcmember.mgid.raw); return 0; } @@ -215,9 +213,8 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, ret = ipoib_mcast_attach(dev, be16_to_cpu(mcast->mcmember.mlid), &mcast->mcmember.mgid, set_qkey); if (ret < 0) { - ipoib_warn(priv, "couldn't attach QP to multicast group " - IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_warn(priv, "couldn't attach QP to multicast group %pI6\n", + mcast->mcmember.mgid.raw); clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags); return ret; @@ -248,9 +245,8 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast, mcast->ah = ah; spin_unlock_irq(&priv->lock); - ipoib_dbg_mcast(priv, "MGID " IPOIB_GID_FMT - " AV %p, LID 0x%04x, SL %d\n", - IPOIB_GID_ARG(mcast->mcmember.mgid), + ipoib_dbg_mcast(priv, "MGID %pI6 AV %p, LID 0x%04x, SL %d\n", + mcast->mcmember.mgid.raw, mcast->ah->ah, be16_to_cpu(mcast->mcmember.mlid), mcast->mcmember.sl); @@ -295,9 +291,8 @@ ipoib_mcast_sendonly_join_complete(int status, if (status) { if (mcast->logcount++ < 20) - ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for " - IPOIB_GID_FMT ", status %d\n", - IPOIB_GID_ARG(mcast->mcmember.mgid), status); + ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for %pI6, status %d\n", + mcast->mcmember.mgid.raw, status); /* Flush out any queued packets */ netif_tx_lock_bh(dev); @@ -356,9 +351,8 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast) ipoib_warn(priv, "ib_sa_join_multicast failed (ret = %d)\n", ret); } else { - ipoib_dbg_mcast(priv, "no multicast record for " IPOIB_GID_FMT - ", starting join\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_dbg_mcast(priv, "no multicast record for %pI6, starting join\n", + mcast->mcmember.mgid.raw); } return ret; @@ -386,9 +380,8 @@ static int ipoib_mcast_join_complete(int status, struct net_device *dev = mcast->dev; struct ipoib_dev_priv *priv = netdev_priv(dev); - ipoib_dbg_mcast(priv, "join completion for " IPOIB_GID_FMT - " (status %d)\n", - IPOIB_GID_ARG(mcast->mcmember.mgid), status); + ipoib_dbg_mcast(priv, "join completion for %pI6 (status %d)\n", + mcast->mcmember.mgid.raw, status); /* We trap for port events ourselves. */ if (status == -ENETRESET) @@ -417,15 +410,11 @@ static int ipoib_mcast_join_complete(int status, if (mcast->logcount++ < 20) { if (status == -ETIMEDOUT) { - ipoib_dbg_mcast(priv, "multicast join failed for " IPOIB_GID_FMT - ", status %d\n", - IPOIB_GID_ARG(mcast->mcmember.mgid), - status); + ipoib_dbg_mcast(priv, "multicast join failed for %pI6, status %d\n", + mcast->mcmember.mgid.raw, status); } else { - ipoib_warn(priv, "multicast join failed for " - IPOIB_GID_FMT ", status %d\n", - IPOIB_GID_ARG(mcast->mcmember.mgid), - status); + ipoib_warn(priv, "multicast join failed for %pI6, status %d\n", + mcast->mcmember.mgid.raw, status); } } @@ -457,8 +446,7 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast, ib_sa_comp_mask comp_mask; int ret = 0; - ipoib_dbg_mcast(priv, "joining MGID " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_dbg_mcast(priv, "joining MGID %pI6\n", mcast->mcmember.mgid.raw); rec.mgid = mcast->mcmember.mgid; rec.port_gid = priv->local_gid; @@ -643,8 +631,8 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast) ib_sa_free_multicast(mcast->mc); if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) { - ipoib_dbg_mcast(priv, "leaving MGID " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_dbg_mcast(priv, "leaving MGID %pI6\n", + mcast->mcmember.mgid.raw); /* Remove ourselves from the multicast group */ ret = ib_detach_mcast(priv->qp, &mcast->mcmember.mgid, @@ -675,8 +663,8 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb) mcast = __ipoib_mcast_find(dev, mgid); if (!mcast) { /* Let's create a new send only group now */ - ipoib_dbg_mcast(priv, "setting up send only multicast group for " - IPOIB_GID_FMT "\n", IPOIB_GID_RAW_ARG(mgid)); + ipoib_dbg_mcast(priv, "setting up send only multicast group for %pI6\n", + mgid); mcast = ipoib_mcast_alloc(dev, 0); if (!mcast) { @@ -809,14 +797,14 @@ void ipoib_mcast_restart_task(struct work_struct *work) /* ignore group which is directly joined by userspace */ if (test_bit(IPOIB_FLAG_UMCAST, &priv->flags) && !ib_sa_get_mcmember_rec(priv->ca, priv->port, &mgid, &rec)) { - ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid " - IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid)); + ipoib_dbg_mcast(priv, "ignoring multicast entry for mgid %pI6\n", + mgid.raw); continue; } /* Not found or send-only group, let's add a new entry */ - ipoib_dbg_mcast(priv, "adding multicast entry for mgid " - IPOIB_GID_FMT "\n", IPOIB_GID_ARG(mgid)); + ipoib_dbg_mcast(priv, "adding multicast entry for mgid %pI6\n", + mgid.raw); nmcast = ipoib_mcast_alloc(dev, 0); if (!nmcast) { @@ -849,8 +837,8 @@ void ipoib_mcast_restart_task(struct work_struct *work) list_for_each_entry_safe(mcast, tmcast, &priv->multicast_list, list) { if (!test_bit(IPOIB_MCAST_FLAG_FOUND, &mcast->flags) && !test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) { - ipoib_dbg_mcast(priv, "deleting multicast group " IPOIB_GID_FMT "\n", - IPOIB_GID_ARG(mcast->mcmember.mgid)); + ipoib_dbg_mcast(priv, "deleting multicast group %pI6\n", + mcast->mcmember.mgid.raw); rb_erase(&mcast->rb_node, &priv->multicast_tree); diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c index 6dc6b174cdd4a7060b5f73dad419d587c5c07853..319b188145be197d5a2fee93edfd204da867df04 100644 --- a/drivers/infiniband/ulp/iser/iser_verbs.c +++ b/drivers/infiniband/ulp/iser/iser_verbs.c @@ -516,14 +516,14 @@ int iser_connect(struct iser_conn *ib_conn, struct sockaddr *src, *dst; int err = 0; - sprintf(ib_conn->name,"%d.%d.%d.%d:%d", - NIPQUAD(dst_addr->sin_addr.s_addr), dst_addr->sin_port); + sprintf(ib_conn->name, "%pI4:%d", + &dst_addr->sin_addr.s_addr, dst_addr->sin_port); /* the device is known only --after-- address resolution */ ib_conn->device = NULL; - iser_err("connecting to: %d.%d.%d.%d, port 0x%x\n", - NIPQUAD(dst_addr->sin_addr), dst_addr->sin_port); + iser_err("connecting to: %pI4, port 0x%x\n", + &dst_addr->sin_addr, dst_addr->sin_port); ib_conn->state = ISER_CONN_PENDING; diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c index 5b8b533f29089a7ccd428abffa65136ae8cb30e0..7c13db885bf67defc836d8d60552865ff0041a62 100644 --- a/drivers/infiniband/ulp/srp/ib_srp.c +++ b/drivers/infiniband/ulp/srp/ib_srp.c @@ -1514,15 +1514,7 @@ static ssize_t show_dgid(struct device *dev, struct device_attribute *attr, target->state == SRP_TARGET_REMOVED) return -ENODEV; - return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - be16_to_cpu(((__be16 *) target->path.dgid.raw)[0]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[1]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[2]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[3]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[4]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[5]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[6]), - be16_to_cpu(((__be16 *) target->path.dgid.raw)[7])); + return sprintf(buf, "%pI6\n", target->path.dgid.raw); } static ssize_t show_orig_dgid(struct device *dev, @@ -1534,15 +1526,7 @@ static ssize_t show_orig_dgid(struct device *dev, target->state == SRP_TARGET_REMOVED) return -ENODEV; - return sprintf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", - be16_to_cpu(target->orig_dgid[0]), - be16_to_cpu(target->orig_dgid[1]), - be16_to_cpu(target->orig_dgid[2]), - be16_to_cpu(target->orig_dgid[3]), - be16_to_cpu(target->orig_dgid[4]), - be16_to_cpu(target->orig_dgid[5]), - be16_to_cpu(target->orig_dgid[6]), - be16_to_cpu(target->orig_dgid[7])); + return sprintf(buf, "%pI6\n", target->orig_dgid); } static ssize_t show_zero_req_lim(struct device *dev, @@ -1883,19 +1867,12 @@ static ssize_t srp_create_target(struct device *dev, shost_printk(KERN_DEBUG, target->scsi_host, PFX "new target: id_ext %016llx ioc_guid %016llx pkey %04x " - "service_id %016llx dgid %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n", + "service_id %016llx dgid %pI6\n", (unsigned long long) be64_to_cpu(target->id_ext), (unsigned long long) be64_to_cpu(target->ioc_guid), be16_to_cpu(target->path.pkey), (unsigned long long) be64_to_cpu(target->service_id), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[0]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[2]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[4]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[6]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[8]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[10]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[12]), - (int) be16_to_cpu(*(__be16 *) &target->path.dgid.raw[14])); + target->path.dgid.raw); ret = srp_create_target_ib(target); if (ret) diff --git a/drivers/isdn/gigaset/asyncdata.c b/drivers/isdn/gigaset/asyncdata.c index c2bd97d29273ce584b5182578d05d41fd995c3da..2a4ce96f04bd7ecfea5ce9111b231e076bc80a28 100644 --- a/drivers/isdn/gigaset/asyncdata.c +++ b/drivers/isdn/gigaset/asyncdata.c @@ -17,8 +17,6 @@ #include #include -//#define GIG_M10x_STUFF_VOICE_DATA - /* check if byte must be stuffed/escaped * I'm not sure which data should be encoded. * Therefore I will go the hard way and decode every value @@ -147,19 +145,17 @@ static inline int hdlc_loop(unsigned char c, unsigned char *src, int numbytes, } byte_stuff: c ^= PPP_TRANS; -#ifdef CONFIG_GIGASET_DEBUG if (unlikely(!muststuff(c))) gig_dbg(DEBUG_HDLC, "byte stuffed: 0x%02x", c); -#endif } else if (unlikely(c == PPP_FLAG)) { if (unlikely(inputstate & INS_skip_frame)) { - if (!(inputstate & INS_have_data)) { /* 7E 7E */ #ifdef CONFIG_GIGASET_DEBUG + if (!(inputstate & INS_have_data)) { /* 7E 7E */ ++bcs->emptycount; -#endif } else gig_dbg(DEBUG_HDLC, "7e----------------------------"); +#endif /* end of frame */ error = 1; @@ -226,11 +222,9 @@ byte_stuff: } break; -#ifdef CONFIG_GIGASET_DEBUG } else if (unlikely(muststuff(c))) { /* Should not happen. Possible after ZDLE=1. */ gig_dbg(DEBUG_HDLC, "not byte stuffed: 0x%02x", c); -#endif } /* add character */ @@ -394,20 +388,16 @@ void gigaset_m10x_input(struct inbuf_t *inbuf) inbuf->inputstate &= ~INS_DLE_char; switch (c) { case 'X': /*begin of command*/ -#ifdef CONFIG_GIGASET_DEBUG if (inbuf->inputstate & INS_command) - dev_err(cs->dev, + dev_warn(cs->dev, "received 'X' in command mode\n"); -#endif inbuf->inputstate |= INS_command | INS_DLE_command; break; case '.': /*end of command*/ -#ifdef CONFIG_GIGASET_DEBUG if (!(inbuf->inputstate & INS_command)) - dev_err(cs->dev, + dev_warn(cs->dev, "received '.' in hdlc mode\n"); -#endif inbuf->inputstate &= cs->dle ? ~(INS_DLE_command|INS_command) : ~INS_DLE_command; diff --git a/drivers/isdn/gigaset/bas-gigaset.c b/drivers/isdn/gigaset/bas-gigaset.c index 3f11910c7ccdbf4c2edb31d360f3e40feba77d4b..18dd8aacbe8d4157bee715943ab0612873c2b75c 100644 --- a/drivers/isdn/gigaset/bas-gigaset.c +++ b/drivers/isdn/gigaset/bas-gigaset.c @@ -2067,7 +2067,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) bcs->hw.bas = ubc = kmalloc(sizeof(struct bas_bc_state), GFP_KERNEL); if (!ubc) { - err("could not allocate bas_bc_state"); + pr_err("out of memory\n"); return 0; } @@ -2081,7 +2081,7 @@ static int gigaset_initbcshw(struct bc_state *bcs) ubc->isooutdone = ubc->isooutfree = ubc->isooutovfl = NULL; ubc->numsub = 0; if (!(ubc->isooutbuf = kmalloc(sizeof(struct isowbuf_t), GFP_KERNEL))) { - err("could not allocate isochronous output buffer"); + pr_err("out of memory\n"); kfree(ubc); bcs->hw.bas = NULL; return 0; @@ -2136,8 +2136,10 @@ static int gigaset_initcshw(struct cardstate *cs) struct bas_cardstate *ucs; cs->hw.bas = ucs = kmalloc(sizeof *ucs, GFP_KERNEL); - if (!ucs) + if (!ucs) { + pr_err("out of memory\n"); return 0; + } ucs->urb_cmd_in = NULL; ucs->urb_cmd_out = NULL; @@ -2503,12 +2505,11 @@ static int __init bas_gigaset_init(void) /* register this driver with the USB subsystem */ result = usb_register(&gigaset_usb_driver); if (result < 0) { - err("usb_register failed (error %d)", -result); + pr_err("error %d registering USB driver\n", -result); goto error; } - info(DRIVER_AUTHOR); - info(DRIVER_DESC); + pr_info(DRIVER_DESC "\n"); return 0; error: diff --git a/drivers/isdn/gigaset/common.c b/drivers/isdn/gigaset/common.c index 9d3ce7718e58faac892540caf6c2e61eadd2f051..0048ce98bfa8d789dd2262db49bf672ec75f64b1 100644 --- a/drivers/isdn/gigaset/common.c +++ b/drivers/isdn/gigaset/common.c @@ -580,7 +580,7 @@ static struct bc_state *gigaset_initbcs(struct bc_state *bcs, } else if ((bcs->skb = dev_alloc_skb(SBUFSIZE + HW_HDR_LEN)) != NULL) skb_reserve(bcs->skb, HW_HDR_LEN); else { - warn("could not allocate skb"); + pr_err("out of memory\n"); bcs->inputstate |= INS_skip_frame; } @@ -634,20 +634,20 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, gig_dbg(DEBUG_INIT, "allocating cs"); if (!(cs = alloc_cs(drv))) { - err("maximum number of devices exceeded"); + pr_err("maximum number of devices exceeded\n"); return NULL; } gig_dbg(DEBUG_INIT, "allocating bcs[0..%d]", channels - 1); cs->bcs = kmalloc(channels * sizeof(struct bc_state), GFP_KERNEL); if (!cs->bcs) { - err("out of memory"); + pr_err("out of memory\n"); goto error; } gig_dbg(DEBUG_INIT, "allocating inbuf"); cs->inbuf = kmalloc(sizeof(struct inbuf_t), GFP_KERNEL); if (!cs->inbuf) { - err("out of memory"); + pr_err("out of memory\n"); goto error; } @@ -690,7 +690,7 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, for (i = 0; i < channels; ++i) { gig_dbg(DEBUG_INIT, "setting up bcs[%d].read", i); if (!gigaset_initbcs(cs->bcs + i, cs, i)) { - err("could not allocate channel %d data", i); + pr_err("could not allocate channel %d data\n", i); goto error; } } @@ -720,17 +720,15 @@ struct cardstate *gigaset_initcs(struct gigaset_driver *drv, int channels, gig_dbg(DEBUG_INIT, "setting up iif"); if (!gigaset_register_to_LL(cs, modulename)) { - err("register_isdn failed"); + pr_err("error registering ISDN device\n"); goto error; } make_valid(cs, VALID_ID); ++cs->cs_init; gig_dbg(DEBUG_INIT, "setting up hw"); - if (!cs->ops->initcshw(cs)) { - err("could not allocate device specific data"); + if (!cs->ops->initcshw(cs)) goto error; - } ++cs->cs_init; @@ -836,7 +834,7 @@ static void cleanup_cs(struct cardstate *cs) for (i = 0; i < cs->channels; ++i) { gigaset_freebcs(cs->bcs + i); if (!gigaset_initbcs(cs->bcs + i, cs, i)) - break; //FIXME error handling + pr_err("could not allocate channel %d data\n", i); } if (cs->waiting) { @@ -1120,8 +1118,7 @@ static int __init gigaset_init_module(void) if (gigaset_debuglevel == 1) gigaset_debuglevel = DEBUG_DEFAULT; - info(DRIVER_AUTHOR); - info(DRIVER_DESC); + pr_info(DRIVER_DESC "\n"); return 0; } diff --git a/drivers/isdn/gigaset/ev-layer.c b/drivers/isdn/gigaset/ev-layer.c index 5cbf64d850eefbbb4405d670d969f5938e38148e..e582a4887bc15b4055e73ac6f9a8556ef8538ddf 100644 --- a/drivers/isdn/gigaset/ev-layer.c +++ b/drivers/isdn/gigaset/ev-layer.c @@ -203,15 +203,6 @@ struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */ {EV_TIMEOUT, 120,121, -1, 0, 0, {ACT_FAILVER, ACT_INIT}}, {RSP_ERROR, 120,121, -1, 0, 0, {ACT_FAILVER, ACT_INIT}}, {RSP_OK, 121,121, -1, 0, 0, {ACT_GOTVER, ACT_INIT}}, -#if 0 - {EV_TIMEOUT, 120,121, -1, 130, 5, {ACT_FAILVER}, "^SGCI=1\r"}, - {RSP_ERROR, 120,121, -1, 130, 5, {ACT_FAILVER}, "^SGCI=1\r"}, - {RSP_OK, 121,121, -1, 130, 5, {ACT_GOTVER}, "^SGCI=1\r"}, - - {RSP_OK, 130,130, -1, 0, 0, {ACT_INIT}}, - {RSP_ERROR, 130,130, -1, 0, 0, {ACT_FAILINIT}}, - {EV_TIMEOUT, 130,130, -1, 0, 0, {ACT_FAILINIT}}, -#endif /* leave dle mode */ {RSP_INIT, 0, 0,SEQ_DLE0, 201, 5, {0}, "^SDLE=0\r"}, @@ -260,10 +251,6 @@ struct reply_t gigaset_tab_nocid_m10x[]= /* with dle mode */ {RSP_INIT, 0, 0,SEQ_NOCID, 0, 0, {ACT_ABORTCID}}, /* reset */ -#if 0 - {RSP_INIT, 0, 0,SEQ_SHUTDOWN, 503, 5, {0}, "^SGCI=0\r"}, - {RSP_OK, 503,503, -1, 504, 5, {0}, "Z\r"}, -#endif {RSP_INIT, 0, 0,SEQ_SHUTDOWN, 504, 5, {0}, "Z\r"}, {RSP_OK, 504,504, -1, 0, 0, {ACT_SDOWN}}, {RSP_ERROR, 501,599, -1, 0, 0, {ACT_FAILSDOWN}}, @@ -391,24 +378,6 @@ struct reply_t gigaset_tab_cid_m10x[] = /* for M10x */ }; -#if 0 -static struct reply_t tab_nocid[]= /* no dle mode */ //FIXME -{ - /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ - - {RSP_ANY, -1, -1, -1, -1,-1, ACT_WARN, NULL}, - {RSP_LAST,0,0,0,0,0,0} -}; - -static struct reply_t tab_cid[] = /* no dle mode */ //FIXME -{ - /* resp_code, min_ConState, max_ConState, parameter, new_ConState, timeout, action, command */ - - {RSP_ANY, -1, -1, -1, -1,-1, ACT_WARN, NULL}, - {RSP_LAST,0,0,0,0,0,0} -}; -#endif - static const struct resp_type_t resp_type[] = { /*{"", RSP_EMPTY, RT_NOTHING},*/ @@ -665,13 +634,8 @@ void gigaset_handle_modem_response(struct cardstate *cs) dev_err(cs->dev, "out of memory\n"); ++curarg; } -#ifdef CONFIG_GIGASET_DEBUG - if (!event->ptr) - gig_dbg(DEBUG_CMD, "string==NULL"); - else - gig_dbg(DEBUG_CMD, "string==%s", - (char *) event->ptr); -#endif + gig_dbg(DEBUG_CMD, "string==%s", + event->ptr ? (char *) event->ptr : "NULL"); break; case RT_ZCAU: event->parameter = -1; @@ -697,9 +661,7 @@ void gigaset_handle_modem_response(struct cardstate *cs) ++curarg; } else event->parameter = -1; -#ifdef CONFIG_GIGASET_DEBUG gig_dbg(DEBUG_CMD, "parameter==%d", event->parameter); -#endif break; } diff --git a/drivers/isdn/gigaset/gigaset.h b/drivers/isdn/gigaset/gigaset.h index 003752954993cffa46534a2a3a95383fcddd8645..747178f03d2c3ec26f50c6d15decda33801b2942 100644 --- a/drivers/isdn/gigaset/gigaset.h +++ b/drivers/isdn/gigaset/gigaset.h @@ -16,6 +16,9 @@ #ifndef GIGASET_H #define GIGASET_H +/* define global prefix for pr_ macros in linux/kernel.h */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include #include #include @@ -97,23 +100,6 @@ enum debuglevel { activated */ }; -/* Kernel message macros for situations where dev_printk and friends cannot be - * used for lack of reliable access to a device structure. - * linux/usb.h already contains these but in an obsolete form which clutters - * the log needlessly, and according to the USB maintainer those should be - * removed rather than fixed anyway. - */ -#undef err -#undef info -#undef warn - -#define err(format, arg...) printk(KERN_ERR KBUILD_MODNAME ": " \ - format "\n" , ## arg) -#define info(format, arg...) printk(KERN_INFO KBUILD_MODNAME ": " \ - format "\n" , ## arg) -#define warn(format, arg...) printk(KERN_WARNING KBUILD_MODNAME ": " \ - format "\n" , ## arg) - #ifdef CONFIG_GIGASET_DEBUG #define gig_dbg(level, format, arg...) \ diff --git a/drivers/isdn/gigaset/i4l.c b/drivers/isdn/gigaset/i4l.c index 3c127a8cbaf2261f473e28a01b29c0e00c2f2c93..69a702f0db93f3fa70ccd7fc6c649e611f4f0a5f 100644 --- a/drivers/isdn/gigaset/i4l.c +++ b/drivers/isdn/gigaset/i4l.c @@ -42,7 +42,7 @@ static int writebuf_from_LL(int driverID, int channel, int ack, unsigned skblen; if (!(cs = gigaset_get_cs_by_id(driverID))) { - err("%s: invalid driver ID (%d)", __func__, driverID); + pr_err("%s: invalid driver ID (%d)\n", __func__, driverID); return -ENODEV; } if (channel < 0 || channel >= cs->channels) { @@ -119,7 +119,7 @@ static int command_from_LL(isdn_ctrl *cntrl) gigaset_debugdrivers(); if (!cs) { - err("%s: invalid driver ID (%d)", __func__, cntrl->driver); + pr_err("%s: invalid driver ID (%d)\n", __func__, cntrl->driver); return -ENODEV; } diff --git a/drivers/isdn/gigaset/interface.c b/drivers/isdn/gigaset/interface.c index 521951a898ece00218d3bd96645e94466c26a349..311e7ca0fb01956eb60ee4d2441e45a4878ea63f 100644 --- a/drivers/isdn/gigaset/interface.c +++ b/drivers/isdn/gigaset/interface.c @@ -107,7 +107,7 @@ static int if_config(struct cardstate *cs, int *arg) return -EBUSY; if (!cs->connected) { - err("not connected!"); + pr_err("%s: not connected\n", __func__); return -ENODEV; } @@ -143,9 +143,6 @@ static const struct tty_operations if_ops = { .set_termios = if_set_termios, .throttle = if_throttle, .unthrottle = if_unthrottle, -#if 0 - .break_ctl = serial_break, -#endif .tiocmget = if_tiocmget, .tiocmset = if_tiocmset, }; @@ -188,7 +185,7 @@ static void if_close(struct tty_struct *tty, struct file *filp) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return; } @@ -222,7 +219,7 @@ static int if_ioctl(struct tty_struct *tty, struct file *file, cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -297,7 +294,7 @@ static int if_tiocmget(struct tty_struct *tty, struct file *file) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -323,7 +320,7 @@ static int if_tiocmset(struct tty_struct *tty, struct file *file, cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -354,7 +351,7 @@ static int if_write(struct tty_struct *tty, const unsigned char *buf, int count) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -388,7 +385,7 @@ static int if_write_room(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -420,7 +417,7 @@ static int if_chars_in_buffer(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return -ENODEV; } @@ -451,7 +448,7 @@ static void if_throttle(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return; } @@ -474,7 +471,7 @@ static void if_unthrottle(struct tty_struct *tty) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return; } @@ -501,7 +498,7 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old) cs = (struct cardstate *) tty->driver_data; if (!cs) { - err("cs==NULL in %s", __func__); + pr_err("%s: no cardstate\n", __func__); return; } @@ -565,29 +562,6 @@ static void if_set_termios(struct tty_struct *tty, struct ktermios *old) cs->ops->set_line_ctrl(cs, cflag); -#if 0 - //FIXME this hangs M101 [ts 2005-03-09] - //FIXME do we need this? - /* - * Set flow control: well, I do not really now how to handle DTR/RTS. - * Just do what we have seen with SniffUSB on Win98. - */ - /* Drop DTR/RTS if no flow control otherwise assert */ - gig_dbg(DEBUG_IF, "%u: control_state %x", - cs->minor_index, control_state); - new_state = control_state; - if ((iflag & IXOFF) || (iflag & IXON) || (cflag & CRTSCTS)) - new_state |= TIOCM_DTR | TIOCM_RTS; - else - new_state &= ~(TIOCM_DTR | TIOCM_RTS); - if (new_state != control_state) { - gig_dbg(DEBUG_IF, "%u: new_state %x", - cs->minor_index, new_state); - gigaset_set_modem_ctrl(cs, control_state, new_state); - control_state = new_state; - } -#endif - /* save off the modified port settings */ cs->control_state = control_state; @@ -701,7 +675,7 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, ret = tty_register_driver(tty); if (ret < 0) { - warn("failed to register tty driver (error %d)", ret); + pr_err("error %d registering tty driver\n", ret); goto error; } gig_dbg(DEBUG_IF, "tty driver initialized"); @@ -709,7 +683,7 @@ void gigaset_if_initdriver(struct gigaset_driver *drv, const char *procname, return; enomem: - warn("could not allocate tty structures"); + pr_err("out of memory\n"); error: if (drv->tty) put_tty_driver(drv->tty); diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index fbce5222d83cbab8e92826706ebfeba3256f1cec..b171e75cb52e51f920125abc984648f22415e961 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c @@ -88,11 +88,9 @@ static inline int isowbuf_startwrite(struct isowbuf_t *iwb) __func__); return 0; } -#ifdef CONFIG_GIGASET_DEBUG gig_dbg(DEBUG_ISO, "%s: acquired iso write semaphore, data[write]=%02x, nbits=%d", __func__, iwb->data[iwb->write], iwb->wbits); -#endif return 1; } @@ -173,13 +171,13 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) __func__, read, write, limit); #ifdef CONFIG_GIGASET_DEBUG if (unlikely(size < 0 || size > BAS_OUTBUFPAD)) { - err("invalid size %d", size); + pr_err("invalid size %d\n", size); return -EINVAL; } src = iwb->read; if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD || (read < src && limit >= src))) { - err("isoc write buffer frame reservation violated"); + pr_err("isoc write buffer frame reservation violated\n"); return -EFAULT; } #endif diff --git a/drivers/isdn/gigaset/ser-gigaset.c b/drivers/isdn/gigaset/ser-gigaset.c index 07052ed2a0c56d46480cb04c375df1afc3779d31..ac245e7e96a557445212e50b0987c39c46efd960 100644 --- a/drivers/isdn/gigaset/ser-gigaset.c +++ b/drivers/isdn/gigaset/ser-gigaset.c @@ -16,7 +16,6 @@ #include #include #include -#include #include /* Version Information */ @@ -408,7 +407,7 @@ static int gigaset_initcshw(struct cardstate *cs) int rc; if (!(cs->hw.ser = kzalloc(sizeof(struct ser_cardstate), GFP_KERNEL))) { - err("%s: out of memory!", __func__); + pr_err("out of memory\n"); return 0; } @@ -416,7 +415,7 @@ static int gigaset_initcshw(struct cardstate *cs) cs->hw.ser->dev.id = cs->minor_index; cs->hw.ser->dev.dev.release = gigaset_device_release; if ((rc = platform_device_register(&cs->hw.ser->dev)) != 0) { - err("error %d registering platform device", rc); + pr_err("error %d registering platform device\n", rc); kfree(cs->hw.ser); cs->hw.ser = NULL; return 0; @@ -514,11 +513,10 @@ gigaset_tty_open(struct tty_struct *tty) gig_dbg(DEBUG_INIT, "Starting HLL for Gigaset M101"); - info(DRIVER_AUTHOR); - info(DRIVER_DESC); + pr_info(DRIVER_DESC "\n"); if (!driver) { - err("%s: no driver structure", __func__); + pr_err("%s: no driver structure\n", __func__); return -ENODEV; } @@ -571,11 +569,10 @@ gigaset_tty_close(struct tty_struct *tty) } /* prevent other callers from entering ldisc methods */ - /* FIXME: should use the tty state flags */ tty->disc_data = NULL; if (!cs->hw.ser) - err("%s: no hw cardstate", __func__); + pr_err("%s: no hw cardstate\n", __func__); else { /* wait for running methods to finish */ if (!atomic_dec_and_test(&cs->hw.ser->refcnt)) @@ -672,18 +669,6 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file, return rc; } -/* - * Poll on the tty. - * Unused, always return zero. - * - * FIXME: should probably return an exception - especially on hangup - */ -static unsigned int -gigaset_tty_poll(struct tty_struct *tty, struct file *file, poll_table *wait) -{ - return 0; -} - /* * Called by the tty driver when a block of data has been received. * Will not be re-entered while running but other ldisc functions @@ -773,7 +758,6 @@ static struct tty_ldisc_ops gigaset_ldisc = { .read = gigaset_tty_read, .write = gigaset_tty_write, .ioctl = gigaset_tty_ioctl, - .poll = gigaset_tty_poll, .receive_buf = gigaset_tty_receive, .write_wakeup = gigaset_tty_wakeup, }; @@ -788,7 +772,7 @@ static int __init ser_gigaset_init(void) gig_dbg(DEBUG_INIT, "%s", __func__); if ((rc = platform_driver_register(&device_driver)) != 0) { - err("error %d registering platform driver", rc); + pr_err("error %d registering platform driver\n", rc); return rc; } @@ -799,7 +783,7 @@ static int __init ser_gigaset_init(void) goto error; if ((rc = tty_register_ldisc(N_GIGASET_M101, &gigaset_ldisc)) != 0) { - err("error %d registering line discipline", rc); + pr_err("error %d registering line discipline\n", rc); goto error; } @@ -826,7 +810,7 @@ static void __exit ser_gigaset_exit(void) } if ((rc = tty_unregister_ldisc(N_GIGASET_M101)) != 0) - err("error %d unregistering line discipline", rc); + pr_err("error %d unregistering line discipline\n", rc); platform_driver_unregister(&device_driver); } diff --git a/drivers/isdn/gigaset/usb-gigaset.c b/drivers/isdn/gigaset/usb-gigaset.c index 4661830a49db9a471f349c4d30fbc323f363ccaa..fba61f6705278250139bc2ac94e51f2409b025f5 100644 --- a/drivers/isdn/gigaset/usb-gigaset.c +++ b/drivers/isdn/gigaset/usb-gigaset.c @@ -407,7 +407,7 @@ static void gigaset_read_int_callback(struct urb *urb) spin_lock_irqsave(&cs->lock, flags); if (!cs->connected) { spin_unlock_irqrestore(&cs->lock, flags); - err("%s: disconnected", __func__); + pr_err("%s: disconnected\n", __func__); return; } r = usb_submit_urb(urb, GFP_ATOMIC); @@ -440,7 +440,7 @@ static void gigaset_write_bulk_callback(struct urb *urb) spin_lock_irqsave(&cs->lock, flags); if (!cs->connected) { - err("%s: not connected", __func__); + pr_err("%s: disconnected\n", __func__); } else { cs->hw.usb->busy = 0; tasklet_schedule(&cs->write_tasklet); @@ -612,8 +612,10 @@ static int gigaset_initcshw(struct cardstate *cs) cs->hw.usb = ucs = kmalloc(sizeof(struct usb_cardstate), GFP_KERNEL); - if (!ucs) + if (!ucs) { + pr_err("out of memory\n"); return 0; + } ucs->bchars[0] = 0; ucs->bchars[1] = 0; @@ -936,13 +938,11 @@ static int __init usb_gigaset_init(void) /* register this driver with the USB subsystem */ result = usb_register(&gigaset_usb_driver); if (result < 0) { - err("usb_gigaset: usb_register failed (error %d)", - -result); + pr_err("error %d registering USB driver\n", -result); goto error; } - info(DRIVER_AUTHOR); - info(DRIVER_DESC); + pr_info(DRIVER_DESC "\n"); return 0; error: diff --git a/drivers/isdn/hardware/eicon/di.c b/drivers/isdn/hardware/eicon/di.c index 10760b3c5eb56bda220b5b6b0d7390241d2b0a6d..b029d130eb2186fa28e5efed25cccdce9342a31b 100644 --- a/drivers/isdn/hardware/eicon/di.c +++ b/drivers/isdn/hardware/eicon/di.c @@ -353,13 +353,13 @@ void scom_clear_int(ADAPTER * a) /*------------------------------------------------------------------*/ /* return code handler */ /*------------------------------------------------------------------*/ -byte isdn_rc(ADAPTER * a, - byte Rc, - byte Id, - byte Ch, - word Ref, - dword extended_info_type, - dword extended_info) +static byte isdn_rc(ADAPTER *a, + byte Rc, + byte Id, + byte Ch, + word Ref, + dword extended_info_type, + dword extended_info) { ENTITY * this; byte e_no; @@ -555,13 +555,13 @@ byte isdn_rc(ADAPTER * a, /*------------------------------------------------------------------*/ /* indication handler */ /*------------------------------------------------------------------*/ -byte isdn_ind(ADAPTER * a, - byte Ind, - byte Id, - byte Ch, - PBUFFER * RBuffer, - byte MInd, - word MLength) +static byte isdn_ind(ADAPTER *a, + byte Ind, + byte Id, + byte Ch, + PBUFFER *RBuffer, + byte MInd, + word MLength) { ENTITY * this; word clength; diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c index 599fed88222d02f82ab4ff2a7d068c02cdafcc13..4cc94f200b724a2843333bb29a87c2bc4c5f0934 100644 --- a/drivers/isdn/hardware/eicon/message.c +++ b/drivers/isdn/hardware/eicon/message.c @@ -592,7 +592,7 @@ word api_put(APPL * appl, CAPI_MSG * msg) /* api_parse function, check the format of api messages */ /*------------------------------------------------------------------*/ -word api_parse(byte * msg, word length, byte * format, API_PARSE * parms) +static word api_parse(byte *msg, word length, byte *format, API_PARSE *parms) { word i; word p; @@ -631,7 +631,7 @@ word api_parse(byte * msg, word length, byte * format, API_PARSE * parms) return false; } -void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out) +static void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out) { word i, j, n = 0; byte *p; @@ -663,7 +663,7 @@ void api_save_msg(API_PARSE *in, byte *format, API_SAVE *out) out->parms[i].length = 0; } -void api_load_msg(API_SAVE *in, API_PARSE *out) +static void api_load_msg(API_SAVE *in, API_PARSE *out) { word i; @@ -3414,7 +3414,8 @@ byte select_b_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, return false; } -byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * parms) +static byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a, + PLCI *plci, APPL *appl, API_PARSE *parms) { word command; word i; @@ -3742,7 +3743,8 @@ byte manufacturer_req(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * p } -byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER * a, PLCI * plci, APPL * appl, API_PARSE * msg) +static byte manufacturer_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a, + PLCI *plci, APPL *appl, API_PARSE *msg) { word indication; @@ -4074,7 +4076,8 @@ capi_callback_suffix: } -void control_rc(PLCI * plci, byte req, byte rc, byte ch, byte global_req, byte nl_rc) +static void control_rc(PLCI *plci, byte req, byte rc, byte ch, byte global_req, + byte nl_rc) { dword Id; dword rId; @@ -4740,7 +4743,7 @@ void control_rc(PLCI * plci, byte req, byte rc, byte ch, byte global_req, byte } } -void data_rc(PLCI * plci, byte ch) +static void data_rc(PLCI *plci, byte ch) { dword Id; DIVA_CAPI_ADAPTER * a; @@ -4776,7 +4779,7 @@ void data_rc(PLCI * plci, byte ch) } } -void data_ack(PLCI * plci, byte ch) +static void data_ack(PLCI *plci, byte ch) { dword Id; DIVA_CAPI_ADAPTER * a; @@ -4802,7 +4805,7 @@ void data_ack(PLCI * plci, byte ch) } } -void sig_ind(PLCI * plci) +static void sig_ind(PLCI *plci) { dword x_Id; dword Id; @@ -6170,7 +6173,7 @@ static void SendSetupInfo(APPL * appl, PLCI * plci, dword Id, byte * * par } -void SendInfo(PLCI * plci, dword Id, byte * * parms, byte iesent) +static void SendInfo(PLCI *plci, dword Id, byte **parms, byte iesent) { word i; word j; @@ -6346,7 +6349,8 @@ void SendInfo(PLCI * plci, dword Id, byte * * parms, byte iesent) } -byte SendMultiIE(PLCI * plci, dword Id, byte * * parms, byte ie_type, dword info_mask, byte setupParse) +static byte SendMultiIE(PLCI *plci, dword Id, byte **parms, byte ie_type, + dword info_mask, byte setupParse) { word i; word j; @@ -6465,7 +6469,7 @@ static void SendSSExtInd(APPL * appl, PLCI * plci, dword Id, byte * * parm } }; -void nl_ind(PLCI * plci) +static void nl_ind(PLCI *plci) { byte ch; word ncci; @@ -7247,7 +7251,7 @@ void nl_ind(PLCI * plci) /* find a free PLCI */ /*------------------------------------------------------------------*/ -word get_plci(DIVA_CAPI_ADAPTER * a) +static word get_plci(DIVA_CAPI_ADAPTER *a) { word i,j; PLCI * plci; @@ -7406,7 +7410,7 @@ static void add_ie(PLCI * plci, byte code, byte * p, word p_length) /* put a unstructured data into the buffer */ /*------------------------------------------------------------------*/ -void add_d(PLCI * plci, word length, byte * p) +static void add_d(PLCI *plci, word length, byte *p) { word i; @@ -7424,7 +7428,7 @@ void add_d(PLCI * plci, word length, byte * p) /* parameter buffer */ /*------------------------------------------------------------------*/ -void add_ai(PLCI * plci, API_PARSE * ai) +static void add_ai(PLCI *plci, API_PARSE *ai) { word i; API_PARSE ai_parms[5]; @@ -7445,7 +7449,8 @@ void add_ai(PLCI * plci, API_PARSE * ai) /* put parameter for b1 protocol in the parameter buffer */ /*------------------------------------------------------------------*/ -word add_b1(PLCI * plci, API_PARSE * bp, word b_channel_info, word b1_facilities) +static word add_b1(PLCI *plci, API_PARSE *bp, word b_channel_info, + word b1_facilities) { API_PARSE bp_parms[8]; API_PARSE mdm_cfg[9]; @@ -7909,7 +7914,7 @@ word add_b1(PLCI * plci, API_PARSE * bp, word b_channel_info, word b1_faciliti /* put parameter for b2 and B3 protocol in the parameter buffer */ /*------------------------------------------------------------------*/ -word add_b23(PLCI * plci, API_PARSE * bp) +static word add_b23(PLCI *plci, API_PARSE *bp) { word i, fax_control_bits; byte pos, len; @@ -8706,7 +8711,7 @@ void sig_req(PLCI * plci, byte req, byte Id) /* send a request for the network layer entity */ /*------------------------------------------------------------------*/ -void nl_req_ncci(PLCI * plci, byte req, byte ncci) +static void nl_req_ncci(PLCI *plci, byte req, byte ncci) { if(!plci) return; if(plci->adapter->adapter_disabled) return; @@ -8728,7 +8733,7 @@ void nl_req_ncci(PLCI * plci, byte req, byte ncci) plci->req_in_start = plci->req_in; } -void send_req(PLCI * plci) +static void send_req(PLCI *plci) { ENTITY * e; word l; @@ -8863,7 +8868,7 @@ void send_data(PLCI * plci) } } -void listen_check(DIVA_CAPI_ADAPTER * a) +static void listen_check(DIVA_CAPI_ADAPTER *a) { word i,j; PLCI * plci; @@ -8906,7 +8911,7 @@ void listen_check(DIVA_CAPI_ADAPTER * a) /* functions for all parameters sent in INDs */ /*------------------------------------------------------------------*/ -void IndParse(PLCI * plci, word * parms_id, byte ** parms, byte multiIEsize) +static void IndParse(PLCI *plci, word *parms_id, byte **parms, byte multiIEsize) { word ploc; /* points to current location within packet */ byte w; @@ -8991,7 +8996,7 @@ void IndParse(PLCI * plci, word * parms_id, byte ** parms, byte multiIEsize) /* try to match a cip from received BC and HLC */ /*------------------------------------------------------------------*/ -byte ie_compare(byte * ie1, byte * ie2) +static byte ie_compare(byte *ie1, byte *ie2) { word i; if(!ie1 || ! ie2) return false; @@ -9000,7 +9005,7 @@ byte ie_compare(byte * ie1, byte * ie2) return true; } -word find_cip(DIVA_CAPI_ADAPTER * a, byte * bc, byte * hlc) +static word find_cip(DIVA_CAPI_ADAPTER *a, byte *bc, byte *hlc) { word i; word j; @@ -9068,7 +9073,7 @@ static byte AddInfo(byte **add_i, /* voice and codec features */ /*------------------------------------------------------------------*/ -void SetVoiceChannel(PLCI *plci, byte *chi, DIVA_CAPI_ADAPTER * a) +static void SetVoiceChannel(PLCI *plci, byte *chi, DIVA_CAPI_ADAPTER *a) { byte voice_chi[] = "\x02\x18\x01"; byte channel; @@ -9086,7 +9091,7 @@ void SetVoiceChannel(PLCI *plci, byte *chi, DIVA_CAPI_ADAPTER * a) } } -void VoiceChannelOff(PLCI *plci) +static void VoiceChannelOff(PLCI *plci) { dbug(1,dprintf("ExtDevOFF")); add_p(plci,FTY,"\x02\x01\x08"); /* B Off */ @@ -9099,7 +9104,8 @@ void VoiceChannelOff(PLCI *plci) } -word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte hook_listen) +static word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, + byte hook_listen) { word j; PLCI *splci; @@ -9195,7 +9201,7 @@ word AdvCodecSupport(DIVA_CAPI_ADAPTER *a, PLCI *plci, APPL *appl, byte ho } -void CodecIdCheck(DIVA_CAPI_ADAPTER *a, PLCI *plci) +static void CodecIdCheck(DIVA_CAPI_ADAPTER *a, PLCI *plci) { dbug(1,dprintf("CodecIdCheck")); diff --git a/drivers/isdn/hardware/mISDN/hfc_multi.h b/drivers/isdn/hardware/mISDN/hfc_multi.h index a33d87afc84367cf6cfc3c03112e493334e522f1..7bbf7300593d3c01c9115a4ce9a6b737c21e4d8c 100644 --- a/drivers/isdn/hardware/mISDN/hfc_multi.h +++ b/drivers/isdn/hardware/mISDN/hfc_multi.h @@ -162,8 +162,8 @@ struct hfc_multi { void (*write_fifo)(struct hfc_multi *hc, u_char *data, int len); u_long pci_origmembase, plx_origmembase, dsp_origmembase; - u_char *pci_membase; /* PCI memory (MUST BE BYTE POINTER) */ - u_char *plx_membase; /* PLX memory */ + void __iomem *pci_membase; /* PCI memory */ + void __iomem *plx_membase; /* PLX memory */ u_char *dsp_membase; /* DSP on PLX */ u_long pci_iobase; /* PCI IO */ struct hfcm_hw hw; /* remember data of write-only-registers */ diff --git a/drivers/isdn/hardware/mISDN/hfcmulti.c b/drivers/isdn/hardware/mISDN/hfcmulti.c index 1eac03f39d0005e0e75b75f3925e1924193e794b..c63e2f49da8ad38df99133197bf12ab6df670ea7 100644 --- a/drivers/isdn/hardware/mISDN/hfcmulti.c +++ b/drivers/isdn/hardware/mISDN/hfcmulti.c @@ -171,9 +171,8 @@ static int (*unregister_interrupt)(void); static int interrupt_registered; static struct hfc_multi *syncmaster; -int plxsd_master; /* if we have a master card (yet) */ +static int plxsd_master; /* if we have a master card (yet) */ static spinlock_t plx_lock; /* may not acquire other lock inside */ -EXPORT_SYMBOL(plx_lock); #define TYP_E1 1 #define TYP_4S 4 @@ -422,7 +421,7 @@ HFC_wait_debug(struct hfc_multi *hc, const char *function, int line) #endif /* write fifo data (REGIO) */ -void +static void write_fifo_regio(struct hfc_multi *hc, u_char *data, int len) { outb(A_FIFO_DATA0, (hc->pci_iobase)+4); @@ -443,7 +442,7 @@ write_fifo_regio(struct hfc_multi *hc, u_char *data, int len) } } /* write fifo data (PCIMEM) */ -void +static void write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) { while (len>>2) { @@ -465,7 +464,7 @@ write_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) } } /* read fifo data (REGIO) */ -void +static void read_fifo_regio(struct hfc_multi *hc, u_char *data, int len) { outb(A_FIFO_DATA0, (hc->pci_iobase)+4); @@ -487,7 +486,7 @@ read_fifo_regio(struct hfc_multi *hc, u_char *data, int len) } /* read fifo data (PCIMEM) */ -void +static void read_fifo_pcimem(struct hfc_multi *hc, u_char *data, int len) { while (len>>2) { @@ -706,7 +705,7 @@ vpm_out(struct hfc_multi *c, int which, unsigned short addr, } -void +static void vpm_init(struct hfc_multi *wc) { unsigned char reg; @@ -789,7 +788,8 @@ vpm_init(struct hfc_multi *wc) } } -void +#ifdef UNUSED +static void vpm_check(struct hfc_multi *hctmp) { unsigned char gpi2; @@ -799,6 +799,7 @@ vpm_check(struct hfc_multi *hctmp) if ((gpi2 & 0x3) != 0x3) printk(KERN_DEBUG "Got interrupt 0x%x from VPM!\n", gpi2); } +#endif /* UNUSED */ /* @@ -812,7 +813,7 @@ vpm_check(struct hfc_multi *hctmp) * */ -void +static void vpm_echocan_on(struct hfc_multi *hc, int ch, int taps) { unsigned int timeslot; @@ -844,7 +845,7 @@ vpm_echocan_on(struct hfc_multi *hc, int ch, int taps) vpm_out(hc, unit, timeslot, 0x7e); } -void +static void vpm_echocan_off(struct hfc_multi *hc, int ch) { unsigned int timeslot; @@ -887,8 +888,9 @@ vpm_echocan_off(struct hfc_multi *hc, int ch) static inline void hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) { - struct hfc_multi *hc, *next, *pcmmaster = 0; - u_int *plx_acc_32, pv; + struct hfc_multi *hc, *next, *pcmmaster = NULL; + void __iomem *plx_acc_32; + u_int pv; u_long flags; spin_lock_irqsave(&HFClock, flags); @@ -916,7 +918,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) /* Disable sync of all cards */ list_for_each_entry_safe(hc, next, &HFClist, list) { if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv &= ~PLX_SYNC_O_EN; writel(pv, plx_acc_32); @@ -938,7 +940,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) printk(KERN_DEBUG "id=%d (0x%p) = syncronized with " "interface.\n", hc->id, hc); /* Enable new sync master */ - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv |= PLX_SYNC_O_EN; writel(pv, plx_acc_32); @@ -968,7 +970,7 @@ hfcmulti_resync(struct hfc_multi *locked, struct hfc_multi *newmaster, int rm) "QUARTZ is automatically " "enabled by HFC-%dS\n", hc->type); } - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv |= PLX_SYNC_O_EN; writel(pv, plx_acc_32); @@ -1013,7 +1015,8 @@ plxsd_checksync(struct hfc_multi *hc, int rm) static void release_io_hfcmulti(struct hfc_multi *hc) { - u_int *plx_acc_32, pv; + void __iomem *plx_acc_32; + u_int pv; u_long plx_flags; if (debug & DEBUG_HFCMULTI_INIT) @@ -1033,7 +1036,7 @@ release_io_hfcmulti(struct hfc_multi *hc) printk(KERN_DEBUG "%s: release PLXSD card %d\n", __func__, hc->id + 1); spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; writel(PLX_GPIOC_INIT, plx_acc_32); pv = readl(plx_acc_32); /* Termination off */ @@ -1055,9 +1058,9 @@ release_io_hfcmulti(struct hfc_multi *hc) test_and_clear_bit(HFC_CHIP_PLXSD, &hc->chip); /* prevent resync */ pci_write_config_word(hc->pci_dev, PCI_COMMAND, 0); if (hc->pci_membase) - iounmap((void *)hc->pci_membase); + iounmap(hc->pci_membase); if (hc->plx_membase) - iounmap((void *)hc->plx_membase); + iounmap(hc->plx_membase); if (hc->pci_iobase) release_region(hc->pci_iobase, 8); @@ -1080,7 +1083,8 @@ init_chip(struct hfc_multi *hc) u_long flags, val, val2 = 0, rev; int i, err = 0; u_char r_conf_en, rval; - u_int *plx_acc_32, pv; + void __iomem *plx_acc_32; + u_int pv; u_long plx_flags, hfc_flags; int plx_count; struct hfc_multi *pos, *next, *plx_last_hc; @@ -1154,7 +1158,7 @@ init_chip(struct hfc_multi *hc) printk(KERN_DEBUG "%s: initializing PLXSD card %d\n", __func__, hc->id + 1); spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; writel(PLX_GPIOC_INIT, plx_acc_32); pv = readl(plx_acc_32); /* The first and the last cards are terminating the PCM bus */ @@ -1190,8 +1194,7 @@ init_chip(struct hfc_multi *hc) "we disable termination\n", __func__, plx_last_hc->id + 1); spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(plx_last_hc->plx_membase - + PLX_GPIOC); + plx_acc_32 = plx_last_hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv &= ~PLX_TERM_ON; writel(pv, plx_acc_32); @@ -1240,7 +1243,7 @@ init_chip(struct hfc_multi *hc) /* Speech Design PLX bridge pcm and sync mode */ if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); /* Connect PCM */ if (hc->hw.r_pcm_md0 & V_PCM_MD) { @@ -1352,8 +1355,7 @@ controller_fail: /* retry with master clock */ if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(hc->plx_membase + - PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv |= PLX_MASTER_EN | PLX_SLAVE_EN_N; pv |= PLX_SYNC_O_EN; @@ -1389,7 +1391,7 @@ controller_fail: if (test_bit(HFC_CHIP_PCM_MASTER, &hc->chip)) plxsd_master = 1; spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc_32 = (u_int *)(hc->plx_membase+PLX_GPIOC); + plx_acc_32 = hc->plx_membase + PLX_GPIOC; pv = readl(plx_acc_32); pv |= PLX_DSP_RES_N; writel(pv, plx_acc_32); @@ -2586,7 +2588,8 @@ hfcmulti_interrupt(int intno, void *dev_id) struct dchannel *dch; u_char r_irq_statech, status, r_irq_misc, r_irq_oview; int i; - u_short *plx_acc, wval; + void __iomem *plx_acc; + u_short wval; u_char e1_syncsta, temp; u_long flags; @@ -2606,7 +2609,7 @@ hfcmulti_interrupt(int intno, void *dev_id) if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, flags); - plx_acc = (u_short *)(hc->plx_membase + PLX_INTCSR); + plx_acc = hc->plx_membase + PLX_INTCSR; wval = readw(plx_acc); spin_unlock_irqrestore(&plx_lock, flags); if (!(wval & PLX_INTCSR_LINTI1_STATUS)) @@ -4091,7 +4094,7 @@ init_card(struct hfc_multi *hc) { int err = -EIO; u_long flags; - u_short *plx_acc; + void __iomem *plx_acc; u_long plx_flags; if (debug & DEBUG_HFCMULTI_INIT) @@ -4113,7 +4116,7 @@ init_card(struct hfc_multi *hc) if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR); + plx_acc = hc->plx_membase + PLX_INTCSR; writew((PLX_INTCSR_PCIINT_ENABLE | PLX_INTCSR_LINTI1_ENABLE), plx_acc); /* enable PCI & LINT1 irq */ spin_unlock_irqrestore(&plx_lock, plx_flags); @@ -4162,7 +4165,7 @@ init_card(struct hfc_multi *hc) error: if (test_bit(HFC_CHIP_PLXSD, &hc->chip)) { spin_lock_irqsave(&plx_lock, plx_flags); - plx_acc = (u_short *)(hc->plx_membase+PLX_INTCSR); + plx_acc = hc->plx_membase + PLX_INTCSR; writew(0x00, plx_acc); /*disable IRQs*/ spin_unlock_irqrestore(&plx_lock, plx_flags); } diff --git a/drivers/isdn/hysdn/hysdn_net.c b/drivers/isdn/hysdn/hysdn_net.c index 3f2a0a20c19b040538ba23fcce7d3d346d2e0f89..7ee5bd9f2bb42db57312be67c22f734aa72f14e4 100644 --- a/drivers/isdn/hysdn/hysdn_net.c +++ b/drivers/isdn/hysdn/hysdn_net.c @@ -76,7 +76,7 @@ static int net_open(struct net_device *dev) { struct in_device *in_dev; - hysdn_card *card = dev->priv; + hysdn_card *card = dev->ml_priv; int i; netif_start_queue(dev); /* start tx-queueing */ @@ -159,7 +159,7 @@ net_send_packet(struct sk_buff *skb, struct net_device *dev) spin_unlock_irq(&lp->lock); if (lp->sk_count <= 3) { - schedule_work(&((hysdn_card *) dev->priv)->irq_queue); + schedule_work(&((hysdn_card *) dev->ml_priv)->irq_queue); } return (0); /* success */ } /* net_send_packet */ @@ -295,7 +295,7 @@ hysdn_net_create(hysdn_card * card) kfree(dev); return (i); } - dev->priv = card; /* remember pointer to own data structure */ + dev->ml_priv = card; /* remember pointer to own data structure */ card->netif = dev; /* setup the local pointer */ if (card->debug_flags & LOG_NET_INIT) diff --git a/drivers/isdn/i4l/isdn_concap.c b/drivers/isdn/i4l/isdn_concap.c index 0193b6f7c70ca705142fe0d7731dd242b4eacbb6..46048e55f241157663a41c5c2fcbe32ecbf50f63 100644 --- a/drivers/isdn/i4l/isdn_concap.c +++ b/drivers/isdn/i4l/isdn_concap.c @@ -42,7 +42,7 @@ static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff *skb) { struct net_device *ndev = concap -> net_dev; - isdn_net_dev *nd = ((isdn_net_local *) ndev->priv)->netdev; + isdn_net_dev *nd = ((isdn_net_local *) netdev_priv(ndev))->netdev; isdn_net_local *lp = isdn_net_get_locked_lp(nd); IX25DEBUG( "isdn_concap_dl_data_req: %s \n", concap->net_dev->name); @@ -61,7 +61,7 @@ static int isdn_concap_dl_data_req(struct concap_proto *concap, struct sk_buff * static int isdn_concap_dl_connect_req(struct concap_proto *concap) { struct net_device *ndev = concap -> net_dev; - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); int ret; IX25DEBUG( "isdn_concap_dl_connect_req: %s \n", ndev -> name); diff --git a/drivers/isdn/i4l/isdn_net.c b/drivers/isdn/i4l/isdn_net.c index 1bfc55d7a26c745d226f840edcfd784dd6930985..023ea11d2f9e399dfb5161e27721f3104a8d204d 100644 --- a/drivers/isdn/i4l/isdn_net.c +++ b/drivers/isdn/i4l/isdn_net.c @@ -120,7 +120,7 @@ static __inline__ int isdn_net_device_busy(isdn_net_local *lp) return 0; if (lp->master) - nd = ((isdn_net_local *) lp->master->priv)->netdev; + nd = ISDN_MASTER_PRIV(lp)->netdev; else nd = lp->netdev; @@ -213,9 +213,9 @@ isdn_net_reset(struct net_device *dev) { #ifdef CONFIG_ISDN_X25 struct concap_device_ops * dops = - ( (isdn_net_local *) dev->priv ) -> dops; + ((isdn_net_local *) netdev_priv(dev))->dops; struct concap_proto * cprot = - ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; + ((isdn_net_local *) netdev_priv(dev))->netdev->cprot; #endif #ifdef CONFIG_ISDN_X25 if( cprot && cprot -> pops && dops ) @@ -250,11 +250,11 @@ isdn_net_open(struct net_device *dev) } /* If this interface has slaves, start them also */ - - if ((p = (((isdn_net_local *) dev->priv)->slave))) { + p = MASTER_TO_SLAVE(dev); + if (p) { while (p) { isdn_net_reset(p); - p = (((isdn_net_local *) p->priv)->slave); + p = MASTER_TO_SLAVE(p); } } isdn_lock_drivers(); @@ -483,7 +483,7 @@ isdn_net_stat_callback(int idx, isdn_ctrl *c) isdn_net_ciscohdlck_connected(lp); if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) { if (lp->master) { /* is lp a slave? */ - isdn_net_dev *nd = ((isdn_net_local *)lp->master->priv)->netdev; + isdn_net_dev *nd = ISDN_MASTER_PRIV(lp)->netdev; isdn_net_add_to_bundle(nd, lp); } } @@ -823,7 +823,7 @@ isdn_net_dial(void) void isdn_net_hangup(struct net_device *d) { - isdn_net_local *lp = (isdn_net_local *) d->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(d); isdn_ctrl cmd; #ifdef CONFIG_ISDN_X25 struct concap_proto *cprot = lp->netdev->cprot; @@ -832,7 +832,7 @@ isdn_net_hangup(struct net_device *d) if (lp->flags & ISDN_NET_CONNECTED) { if (lp->slave != NULL) { - isdn_net_local *slp = (isdn_net_local *)lp->slave->priv; + isdn_net_local *slp = ISDN_SLAVE_PRIV(lp); if (slp->flags & ISDN_NET_CONNECTED) { printk(KERN_INFO "isdn_net: hang up slave %s before %s\n", @@ -865,8 +865,8 @@ isdn_net_hangup(struct net_device *d) } typedef struct { - unsigned short source; - unsigned short dest; + __be16 source; + __be16 dest; } ip_ports; static void @@ -890,15 +890,15 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) proto = ETH_P_IP; switch (lp->p_encap) { case ISDN_NET_ENCAP_IPTYP: - proto = ntohs(*(unsigned short *) &buf[0]); + proto = ntohs(*(__be16 *)&buf[0]); p = &buf[2]; break; case ISDN_NET_ENCAP_ETHER: - proto = ntohs(*(unsigned short *) &buf[12]); + proto = ntohs(*(__be16 *)&buf[12]); p = &buf[14]; break; case ISDN_NET_ENCAP_CISCOHDLC: - proto = ntohs(*(unsigned short *) &buf[2]); + proto = ntohs(*(__be16 *)&buf[2]); p = &buf[4]; break; #ifdef CONFIG_ISDN_PPP @@ -942,18 +942,12 @@ isdn_net_log_skb(struct sk_buff * skb, isdn_net_local * lp) strcpy(addinfo, " IDP"); break; } - printk(KERN_INFO - "OPEN: %d.%d.%d.%d -> %d.%d.%d.%d%s\n", - - p[12], p[13], p[14], p[15], - p[16], p[17], p[18], p[19], - addinfo); + printk(KERN_INFO "OPEN: %pI4 -> %pI4%s\n", + p + 12, p + 16, addinfo); break; case ETH_P_ARP: - printk(KERN_INFO - "OPEN: ARP %d.%d.%d.%d -> *.*.*.* ?%d.%d.%d.%d\n", - p[14], p[15], p[16], p[17], - p[24], p[25], p[26], p[27]); + printk(KERN_INFO "OPEN: ARP %pI4 -> *.*.*.* ?%pI4\n", + p + 14, p + 24); break; } } @@ -1054,10 +1048,10 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) { isdn_net_dev *nd; isdn_net_local *slp; - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); int retv = 0; - if (((isdn_net_local *) (ndev->priv))->master) { + if (((isdn_net_local *) netdev_priv(ndev))->master) { printk("isdn BUG at %s:%d!\n", __FILE__, __LINE__); dev_kfree_skb(skb); return 0; @@ -1069,7 +1063,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) return isdn_ppp_xmit(skb, ndev); } #endif - nd = ((isdn_net_local *) ndev->priv)->netdev; + nd = ((isdn_net_local *) netdev_priv(ndev))->netdev; lp = isdn_net_get_locked_lp(nd); if (!lp) { printk(KERN_WARNING "%s: all channels busy - requeuing!\n", ndev->name); @@ -1096,9 +1090,9 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) } else { /* subsequent overload: if slavedelay exceeded, start dialing */ if (time_after(jiffies, lp->sqfull_stamp + lp->slavedelay)) { - slp = lp->slave->priv; + slp = ISDN_SLAVE_PRIV(lp); if (!(slp->flags & ISDN_NET_CONNECTED)) { - isdn_net_force_dial_lp((isdn_net_local *) lp->slave->priv); + isdn_net_force_dial_lp(ISDN_SLAVE_PRIV(lp)); } } } @@ -1118,7 +1112,7 @@ isdn_net_xmit(struct net_device *ndev, struct sk_buff *skb) static void isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev) { - isdn_net_local *lp = (isdn_net_local *) dev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev); if (!skb) return; if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { @@ -1133,7 +1127,7 @@ isdn_net_adjust_hdr(struct sk_buff *skb, struct net_device *dev) static void isdn_net_tx_timeout(struct net_device * ndev) { - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); printk(KERN_WARNING "isdn_tx_timeout dev %s dialstate %d\n", ndev->name, lp->dialstate); if (!lp->dialstate){ @@ -1167,7 +1161,7 @@ static void isdn_net_tx_timeout(struct net_device * ndev) static int isdn_net_start_xmit(struct sk_buff *skb, struct net_device *ndev) { - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); #ifdef CONFIG_ISDN_X25 struct concap_proto * cprot = lp -> netdev -> cprot; /* At this point hard_start_xmit() passes control to the encapsulation @@ -1316,7 +1310,7 @@ isdn_net_close(struct net_device *dev) struct net_device *p; #ifdef CONFIG_ISDN_X25 struct concap_proto * cprot = - ( (isdn_net_local *) dev->priv ) -> netdev -> cprot; + ((isdn_net_local *) netdev_priv(dev))->netdev->cprot; /* printk(KERN_DEBUG "isdn_net_close %s\n" , dev-> name ); */ #endif @@ -1324,17 +1318,18 @@ isdn_net_close(struct net_device *dev) if( cprot && cprot -> pops ) cprot -> pops -> close( cprot ); #endif netif_stop_queue(dev); - if ((p = (((isdn_net_local *) dev->priv)->slave))) { + p = MASTER_TO_SLAVE(dev); + if (p) { /* If this interface has slaves, stop them also */ while (p) { #ifdef CONFIG_ISDN_X25 - cprot = ( (isdn_net_local *) p->priv ) + cprot = ((isdn_net_local *) netdev_priv(p)) -> netdev -> cprot; if( cprot && cprot -> pops ) cprot -> pops -> close( cprot ); #endif isdn_net_hangup(p); - p = (((isdn_net_local *) p->priv)->slave); + p = MASTER_TO_SLAVE(p); } } isdn_net_hangup(dev); @@ -1348,7 +1343,7 @@ isdn_net_close(struct net_device *dev) static struct net_device_stats * isdn_net_get_stats(struct net_device *dev) { - isdn_net_local *lp = (isdn_net_local *) dev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev); return &lp->stats; } @@ -1361,7 +1356,7 @@ isdn_net_get_stats(struct net_device *dev) * This is normal practice and works for any 'now in use' protocol. */ -static unsigned short +static __be16 isdn_net_type_trans(struct sk_buff *skb, struct net_device *dev) { struct ethhdr *eth; @@ -1427,7 +1422,7 @@ isdn_net_ciscohdlck_alloc_skb(isdn_net_local *lp, int len) static int isdn_ciscohdlck_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - isdn_net_local *lp = (isdn_net_local *) dev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev); unsigned long len = 0; unsigned long expires = 0; int tmp = 0; @@ -1539,15 +1534,16 @@ isdn_net_ciscohdlck_slarp_send_keepalive(unsigned long data) p = skb_put(skb, 4 + 14); /* cisco header */ - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, CISCO_TYPE_SLARP); + *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; + *(u8 *)(p + 1) = CISCO_CTRL; + *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); /* slarp keepalive */ - p += put_u32(p, CISCO_SLARP_KEEPALIVE); - p += put_u32(p, lp->cisco_myseq); - p += put_u32(p, lp->cisco_yourseq); - p += put_u16(p, 0xffff); // reliablity, always 0xffff + *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_KEEPALIVE); + *(__be32 *)(p + 8) = cpu_to_be32(lp->cisco_myseq); + *(__be32 *)(p + 12) = cpu_to_be32(lp->cisco_yourseq); + *(__be16 *)(p + 16) = cpu_to_be16(0xffff); // reliablity, always 0xffff + p += 18; isdn_net_write_super(lp, skb); @@ -1569,15 +1565,16 @@ isdn_net_ciscohdlck_slarp_send_request(isdn_net_local *lp) p = skb_put(skb, 4 + 14); /* cisco header */ - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, CISCO_TYPE_SLARP); + *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; + *(u8 *)(p + 1) = CISCO_CTRL; + *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); /* slarp request */ - p += put_u32(p, CISCO_SLARP_REQUEST); - p += put_u32(p, 0); // address - p += put_u32(p, 0); // netmask - p += put_u16(p, 0); // unused + *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REQUEST); + *(__be32 *)(p + 8) = cpu_to_be32(0); // address + *(__be32 *)(p + 12) = cpu_to_be32(0); // netmask + *(__be16 *)(p + 16) = cpu_to_be16(0); // unused + p += 18; isdn_net_write_super(lp, skb); } @@ -1634,18 +1631,17 @@ isdn_net_ciscohdlck_slarp_send_reply(isdn_net_local *lp) p = skb_put(skb, 4 + 14); /* cisco header */ - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, CISCO_TYPE_SLARP); + *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; + *(u8 *)(p + 1) = CISCO_CTRL; + *(__be16 *)(p + 2) = cpu_to_be16(CISCO_TYPE_SLARP); /* slarp reply, send own ip/netmask; if values are nonsense remote * should think we are unable to provide it with an address via SLARP */ - p += put_u32(p, CISCO_SLARP_REPLY); - *(__be32 *)p = addr; // address - p += 4; - *(__be32 *)p = mask; // netmask - p += 4; - p += put_u16(p, 0); // unused + *(__be32 *)(p + 4) = cpu_to_be32(CISCO_SLARP_REPLY); + *(__be32 *)(p + 8) = addr; // address + *(__be32 *)(p + 12) = mask; // netmask + *(__be16 *)(p + 16) = cpu_to_be16(0); // unused + p += 18; isdn_net_write_super(lp, skb); } @@ -1656,44 +1652,39 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) unsigned char *p; int period; u32 code; - u32 my_seq, addr; - u32 your_seq, mask; - u32 local; + u32 my_seq; + u32 your_seq; + __be32 local; + __be32 *addr, *mask; u16 unused; if (skb->len < 14) return; p = skb->data; - p += get_u32(p, &code); - + code = be32_to_cpup((__be32 *)p); + p += 4; + switch (code) { case CISCO_SLARP_REQUEST: lp->cisco_yourseq = 0; isdn_net_ciscohdlck_slarp_send_reply(lp); break; case CISCO_SLARP_REPLY: - addr = ntohl(*(u32 *)p); - mask = ntohl(*(u32 *)(p+4)); - if (mask != 0xfffffffc) + addr = (__be32 *)p; + mask = (__be32 *)(p + 4); + if (*mask != cpu_to_be32(0xfffffffc)) goto slarp_reply_out; - if ((addr & 3) == 0 || (addr & 3) == 3) + if ((*addr & cpu_to_be32(3)) == cpu_to_be32(0) || + (*addr & cpu_to_be32(3)) == cpu_to_be32(3)) goto slarp_reply_out; - local = addr ^ 3; - printk(KERN_INFO "%s: got slarp reply: " - "remote ip: %d.%d.%d.%d, " - "local ip: %d.%d.%d.%d " - "mask: %d.%d.%d.%d\n", - lp->netdev->dev->name, - HIPQUAD(addr), - HIPQUAD(local), - HIPQUAD(mask)); + local = *addr ^ cpu_to_be32(3); + printk(KERN_INFO "%s: got slarp reply: remote ip: %pI4, local ip: %pI4 mask: %pI4\n", + lp->netdev->dev->name, addr, &local, mask); break; slarp_reply_out: - printk(KERN_INFO "%s: got invalid slarp " - "reply (%d.%d.%d.%d/%d.%d.%d.%d) " - "- ignored\n", lp->netdev->dev->name, - HIPQUAD(addr), HIPQUAD(mask)); + printk(KERN_INFO "%s: got invalid slarp reply (%pI4/%pI4) - ignored\n", + lp->netdev->dev->name, addr, mask); break; case CISCO_SLARP_KEEPALIVE: period = (int)((jiffies - lp->cisco_last_slarp_in @@ -1707,9 +1698,10 @@ isdn_net_ciscohdlck_slarp_in(isdn_net_local *lp, struct sk_buff *skb) lp->cisco_keepalive_period); } lp->cisco_last_slarp_in = jiffies; - p += get_u32(p, &my_seq); - p += get_u32(p, &your_seq); - p += get_u16(p, &unused); + my_seq = be32_to_cpup((__be32 *)(p + 0)); + your_seq = be32_to_cpup((__be32 *)(p + 4)); + unused = be16_to_cpup((__be16 *)(p + 8)); + p += 10; lp->cisco_yourseq = my_seq; lp->cisco_mineseen = your_seq; break; @@ -1728,9 +1720,10 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb) goto out_free; p = skb->data; - p += get_u8 (p, &addr); - p += get_u8 (p, &ctrl); - p += get_u16(p, &type); + addr = *(u8 *)(p + 0); + ctrl = *(u8 *)(p + 1); + type = be16_to_cpup((__be16 *)(p + 2)); + p += 4; skb_pull(skb, 4); if (addr != CISCO_ADDR_UNICAST && addr != CISCO_ADDR_BROADCAST) { @@ -1771,7 +1764,7 @@ isdn_net_ciscohdlck_receive(isdn_net_local *lp, struct sk_buff *skb) static void isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) { - isdn_net_local *lp = (isdn_net_local *) ndev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(ndev); isdn_net_local *olp = lp; /* original 'lp' */ #ifdef CONFIG_ISDN_X25 struct concap_proto *cprot = lp -> netdev -> cprot; @@ -1785,7 +1778,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) * handle master's statistics and hangup-timeout */ ndev = lp->master; - lp = (isdn_net_local *) ndev->priv; + lp = (isdn_net_local *) netdev_priv(ndev); lp->stats.rx_packets++; lp->stats.rx_bytes += skb->len; } @@ -1825,7 +1818,7 @@ isdn_net_receive(struct net_device *ndev, struct sk_buff *skb) /* IP with type field */ olp->huptimer = 0; lp->huptimer = 0; - skb->protocol = *(unsigned short *) &(skb->data[0]); + skb->protocol = *(__be16 *)&(skb->data[0]); skb_pull(skb, 2); if (*(unsigned short *) skb->data == 0xFFFF) skb->protocol = htons(ETH_P_802_3); @@ -1886,7 +1879,7 @@ static int isdn_net_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, const void *daddr, const void *saddr, unsigned plen) { - isdn_net_local *lp = dev->priv; + isdn_net_local *lp = netdev_priv(dev); unsigned char *p; ushort len = 0; @@ -1907,20 +1900,21 @@ static int isdn_net_header(struct sk_buff *skb, struct net_device *dev, break; case ISDN_NET_ENCAP_IPTYP: /* ethernet type field */ - *((ushort *) skb_push(skb, 2)) = htons(type); + *((__be16 *)skb_push(skb, 2)) = htons(type); len = 2; break; case ISDN_NET_ENCAP_UIHDLC: /* HDLC with UI-Frames (for ispa with -h1 option) */ - *((ushort *) skb_push(skb, 2)) = htons(0x0103); + *((__be16 *)skb_push(skb, 2)) = htons(0x0103); len = 2; break; case ISDN_NET_ENCAP_CISCOHDLC: case ISDN_NET_ENCAP_CISCOHDLCK: p = skb_push(skb, 4); - p += put_u8 (p, CISCO_ADDR_UNICAST); - p += put_u8 (p, CISCO_CTRL); - p += put_u16(p, type); + *(u8 *)(p + 0) = CISCO_ADDR_UNICAST; + *(u8 *)(p + 1) = CISCO_CTRL; + *(__be16 *)(p + 2) = cpu_to_be16(type); + p += 4; len = 4; break; #ifdef CONFIG_ISDN_X25 @@ -1942,7 +1936,7 @@ static int isdn_net_rebuild_header(struct sk_buff *skb) { struct net_device *dev = skb->dev; - isdn_net_local *lp = dev->priv; + isdn_net_local *lp = netdev_priv(dev); int ret = 0; if (lp->p_encap == ISDN_NET_ENCAP_ETHER) { @@ -1972,7 +1966,7 @@ isdn_net_rebuild_header(struct sk_buff *skb) static int isdn_header_cache(const struct neighbour *neigh, struct hh_cache *hh) { const struct net_device *dev = neigh->dev; - isdn_net_local *lp = dev->priv; + isdn_net_local *lp = netdev_priv(dev); if (lp->p_encap == ISDN_NET_ENCAP_ETHER) return eth_header_cache(neigh, hh); @@ -1983,9 +1977,9 @@ static void isdn_header_cache_update(struct hh_cache *hh, const struct net_device *dev, const unsigned char *haddr) { - isdn_net_local *lp = dev->priv; + isdn_net_local *lp = netdev_priv(dev); if (lp->p_encap == ISDN_NET_ENCAP_ETHER) - return eth_header_cache_update(hh, dev, haddr); + eth_header_cache_update(hh, dev, haddr); } static const struct header_ops isdn_header_ops = { @@ -2298,16 +2292,16 @@ isdn_net_find_icall(int di, int ch, int idx, setup_parm *setup) * it's master and parent slave is online. If not, reject the call. */ if (lp->master) { - isdn_net_local *mlp = (isdn_net_local *) lp->master->priv; + isdn_net_local *mlp = ISDN_MASTER_PRIV(lp); printk(KERN_DEBUG "ICALLslv: %s\n", p->dev->name); printk(KERN_DEBUG "master=%s\n", lp->master->name); if (mlp->flags & ISDN_NET_CONNECTED) { printk(KERN_DEBUG "master online\n"); /* Master is online, find parent-slave (master if first slave) */ while (mlp->slave) { - if ((isdn_net_local *) mlp->slave->priv == lp) + if (ISDN_SLAVE_PRIV(mlp) == lp) break; - mlp = (isdn_net_local *) mlp->slave->priv; + mlp = ISDN_SLAVE_PRIV(mlp); } } else printk(KERN_DEBUG "master offline\n"); @@ -2519,7 +2513,7 @@ isdn_net_force_dial(char *name) */ static void _isdn_setup(struct net_device *dev) { - isdn_net_local *lp = dev->priv; + isdn_net_local *lp = netdev_priv(dev); dev->flags = IFF_NOARP | IFF_POINTOPOINT; lp->p_encap = ISDN_NET_ENCAP_RAWIP; @@ -2575,20 +2569,20 @@ isdn_net_new(char *name, struct net_device *master) kfree(netdev); return NULL; } - netdev->local = netdev->dev->priv; + netdev->local = netdev_priv(netdev->dev); netdev->dev->init = isdn_net_init; if (master) { /* Device shall be a slave */ - struct net_device *p = (((isdn_net_local *) master->priv)->slave); + struct net_device *p = MASTER_TO_SLAVE(master); struct net_device *q = master; netdev->local->master = master; /* Put device at end of slave-chain */ while (p) { q = p; - p = (((isdn_net_local *) p->priv)->slave); + p = MASTER_TO_SLAVE(p); } - ((isdn_net_local *) q->priv)->slave = netdev->dev; + MASTER_TO_SLAVE(q) = netdev->dev; } else { /* Device shall be a master */ /* @@ -3086,7 +3080,7 @@ isdn_net_force_hangup(char *name) /* If this interface has slaves, do a hangup for them also. */ while (q) { isdn_net_hangup(q); - q = (((isdn_net_local *) q->priv)->slave); + q = MASTER_TO_SLAVE(q); } isdn_net_hangup(p->dev); return 0; @@ -3116,8 +3110,10 @@ isdn_net_realrm(isdn_net_dev * p, isdn_net_dev * q) isdn_unexclusive_channel(p->local->pre_device, p->local->pre_channel); if (p->local->master) { /* It's a slave-device, so update master's slave-pointer if necessary */ - if (((isdn_net_local *) (p->local->master->priv))->slave == p->dev) - ((isdn_net_local *) (p->local->master->priv))->slave = p->local->slave; + if (((isdn_net_local *) ISDN_MASTER_PRIV(p->local))->slave == + p->dev) + ((isdn_net_local *)ISDN_MASTER_PRIV(p->local))->slave = + p->local->slave; } else { /* Unregister only if it's a master-device */ unregister_netdev(p->dev); diff --git a/drivers/isdn/i4l/isdn_net.h b/drivers/isdn/i4l/isdn_net.h index be4949715d55f605206f99e86430fe0c46ff1f1d..74032d0881efab82d80b93193a2ebfc372e9bd58 100644 --- a/drivers/isdn/i4l/isdn_net.h +++ b/drivers/isdn/i4l/isdn_net.h @@ -56,6 +56,11 @@ extern void isdn_net_write_super(isdn_net_local *lp, struct sk_buff *skb); #define ISDN_NET_MAX_QUEUE_LENGTH 2 +#define ISDN_MASTER_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->master)) +#define ISDN_SLAVE_PRIV(lp) ((isdn_net_local *) netdev_priv(lp->slave)) +#define MASTER_TO_SLAVE(master) \ + (((isdn_net_local *) netdev_priv(master))->slave) + /* * is this particular channel busy? */ @@ -126,7 +131,7 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) unsigned long flags; if (lp->master) - master_lp = (isdn_net_local *) lp->master->priv; + master_lp = ISDN_MASTER_PRIV(lp); // printk(KERN_DEBUG "%s: lp:%s(%p) mlp:%s(%p) last(%p) next(%p) mndq(%p)\n", // __func__, lp->name, lp, master_lp->name, master_lp, lp->last, lp->next, master_lp->netdev->queue); @@ -145,46 +150,3 @@ static __inline__ void isdn_net_rm_from_bundle(isdn_net_local *lp) spin_unlock_irqrestore(&master_lp->netdev->queue_lock, flags); } -static inline int -put_u8(unsigned char *p, u8 x) -{ - *p = x; - return 1; -} - -static inline int -put_u16(unsigned char *p, u16 x) -{ - *((u16 *)p) = htons(x); - return 2; -} - -static inline int -put_u32(unsigned char *p, u32 x) -{ - *((u32 *)p) = htonl(x); - return 4; -} - -static inline int -get_u8(unsigned char *p, u8 *x) -{ - *x = *p; - return 1; -} - -static inline int -get_u16(unsigned char *p, u16 *x) -{ - *x = ntohs(*((u16 *)p)); - return 2; -} - -static inline int -get_u32(unsigned char *p, u32 *x) -{ - *x = ntohl(*((u32 *)p)); - return 4; -} - - diff --git a/drivers/isdn/i4l/isdn_ppp.c b/drivers/isdn/i4l/isdn_ppp.c index 77c280ef2eb64ddbb81cff6b78c40bcf7e302b3e..a3551dd0324d420664ea30df2978b772434ce418 100644 --- a/drivers/isdn/i4l/isdn_ppp.c +++ b/drivers/isdn/i4l/isdn_ppp.c @@ -1040,7 +1040,7 @@ isdn_ppp_push_higher(isdn_net_dev * net_dev, isdn_net_local * lp, struct sk_buff is = ippp_table[slot]; if (lp->master) { // FIXME? - mlp = (isdn_net_local *) lp->master->priv; + mlp = ISDN_MASTER_PRIV(lp); slot = mlp->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "isdn_ppp_push_higher: master->ppp_slot(%d)\n", @@ -1223,7 +1223,7 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) struct ippp_struct *ipt,*ipts; int slot, retval = 0; - mlp = (isdn_net_local *) (netdev->priv); + mlp = (isdn_net_local *) netdev_priv(netdev); nd = mlp->netdev; /* get master lp */ slot = mlp->ppp_slot; @@ -1289,10 +1289,10 @@ isdn_ppp_xmit(struct sk_buff *skb, struct net_device *netdev) *skb_push(skb, 4) = 1; /* indicate outbound */ { - u_int16_t *p = (u_int16_t *) skb->data; + __be16 *p = (__be16 *)skb->data; p++; - *p = htons(proto); + *p = htons(proto); } if (ipt->pass_filter @@ -1487,10 +1487,10 @@ int isdn_ppp_autodial_filter(struct sk_buff *skb, isdn_net_local *lp) *skb_pull(skb, IPPP_MAX_HEADER - 4) = 1; /* indicate outbound */ { - u_int16_t *p = (u_int16_t *) skb->data; + __be16 *p = (__be16 *)skb->data; p++; - *p = htons(proto); + *p = htons(proto); } drop |= is->pass_filter @@ -1810,14 +1810,14 @@ static u32 isdn_ppp_mp_get_seq( int short_seq, if( !short_seq ) { - seq = ntohl(*(u32*)skb->data) & MP_LONGSEQ_MASK; + seq = ntohl(*(__be32 *)skb->data) & MP_LONGSEQ_MASK; skb_push(skb,1); } else { /* convert 12-bit short seq number to 24-bit long one */ - seq = ntohs(*(u16*)skb->data) & MP_SHORTSEQ_MASK; + seq = ntohs(*(__be16 *)skb->data) & MP_SHORTSEQ_MASK; /* check for seqence wrap */ if( !(seq & MP_SHORTSEQ_MAXBIT) && @@ -2013,7 +2013,7 @@ isdn_ppp_dev_ioctl_stats(int slot, struct ifreq *ifr, struct net_device *dev) { struct ppp_stats __user *res = ifr->ifr_data; struct ppp_stats t; - isdn_net_local *lp = (isdn_net_local *) dev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev); if (!access_ok(VERIFY_WRITE, res, sizeof(struct ppp_stats))) return -EFAULT; @@ -2052,7 +2052,7 @@ isdn_ppp_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { int error=0; int len; - isdn_net_local *lp = (isdn_net_local *) dev->priv; + isdn_net_local *lp = (isdn_net_local *) netdev_priv(dev); if (lp->p_encap != ISDN_NET_ENCAP_SYNCPPP) @@ -2119,7 +2119,7 @@ isdn_ppp_dial_slave(char *name) sdev = lp->slave; while (sdev) { - isdn_net_local *mlp = (isdn_net_local *) sdev->priv; + isdn_net_local *mlp = (isdn_net_local *) netdev_priv(sdev); if (!(mlp->flags & ISDN_NET_CONNECTED)) break; sdev = mlp->slave; @@ -2127,7 +2127,7 @@ isdn_ppp_dial_slave(char *name) if (!sdev) return 2; - isdn_net_dial_req((isdn_net_local *) sdev->priv); + isdn_net_dial_req((isdn_net_local *) netdev_priv(sdev)); return 0; #else return -1; @@ -2150,10 +2150,10 @@ isdn_ppp_hangup_slave(char *name) sdev = lp->slave; while (sdev) { - isdn_net_local *mlp = (isdn_net_local *) sdev->priv; + isdn_net_local *mlp = (isdn_net_local *) netdev_priv(sdev); if (mlp->slave) { /* find last connected link in chain */ - isdn_net_local *nlp = (isdn_net_local *) mlp->slave->priv; + isdn_net_local *nlp = ISDN_SLAVE_PRIV(mlp); if (!(nlp->flags & ISDN_NET_CONNECTED)) break; @@ -2688,7 +2688,7 @@ static void isdn_ppp_receive_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, isdn_ppp_frame_log("ccp-rcv", skb->data, skb->len, 32, is->unit,lp->ppp_slot); if(lp->master) { - int slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; + int slot = ISDN_MASTER_PRIV(lp)->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", __func__, slot); @@ -2875,7 +2875,7 @@ static void isdn_ppp_send_ccp(isdn_net_dev *net_dev, isdn_net_local *lp, struct isdn_ppp_frame_log("ccp-xmit", skb->data, skb->len, 32, is->unit,lp->ppp_slot); if (lp->master) { - slot = ((isdn_net_local *) (lp->master->priv))->ppp_slot; + slot = ISDN_MASTER_PRIV(lp)->ppp_slot; if (slot < 0 || slot >= ISDN_MAX_CHANNELS) { printk(KERN_ERR "%s: slot(%d) out of range\n", __func__, slot); diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index 33068177b7c9486da1866344d2e25654ec2ad7d1..751665c448d0e9ebe284d6942cf709e4e29e9160 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c @@ -26,12 +26,12 @@ MODULE_LICENSE("GPL"); module_param(debug, uint, S_IRUGO | S_IWUSR); static LIST_HEAD(devices); -DEFINE_RWLOCK(device_lock); +static DEFINE_RWLOCK(device_lock); static u64 device_ids; #define MAX_DEVICE_ID 63 static LIST_HEAD(Bprotocols); -DEFINE_RWLOCK(bp_lock); +static DEFINE_RWLOCK(bp_lock); struct mISDNdevice *get_mdevice(u_int id) @@ -192,7 +192,7 @@ mISDN_unregister_Bprotocol(struct Bprotocol *bp) } EXPORT_SYMBOL(mISDN_unregister_Bprotocol); -int +static int mISDNInit(void) { int err; @@ -224,7 +224,7 @@ error: return err; } -void mISDN_cleanup(void) +static void mISDN_cleanup(void) { misdn_sock_cleanup(); mISDN_timer_cleanup(); diff --git a/drivers/isdn/mISDN/dsp_audio.c b/drivers/isdn/mISDN/dsp_audio.c index 1c2dd56947737aa0cf82e07582c081bbeba199c5..de3795e3f43291ab2dd50df0bbc5f2975f4fb477 100644 --- a/drivers/isdn/mISDN/dsp_audio.c +++ b/drivers/isdn/mISDN/dsp_audio.c @@ -30,7 +30,7 @@ EXPORT_SYMBOL(dsp_audio_s16_to_law); /* alaw -> ulaw */ u8 dsp_audio_alaw_to_ulaw[256]; /* ulaw -> alaw */ -u8 dsp_audio_ulaw_to_alaw[256]; +static u8 dsp_audio_ulaw_to_alaw[256]; u8 dsp_silence; diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index c2f51cc507608bada189220168178d05b34f908a..c884511e2d49038a465ab9e550a8e04739463de0 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -1540,11 +1540,13 @@ send_packet: schedule_work(&dsp->workq); } -u32 samplecount; +static u32 samplecount; struct timer_list dsp_spl_tl; u32 dsp_spl_jiffies; /* calculate the next time to fire */ -u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */ -struct timeval dsp_start_tv; /* time at start of calculation */ +#ifdef UNUSED +static u32 dsp_start_jiffies; /* jiffies at the time, the calculation begins */ +#endif /* UNUSED */ +static struct timeval dsp_start_tv; /* time at start of calculation */ void dsp_cmx_send(void *arg) diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 2f10ed82c0db6a82756694f3290ceed075ad718b..1dc21d8034109f7a71b7f015baae329a994535b4 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -161,7 +161,7 @@ #include "core.h" #include "dsp.h" -const char *mISDN_dsp_revision = "2.0"; +static const char *mISDN_dsp_revision = "2.0"; static int debug; static int options; @@ -631,7 +631,6 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) int ret = 0; u8 *digits; int cont; - struct sk_buff *nskb; u_long flags; hh = mISDN_HEAD_P(skb); @@ -690,6 +689,7 @@ dsp_function(struct mISDNchannel *ch, struct sk_buff *skb) digits = dsp_dtmf_goertzel_decode(dsp, skb->data, skb->len, (dsp_options&DSP_OPT_ULAW)?1:0); while (*digits) { + struct sk_buff *nskb; if (dsp_debug & DEBUG_DSP_DTMF) printk(KERN_DEBUG "%s: digit" "(%c) to layer %s\n", diff --git a/drivers/isdn/mISDN/dsp_hwec.c b/drivers/isdn/mISDN/dsp_hwec.c index eb892d9dd5c60db0b98631dcbdf8f86c062a0213..806a997fe7cc2907c7c21fb1cc130845b2cdcc9a 100644 --- a/drivers/isdn/mISDN/dsp_hwec.c +++ b/drivers/isdn/mISDN/dsp_hwec.c @@ -43,7 +43,7 @@ static struct mISDN_dsp_element dsp_hwec_p = { .free = NULL, .process_tx = NULL, .process_rx = NULL, - .num_args = sizeof(args) / sizeof(struct mISDN_dsp_element_arg), + .num_args = ARRAY_SIZE(args), .args = args, }; struct mISDN_dsp_element *dsp_hwec = &dsp_hwec_p; diff --git a/drivers/isdn/mISDN/dsp_pipeline.c b/drivers/isdn/mISDN/dsp_pipeline.c index 850260ab57d041cf7a55c86061bb134820021c35..5ee6651b45b903c3e1931fe316956e1166ce5d40 100644 --- a/drivers/isdn/mISDN/dsp_pipeline.c +++ b/drivers/isdn/mISDN/dsp_pipeline.c @@ -249,7 +249,7 @@ int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg) name = strsep(&tok, "("); args = strsep(&tok, ")"); if (args && !*args) - args = 0; + args = NULL; list_for_each_entry_safe(entry, n, &dsp_elements, list) if (!strcmp(entry->elem->name, name)) { diff --git a/drivers/isdn/mISDN/dsp_tones.c b/drivers/isdn/mISDN/dsp_tones.c index 23dd0dd215242dd37dfb111383181bdb3f194b4e..7a9af66f4b196b3e0ea79dff510e6c796df01038 100644 --- a/drivers/isdn/mISDN/dsp_tones.c +++ b/drivers/isdn/mISDN/dsp_tones.c @@ -231,120 +231,120 @@ dsp_audio_generate_ulaw_samples(void) * tone sequence definition * ****************************/ -struct pattern { +static struct pattern { int tone; u8 *data[10]; u32 *siz[10]; u32 seq[10]; } pattern[] = { {TONE_GERMAN_DIALTONE, - {DATA_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {1900, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDDIALTONE, - {DATA_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {1998, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_DIALTONE, - {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_DIALPBX, - {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0}, + {DATA_GA, DATA_S, DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_GERMAN_OLDDIALPBX, - {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0}, + {DATA_GO, DATA_S, DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_AMERICAN_DIALPBX, - {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, 0, 0, 0, 0}, - {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, 0, 0, 0, 0}, + {DATA_DT, DATA_S, DATA_DT, DATA_S, DATA_DT, DATA_S, NULL, NULL, NULL, NULL}, + {SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, SIZE_DT, SIZE_S, NULL, NULL, NULL, NULL}, {2000, 2000, 2000, 2000, 2000, 12000, 0, 0, 0, 0} }, {TONE_GERMAN_RINGING, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDRINGING, - {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {8000, 40000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_RINGING, - {DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {8000, 32000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_RINGPBX, - {DATA_GA, DATA_S, DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0}, + {DATA_GA, DATA_S, DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDRINGPBX, - {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, + {DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_RINGPBX, - {DATA_RI, DATA_S, DATA_RI, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, 0, 0, 0, 0, 0, 0}, + {DATA_RI, DATA_S, DATA_RI, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_RI, SIZE_S, SIZE_RI, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 4000, 28000, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_BUSY, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDBUSY, - {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_BUSY, - {DATA_BU, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_BU, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_BU, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_BU, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_HANGUP, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {4000, 4000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_OLDHANGUP, - {DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {1000, 5000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_AMERICAN_HANGUP, - {DATA_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_DT, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_DT, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {8000, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_SPECIAL_INFO, - {DATA_S1, DATA_S2, DATA_S3, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, 0, 0, 0, 0, 0, 0}, + {DATA_S1, DATA_S2, DATA_S3, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_S1, SIZE_S2, SIZE_S3, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, {2666, 2666, 2666, 8002, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_GASSENBESETZT, - {DATA_GA, DATA_S, 0, 0, 0, 0, 0, 0, 0, 0}, - {SIZE_GA, SIZE_S, 0, 0, 0, 0, 0, 0, 0, 0}, + {DATA_GA, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GA, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {2000, 2000, 0, 0, 0, 0, 0, 0, 0, 0} }, {TONE_GERMAN_AUFSCHALTTON, - {DATA_GO, DATA_S, DATA_GO, DATA_S, 0, 0, 0, 0, 0, 0}, - {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, 0, 0, 0, 0, 0, 0}, + {DATA_GO, DATA_S, DATA_GO, DATA_S, NULL, NULL, NULL, NULL, NULL, NULL}, + {SIZE_GO, SIZE_S, SIZE_GO, SIZE_S, NULL, NULL, NULL, NULL, NULL, NULL}, {1000, 5000, 1000, 17000, 0, 0, 0, 0, 0, 0} }, {0, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, - {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }, }; @@ -467,7 +467,7 @@ dsp_tone_timeout(void *arg) /* set next tone */ if (pat->data[index] == DATA_S) - dsp_tone_hw_message(dsp, 0, 0); + dsp_tone_hw_message(dsp, NULL, 0); else dsp_tone_hw_message(dsp, pat->data[index], *(pat->siz[index])); /* set timer */ diff --git a/drivers/isdn/mISDN/l1oip_codec.c b/drivers/isdn/mISDN/l1oip_codec.c index a2dc4570ef434064170d440f7461ca2f801405d9..2ec4b28d9edc85aecf80c7007c3ea0f4038eb62a 100644 --- a/drivers/isdn/mISDN/l1oip_codec.c +++ b/drivers/isdn/mISDN/l1oip_codec.c @@ -49,6 +49,7 @@ NOTE: The bytes are handled as they are law-encoded. #include #include #include "core.h" +#include "l1oip.h" /* definitions of codec. don't use calculations, code may run slower. */ diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index e42150a577805a7ad5f8d38971d34e4b5b04020d..0884dd6892f813868417a8b54d90bdf7025227f5 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -469,7 +469,7 @@ l1oip_socket_recv(struct l1oip *hc, u8 remotecodec, u8 channel, u16 timebase, static void l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) { - u32 id; + u32 packet_id; u8 channel; u8 remotecodec; u16 timebase; @@ -508,7 +508,7 @@ l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) } /* get id flag */ - id = (*buf>>4)&1; + packet_id = (*buf>>4)&1; /* check coding */ remotecodec = (*buf) & 0x0f; @@ -520,11 +520,11 @@ l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) buf++; len--; - /* check id */ - if (id) { + /* check packet_id */ + if (packet_id) { if (!hc->id) { printk(KERN_WARNING "%s: packet error - packet has id " - "0x%x, but we have not\n", __func__, id); + "0x%x, but we have not\n", __func__, packet_id); return; } if (len < 4) { @@ -532,16 +532,16 @@ l1oip_socket_parse(struct l1oip *hc, struct sockaddr_in *sin, u8 *buf, int len) "short for ID value\n", __func__); return; } - id = (*buf++) << 24; - id += (*buf++) << 16; - id += (*buf++) << 8; - id += (*buf++); + packet_id = (*buf++) << 24; + packet_id += (*buf++) << 16; + packet_id += (*buf++) << 8; + packet_id += (*buf++); len -= 4; - if (id != hc->id) { + if (packet_id != hc->id) { printk(KERN_WARNING "%s: packet error - ID mismatch, " "got 0x%x, we 0x%x\n", - __func__, id, hc->id); + __func__, packet_id, hc->id); return; } } else { diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c index fced1a2755f88dea2709273c3448d86be7b1b33b..b73e952d12cf0674f6eb09782f009b530c9b1720 100644 --- a/drivers/isdn/mISDN/layer1.c +++ b/drivers/isdn/mISDN/layer1.c @@ -18,10 +18,11 @@ #include #include +#include "core.h" #include "layer1.h" #include "fsm.h" -static int *debug; +static u_int *debug; struct layer1 { u_long Flags; diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index a7915a156c0419eff3cbafede3b69d649549e934..d6e2863f224a4aa6c0f76adac0681bf173ec81f9 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -15,10 +15,12 @@ * */ +#include +#include "core.h" #include "fsm.h" #include "layer2.h" -static int *debug; +static u_int *debug; static struct Fsm l2fsm = {NULL, 0, 0, NULL, NULL}; @@ -465,7 +467,7 @@ IsRNR(u_char *data, struct layer2 *l2) data[0] == RNR : (data[0] & 0xf) == RNR; } -int +static int iframe_error(struct layer2 *l2, struct sk_buff *skb) { u_int i; @@ -483,7 +485,7 @@ iframe_error(struct layer2 *l2, struct sk_buff *skb) return 0; } -int +static int super_error(struct layer2 *l2, struct sk_buff *skb) { if (skb->len != l2addrsize(l2) + @@ -492,7 +494,7 @@ super_error(struct layer2 *l2, struct sk_buff *skb) return 0; } -int +static int unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp) { int rsp = (*skb->data & 0x2) >> 1; @@ -505,7 +507,7 @@ unnum_error(struct layer2 *l2, struct sk_buff *skb, int wantrsp) return 0; } -int +static int UI_error(struct layer2 *l2, struct sk_buff *skb) { int rsp = *skb->data & 0x2; @@ -518,7 +520,7 @@ UI_error(struct layer2 *l2, struct sk_buff *skb) return 0; } -int +static int FRMR_error(struct layer2 *l2, struct sk_buff *skb) { u_int headers = l2addrsize(l2) + 1; @@ -1065,7 +1067,7 @@ l2_st6_dm_release(struct FsmInst *fi, int event, void *arg) } } -void +static void enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) { struct sk_buff *skb; diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c index e5a20f9542d1bb4456c602f73b4343879d268bac..37a2de18cfd0f68d13c537a5f0c53ffbb252e509 100644 --- a/drivers/isdn/mISDN/socket.c +++ b/drivers/isdn/mISDN/socket.c @@ -18,7 +18,7 @@ #include #include "core.h" -static int *debug; +static u_int *debug; static struct proto mISDN_proto = { .name = "misdn", diff --git a/drivers/isdn/mISDN/stack.c b/drivers/isdn/mISDN/stack.c index 54cfddcc47849403791602baba2b612b4fcc96ec..d55b14ae4e99d4e1ffbf58e76d9bda93df2cfb63 100644 --- a/drivers/isdn/mISDN/stack.c +++ b/drivers/isdn/mISDN/stack.c @@ -36,7 +36,7 @@ _queue_message(struct mISDNstack *st, struct sk_buff *skb) } } -int +static int mISDN_queue_message(struct mISDNchannel *ch, struct sk_buff *skb) { _queue_message(ch->st, skb); diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index 6fbae42127bfd8ebcc268db5dc029781d7618ad8..5c43d19e7c11676716e32be9357452a5f4db8a8c 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -393,7 +393,7 @@ dl_unit_data(struct manager *mgr, struct sk_buff *skb) return 0; } -unsigned int +static unsigned int random_ri(void) { u16 x; @@ -1287,7 +1287,7 @@ create_teimanager(struct mISDNdevice *dev) if (!mgr) return -ENOMEM; INIT_LIST_HEAD(&mgr->layer2); - mgr->lock = __RW_LOCK_UNLOCKED(mgr->lock); + rwlock_init(&mgr->lock); skb_queue_head_init(&mgr->sendq); mgr->nextid = 1; mgr->lastid = MISDN_ID_NONE; diff --git a/drivers/isdn/mISDN/timerdev.c b/drivers/isdn/mISDN/timerdev.c index 875fabe16e368c32b87f1a2e697accf45369eac6..f2b32186d4a19f2fbec632b5a7cf7c915a94134a 100644 --- a/drivers/isdn/mISDN/timerdev.c +++ b/drivers/isdn/mISDN/timerdev.c @@ -23,8 +23,9 @@ #include #include #include +#include "core.h" -static int *debug; +static u_int *debug; struct mISDNtimerdev { @@ -85,7 +86,7 @@ mISDN_close(struct inode *ino, struct file *filep) } static ssize_t -mISDN_read(struct file *filep, char *buf, size_t count, loff_t *off) +mISDN_read(struct file *filep, char __user *buf, size_t count, loff_t *off) { struct mISDNtimerdev *dev = filep->private_data; struct mISDNtimer *timer; @@ -115,7 +116,7 @@ mISDN_read(struct file *filep, char *buf, size_t count, loff_t *off) timer = (struct mISDNtimer *)dev->expired.next; list_del(&timer->list); spin_unlock_irqrestore(&dev->lock, flags); - if (put_user(timer->id, (int *)buf)) + if (put_user(timer->id, (int __user *)buf)) ret = -EFAULT; else ret = sizeof(int); @@ -274,7 +275,7 @@ static struct miscdevice mISDNtimer = { }; int -mISDN_inittimer(int *deb) +mISDN_inittimer(u_int *deb) { int err; diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 5f79c8dc383651aa9349e3445f854d24947aab9a..676413a915b45c3302995dfe82d49d283843c625 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -270,7 +270,7 @@ int flexcop_device_initialize(struct flexcop_device *fc) /* do the MAC address reading after initializing the dvb_adapter */ if (fc->get_mac_addr(fc, 0) == 0) { u8 *b = fc->dvb_adapter.proposed_mac; - info("MAC address = %02x:%02x:%02x:%02x:%02x:%02x", b[0],b[1],b[2],b[3],b[4],b[5]); + info("MAC address = %pM", b); flexcop_set_mac_filter(fc,b); flexcop_mac_filter_ctrl(fc,1); } else diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index aa3db57d32d94ce7ac01abb81b3ab41bbb501e2a..29e8f1546ab6d3dbafc2cd7ede40485fb771deea 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -917,9 +917,7 @@ static int dst_get_mac(struct dst_state *state) } memset(&state->mac_address, '\0', 8); memcpy(&state->mac_address, &state->rxbuffer, 6); - dprintk(verbose, DST_ERROR, 1, "MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]", - state->mac_address[0], state->mac_address[1], state->mac_address[2], - state->mac_address[4], state->mac_address[5], state->mac_address[6]); + dprintk(verbose, DST_ERROR, 1, "MAC Address=[%pM]", state->mac_address); return 0; } diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c index c1d92f838ca83ba608bd28678709bf9a5afa7be1..a21ce9edcc7ee1f383567ed8bc48a0d5d452c143 100644 --- a/drivers/media/dvb/dm1105/dm1105.c +++ b/drivers/media/dvb/dm1105/dm1105.c @@ -697,8 +697,7 @@ static void __devinit dm1105dvb_read_mac(struct dm1105dvb *dm1105dvb, u8 *mac) }; dm1105_i2c_xfer(&dm1105dvb->i2c_adap, msg , 2); - dev_info(&dm1105dvb->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + dev_info(&dm1105dvb->pdev->dev, "MAC %pM\n", mac); } static int __devinit dm1105_probe(struct pci_dev *pdev, diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index c93019ca519e677e8a979e5feab9e22f93a5dc0d..03fd9dd5c6850472d520dbbe8609709a898087db 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -345,7 +345,7 @@ static inline void reset_ule( struct dvb_net_priv *p ) */ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); unsigned long skipped = 0L; const u8 *ts, *ts_end, *from_where = NULL; u8 ts_remain = 0, how_much = 0, new_ts = 1; @@ -460,8 +460,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) /* Drop partly decoded SNDU, reset state, resync on PUSI. */ if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++; + priv->stats.rx_errors++; + priv->stats.rx_frame_errors++; } reset_ule(priv); priv->need_pusi = 1; @@ -573,7 +573,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); - ((struct dvb_net_priv *)dev->priv)->stats.rx_dropped++; + priv->stats.rx_dropped++; return; } @@ -800,7 +800,8 @@ static void dvb_net_sec(struct net_device *dev, { u8 *eth; struct sk_buff *skb; - struct net_device_stats *stats = &(((struct dvb_net_priv *) dev->priv)->stats); + struct net_device_stats *stats = + &((struct dvb_net_priv *) netdev_priv(dev))->stats; int snap = 0; /* note: pkt_len includes a 32bit checksum */ @@ -917,7 +918,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev, struct dmx_section_filter **secfilter, u8 *mac, u8 *mac_mask) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); int ret; *secfilter=NULL; @@ -961,7 +962,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev, static int dvb_net_feed_start(struct net_device *dev) { int ret = 0, i; - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); struct dmx_demux *demux = priv->demux; unsigned char *mac = (unsigned char *) dev->dev_addr; @@ -1060,7 +1061,7 @@ error: static int dvb_net_feed_stop(struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); int i, ret = 0; dprintk("%s\n", __func__); @@ -1113,7 +1114,7 @@ static int dvb_net_feed_stop(struct net_device *dev) static int dvb_set_mc_filter (struct net_device *dev, struct dev_mc_list *mc) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); if (priv->multi_num == DVB_NET_MULTICAST_MAX) return -ENOMEM; @@ -1165,7 +1166,7 @@ static void wq_set_multicast_list (struct work_struct *work) static void dvb_net_set_multicast_list (struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); schedule_work(&priv->set_multicast_list_wq); } @@ -1185,7 +1186,7 @@ static void wq_restart_net_feed (struct work_struct *work) static int dvb_net_set_mac (struct net_device *dev, void *p) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); struct sockaddr *addr=p; memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); @@ -1199,7 +1200,7 @@ static int dvb_net_set_mac (struct net_device *dev, void *p) static int dvb_net_open(struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); priv->in_use++; dvb_net_feed_start(dev); @@ -1209,7 +1210,7 @@ static int dvb_net_open(struct net_device *dev) static int dvb_net_stop(struct net_device *dev) { - struct dvb_net_priv *priv = dev->priv; + struct dvb_net_priv *priv = netdev_priv(dev); priv->in_use--; return dvb_net_feed_stop(dev); @@ -1217,7 +1218,7 @@ static int dvb_net_stop(struct net_device *dev) static struct net_device_stats * dvb_net_get_stats(struct net_device *dev) { - return &((struct dvb_net_priv*) dev->priv)->stats; + return &((struct dvb_net_priv *) netdev_priv(dev))->stats; } static const struct header_ops dvb_header_ops = { @@ -1287,7 +1288,7 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) dvbnet->device[if_num] = net; - priv = net->priv; + priv = netdev_priv(net); priv->net = net; priv->demux = dvbnet->demux; priv->pid = pid; @@ -1320,7 +1321,7 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num) if (!dvbnet->state[num]) return -EINVAL; - priv = net->priv; + priv = netdev_priv(net); if (priv->in_use) return -EBUSY; @@ -1376,7 +1377,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, netdev = dvbnet->device[dvbnetif->if_num]; - priv_data = netdev->priv; + priv_data = netdev_priv(netdev); dvbnetif->pid=priv_data->pid; dvbnetif->feedtype=priv_data->feedtype; break; @@ -1427,7 +1428,7 @@ static int dvb_net_do_ioctl(struct inode *inode, struct file *file, netdev = dvbnet->device[dvbnetif->if_num]; - priv_data = netdev->priv; + priv_data = netdev_priv(netdev); dvbnetif->pid=priv_data->pid; break; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index ce8cd0c5d83120b173ad5fa4950d1f43a8c0a585..8a7d87bcd1d98b71c3bbbd6b62150ad8c9e8fba9 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -91,10 +91,7 @@ int dvb_usb_adapter_dvb_init(struct dvb_usb_adapter *adap, short *adapter_nums) if (adap->dev->props.read_mac_address) { if (adap->dev->props.read_mac_address(adap->dev,adap->dvb_adap.proposed_mac) == 0) - info("MAC address: %02x:%02x:%02x:%02x:%02x:%02x",adap->dvb_adap.proposed_mac[0], - adap->dvb_adap.proposed_mac[1], adap->dvb_adap.proposed_mac[2], - adap->dvb_adap.proposed_mac[3], adap->dvb_adap.proposed_mac[4], - adap->dvb_adap.proposed_mac[5]); + info("MAC address: %pM",adap->dvb_adap.proposed_mac); else err("MAC address reading failed."); } diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index a9653c63f4db8350b5fb66c4e184b6d44a16421f..d101b304e9b0e7348614ec4ec2c8d28e15a31317 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -560,8 +560,7 @@ static void __devinit pluto_read_mac(struct pluto *pluto, u8 *mac) mac[4] = (val >> 8) & 0xff; mac[5] = (val >> 0) & 0xff; - dev_info(&pluto->pdev->dev, "MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); + dev_info(&pluto->pdev->dev, "MAC %pM\n", mac); } static int __devinit pluto_read_serial(struct pluto *pluto) diff --git a/drivers/message/fusion/mptlan.c b/drivers/message/fusion/mptlan.c index 603ffd008c73fb65275e1001af623f02332163d8..a13f6eecd25b87f4d82d51ae3d67d761cce29e41 100644 --- a/drivers/message/fusion/mptlan.c +++ b/drivers/message/fusion/mptlan.c @@ -815,7 +815,7 @@ mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority) * @priority: 0 = put it on the timer queue, 1 = put it on the immediate queue */ { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); if (test_and_set_bit(0, &priv->post_buckets_active) == 0) { if (priority) { @@ -834,7 +834,7 @@ mpt_lan_wake_post_buckets_task(struct net_device *dev, int priority) static int mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); skb->protocol = mpt_lan_type_trans(skb, dev); @@ -866,7 +866,7 @@ mpt_lan_receive_skb(struct net_device *dev, struct sk_buff *skb) static int mpt_lan_receive_post_turbo(struct net_device *dev, u32 tmsg) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; struct sk_buff *skb, *old_skb; unsigned long flags; @@ -921,7 +921,7 @@ static int mpt_lan_receive_post_free(struct net_device *dev, LANReceivePostReply_t *pRecvRep) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; unsigned long flags; struct sk_buff *skb; @@ -976,7 +976,7 @@ static int mpt_lan_receive_post_reply(struct net_device *dev, LANReceivePostReply_t *pRecvRep) { - struct mpt_lan_priv *priv = dev->priv; + struct mpt_lan_priv *priv = netdev_priv(dev); MPT_ADAPTER *mpt_dev = priv->mpt_dev; struct sk_buff *skb, *old_skb; unsigned long flags; @@ -1427,11 +1427,9 @@ mptlan_probe(struct pci_dev *pdev, const struct pci_device_id *id) printk(KERN_INFO MYNAM ": %s: Fusion MPT LAN device " "registered as '%s'\n", ioc->name, dev->name); printk(KERN_INFO MYNAM ": %s/%s: " - "LanAddr = %02X:%02X:%02X:%02X:%02X:%02X\n", + "LanAddr = %pM\n", IOC_AND_NETDEV_NAMES_s_s(dev), - dev->dev_addr[0], dev->dev_addr[1], - dev->dev_addr[2], dev->dev_addr[3], - dev->dev_addr[4], dev->dev_addr[5]); + dev->dev_addr); ioc->netdev = dev; @@ -1516,9 +1514,8 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) printk (KERN_WARNING MYNAM ": %s: WARNING - Broadcast swap F/W bug detected!\n", NETDEV_PTR_TO_IOC_NAME_s(dev)); - printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %02x:%02x:%02x:%02x:%02x:%02x\n", - fch->saddr[0], fch->saddr[1], fch->saddr[2], - fch->saddr[3], fch->saddr[4], fch->saddr[5]); + printk (KERN_WARNING MYNAM ": Please update sender @ MAC_addr = %pM\n", + fch->saddr); } if (*fch->daddr & 1) { @@ -1537,7 +1534,6 @@ mpt_lan_type_trans(struct sk_buff *skb, struct net_device *dev) fcllc = (struct fcllc *)skb->data; - /* Strip the SNAP header from ARP packets since we don't * pass them through to the 802.2/SNAP layers. */ diff --git a/drivers/message/fusion/mptlan.h b/drivers/message/fusion/mptlan.h index 33927ee7dc3bcc791d604ea374935fa5e185a75c..c171afa93239ac775bf5081dd24c96e836530eb4 100644 --- a/drivers/message/fusion/mptlan.h +++ b/drivers/message/fusion/mptlan.h @@ -122,7 +122,7 @@ MODULE_DESCRIPTION(LANAME); #define dlprintk(x) #endif -#define NETDEV_TO_LANPRIV_PTR(d) ((struct mpt_lan_priv *)(d)->priv) +#define NETDEV_TO_LANPRIV_PTR(d) ((struct mpt_lan_priv *)netdev_priv(d)) #define NETDEV_PTR_TO_IOC_NAME_s(d) (NETDEV_TO_LANPRIV_PTR(d)->mpt_dev->name) #define IOC_AND_NETDEV_NAMES_s_s(d) NETDEV_PTR_TO_IOC_NAME_s(d), (d)->name diff --git a/drivers/misc/sgi-xp/xpnet.c b/drivers/misc/sgi-xp/xpnet.c index 71513b3af7088e5f1ec115f5c08ff0c16039db04..8e6aa9508f4603dd2f4fa3f986e2612693da78f7 100644 --- a/drivers/misc/sgi-xp/xpnet.c +++ b/drivers/misc/sgi-xp/xpnet.c @@ -153,8 +153,7 @@ xpnet_receive(short partid, int channel, struct xpnet_message *msg) struct sk_buff *skb; void *dst; enum xp_retval ret; - struct xpnet_dev_private *priv = - (struct xpnet_dev_private *)xpnet_device->priv; + struct xpnet_dev_private *priv = netdev_priv(xpnet_device); if (!XPNET_VALID_MSG(msg)) { /* @@ -368,9 +367,7 @@ xpnet_dev_set_config(struct net_device *dev, struct ifmap *new_map) static struct net_device_stats * xpnet_dev_get_stats(struct net_device *dev) { - struct xpnet_dev_private *priv; - - priv = (struct xpnet_dev_private *)dev->priv; + struct xpnet_dev_private *priv = netdev_priv(dev); return &priv->stats; } @@ -456,7 +453,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) struct xpnet_pending_msg *queued_msg; u64 start_addr, end_addr; short dest_partid; - struct xpnet_dev_private *priv = (struct xpnet_dev_private *)dev->priv; + struct xpnet_dev_private *priv = netdev_priv(dev); u16 embedded_bytes = 0; dev_dbg(xpnet, ">skb->head=0x%p skb->data=0x%p skb->tail=0x%p " @@ -541,9 +538,7 @@ xpnet_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static void xpnet_dev_tx_timeout(struct net_device *dev) { - struct xpnet_dev_private *priv; - - priv = (struct xpnet_dev_private *)dev->priv; + struct xpnet_dev_private *priv = netdev_priv(dev); priv->stats.tx_errors++; return; diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c index 7d15e7c6bcad51f65860ff6b42e09881e8e2064a..3d1318a3e6885901a5f1e4efab65b0964a5dc48e 100644 --- a/drivers/net/3c501.c +++ b/drivers/net/3c501.c @@ -297,8 +297,8 @@ static int __init el1_probe1(struct net_device *dev, int ioaddr) if (el_debug) printk(KERN_DEBUG "%s", version); - memset(dev->priv, 0, sizeof(struct net_local)); lp = netdev_priv(dev); + memset(lp, 0, sizeof(struct net_local)); spin_lock_init(&lp->lock); /* @@ -725,7 +725,6 @@ static void el_receive(struct net_device *dev) insb(DATAPORT, skb_put(skb, pkt_len), pkt_len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/3c501.h b/drivers/net/3c501.h index cfec64efff78017b5db4ee3dd6d24ac42a983e32..f40b0493337a05162b2e522c09c5d7b867dbd52a 100644 --- a/drivers/net/3c501.h +++ b/drivers/net/3c501.h @@ -23,7 +23,7 @@ static const struct ethtool_ops netdev_ethtool_ops; static int el_debug = EL_DEBUG; /* - * Board-specific info in dev->priv. + * Board-specific info in netdev_priv(dev). */ struct net_local diff --git a/drivers/net/3c503.c b/drivers/net/3c503.c index 900b0ffdcc686c576e5eefaddd973eff7a80b018..c092c3929224d6fd3925f53107cea65ca427aa3f 100644 --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -168,6 +168,21 @@ out: } #endif +static const struct net_device_ops el2_netdev_ops = { + .ndo_open = el2_open, + .ndo_stop = el2_close, + + .ndo_start_xmit = eip_start_xmit, + .ndo_tx_timeout = eip_tx_timeout, + .ndo_get_stats = eip_get_stats, + .ndo_set_multicast_list = eip_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = eip_poll, +#endif +}; + /* Probe for the Etherlink II card at I/O port base IOADDR, returning non-zero on success. If found, set the station address and memory parameters in DEVICE. */ @@ -177,7 +192,6 @@ el2_probe1(struct net_device *dev, int ioaddr) int i, iobase_reg, membase_reg, saved_406, wordlength, retval; static unsigned version_printed; unsigned long vendor_id; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, EL2_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -228,7 +242,7 @@ el2_probe1(struct net_device *dev, int ioaddr) /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); /* Map the 8390 back into the window. */ outb(ECNTRL_THIN, ioaddr + 0x406); @@ -336,8 +350,7 @@ el2_probe1(struct net_device *dev, int ioaddr) ei_status.saved_irq = dev->irq; - dev->open = &el2_open; - dev->stop = &el2_close; + dev->netdev_ops = &el2_netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = eip_poll; diff --git a/drivers/net/3c505.c b/drivers/net/3c505.c index a424869707a5225b1f04e9d2e070a87d1987f19a..6124605bef05404bb2dee77114d5f8fcd1a1aff8 100644 --- a/drivers/net/3c505.c +++ b/drivers/net/3c505.c @@ -203,10 +203,10 @@ static inline int inb_command(unsigned int base_addr) static inline void outb_control(unsigned char val, struct net_device *dev) { outb(val, dev->base_addr + PORT_CONTROL); - ((elp_device *)(dev->priv))->hcr_val = val; + ((elp_device *)(netdev_priv(dev)))->hcr_val = val; } -#define HCR_VAL(x) (((elp_device *)((x)->priv))->hcr_val) +#define HCR_VAL(x) (((elp_device *)(netdev_priv(x)))->hcr_val) static inline void outb_command(unsigned char val, unsigned int base_addr) { @@ -247,7 +247,7 @@ static inline int get_status(unsigned int base_addr) static inline void set_hsf(struct net_device *dev, int hsf) { - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&adapter->lock, flags); @@ -260,7 +260,7 @@ static bool start_receive(struct net_device *, pcb_struct *); static inline void adapter_reset(struct net_device *dev) { unsigned long timeout; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); unsigned char orig_hcr = adapter->hcr_val; outb_control(0, dev); @@ -293,7 +293,7 @@ static inline void adapter_reset(struct net_device *dev) */ static inline void check_3c505_dma(struct net_device *dev) { - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); if (adapter->dmaing && time_after(jiffies, adapter->current_dma.start_time + 10)) { unsigned long flags, f; printk(KERN_ERR "%s: DMA %s timed out, %d bytes left\n", dev->name, adapter->current_dma.direction ? "download" : "upload", get_dma_residue(dev->dma)); @@ -340,7 +340,7 @@ static inline bool send_pcb_fast(unsigned int base_addr, unsigned char byte) /* Check to see if the receiver needs restarting, and kick it if so */ static inline void prime_rx(struct net_device *dev) { - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); while (adapter->rx_active < ELP_RX_PCBS && netif_running(dev)) { if (!start_receive(dev, &adapter->itx_pcb)) break; @@ -375,7 +375,7 @@ static bool send_pcb(struct net_device *dev, pcb_struct * pcb) { int i; unsigned long timeout; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); unsigned long flags; check_3c505_dma(dev); @@ -463,7 +463,7 @@ static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) unsigned long timeout; unsigned long flags; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); set_hsf(dev, 0); @@ -543,7 +543,7 @@ static bool receive_pcb(struct net_device *dev, pcb_struct * pcb) static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb) { bool status; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) printk(KERN_DEBUG "%s: restarting receiver\n", dev->name); @@ -571,7 +571,7 @@ static bool start_receive(struct net_device *dev, pcb_struct * tx_pcb) static void receive_packet(struct net_device *dev, int len) { int rlen; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); void *target; struct sk_buff *skb; unsigned long flags; @@ -638,13 +638,10 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) int len; int dlen; int icount = 0; - struct net_device *dev; - elp_device *adapter; + struct net_device *dev = dev_id; + elp_device *adapter = netdev_priv(dev); unsigned long timeout; - dev = dev_id; - adapter = (elp_device *) dev->priv; - spin_lock(&adapter->lock); do { @@ -672,7 +669,6 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) skb->protocol = eth_type_trans(skb,dev); dev->stats.rx_bytes += skb->len; netif_rx(skb); - dev->last_rx = jiffies; } } adapter->dmaing = 0; @@ -838,11 +834,9 @@ static irqreturn_t elp_interrupt(int irq, void *dev_id) static int elp_open(struct net_device *dev) { - elp_device *adapter; + elp_device *adapter = netdev_priv(dev); int retval; - adapter = dev->priv; - if (elp_debug >= 3) printk(KERN_DEBUG "%s: request to open device\n", dev->name); @@ -971,7 +965,7 @@ static int elp_open(struct net_device *dev) static bool send_packet(struct net_device *dev, struct sk_buff *skb) { - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); unsigned long target; unsigned long flags; @@ -1062,7 +1056,7 @@ static void elp_timeout(struct net_device *dev) static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); spin_lock_irqsave(&adapter->lock, flags); check_3c505_dma(dev); @@ -1104,7 +1098,7 @@ static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *elp_get_stats(struct net_device *dev) { - elp_device *adapter = (elp_device *) dev->priv; + elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) printk(KERN_DEBUG "%s: request for stats\n", dev->name); @@ -1166,9 +1160,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { static int elp_close(struct net_device *dev) { - elp_device *adapter; - - adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); if (elp_debug >= 3) printk(KERN_DEBUG "%s: request to close device\n", dev->name); @@ -1209,7 +1201,7 @@ static int elp_close(struct net_device *dev) static void elp_set_mc_list(struct net_device *dev) { - elp_device *adapter = (elp_device *) dev->priv; + elp_device *adapter = netdev_priv(dev); struct dev_mc_list *dmi = dev->mc_list; int i; unsigned long flags; @@ -1380,12 +1372,11 @@ static int __init elp_autodetect(struct net_device *dev) static int __init elplus_setup(struct net_device *dev) { - elp_device *adapter = dev->priv; + elp_device *adapter = netdev_priv(dev); int i, tries, tries1, okay; unsigned long timeout; unsigned long cookie = 0; int err = -ENODEV; - DECLARE_MAC_BUF(mac); /* * setup adapter structure @@ -1522,9 +1513,9 @@ static int __init elplus_setup(struct net_device *dev) * print remainder of startup message */ printk(KERN_INFO "%s: 3c505 at %#lx, irq %d, dma %d, " - "addr %s, ", + "addr %pM, ", dev->name, dev->base_addr, dev->irq, dev->dma, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); /* * read more information from the adapter diff --git a/drivers/net/3c507.c b/drivers/net/3c507.c index 030c147211baf1184662c7d69373277cd309474c..423e65d0ba737740091fa9488f5305776475200b 100644 --- a/drivers/net/3c507.c +++ b/drivers/net/3c507.c @@ -357,7 +357,6 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) static unsigned char init_ID_done, version_printed; int i, irq, irqval, retval; struct net_local *lp; - DECLARE_MAC_BUF(mac); if (init_ID_done == 0) { ushort lrs_state = 0xff; @@ -405,7 +404,7 @@ static int __init el16_probe1(struct net_device *dev, int ioaddr) outb(0x01, ioaddr + MISC_CTRL); for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); if (mem_start) net_debug = mem_start & 7; @@ -866,7 +865,6 @@ static void el16_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -938,14 +936,3 @@ cleanup_module(void) } #endif /* MODULE */ MODULE_LICENSE("GPL"); - - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c 3c507.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * c-indent-level: 4 - * End: - */ diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index c7a4f3bcc2bc1fd31f597304c6fff13ee0aaba3b..535c234286ea80c27f8a2ca8170b88b1b9c87208 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -541,7 +541,6 @@ static int __devinit el3_common_init(struct net_device *dev) { struct el3_private *lp = netdev_priv(dev); int err; - DECLARE_MAC_BUF(mac); const char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; spin_lock_init(&lp->lock); @@ -575,9 +574,9 @@ static int __devinit el3_common_init(struct net_device *dev) } printk(KERN_INFO "%s: 3c5x9 found at %#3.3lx, %s port, " - "address %s, IRQ %d.\n", + "address %pM, IRQ %d.\n", dev->name, dev->base_addr, if_names[(dev->if_port & 0x03)], - print_mac(mac, dev->dev_addr), dev->irq); + dev->dev_addr, dev->irq); if (el3_debug > 0) printk(KERN_INFO "%s", version); @@ -1075,7 +1074,6 @@ el3_rx(struct net_device *dev) outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_bytes += pkt_len; dev->stats.rx_packets++; continue; diff --git a/drivers/net/3c515.c b/drivers/net/3c515.c index a0f8b6e2d0af80af13b5774fe40ec9c5ee132db7..39ac12233aa72778362d0e00eee37830f7d387ce 100644 --- a/drivers/net/3c515.c +++ b/drivers/net/3c515.c @@ -570,7 +570,6 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, unsigned int eeprom[0x40], checksum = 0; /* EEPROM contents */ int i; int irq; - DECLARE_MAC_BUF(mac); #ifdef __ISAPNP__ if (idev) { @@ -636,7 +635,7 @@ static int corkscrew_setup(struct net_device *dev, int ioaddr, checksum = (checksum ^ (checksum >> 8)) & 0xff; if (checksum != 0x00) printk(" ***INVALID CHECKSUM %4.4x*** ", checksum); - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); if (eeprom[16] == 0x11c7) { /* Corkscrew */ if (request_dma(dev->dma, "3c515")) { printk(", DMA %d allocation failed", dev->dma); @@ -1302,7 +1301,6 @@ static int corkscrew_rx(struct net_device *dev) outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; /* Wait a limited time to go to next packet. */ @@ -1389,7 +1387,6 @@ static int boomerang_rx(struct net_device *dev) } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } entry = (++vp->cur_rx) % RX_RING_SIZE; @@ -1580,11 +1577,3 @@ void cleanup_module(void) } } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c515.c" - * c-indent-level: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/3c523.c b/drivers/net/3c523.c index e2ce41d3828ed47e90b31c7e09d7cb29649a1373..ff41e1ff56031876862db4a387c45a0dedb5d0b9 100644 --- a/drivers/net/3c523.c +++ b/drivers/net/3c523.c @@ -308,7 +308,7 @@ static int elmc_open(struct net_device *dev) static int __init check586(struct net_device *dev, unsigned long where, unsigned size) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); char *iscp_addrs[2]; int i = 0; @@ -347,9 +347,9 @@ static int __init check586(struct net_device *dev, unsigned long where, unsigned * set iscp at the right place, called by elmc_probe and open586. */ -void alloc586(struct net_device *dev) +static void alloc586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); elmc_id_reset586(); DELAY(2); @@ -383,7 +383,6 @@ static int elmc_getinfo(char *buf, int slot, void *d) { int len = 0; struct net_device *dev = d; - DECLARE_MAC_BUF(mac); if (dev == NULL) return len; @@ -398,8 +397,8 @@ static int elmc_getinfo(char *buf, int slot, void *d) len += sprintf(buf + len, "Transceiver: %s\n", dev->if_port ? "External" : "Internal"); len += sprintf(buf + len, "Device: %s\n", dev->name); - len += sprintf(buf + len, "Hardware Address: %s\n", - print_mac(mac, dev->dev_addr)); + len += sprintf(buf + len, "Hardware Address: %pM\n", + dev->dev_addr); return len; } /* elmc_getinfo() */ @@ -416,8 +415,7 @@ static int __init do_elmc_probe(struct net_device *dev) int i = 0; unsigned int size = 0; int retval; - struct priv *pr = dev->priv; - DECLARE_MAC_BUF(mac); + struct priv *pr = netdev_priv(dev); if (MCA_bus == 0) { return -ENODEV; @@ -543,8 +541,8 @@ static int __init do_elmc_probe(struct net_device *dev) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(dev->base_addr + i); - printk(KERN_INFO "%s: hardware address %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: hardware address %pM\n", + dev->name, dev->dev_addr); dev->open = &elmc_open; dev->stop = &elmc_close; @@ -578,13 +576,14 @@ err_out: return retval; } +#ifdef MODULE static void cleanup_card(struct net_device *dev) { - mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot, NULL, NULL); + mca_set_adapter_procfn(((struct priv *)netdev_priv(dev))->slot, + NULL, NULL); release_region(dev->base_addr, ELMC_IO_EXTENT); } - -#ifndef MODULE +#else struct net_device * __init elmc_probe(int unit) { struct net_device *dev = alloc_etherdev(sizeof(struct priv)); @@ -616,7 +615,7 @@ static int init586(struct net_device *dev) void *ptr; unsigned long s; int i, result = 0; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); volatile struct configure_cmd_struct *cfg_cmd; volatile struct iasetup_cmd_struct *ias_cmd; volatile struct tdr_cmd_struct *tdr_cmd; @@ -852,7 +851,7 @@ static void *alloc_rfa(struct net_device *dev, void *ptr) volatile struct rfd_struct *rfd = (struct rfd_struct *) ptr; volatile struct rbd_struct *rbd; int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); memset((char *) rfd, 0, sizeof(struct rfd_struct) * p->num_recv_buffs); p->rfd_first = rfd; @@ -913,7 +912,7 @@ elmc_interrupt(int irq, void *dev_id) } /* reading ELMC_CTRL also clears the INT bit. */ - p = (struct priv *) dev->priv; + p = netdev_priv(dev); while ((stat = p->scb->status & STAT_MASK)) { @@ -969,7 +968,7 @@ static void elmc_rcv_int(struct net_device *dev) unsigned short totlen; struct sk_buff *skb; struct rbd_struct *rbd; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); for (; (status = p->rfd_top->status) & STAT_COMPL;) { rbd = (struct rbd_struct *) make32(p->rfd_top->rbd_offset); @@ -985,7 +984,6 @@ static void elmc_rcv_int(struct net_device *dev) skb_copy_to_linear_data(skb, (char *) p->base+(unsigned long) rbd->buffer,totlen); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += totlen; } else { @@ -1013,7 +1011,7 @@ static void elmc_rcv_int(struct net_device *dev) static void elmc_rnr_int(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); dev->stats.rx_errors++; @@ -1036,7 +1034,7 @@ static void elmc_rnr_int(struct net_device *dev) static void elmc_xmt_int(struct net_device *dev) { int status; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); status = p->xmit_cmds[p->xmit_last]->cmd_status; if (!(status & STAT_COMPL)) { @@ -1079,7 +1077,7 @@ static void elmc_xmt_int(struct net_device *dev) static void startrecv586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); p->scb->rfa_offset = make16(p->rfd_first); p->scb->cmd = RUC_START; @@ -1093,7 +1091,7 @@ static void startrecv586(struct net_device *dev) static void elmc_timeout(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); /* COMMAND-UNIT active? */ if (p->scb->status & CU_ACTIVE) { #ifdef DEBUG @@ -1129,7 +1127,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) #ifndef NO_NOPCOMMANDS int next_nop; #endif - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); netif_stop_queue(dev); @@ -1200,7 +1198,7 @@ static int elmc_send_packet(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *elmc_get_stats(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); unsigned short crc, aln, rsc, ovrn; crc = p->scb->crc_errs; /* get error-statistic from the ni82586 */ diff --git a/drivers/net/3c527.c b/drivers/net/3c527.c index abc84f765973e2c30ef55b8e5c34973799dad415..2df3af3b9b20130ead927f93db05730029430d9c 100644 --- a/drivers/net/3c527.c +++ b/drivers/net/3c527.c @@ -335,7 +335,6 @@ static int __init mc32_probe1(struct net_device *dev, int slot) "82586 initialisation failure", "Adapter list configuration error" }; - DECLARE_MAC_BUF(mac); /* Time to play MCA games */ @@ -405,7 +404,7 @@ static int __init mc32_probe1(struct net_device *dev, int slot) dev->dev_addr[i] = mca_read_pos(slot,3); } - printk("%s: Address %s", dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: Address %pM", dev->name, dev->dev_addr); mca_write_pos(slot, 6, 0); mca_write_pos(slot, 7, 0); @@ -1187,7 +1186,6 @@ static void mc32_rx_ring(struct net_device *dev) } skb->protocol=eth_type_trans(skb,dev); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += length; netif_rx(skb); diff --git a/drivers/net/3c59x.c b/drivers/net/3c59x.c index 9ba295d9dd973b5713f7d49150a3807899ff3a77..665e7fdf27a15707f2a7aeffae50346371ff4ec1 100644 --- a/drivers/net/3c59x.c +++ b/drivers/net/3c59x.c @@ -803,7 +803,7 @@ static int vortex_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); - if (dev && dev->priv) { + if (dev && netdev_priv(dev)) { if (netif_running(dev)) { netif_device_detach(dev); vortex_down(dev, 1); @@ -1013,7 +1013,6 @@ static int __devinit vortex_probe1(struct device *gendev, const char *print_name = "3c59x"; struct pci_dev *pdev = NULL; struct eisa_device *edev = NULL; - DECLARE_MAC_BUF(mac); if (!printed_version) { printk (version); @@ -1026,7 +1025,7 @@ static int __devinit vortex_probe1(struct device *gendev, } if ((edev = DEVICE_EISA(gendev))) { - print_name = edev->dev.bus_id; + print_name = dev_name(&edev->dev); } } @@ -1206,7 +1205,7 @@ static int __devinit vortex_probe1(struct device *gendev, ((__be16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); if (print_info) - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); /* Unfortunately an all zero eeprom passes the checksum and this gets found in the wild in failure cases. Crypto is hard 8) */ if (!is_valid_ether_addr(dev->dev_addr)) { @@ -2447,7 +2446,6 @@ static int vortex_rx(struct net_device *dev) iowrite16(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */ skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; /* Wait a limited time to go to next packet. */ for (i = 200; i >= 0; i--) @@ -2530,7 +2528,6 @@ boomerang_rx(struct net_device *dev) } } netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } entry = (++vp->cur_rx) % RX_RING_SIZE; @@ -2886,7 +2883,7 @@ static void vortex_get_drvinfo(struct net_device *dev, strcpy(info->bus_info, pci_name(VORTEX_PCI(vp))); } else { if (VORTEX_EISA(vp)) - sprintf(info->bus_info, vp->gendev->bus_id); + sprintf(info->bus_info, dev_name(vp->gendev)); else sprintf(info->bus_info, "EISA 0x%lx %d", dev->base_addr, dev->irq); @@ -3217,7 +3214,7 @@ static void __exit vortex_eisa_cleanup(void) #endif if (compaq_net_device) { - vp = compaq_net_device->priv; + vp = netdev_priv(compaq_net_device); ioaddr = ioport_map(compaq_net_device->base_addr, VORTEX_TOTAL_SIZE); diff --git a/drivers/net/7990.c b/drivers/net/7990.c index ad6b8a5b6574b4865b327bff0bb719878316ce27..7a331acc34add0b755b92c1c4379f4292c5b14e8 100644 --- a/drivers/net/7990.c +++ b/drivers/net/7990.c @@ -336,7 +336,6 @@ static int lance_rx (struct net_device *dev) len); skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; } diff --git a/drivers/net/8139cp.c b/drivers/net/8139cp.c index 9ba1f0b4642950d860375768c21bdae6624c321f..dd7ac8290aecfc7323554e90ab0850fe64713346 100644 --- a/drivers/net/8139cp.c +++ b/drivers/net/8139cp.c @@ -457,7 +457,6 @@ static inline void cp_rx_skb (struct cp_private *cp, struct sk_buff *skb, cp->dev->stats.rx_packets++; cp->dev->stats.rx_bytes += skb->len; - cp->dev->last_rx = jiffies; #if CP_VLAN_TAG_USED if (cp->vlgrp && (desc->opts2 & cpu_to_le32(RxVlanTagged))) { @@ -605,7 +604,7 @@ rx_next: spin_lock_irqsave(&cp->lock, flags); cpw16_f(IntrMask, cp_intr_mask); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); spin_unlock_irqrestore(&cp->lock, flags); } @@ -642,9 +641,9 @@ static irqreturn_t cp_interrupt (int irq, void *dev_instance) } if (status & (RxOK | RxErr | RxEmpty | RxFIFOOvr)) - if (netif_rx_schedule_prep(dev, &cp->napi)) { + if (netif_rx_schedule_prep(&cp->napi)) { cpw16_f(IntrMask, cp_norx_intr_mask); - __netif_rx_schedule(dev, &cp->napi); + __netif_rx_schedule(&cp->napi); } if (status & (TxOK | TxErr | TxEmpty | SWInt)) @@ -1818,6 +1817,26 @@ static void cp_set_d3_state (struct cp_private *cp) pci_set_power_state (cp->pdev, PCI_D3hot); } +static const struct net_device_ops cp_netdev_ops = { + .ndo_open = cp_open, + .ndo_stop = cp_close, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = cp_set_rx_mode, + .ndo_get_stats = cp_get_stats, + .ndo_do_ioctl = cp_ioctl, + .ndo_start_xmit = cp_start_xmit, + .ndo_tx_timeout = cp_tx_timeout, +#if CP_VLAN_TAG_USED + .ndo_vlan_rx_register = cp_vlan_rx_register, +#endif +#ifdef BROKEN + .ndo_change_mtu = cp_change_mtu, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cp_poll_controller, +#endif +}; + static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *dev; @@ -1826,7 +1845,6 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) void __iomem *regs; resource_size_t pciaddr; unsigned int addr_len, i, pci_using_dac; - DECLARE_MAC_BUF(mac); #ifndef MODULE static int version_printed; @@ -1931,26 +1949,13 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) cpu_to_le16(read_eeprom (regs, i + 7, addr_len)); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - dev->open = cp_open; - dev->stop = cp_close; - dev->set_multicast_list = cp_set_rx_mode; - dev->hard_start_xmit = cp_start_xmit; - dev->get_stats = cp_get_stats; - dev->do_ioctl = cp_ioctl; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = cp_poll_controller; -#endif + dev->netdev_ops = &cp_netdev_ops; netif_napi_add(dev, &cp->napi, cp_rx_poll, 16); -#ifdef BROKEN - dev->change_mtu = cp_change_mtu; -#endif dev->ethtool_ops = &cp_ethtool_ops; - dev->tx_timeout = cp_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; #if CP_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = cp_vlan_rx_register; #endif if (pci_using_dac) @@ -1967,10 +1972,10 @@ static int cp_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_iomap; printk (KERN_INFO "%s: RTL-8139C+ at 0x%lx, " - "%s, IRQ %d\n", + "%pM, IRQ %d\n", dev->name, dev->base_addr, - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/8139too.c b/drivers/net/8139too.c index 63f906b04899de12271baa196bc7b424d0c067f8..fe370f8057933244e544cd5849e064e514edaa11 100644 --- a/drivers/net/8139too.c +++ b/drivers/net/8139too.c @@ -741,8 +741,7 @@ static void rtl8139_chip_reset (void __iomem *ioaddr) } -static int __devinit rtl8139_init_board (struct pci_dev *pdev, - struct net_device **dev_out) +static __devinit struct net_device * rtl8139_init_board (struct pci_dev *pdev) { void __iomem *ioaddr; struct net_device *dev; @@ -756,13 +755,11 @@ static int __devinit rtl8139_init_board (struct pci_dev *pdev, assert (pdev != NULL); - *dev_out = NULL; - /* dev and priv zeroed in alloc_etherdev */ dev = alloc_etherdev (sizeof (*tp)); if (dev == NULL) { dev_err(&pdev->dev, "Unable to alloc new net device\n"); - return -ENOMEM; + return ERR_PTR(-ENOMEM); } SET_NETDEV_DEV(dev, &pdev->dev); @@ -906,16 +903,29 @@ match: rtl8139_chip_reset (ioaddr); - *dev_out = dev; - return 0; + return dev; err_out: __rtl8139_cleanup_dev (dev); if (disable_dev_on_err) pci_disable_device (pdev); - return rc; + return ERR_PTR(rc); } +static const struct net_device_ops rtl8139_netdev_ops = { + .ndo_open = rtl8139_open, + .ndo_stop = rtl8139_close, + .ndo_get_stats = rtl8139_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_start_xmit = rtl8139_start_xmit, + .ndo_set_multicast_list = rtl8139_set_rx_mode, + .ndo_do_ioctl = netdev_ioctl, + .ndo_tx_timeout = rtl8139_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = rtl8139_poll_controller, +#endif + +}; static int __devinit rtl8139_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -925,7 +935,6 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, int i, addr_len, option; void __iomem *ioaddr; static int board_idx = -1; - DECLARE_MAC_BUF(mac); assert (pdev != NULL); assert (ent != NULL); @@ -959,9 +968,9 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, use_io = 1; } - i = rtl8139_init_board (pdev, &dev); - if (i < 0) - return i; + dev = rtl8139_init_board (pdev); + if (IS_ERR(dev)) + return PTR_ERR(dev); assert (dev != NULL); tp = netdev_priv(dev); @@ -977,19 +986,10 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); /* The Rtl8139-specific entries in the device structure. */ - dev->open = rtl8139_open; - dev->hard_start_xmit = rtl8139_start_xmit; - netif_napi_add(dev, &tp->napi, rtl8139_poll, 64); - dev->stop = rtl8139_close; - dev->get_stats = rtl8139_get_stats; - dev->set_multicast_list = rtl8139_set_rx_mode; - dev->do_ioctl = netdev_ioctl; + dev->netdev_ops = &rtl8139_netdev_ops; dev->ethtool_ops = &rtl8139_ethtool_ops; - dev->tx_timeout = rtl8139_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = rtl8139_poll_controller; -#endif + netif_napi_add(dev, &tp->napi, rtl8139_poll, 64); /* note: the hardware is not capable of sg/csum/highdma, however * through the use of skb_copy_and_csum_dev we enable these @@ -1024,11 +1024,11 @@ static int __devinit rtl8139_init_one (struct pci_dev *pdev, pci_set_drvdata (pdev, dev); printk (KERN_INFO "%s: %s at 0x%lx, " - "%s, IRQ %d\n", + "%pM, IRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", @@ -2026,7 +2026,6 @@ no_early_rx: skb->protocol = eth_type_trans (skb, dev); - dev->last_rx = jiffies; dev->stats.rx_bytes += pkt_size; dev->stats.rx_packets++; @@ -2129,7 +2128,7 @@ static int rtl8139_poll(struct napi_struct *napi, int budget) */ spin_lock_irqsave(&tp->lock, flags); RTL_W16_F(IntrMask, rtl8139_intr_mask); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); spin_unlock_irqrestore(&tp->lock, flags); } spin_unlock(&tp->rx_lock); @@ -2179,9 +2178,9 @@ static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance) /* Receive packets are processed by poll routine. If not running start it now. */ if (status & RxAckBits){ - if (netif_rx_schedule_prep(dev, &tp->napi)) { + if (netif_rx_schedule_prep(&tp->napi)) { RTL_W16_F (IntrMask, rtl8139_norx_intr_mask); - __netif_rx_schedule(dev, &tp->napi); + __netif_rx_schedule(&tp->napi); } } diff --git a/drivers/net/82596.c b/drivers/net/82596.c index da292e647eb117c496e3c4c6f6108e0e8c316c94..b273596368e36d9c2a99e1143b673e518f93aeed 100644 --- a/drivers/net/82596.c +++ b/drivers/net/82596.c @@ -457,7 +457,7 @@ static inline int wait_cfg(struct net_device *dev, struct i596_cmd *cmd, int del static void i596_display_data(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; struct i596_cmd *cmd; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -527,7 +527,7 @@ static irqreturn_t i596_error(int irq, void *dev_id) static inline void init_rx_bufs(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; int i; struct i596_rfd *rfd; struct i596_rbd *rbd; @@ -578,7 +578,7 @@ static inline void init_rx_bufs(struct net_device *dev) static inline void remove_rx_bufs(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; struct i596_rbd *rbd; int i; @@ -592,7 +592,7 @@ static inline void remove_rx_bufs(struct net_device *dev) static void rebuild_rx_bufs(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; int i; /* Ensure rx frame/buffer descriptors are tidy */ @@ -611,7 +611,7 @@ static void rebuild_rx_bufs(struct net_device *dev) static int init_i596_mem(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; #if !defined(ENABLE_MVME16x_NET) && !defined(ENABLE_BVME6000_NET) || defined(ENABLE_APRICOT) short ioaddr = dev->base_addr; #endif @@ -764,7 +764,7 @@ failed: static inline int i596_rx(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; struct i596_rfd *rfd; struct i596_rbd *rbd; int frames = 0; @@ -841,7 +841,6 @@ memory_squeeze: pkt_len); #endif netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes+=pkt_len; } @@ -959,7 +958,7 @@ static void i596_reset(struct net_device *dev, struct i596_private *lp, static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; int ioaddr = dev->base_addr; unsigned long flags; @@ -1029,7 +1028,7 @@ static int i596_open(struct net_device *dev) static void i596_tx_timeout (struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ @@ -1058,7 +1057,7 @@ static void i596_tx_timeout (struct net_device *dev) static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; struct tx_cmd *tx_cmd; struct i596_tbd *tbd; short length = skb->len; @@ -1116,12 +1115,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) static void print_eth(unsigned char *add, char *str) { - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - - printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n", - add, print_mac(mac, add + 6), print_mac(mac2, add), - add[12], add[13], str); + printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n", + add, add + 6, add, add[12], add[13], str); } static int io = 0x300; @@ -1244,9 +1239,9 @@ found: dev->tx_timeout = i596_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - dev->priv = (void *)(dev->mem_start); + dev->ml_priv = (void *)(dev->mem_start); - lp = dev->priv; + lp = dev->ml_priv; DEB(DEB_INIT,printk(KERN_DEBUG "%s: lp at 0x%08lx (%zd bytes), " "lp->scb at 0x%08lx\n", dev->name, (unsigned long)lp, @@ -1307,7 +1302,7 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) } ioaddr = dev->base_addr; - lp = dev->priv; + lp = dev->ml_priv; spin_lock (&lp->lock); @@ -1450,7 +1445,7 @@ static irqreturn_t i596_interrupt(int irq, void *dev_id) static int i596_close(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; unsigned long flags; netif_stop_queue(dev); @@ -1500,7 +1495,7 @@ static int i596_close(struct net_device *dev) static void set_multicast_list(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = dev->ml_priv; int config = 0, cnt; DEB(DEB_MULTI,printk(KERN_DEBUG "%s: set multicast list, %d entries, promisc %s, allmulti %s\n", @@ -1544,7 +1539,6 @@ static void set_multicast_list(struct net_device *dev) struct dev_mc_list *dmi; unsigned char *cp; struct mc_cmd *cmd; - DECLARE_MAC_BUF(mac); if (wait_cfg(dev, &lp->mc_cmd.cmd, 1000, "multicast list change request timed out")) return; @@ -1555,8 +1549,8 @@ static void set_multicast_list(struct net_device *dev) for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) { memcpy(cp, dmi->dmi_addr, 6); if (i596_debug > 1) - DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %s\n", - dev->name, print_mac(mac, cp))); + DEB(DEB_MULTI,printk(KERN_INFO "%s: Adding address %pM\n", + dev->name, cp)); } i596_add_cmd(dev, &cmd->cmd); } @@ -1604,9 +1598,3 @@ void __exit cleanup_module(void) } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 82596.c" - * End: - */ diff --git a/drivers/net/8390.c b/drivers/net/8390.c index f72a2e87d5697339045421b8c14568af4eeb789c..fbe609a51e02c5952e6b437f8183e344af0c4fbc 100644 --- a/drivers/net/8390.c +++ b/drivers/net/8390.c @@ -17,6 +17,30 @@ int ei_close(struct net_device *dev) } EXPORT_SYMBOL(ei_close); +int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + return __ei_start_xmit(skb, dev); +} +EXPORT_SYMBOL(ei_start_xmit); + +struct net_device_stats *ei_get_stats(struct net_device *dev) +{ + return __ei_get_stats(dev); +} +EXPORT_SYMBOL(ei_get_stats); + +void ei_set_multicast_list(struct net_device *dev) +{ + __ei_set_multicast_list(dev); +} +EXPORT_SYMBOL(ei_set_multicast_list); + +void ei_tx_timeout(struct net_device *dev) +{ + __ei_tx_timeout(dev); +} +EXPORT_SYMBOL(ei_tx_timeout); + irqreturn_t ei_interrupt(int irq, void *dev_id) { return __ei_interrupt(irq, dev_id); @@ -31,9 +55,33 @@ void ei_poll(struct net_device *dev) EXPORT_SYMBOL(ei_poll); #endif +const struct net_device_ops ei_netdev_ops = { + .ndo_open = ei_open, + .ndo_stop = ei_close, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; +EXPORT_SYMBOL(ei_netdev_ops); + struct net_device *__alloc_ei_netdev(int size) { - return ____alloc_ei_netdev(size); + struct net_device *dev = ____alloc_ei_netdev(size); +#ifdef CONFIG_COMPAT_NET_DEV_OPS + if (dev) { + dev->hard_start_xmit = ei_start_xmit; + dev->get_stats = ei_get_stats; + dev->set_multicast_list = ei_set_multicast_list; + dev->tx_timeout = ei_tx_timeout; + } +#endif + return dev; } EXPORT_SYMBOL(__alloc_ei_netdev); diff --git a/drivers/net/8390.h b/drivers/net/8390.h index 8e209f5e7c1179e26eceef42f5abf250372db91e..3c61d6d2748a424e00ecc56c2cd15fc72fdb88cf 100644 --- a/drivers/net/8390.h +++ b/drivers/net/8390.h @@ -33,11 +33,19 @@ extern void ei_poll(struct net_device *dev); extern void eip_poll(struct net_device *dev); #endif + /* Without I/O delay - non ISA or later chips */ extern void NS8390_init(struct net_device *dev, int startp); extern int ei_open(struct net_device *dev); extern int ei_close(struct net_device *dev); extern irqreturn_t ei_interrupt(int irq, void *dev_id); +extern void ei_tx_timeout(struct net_device *dev); +extern int ei_start_xmit(struct sk_buff *skb, struct net_device *dev); +extern void ei_set_multicast_list(struct net_device *dev); +extern struct net_device_stats *ei_get_stats(struct net_device *dev); + +extern const struct net_device_ops ei_netdev_ops; + extern struct net_device *__alloc_ei_netdev(int size); static inline struct net_device *alloc_ei_netdev(void) { @@ -49,6 +57,13 @@ extern void NS8390p_init(struct net_device *dev, int startp); extern int eip_open(struct net_device *dev); extern int eip_close(struct net_device *dev); extern irqreturn_t eip_interrupt(int irq, void *dev_id); +extern void eip_tx_timeout(struct net_device *dev); +extern int eip_start_xmit(struct sk_buff *skb, struct net_device *dev); +extern void eip_set_multicast_list(struct net_device *dev); +extern struct net_device_stats *eip_get_stats(struct net_device *dev); + +extern const struct net_device_ops eip_netdev_ops; + extern struct net_device *__alloc_eip_netdev(int size); static inline struct net_device *alloc_eip_netdev(void) { diff --git a/drivers/net/8390p.c b/drivers/net/8390p.c index 4c6eea4611a2c213a1bbff4079c02a3006b65d98..ee70b358a816aedf83535017c55ab3af8d4cc254 100644 --- a/drivers/net/8390p.c +++ b/drivers/net/8390p.c @@ -22,6 +22,30 @@ int eip_close(struct net_device *dev) } EXPORT_SYMBOL(eip_close); +int eip_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + return __ei_start_xmit(skb, dev); +} +EXPORT_SYMBOL(eip_start_xmit); + +struct net_device_stats *eip_get_stats(struct net_device *dev) +{ + return __ei_get_stats(dev); +} +EXPORT_SYMBOL(eip_get_stats); + +void eip_set_multicast_list(struct net_device *dev) +{ + __ei_set_multicast_list(dev); +} +EXPORT_SYMBOL(eip_set_multicast_list); + +void eip_tx_timeout(struct net_device *dev) +{ + __ei_tx_timeout(dev); +} +EXPORT_SYMBOL(eip_tx_timeout); + irqreturn_t eip_interrupt(int irq, void *dev_id) { return __ei_interrupt(irq, dev_id); @@ -36,9 +60,33 @@ void eip_poll(struct net_device *dev) EXPORT_SYMBOL(eip_poll); #endif +const struct net_device_ops eip_netdev_ops = { + .ndo_open = eip_open, + .ndo_stop = eip_close, + .ndo_start_xmit = eip_start_xmit, + .ndo_tx_timeout = eip_tx_timeout, + .ndo_get_stats = eip_get_stats, + .ndo_set_multicast_list = eip_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = eip_poll, +#endif +}; +EXPORT_SYMBOL(eip_netdev_ops); + struct net_device *__alloc_eip_netdev(int size) { - return ____alloc_ei_netdev(size); + struct net_device *dev = ____alloc_ei_netdev(size); +#ifdef CONFIG_COMPAT_NET_DEV_OPS + if (dev) { + dev->hard_start_xmit = eip_start_xmit; + dev->get_stats = eip_get_stats; + dev->set_multicast_list = eip_set_multicast_list; + dev->tx_timeout = eip_tx_timeout; + } +#endif + return dev; } EXPORT_SYMBOL(__alloc_eip_netdev); diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 231eeaf1d5522513e44941871d76b67b38b0f38b..72a9212da865ebcd9e59c1198c3c2cb79c06df7a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig @@ -61,6 +61,7 @@ config DUMMY config BONDING tristate "Bonding driver support" depends on INET + depends on IPV6 || IPV6=n ---help--- Say 'Y' or 'M' if you wish to be able to 'bond' multiple Ethernet Channels together. This is called 'Etherchannel' by Cisco, @@ -978,6 +979,20 @@ config SMC911X called smc911x. If you want to compile it as a module, say M here and read +config SMSC911X + tristate "SMSC LAN911x/LAN921x families embedded ethernet support" + depends on ARM || SUPERH + select CRC32 + select MII + select PHYLIB + ---help--- + Say Y here if you want support for SMSC LAN911x and LAN921x families + of ethernet controllers. + + To compile this driver as a module, choose M here and read + . The module + will be called smsc911x. + config NET_VENDOR_RACAL bool "Racal-Interlan (Micom) NI cards" depends on ISA @@ -1414,19 +1429,6 @@ config TC35815 depends on NET_PCI && PCI && MIPS select PHYLIB -config EEPRO100 - tristate "EtherExpressPro/100 support (eepro100, original Becker driver)" - depends on NET_PCI && PCI - select MII - help - If you have an Intel EtherExpress PRO/100 PCI network (Ethernet) - card, say Y and read the Ethernet-HOWTO, available from - . - - To compile this driver as a module, choose M here. The module - will be called eepro100. - - config E100 tristate "Intel(R) PRO/100+ support" depends on NET_PCI && PCI @@ -1636,6 +1638,22 @@ config EPIC100 More specific information and updates are available from . +config SMSC9420 + tristate "SMSC LAN9420 PCI ethernet adapter support" + depends on NET_PCI && PCI + select CRC32 + select PHYLIB + select SMSC_PHY + help + This is a driver for SMSC's LAN9420 PCI ethernet adapter. + Say Y if you want it compiled into the kernel, + and read the Ethernet-HOWTO, available from + . + + This driver is also available as a module. The module will be + called smsc9420. If you want to compile it as a module, say M + here and read + config SUNDANCE tristate "Sundance Alta support" depends on NET_PCI && PCI @@ -1981,10 +1999,10 @@ config IP1000 will be called ipg. This is recommended. config IGB - tristate "Intel(R) 82575 PCI-Express Gigabit Ethernet support" + tristate "Intel(R) 82575/82576 PCI-Express Gigabit Ethernet support" depends on PCI ---help--- - This driver supports Intel(R) 82575 gigabit ethernet family of + This driver supports Intel(R) 82575/82576 gigabit ethernet family of adapters. For more information on how to identify your adapter, go to the Adapter & Driver ID Guide at: @@ -2276,10 +2294,6 @@ config UGETH_MAGIC_PACKET bool "Magic Packet detection support" depends on UCC_GETH -config UGETH_FILTERING - bool "Mac address filtering support" - depends on UCC_GETH - config UGETH_TX_ON_DEMAND bool "Transmit on Demand support" depends on UCC_GETH @@ -2450,6 +2464,16 @@ config IXGBE_DCA driver. DCA is a method for warming the CPU cache before data is used, with the intent of lessening the impact of cache misses. +config IXGBE_DCB + bool "Data Center Bridging (DCB) Support" + default n + depends on IXGBE && DCB + ---help--- + Say Y here if you want to use Data Center Bridging (DCB) in the + driver. + + If unsure, say N. + config IXGB tristate "Intel(R) PRO/10GbE support" depends on PCI @@ -2626,7 +2650,7 @@ config RIONET_RX_SIZE default "128" config FDDI - bool "FDDI driver support" + tristate "FDDI driver support" depends on (PCI || EISA || TC) help Fiber Distributed Data Interface is a high speed local area network diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 017383ad5ec6e6de671b71c0165d783b525386f2..e5c34b4642111b22cc692362aac3c8ae881ab84d 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -53,10 +53,10 @@ obj-$(CONFIG_VORTEX) += 3c59x.o obj-$(CONFIG_TYPHOON) += typhoon.o obj-$(CONFIG_NE2K_PCI) += ne2k-pci.o 8390.o obj-$(CONFIG_PCNET32) += pcnet32.o -obj-$(CONFIG_EEPRO100) += eepro100.o obj-$(CONFIG_E100) += e100.o obj-$(CONFIG_TLAN) += tlan.o obj-$(CONFIG_EPIC100) += epic100.o +obj-$(CONFIG_SMSC9420) += smsc9420.o obj-$(CONFIG_SIS190) += sis190.o obj-$(CONFIG_SIS900) += sis900.o obj-$(CONFIG_R6040) += r6040.o @@ -98,7 +98,7 @@ obj-$(CONFIG_HAMACHI) += hamachi.o obj-$(CONFIG_NET) += Space.o loopback.o obj-$(CONFIG_SEEQ8005) += seeq8005.o obj-$(CONFIG_NET_SB1000) += sb1000.o -obj-$(CONFIG_MAC8390) += mac8390.o +obj-$(CONFIG_MAC8390) += mac8390.o 8390.o obj-$(CONFIG_APNE) += apne.o 8390.o obj-$(CONFIG_PCMCIA_PCNET) += 8390.o obj-$(CONFIG_HP100) += hp100.o @@ -125,7 +125,7 @@ obj-$(CONFIG_NE3210) += ne3210.o 8390.o obj-$(CONFIG_SB1250_MAC) += sb1250-mac.o obj-$(CONFIG_B44) += b44.o obj-$(CONFIG_FORCEDETH) += forcedeth.o -obj-$(CONFIG_NE_H8300) += ne-h8300.o +obj-$(CONFIG_NE_H8300) += ne-h8300.o 8390.o obj-$(CONFIG_AX88796) += ax88796.o obj-$(CONFIG_TSI108_ETH) += tsi108_eth.o @@ -191,7 +191,7 @@ obj-$(CONFIG_SC92031) += sc92031.o obj-$(CONFIG_LP486E) += lp486e.o obj-$(CONFIG_ETH16I) += eth16i.o -obj-$(CONFIG_ZORRO8390) += zorro8390.o +obj-$(CONFIG_ZORRO8390) += zorro8390.o 8390.o obj-$(CONFIG_HPLANCE) += hplance.o 7990.o obj-$(CONFIG_MVME147_NET) += mvme147.o 7990.o obj-$(CONFIG_EQUALIZER) += eql.o @@ -203,7 +203,7 @@ obj-$(CONFIG_SGI_IOC3_ETH) += ioc3-eth.o obj-$(CONFIG_DECLANCE) += declance.o obj-$(CONFIG_ATARILANCE) += atarilance.o obj-$(CONFIG_A2065) += a2065.o -obj-$(CONFIG_HYDRA) += hydra.o +obj-$(CONFIG_HYDRA) += hydra.o 8390.o obj-$(CONFIG_ARIADNE) += ariadne.o obj-$(CONFIG_CS89x0) += cs89x0.o obj-$(CONFIG_MACSONIC) += macsonic.o @@ -220,6 +220,7 @@ obj-$(CONFIG_S2IO) += s2io.o obj-$(CONFIG_MYRI10GE) += myri10ge/ obj-$(CONFIG_SMC91X) += smc91x.o obj-$(CONFIG_SMC911X) += smc911x.o +obj-$(CONFIG_SMSC911X) += smsc911x.o obj-$(CONFIG_BFIN_MAC) += bfin_mac.o obj-$(CONFIG_DM9000) += dm9000.o obj-$(CONFIG_PASEMI_MAC) += pasemi_mac_driver.o diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index 9c0837435b68dd83b88fca7355308796c2257e2e..7a60bdd9a242f27320b23249455b794bb90bf4c8 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -324,7 +324,6 @@ static int lance_rx (struct net_device *dev) len); skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; } @@ -710,7 +709,6 @@ static int __devinit a2065_init_one(struct zorro_dev *z, unsigned long board, base_addr, mem_start; struct resource *r1, *r2; int err; - DECLARE_MAC_BUF(mac); board = z->resource.start; base_addr = board+A2065_LANCE; @@ -787,8 +785,7 @@ static int __devinit a2065_init_one(struct zorro_dev *z, zorro_set_drvdata(z, dev); printk(KERN_INFO "%s: A2065 at 0x%08lx, Ethernet Address " - "%s\n", dev->name, board, - print_mac(mac, dev->dev_addr)); + "%pM\n", dev->name, board, dev->dev_addr); return 0; } diff --git a/drivers/net/ac3200.c b/drivers/net/ac3200.c index b1448637107f3fada6f1a97536dfd6492a9d9117..071a851a2ea1d6b5a4b4db6b0c0e51625ad38222 100644 --- a/drivers/net/ac3200.c +++ b/drivers/net/ac3200.c @@ -146,7 +146,6 @@ out: static int __init ac_probe1(int ioaddr, struct net_device *dev) { int i, retval; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, AC_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -171,8 +170,8 @@ static int __init ac_probe1(int ioaddr, struct net_device *dev) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i); - printk(KERN_DEBUG "AC3200 in EISA slot %d, node %s", - ioaddr/0x1000, print_mac(mac, dev->dev_addr)); + printk(KERN_DEBUG "AC3200 in EISA slot %d, node %pM", + ioaddr/0x1000, dev->dev_addr); #if 0 /* Check the vendor ID/prefix. Redundant after checking the EISA ID */ if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0 diff --git a/drivers/net/acenic.c b/drivers/net/acenic.c index 66de80b64b92a3f937edf821e49ec748c6478ed3..517fce48d94a0c2eac28ed49110e05ab322d0e97 100644 --- a/drivers/net/acenic.c +++ b/drivers/net/acenic.c @@ -450,6 +450,20 @@ static const struct ethtool_ops ace_ethtool_ops = { static void ace_watchdog(struct net_device *dev); +static const struct net_device_ops ace_netdev_ops = { + .ndo_open = ace_open, + .ndo_stop = ace_close, + .ndo_tx_timeout = ace_watchdog, + .ndo_get_stats = ace_get_stats, + .ndo_start_xmit = ace_start_xmit, + .ndo_set_multicast_list = ace_set_multicast_list, + .ndo_set_mac_address = ace_set_mac_addr, + .ndo_change_mtu = ace_change_mtu, +#if ACENIC_DO_VLAN + .ndo_vlan_rx_register = ace_vlan_rx_register, +#endif +}; + static int __devinit acenic_probe_one(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -466,27 +480,19 @@ static int __devinit acenic_probe_one(struct pci_dev *pdev, SET_NETDEV_DEV(dev, &pdev->dev); - ap = dev->priv; + ap = netdev_priv(dev); ap->pdev = pdev; ap->name = pci_name(pdev); dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; #if ACENIC_DO_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = ace_vlan_rx_register; #endif - dev->tx_timeout = &ace_watchdog; dev->watchdog_timeo = 5*HZ; - dev->open = &ace_open; - dev->stop = &ace_close; - dev->hard_start_xmit = &ace_start_xmit; - dev->get_stats = &ace_get_stats; - dev->set_multicast_list = &ace_set_multicast_list; + dev->netdev_ops = &ace_netdev_ops; SET_ETHTOOL_OPS(dev, &ace_ethtool_ops); - dev->set_mac_address = &ace_set_mac_addr; - dev->change_mtu = &ace_change_mtu; /* we only display this string ONCE */ if (!boards_found) @@ -892,7 +898,6 @@ static int __devinit ace_init(struct net_device *dev) int board_idx, ecode = 0; short i; unsigned char cache_size; - DECLARE_MAC_BUF(mac); ap = netdev_priv(dev); regs = ap->regs; @@ -1019,7 +1024,7 @@ static int __devinit ace_init(struct net_device *dev) dev->dev_addr[4] = (mac2 >> 8) & 0xff; dev->dev_addr[5] = mac2 & 0xff; - printk("MAC: %s\n", print_mac(mac, dev->dev_addr)); + printk("MAC: %pM\n", dev->dev_addr); /* * Looks like this is necessary to deal with on all architectures, @@ -2034,7 +2039,6 @@ static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm) #endif netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += retdesc->size; @@ -3220,10 +3224,3 @@ static int __devinit read_eeprom_byte(struct net_device *dev, ap->name, offset); goto out; } - - -/* - * Local variables: - * compile-command: "gcc -D__SMP__ -D__KERNEL__ -DMODULE -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -DMODVERSIONS -include ../../include/linux/modversions.h -c -o acenic.o acenic.c" - * End: - */ diff --git a/drivers/net/amd8111e.c b/drivers/net/amd8111e.c index 07a6697e3635608466a00a41d5139281d8eef686..187ac6eb6e945e69f8fca9cd87e1161dd1ceb919 100644 --- a/drivers/net/amd8111e.c +++ b/drivers/net/amd8111e.c @@ -809,7 +809,6 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget) lp->coal_conf.rx_packets++; lp->coal_conf.rx_bytes += pkt_len; num_rx_pkt++; - dev->last_rx = jiffies; err_next_pkt: lp->rx_ring[rx_index].buff_phy_addr @@ -832,7 +831,7 @@ static int amd8111e_rx_poll(struct napi_struct *napi, int budget) if (rx_pkt_limit > 0) { /* Receive descriptor is empty now */ spin_lock_irqsave(&lp->lock, flags); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); writel(VAL0|RINTEN0, mmio + INTEN0); writel(VAL2 | RDMD0, mmio + CMD0); spin_unlock_irqrestore(&lp->lock, flags); @@ -1171,11 +1170,11 @@ static irqreturn_t amd8111e_interrupt(int irq, void *dev_id) /* Check if Receive Interrupt has occurred. */ if (intr0 & RINT0) { - if (netif_rx_schedule_prep(dev, &lp->napi)) { + if (netif_rx_schedule_prep(&lp->napi)) { /* Disable receive interupts */ writel(RINTEN0, mmio + INTEN0); /* Schedule a polling routine */ - __netif_rx_schedule(dev, &lp->napi); + __netif_rx_schedule(&lp->napi); } else if (intren0 & RINTEN0) { printk("************Driver bug! \ interrupt while in poll\n"); @@ -1821,7 +1820,6 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, unsigned long reg_addr,reg_len; struct amd8111e_priv* lp; struct net_device* dev; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if(err){ @@ -1963,8 +1961,8 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev, chip_version = (readl(lp->mmio + CHIPID) & 0xf0000000)>>28; printk(KERN_INFO "%s: AMD-8111e Driver Version: %s\n", dev->name,MODULE_VERS); - printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %s\n", - dev->name, chip_version, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: [ Rev %x ] PCI 10/100BaseT Ethernet %pM\n", + dev->name, chip_version, dev->dev_addr); if (lp->ext_phy_id) printk(KERN_INFO "%s: Found MII PHY ID 0x%08x at address 0x%02x\n", dev->name, lp->ext_phy_id, lp->ext_phy_addr); diff --git a/drivers/net/apne.c b/drivers/net/apne.c index 867f6fff543c848bfd95a741173c746005344017..1437f5d121214b18f6dcffe5e3a5937d17c03e95 100644 --- a/drivers/net/apne.c +++ b/drivers/net/apne.c @@ -78,9 +78,6 @@ struct net_device * __init apne_probe(int unit); static int apne_probe1(struct net_device *dev, int ioaddr); -static int apne_open(struct net_device *dev); -static int apne_close(struct net_device *dev); - static void apne_reset_8390(struct net_device *dev); static void apne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -207,7 +204,6 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) int neX000, ctron; #endif static unsigned version_printed; - DECLARE_MAC_BUF(mac); if (ei_debug && version_printed++ == 0) printk(version); @@ -315,6 +311,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) dev->base_addr = ioaddr; dev->irq = IRQ_AMIGA_PORTS; + dev->netdev_ops = &ei_netdev_ops; /* Install the Interrupt handler */ i = request_irq(dev->irq, apne_interrupt, IRQF_SHARED, DRV_NAME, dev); @@ -323,7 +320,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - printk(" %s\n", print_mac(mac, dev->dev_addr)); + printk(" %pM\n", dev->dev_addr); printk("%s: %s found.\n", dev->name, name); @@ -338,11 +335,7 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) ei_status.block_input = &apne_block_input; ei_status.block_output = &apne_block_output; ei_status.get_8390_hdr = &apne_get_8390_hdr; - dev->open = &apne_open; - dev->stop = &apne_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + NS8390_init(dev, 0); pcmcia_ack_int(pcmcia_get_intreq()); /* ack PCMCIA int req */ @@ -353,22 +346,6 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr) return 0; } -static int -apne_open(struct net_device *dev) -{ - ei_open(dev); - return 0; -} - -static int -apne_close(struct net_device *dev) -{ - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - ei_close(dev); - return 0; -} - /* Hard reset the card. This used to pause for the same period that a 8390 reset command required, but that shouldn't be necessary. */ static void diff --git a/drivers/net/appletalk/cops.c b/drivers/net/appletalk/cops.c index 735fc9476403c4df27229298af32021ddd9f1762..54819a34ba0a28a454c3e9684e8162f10ff4b977 100644 --- a/drivers/net/appletalk/cops.c +++ b/drivers/net/appletalk/cops.c @@ -851,7 +851,6 @@ static void cops_rx(struct net_device *dev) /* Send packet to a higher place. */ netif_rx(skb); - dev->last_rx = jiffies; } static void cops_timeout(struct net_device *dev) @@ -1025,11 +1024,3 @@ static void __exit cops_module_exit(void) module_init(cops_module_init); module_exit(cops_module_exit); #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -c cops.c" - * c-basic-offset: 4 - * c-file-offsets: ((substatement-open . 0)) - * End: - */ diff --git a/drivers/net/appletalk/ipddp.c b/drivers/net/appletalk/ipddp.c index 1071144edd66fbdf0f594ec0104c065fdee06e82..9a0be9b2eaad66d5bec2776c54871d29b08e5e6f 100644 --- a/drivers/net/appletalk/ipddp.c +++ b/drivers/net/appletalk/ipddp.c @@ -108,7 +108,7 @@ static struct net_device * __init ipddp_init(void) */ static struct net_device_stats *ipddp_get_stats(struct net_device *dev) { - return dev->priv; + return netdev_priv(dev); } /* @@ -170,8 +170,8 @@ static int ipddp_xmit(struct sk_buff *skb, struct net_device *dev) skb->protocol = htons(ETH_P_ATALK); /* Protocol has changed */ - ((struct net_device_stats *) dev->priv)->tx_packets++; - ((struct net_device_stats *) dev->priv)->tx_bytes+=skb->len; + ((struct net_device_stats *) netdev_priv(dev))->tx_packets++; + ((struct net_device_stats *) netdev_priv(dev))->tx_bytes += skb->len; if(aarp_send_ddp(rt->dev, skb, &rt->at, NULL) < 0) dev_kfree_skb(skb); diff --git a/drivers/net/appletalk/ltpc.c b/drivers/net/appletalk/ltpc.c index fef5560bc7a2ee2d8c6aee66f6e413022fdfdca1..dc4d49605603147acc93acb476ec9aa94cc714cb 100644 --- a/drivers/net/appletalk/ltpc.c +++ b/drivers/net/appletalk/ltpc.c @@ -726,7 +726,8 @@ static int sendup_buffer (struct net_device *dev) int dnode, snode, llaptype, len; int sklen; struct sk_buff *skb; - struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats; + struct ltpc_private *ltpc_priv = netdev_priv(dev); + struct net_device_stats *stats = <pc_priv->stats; struct lt_rcvlap *ltc = (struct lt_rcvlap *) ltdmacbuf; if (ltc->command != LT_RCVLAP) { @@ -783,7 +784,6 @@ static int sendup_buffer (struct net_device *dev) /* toss it onwards */ netif_rx(skb); - dev->last_rx = jiffies; return 0; } @@ -823,7 +823,8 @@ static int ltpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct sockaddr_at *sa = (struct sockaddr_at *) &ifr->ifr_addr; /* we'll keep the localtalk node address in dev->pa_addr */ - struct atalk_addr *aa = &((struct ltpc_private *)dev->priv)->my_addr; + struct ltpc_private *ltpc_priv = netdev_priv(dev); + struct atalk_addr *aa = <pc_priv->my_addr; struct lt_init c; int ltflags; @@ -904,7 +905,8 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) * and skb->len is the length of the ddp data + ddp header */ - struct net_device_stats *stats = &((struct ltpc_private *)dev->priv)->stats; + struct ltpc_private *ltpc_priv = netdev_priv(dev); + struct net_device_stats *stats = <pc_priv->stats; int i; struct lt_sendlap cbuf; @@ -943,7 +945,8 @@ static int ltpc_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *ltpc_get_stats(struct net_device *dev) { - struct net_device_stats *stats = &((struct ltpc_private *) dev->priv)->stats; + struct ltpc_private *ltpc_priv = netdev_priv(dev); + struct net_device_stats *stats = <pc_priv->stats; return stats; } diff --git a/drivers/net/arcnet/arc-rawmode.c b/drivers/net/arcnet/arc-rawmode.c index e0a18e7c73cb59d36150bc9007fb82d39819bb21..3ff9affb1a914e212de008728985598e8e724bf8 100644 --- a/drivers/net/arcnet/arc-rawmode.c +++ b/drivers/net/arcnet/arc-rawmode.c @@ -87,7 +87,7 @@ MODULE_LICENSE("GPL"); static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct sk_buff *skb; struct archdr *pkt = pkthdr; int ofs; @@ -125,7 +125,6 @@ static void rx(struct net_device *dev, int bufnum, skb->protocol = __constant_htons(ETH_P_ARCNET); ; netif_rx(skb); - dev->last_rx = jiffies; } @@ -168,7 +167,7 @@ static int build_header(struct sk_buff *skb, struct net_device *dev, static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct arc_hardware *hard = &pkt->hard; int ofs; diff --git a/drivers/net/arcnet/arc-rimi.c b/drivers/net/arcnet/arc-rimi.c index 8c8d6c453c457e3b5f236d15f812dc66ede25d49..e3082a9350fcafcd2b1a90ae21cdc08a284f15b4 100644 --- a/drivers/net/arcnet/arc-rimi.c +++ b/drivers/net/arcnet/arc-rimi.c @@ -194,7 +194,7 @@ static int __init arcrimi_found(struct net_device *dev) /* initialize the rest of the device structure. */ - lp = dev->priv; + lp = netdev_priv(dev); lp->card_name = "RIM I"; lp->hw.command = arcrimi_command; lp->hw.status = arcrimi_status; @@ -260,7 +260,7 @@ err_free_irq: */ static int arcrimi_reset(struct net_device *dev, int really_reset) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->mem_start + 0x800; BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); @@ -281,7 +281,7 @@ static int arcrimi_reset(struct net_device *dev, int really_reset) static void arcrimi_setmask(struct net_device *dev, int mask) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->mem_start + 0x800; AINTMASK(mask); @@ -289,7 +289,7 @@ static void arcrimi_setmask(struct net_device *dev, int mask) static int arcrimi_status(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->mem_start + 0x800; return ASTATUS(); @@ -297,7 +297,7 @@ static int arcrimi_status(struct net_device *dev) static void arcrimi_command(struct net_device *dev, int cmd) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *ioaddr = lp->mem_start + 0x800; ACOMMAND(cmd); @@ -306,7 +306,7 @@ static void arcrimi_command(struct net_device *dev, int cmd) static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); } @@ -315,7 +315,7 @@ static void arcrimi_copy_to_card(struct net_device *dev, int bufnum, int offset, static void arcrimi_copy_from_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *memaddr = lp->mem_start + 0x800 + bufnum * 512 + offset; TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } @@ -361,7 +361,7 @@ static int __init arc_rimi_init(void) static void __exit arc_rimi_exit(void) { struct net_device *dev = my_dev; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); unregister_netdev(dev); iounmap(lp->mem_start); diff --git a/drivers/net/arcnet/arcnet.c b/drivers/net/arcnet/arcnet.c index a5b07691e466d6cc43b210796144eece8947d15c..6b53e5ed125cfbb10c2be5f34edca1a04fe36097 100644 --- a/drivers/net/arcnet/arcnet.c +++ b/drivers/net/arcnet/arcnet.c @@ -181,7 +181,7 @@ EXPORT_SYMBOL(arcnet_dump_skb); static void arcnet_dump_packet(struct net_device *dev, int bufnum, char *desc, int take_arcnet_lock) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int i, length; unsigned long flags = 0; static uint8_t buf[512]; @@ -247,7 +247,7 @@ void arcnet_unregister_proto(struct ArcProto *proto) */ static void release_arcbuf(struct net_device *dev, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int i; lp->buf_queue[lp->first_free_buf++] = bufnum; @@ -269,7 +269,7 @@ static void release_arcbuf(struct net_device *dev, int bufnum) */ static int get_arcbuf(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int buf = -1, i; if (!atomic_dec_and_test(&lp->buf_lock)) { @@ -357,7 +357,7 @@ struct net_device *alloc_arcdev(char *name) dev = alloc_netdev(sizeof(struct arcnet_local), name && *name ? name : "arc%d", arcdev_setup); if(dev) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = netdev_priv(dev); spin_lock_init(&lp->lock); } @@ -374,7 +374,7 @@ struct net_device *alloc_arcdev(char *name) */ static int arcnet_open(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int count, newmtu, error; BUGMSG(D_INIT,"opened."); @@ -474,7 +474,7 @@ static int arcnet_open(struct net_device *dev) /* The inverse routine to arcnet_open - shuts down the card. */ static int arcnet_close(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); netif_stop_queue(dev); @@ -556,7 +556,7 @@ static int arcnet_header(struct sk_buff *skb, struct net_device *dev, static int arcnet_rebuild_header(struct sk_buff *skb) { struct net_device *dev = skb->dev; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int status = 0; /* default is failure */ unsigned short type; uint8_t daddr=0; @@ -603,7 +603,7 @@ static int arcnet_rebuild_header(struct sk_buff *skb) /* Called by the kernel in order to transmit a packet. */ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct archdr *pkt; struct arc_rfc1201 *soft; struct ArcProto *proto; @@ -693,7 +693,7 @@ static int arcnet_send_packet(struct sk_buff *skb, struct net_device *dev) */ static int go_tx(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); BUGMSG(D_DURING, "go_tx: status=%Xh, intmask=%Xh, next_tx=%d, cur_tx=%d\n", ASTATUS(), lp->intmask, lp->next_tx, lp->cur_tx); @@ -723,7 +723,7 @@ static int go_tx(struct net_device *dev) static void arcnet_timeout(struct net_device *dev) { unsigned long flags; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int status = ASTATUS(); char *msg; @@ -771,8 +771,8 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) BUGMSG(D_DURING, "\n"); BUGMSG(D_DURING, "in arcnet_interrupt\n"); - - lp = dev->priv; + + lp = netdev_priv(dev); BUG_ON(!lp); spin_lock(&lp->lock); @@ -1010,7 +1010,7 @@ irqreturn_t arcnet_interrupt(int irq, void *dev_id) */ static void arcnet_rx(struct net_device *dev, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct archdr pkt; struct arc_rfc1201 *soft; int length, ofs; @@ -1074,7 +1074,7 @@ static void arcnet_rx(struct net_device *dev, int bufnum) */ static struct net_device_stats *arcnet_get_stats(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); return &lp->stats; } @@ -1091,7 +1091,7 @@ static void null_rx(struct net_device *dev, int bufnum, static int null_build_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, uint8_t daddr) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); BUGMSG(D_PROTO, "tx: can't build header for encap %02Xh; load a protocol driver.\n", @@ -1106,7 +1106,7 @@ static int null_build_header(struct sk_buff *skb, struct net_device *dev, static int null_prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct arc_hardware newpkt; BUGMSG(D_PROTO, "tx: no encap for this host; load a protocol driver.\n"); diff --git a/drivers/net/arcnet/capmode.c b/drivers/net/arcnet/capmode.c index 02cb8f1c11484b23460100c85f60faec62bd3ea5..30580bbe252d4ff11a346d0d7bbc0db1a0a2bef5 100644 --- a/drivers/net/arcnet/capmode.c +++ b/drivers/net/arcnet/capmode.c @@ -61,7 +61,7 @@ static struct ArcProto capmode_proto = }; -void arcnet_cap_init(void) +static void arcnet_cap_init(void) { int count; @@ -103,7 +103,7 @@ MODULE_LICENSE("GPL"); static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct sk_buff *skb; struct archdr *pkt = pkthdr; char *pktbuf, *pkthdrbuf; @@ -151,7 +151,6 @@ static void rx(struct net_device *dev, int bufnum, skb->protocol = __constant_htons(ETH_P_ARCNET); ; netif_rx(skb); - dev->last_rx = jiffies; } @@ -198,7 +197,7 @@ static int build_header(struct sk_buff *skb, static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct arc_hardware *hard = &pkt->hard; int ofs; @@ -250,7 +249,7 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, static int ack_tx(struct net_device *dev, int acked) { - struct arcnet_local *lp = (struct arcnet_local *) dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct sk_buff *ackskb; struct archdr *ackpkt; int length=sizeof(struct arc_cap); diff --git a/drivers/net/arcnet/com20020-isa.c b/drivers/net/arcnet/com20020-isa.c index 9289e6103de5ac039dbde468fe7e282254739e57..ea53a940272f1172ec4b51070d608becbf71e134 100644 --- a/drivers/net/arcnet/com20020-isa.c +++ b/drivers/net/arcnet/com20020-isa.c @@ -52,7 +52,7 @@ static int __init com20020isa_probe(struct net_device *dev) { int ioaddr; unsigned long airqmask; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int err; BUGLVL(D_NORMAL) printk(VERSION); @@ -151,7 +151,7 @@ static int __init com20020_init(void) if (node && node != 0xff) dev->dev_addr[0] = node; - lp = dev->priv; + lp = netdev_priv(dev); lp->backplane = backplane; lp->clockp = clockp & 7; lp->clockm = clockm & 3; diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c index b8c0fa6d401db146998c21c29b7928806a5fe9f3..8b51f632581d1810f2f712e2b3b63ae942b33ed3 100644 --- a/drivers/net/arcnet/com20020-pci.c +++ b/drivers/net/arcnet/com20020-pci.c @@ -72,7 +72,7 @@ static int __devinit com20020pci_probe(struct pci_dev *pdev, const struct pci_de dev = alloc_arcdev(device); if (!dev) return -ENOMEM; - lp = dev->priv; + lp = netdev_priv(dev); pci_set_drvdata(pdev, dev); diff --git a/drivers/net/arcnet/com20020.c b/drivers/net/arcnet/com20020.c index 70124a944e7d61f59b89fdb7544339278d7d3f40..103688358fb84721af7568c9a4f14a90ba81659c 100644 --- a/drivers/net/arcnet/com20020.c +++ b/drivers/net/arcnet/com20020.c @@ -89,7 +89,7 @@ static void com20020_copy_to_card(struct net_device *dev, int bufnum, int com20020_check(struct net_device *dev) { int ioaddr = dev->base_addr, status; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); ARCRESET0; mdelay(RESETtime); @@ -159,7 +159,7 @@ int com20020_found(struct net_device *dev, int shared) /* Initialize the rest of the device structure. */ - lp = dev->priv; + lp = netdev_priv(dev); lp->hw.owner = THIS_MODULE; lp->hw.command = com20020_command; @@ -233,7 +233,7 @@ int com20020_found(struct net_device *dev, int shared) */ static int com20020_reset(struct net_device *dev, int really_reset) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); u_int ioaddr = dev->base_addr; u_char inbyte; @@ -300,7 +300,7 @@ static int com20020_status(struct net_device *dev) static void com20020_close(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* disable transmitter */ @@ -317,7 +317,7 @@ static void com20020_close(struct net_device *dev) */ static void com20020_set_mc_list(struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; if ((dev->flags & IFF_PROMISC) && (dev->flags & IFF_UP)) { /* Enable promiscuous mode */ diff --git a/drivers/net/arcnet/com90io.c b/drivers/net/arcnet/com90io.c index 6599f1046c7b844aec858e5456196122e67ced64..89de29b3b1dc0d09628b093fb6ac34483984716e 100644 --- a/drivers/net/arcnet/com90io.c +++ b/drivers/net/arcnet/com90io.c @@ -248,7 +248,7 @@ static int __init com90io_found(struct net_device *dev) return -EBUSY; } - lp = dev->priv; + lp = netdev_priv(dev); lp->card_name = "COM90xx I/O"; lp->hw.command = com90io_command; lp->hw.status = com90io_status; @@ -290,7 +290,7 @@ static int __init com90io_found(struct net_device *dev) */ static int com90io_reset(struct net_device *dev, int really_reset) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; BUGMSG(D_INIT, "Resetting %s (status=%02Xh)\n", dev->name, ASTATUS()); diff --git a/drivers/net/arcnet/com90xx.c b/drivers/net/arcnet/com90xx.c index 0d45553ff75c8c08032c57cfa041f28d617d64be..d762fe46251eb0fc62bdbacda2990cf3f89ff066 100644 --- a/drivers/net/arcnet/com90xx.c +++ b/drivers/net/arcnet/com90xx.c @@ -468,7 +468,7 @@ static int __init com90xx_found(int ioaddr, int airq, u_long shmem, void __iomem release_mem_region(shmem, MIRROR_SIZE); return -ENOMEM; } - lp = dev->priv; + lp = netdev_priv(dev); /* find the real shared memory start/end points, including mirrors */ /* guess the actual size of one "memory mirror" - the number of @@ -583,9 +583,9 @@ static void com90xx_setmask(struct net_device *dev, int mask) * * However, it does make sure the card is in a defined state. */ -int com90xx_reset(struct net_device *dev, int really_reset) +static int com90xx_reset(struct net_device *dev, int really_reset) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); short ioaddr = dev->base_addr; BUGMSG(D_INIT, "Resetting (status=%02Xh)\n", ASTATUS()); @@ -621,7 +621,7 @@ int com90xx_reset(struct net_device *dev, int really_reset) static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; TIME("memcpy_toio", count, memcpy_toio(memaddr, buf, count)); } @@ -630,7 +630,7 @@ static void com90xx_copy_to_card(struct net_device *dev, int bufnum, int offset, static void com90xx_copy_from_card(struct net_device *dev, int bufnum, int offset, void *buf, int count) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); void __iomem *memaddr = lp->mem_start + bufnum * 512 + offset; TIME("memcpy_fromio", count, memcpy_fromio(buf, memaddr, count)); } @@ -656,7 +656,7 @@ static void __exit com90xx_exit(void) for (count = 0; count < numcards; count++) { dev = cards[count]; - lp = dev->priv; + lp = netdev_priv(dev); unregister_netdev(dev); free_irq(dev->irq, dev); diff --git a/drivers/net/arcnet/rfc1051.c b/drivers/net/arcnet/rfc1051.c index dab185bc51f1a1bc05b3c689ed7fac5834b06c96..49d39a9cb696331052f7a590cb72b71e4dab2452 100644 --- a/drivers/net/arcnet/rfc1051.c +++ b/drivers/net/arcnet/rfc1051.c @@ -88,7 +88,7 @@ MODULE_LICENSE("GPL"); */ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct archdr *pkt = (struct archdr *) skb->data; struct arc_rfc1051 *soft = &pkt->soft.rfc1051; int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; @@ -125,7 +125,7 @@ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct sk_buff *skb; struct archdr *pkt = pkthdr; int ofs; @@ -159,7 +159,6 @@ static void rx(struct net_device *dev, int bufnum, skb->protocol = type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; } @@ -169,7 +168,7 @@ static void rx(struct net_device *dev, int bufnum, static int build_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, uint8_t daddr) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int hdr_size = ARC_HDR_SIZE + RFC1051_HDR_SIZE; struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); struct arc_rfc1051 *soft = &pkt->soft.rfc1051; @@ -220,7 +219,7 @@ static int build_header(struct sk_buff *skb, struct net_device *dev, static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct arc_hardware *hard = &pkt->hard; int ofs; diff --git a/drivers/net/arcnet/rfc1201.c b/drivers/net/arcnet/rfc1201.c index 6d6d95cc4404b7a727a20f049dc8240db595351d..2303d3a1f4b63d512aea87ef1287fb39e54b10d9 100644 --- a/drivers/net/arcnet/rfc1201.c +++ b/drivers/net/arcnet/rfc1201.c @@ -92,7 +92,7 @@ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) { struct archdr *pkt = (struct archdr *) skb->data; struct arc_rfc1201 *soft = &pkt->soft.rfc1201; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; /* Pull off the arcnet header. */ @@ -134,7 +134,7 @@ static __be16 type_trans(struct sk_buff *skb, struct net_device *dev) static void rx(struct net_device *dev, int bufnum, struct archdr *pkthdr, int length) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct sk_buff *skb; struct archdr *pkt = pkthdr; struct arc_rfc1201 *soft = &pkthdr->soft.rfc1201; @@ -230,7 +230,6 @@ static void rx(struct net_device *dev, int bufnum, skb->protocol = type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; } else { /* split packet */ /* * NOTE: MSDOS ARP packet correction should only need to apply to @@ -366,7 +365,6 @@ static void rx(struct net_device *dev, int bufnum, skb->protocol = type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; } } } @@ -376,7 +374,7 @@ static void rx(struct net_device *dev, int bufnum, static int build_header(struct sk_buff *skb, struct net_device *dev, unsigned short type, uint8_t daddr) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int hdr_size = ARC_HDR_SIZE + RFC1201_HDR_SIZE; struct archdr *pkt = (struct archdr *) skb_push(skb, hdr_size); struct arc_rfc1201 *soft = &pkt->soft.rfc1201; @@ -443,7 +441,7 @@ static int build_header(struct sk_buff *skb, struct net_device *dev, static void load_pkt(struct net_device *dev, struct arc_hardware *hard, struct arc_rfc1201 *soft, int softlen, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); int ofs; /* assume length <= XMTU: someone should have handled that by now. */ @@ -476,7 +474,7 @@ static void load_pkt(struct net_device *dev, struct arc_hardware *hard, static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); const int maxsegsize = XMTU - RFC1201_HDR_SIZE; struct Outgoing *out; @@ -511,7 +509,7 @@ static int prepare_tx(struct net_device *dev, struct archdr *pkt, int length, static int continue_tx(struct net_device *dev, int bufnum) { - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); struct Outgoing *out = &lp->outgoing; struct arc_hardware *hard = &out->pkt->hard; struct arc_rfc1201 *soft = &out->pkt->soft.rfc1201, *newsoft; diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 29e53eb71c7484c2c8f2e4c0ecef185786bbb00c..e1d72e06f3e1b07849997566dd3b3502251ba347 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -165,7 +165,6 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, struct net_device *dev; struct ariadne_private *priv; int err; - DECLARE_MAC_BUF(mac); r1 = request_mem_region(base_addr, sizeof(struct Am79C960), "Am79C960"); if (!r1) @@ -215,9 +214,8 @@ static int __devinit ariadne_init_one(struct zorro_dev *z, } zorro_set_drvdata(z, dev); - printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address " - "%s\n", dev->name, board, - print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Ariadne at 0x%08lx, Ethernet Address %pM\n", + dev->name, board, dev->dev_addr); return 0; } @@ -613,14 +611,10 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct net_device *dev) #if 0 { - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - - printk(KERN_DEBUG "TX pkt type 0x%04x from %s to %s " + printk(KERN_DEBUG "TX pkt type 0x%04x from %pM to %pM " " data 0x%08x len %d\n", ((u_short *)skb->data)[6], - print_mac(mac, ((const u8 *)skb->data)+6), - print_mac(mac, (const u8 *)skb->data), + skb->data + 6, skb->data, (int)skb->data, (int)skb->len); } #endif @@ -743,25 +737,22 @@ static int ariadne_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); #if 0 { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "RX pkt type 0x%04x from ", ((u_short *)skb->data)[6]); { u_char *ptr = &((u_char *)skb->data)[6]; - printk("%s", print_mac(mac, ptr)); + printk("%pM", ptr); } printk(" to "); { u_char *ptr = (u_char *)skb->data; - printk("%s", print_mac(mac, ptr)); + printk("%pM", ptr); } printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len); } #endif netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/arm/Kconfig b/drivers/net/arm/Kconfig index 8eda6eeb43b70ffbbc39463d0c9161cb89585fd1..2895db13bfa4459cebc86b89c2e7dc1fc5971495 100644 --- a/drivers/net/arm/Kconfig +++ b/drivers/net/arm/Kconfig @@ -40,6 +40,14 @@ config ARM_AT91_ETHER If you wish to compile a kernel for the AT91RM9200 and enable ethernet support, then you should always answer Y to this. +config ARM_KS8695_ETHER + tristate "KS8695 Ethernet support" + depends on ARM && ARCH_KS8695 + select MII + help + If you wish to compile a kernel for the KS8695 and want to + use the internal ethernet then you should answer Y to this. + config EP93XX_ETH tristate "EP93xx Ethernet support" depends on ARM && ARCH_EP93XX @@ -51,7 +59,7 @@ config EP93XX_ETH config IXP4XX_ETH tristate "Intel IXP4xx Ethernet support" depends on ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR - select MII + select PHYLIB help Say Y here if you want to use built-in Ethernet ports on IXP4xx processor. diff --git a/drivers/net/arm/Makefile b/drivers/net/arm/Makefile index 7c812ac2b6a51c7305f8b5e69b51b219959f20df..c69c0cdba4a26b1cc254f1ac112cce46171c5f04 100644 --- a/drivers/net/arm/Makefile +++ b/drivers/net/arm/Makefile @@ -4,9 +4,10 @@ # obj-$(CONFIG_ARM_AM79C961A) += am79c961a.o -obj-$(CONFIG_ARM_ETHERH) += etherh.o +obj-$(CONFIG_ARM_ETHERH) += etherh.o ../8390.o obj-$(CONFIG_ARM_ETHER3) += ether3.o obj-$(CONFIG_ARM_ETHER1) += ether1.o obj-$(CONFIG_ARM_AT91_ETHER) += at91_ether.o +obj-$(CONFIG_ARM_KS8695_ETHER) += ks8695net.o obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o obj-$(CONFIG_IXP4XX_ETH) += ixp4xx_eth.o diff --git a/drivers/net/arm/am79c961a.c b/drivers/net/arm/am79c961a.c index aa4a5246be534a483e6ec42a6b67ba8986e371cd..0c628a9e5339af44f5c4cee91c39a279402d3f38 100644 --- a/drivers/net/arm/am79c961a.c +++ b/drivers/net/arm/am79c961a.c @@ -532,7 +532,6 @@ am79c961_rx(struct net_device *dev, struct dev_priv *priv) am_writeword(dev, hdraddr + 2, RMD_OWN); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; priv->stats.rx_bytes += len; priv->stats.rx_packets ++; } else { @@ -745,10 +744,8 @@ static int __init am79c961_probe(struct platform_device *pdev) ret = register_netdev(dev); if (ret == 0) { - DECLARE_MAC_BUF(mac); - - printk(KERN_INFO "%s: ether address %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: ether address %pM\n", + dev->name, dev->dev_addr); return 0; } diff --git a/drivers/net/arm/at91_ether.c b/drivers/net/arm/at91_ether.c index 6f431a887e7e5fb4f2b6ca27217f204a3d063291..442938d5038020dfd334100b7c3faf73e1f72c02 100644 --- a/drivers/net/arm/at91_ether.c +++ b/drivers/net/arm/at91_ether.c @@ -485,7 +485,6 @@ static void update_mac_address(struct net_device *dev) static int set_mac_address(struct net_device *dev, void* addr) { struct sockaddr *address = addr; - DECLARE_MAC_BUF(mac); if (!is_valid_ether_addr(address->sa_data)) return -EADDRNOTAVAIL; @@ -493,8 +492,8 @@ static int set_mac_address(struct net_device *dev, void* addr) memcpy(dev->dev_addr, address->sa_data, dev->addr_len); update_mac_address(dev); - printk("%s: Setting MAC address to %s\n", dev->name, - print_mac(mac, dev->dev_addr)); + printk("%s: Setting MAC address to %pM\n", dev->name, + dev->dev_addr); return 0; } @@ -894,7 +893,6 @@ static void at91ether_rx(struct net_device *dev) memcpy(skb_put(skb, pktlen), p_recv, pktlen); skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; dev->stats.rx_bytes += pktlen; netif_rx(skb); } @@ -978,7 +976,6 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add struct at91_private *lp; unsigned int val; int res; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct at91_private)); if (!dev) @@ -1084,11 +1081,11 @@ static int __init at91ether_setup(unsigned long phy_type, unsigned short phy_add gpio_request(lp->board_data.phy_irq_pin, "ethernet_phy"); /* Display ethernet banner */ - printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%s)\n", + printk(KERN_INFO "%s: AT91 ethernet at 0x%08x int=%d %s%s (%pM)\n", dev->name, (uint) dev->base_addr, dev->irq, at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_SPD ? "100-" : "10-", at91_emac_read(AT91_EMAC_CFG) & AT91_EMAC_FD ? "FullDuplex" : "HalfDuplex", - print_mac(mac, dev->dev_addr)); + dev->dev_addr); if ((phy_type == MII_DM9161_ID) || (lp->phy_type == MII_DM9161A_ID)) printk(KERN_INFO "%s: Davicom 9161 PHY %s\n", dev->name, (lp->phy_media == PORT_FIBRE) ? "(Fiber)" : "(Copper)"); else if (phy_type == MII_LXT971A_ID) diff --git a/drivers/net/arm/ep93xx_eth.c b/drivers/net/arm/ep93xx_eth.c index 1267444d79da80d0e1fb18e12d204db06bae6efc..6ecc600c1bccd05c5e22e17af5248fe998e9ecb0 100644 --- a/drivers/net/arm/ep93xx_eth.c +++ b/drivers/net/arm/ep93xx_eth.c @@ -259,8 +259,6 @@ static int ep93xx_rx(struct net_device *dev, int processed, int budget) skb_put(skb, length); skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; - netif_receive_skb(skb); ep->stats.rx_packets++; @@ -300,7 +298,7 @@ poll_some_more: int more = 0; spin_lock_irq(&ep->rx_lock); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); wrl(ep, REG_INTEN, REG_INTEN_TX | REG_INTEN_RX); if (ep93xx_have_more_rx(ep)) { wrl(ep, REG_INTEN, REG_INTEN_TX); @@ -417,9 +415,9 @@ static irqreturn_t ep93xx_irq(int irq, void *dev_id) if (status & REG_INTSTS_RX) { spin_lock(&ep->rx_lock); - if (likely(netif_rx_schedule_prep(dev, &ep->napi))) { + if (likely(netif_rx_schedule_prep(&ep->napi))) { wrl(ep, REG_INTEN, REG_INTEN_TX); - __netif_rx_schedule(dev, &ep->napi); + __netif_rx_schedule(&ep->napi); } spin_unlock(&ep->rx_lock); } diff --git a/drivers/net/arm/ether1.c b/drivers/net/arm/ether1.c index 3bb9e293e2efea6ba066b6ad61960002f89d1675..e380de4544637629dcd3260e8b463d10af272200 100644 --- a/drivers/net/arm/ether1.c +++ b/drivers/net/arm/ether1.c @@ -996,7 +996,6 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id) { struct net_device *dev; int i, ret = 0; - DECLARE_MAC_BUF(mac); ether1_banner(); @@ -1044,8 +1043,8 @@ ether1_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk(KERN_INFO "%s: ether1 in slot %d, %s\n", - dev->name, ec->slot_no, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: ether1 in slot %d, %pM\n", + dev->name, ec->slot_no, dev->dev_addr); ecard_set_drvdata(ec, dev); return 0; diff --git a/drivers/net/arm/ether3.c b/drivers/net/arm/ether3.c index 67e96ae85035638ee009f2aadac0e5a7a538269b..21a7bef12d3b1c1965d166dad6db7ae9d5eecd6c 100644 --- a/drivers/net/arm/ether3.c +++ b/drivers/net/arm/ether3.c @@ -776,7 +776,6 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id) const struct ether3_data *data = id->data; struct net_device *dev; int bus_type, ret; - DECLARE_MAC_BUF(mac); ether3_banner(); @@ -859,8 +858,8 @@ ether3_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk("%s: %s in slot %d, %s\n", - dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr)); + printk("%s: %s in slot %d, %pM\n", + dev->name, data->name, ec->slot_no, dev->dev_addr); ecard_set_drvdata(ec, dev); return 0; diff --git a/drivers/net/arm/etherh.c b/drivers/net/arm/etherh.c index 5c5f1e470d3c2d05fcc910fb97917cb487bf7533..6278606d1049546966f0b51aaad941dfbded6973 100644 --- a/drivers/net/arm/etherh.c +++ b/drivers/net/arm/etherh.c @@ -637,6 +637,21 @@ static const struct ethtool_ops etherh_ethtool_ops = { .get_drvinfo = etherh_get_drvinfo, }; +static const struct net_device_ops etherh_netdev_ops = { + .ndo_open = etherh_open, + .ndo_stop = etherh_close, + .ndo_set_config = etherh_set_config, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static u32 etherh_regoffsets[16]; static u32 etherm_regoffsets[16]; @@ -648,7 +663,6 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) struct net_device *dev; struct etherh_priv *eh; int ret; - DECLARE_MAC_BUF(mac); etherh_banner(); @@ -664,9 +678,7 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) SET_NETDEV_DEV(dev, &ec->dev); - dev->open = etherh_open; - dev->stop = etherh_close; - dev->set_config = etherh_set_config; + dev->netdev_ops = ðerh_netdev_ops; dev->irq = ec->irq; dev->ethtool_ops = ðerh_ethtool_ops; @@ -746,8 +758,8 @@ etherh_probe(struct expansion_card *ec, const struct ecard_id *id) if (ret) goto free; - printk(KERN_INFO "%s: %s in slot %d, %s\n", - dev->name, data->name, ec->slot_no, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: %s in slot %d, %pM\n", + dev->name, data->name, ec->slot_no, dev->dev_addr); ecard_set_drvdata(ec, dev); diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c index e2d702b8b2e4766321824c26941074b40c950fa5..26af411fc42819f8b7190fc4b4ba263965f003d8 100644 --- a/drivers/net/arm/ixp4xx_eth.c +++ b/drivers/net/arm/ixp4xx_eth.c @@ -30,12 +30,11 @@ #include #include #include -#include +#include #include #include #include -#define DEBUG_QUEUES 0 #define DEBUG_DESC 0 #define DEBUG_RX 0 #define DEBUG_TX 0 @@ -59,7 +58,6 @@ #define NAPI_WEIGHT 16 #define MDIO_INTERVAL (3 * HZ) #define MAX_MDIO_RETRIES 100 /* microseconds, typically 30 cycles */ -#define MAX_MII_RESET_RETRIES 100 /* mdio_read() cycles, typically 4 */ #define MAX_CLOSE_WAIT 1000 /* microseconds, typically 2-3 cycles */ #define NPE_ID(port_id) ((port_id) >> 4) @@ -164,15 +162,14 @@ struct port { struct npe *npe; struct net_device *netdev; struct napi_struct napi; - struct net_device_stats stat; - struct mii_if_info mii; - struct delayed_work mdio_thread; + struct phy_device *phydev; struct eth_plat_info *plat; buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS]; struct desc *desc_tab; /* coherent */ u32 desc_tab_phys; int id; /* logical port ID */ - u16 mii_bmcr; + int speed, duplex; + u8 firmware[4]; }; /* NPE message structure */ @@ -243,19 +240,20 @@ static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt) static spinlock_t mdio_lock; static struct eth_regs __iomem *mdio_regs; /* mdio command and status only */ +struct mii_bus *mdio_bus; static int ports_open; static struct port *npe_port_tab[MAX_NPES]; static struct dma_pool *dma_pool; -static u16 mdio_cmd(struct net_device *dev, int phy_id, int location, - int write, u16 cmd) +static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location, + int write, u16 cmd) { int cycles = 0; if (__raw_readl(&mdio_regs->mdio_command[3]) & 0x80) { - printk(KERN_ERR "%s: MII not ready to transmit\n", dev->name); - return 0; + printk(KERN_ERR "%s: MII not ready to transmit\n", bus->name); + return -1; } if (write) { @@ -274,107 +272,119 @@ static u16 mdio_cmd(struct net_device *dev, int phy_id, int location, } if (cycles == MAX_MDIO_RETRIES) { - printk(KERN_ERR "%s: MII write failed\n", dev->name); - return 0; + printk(KERN_ERR "%s #%i: MII write failed\n", bus->name, + phy_id); + return -1; } #if DEBUG_MDIO - printk(KERN_DEBUG "%s: mdio_cmd() took %i cycles\n", dev->name, - cycles); + printk(KERN_DEBUG "%s #%i: mdio_%s() took %i cycles\n", bus->name, + phy_id, write ? "write" : "read", cycles); #endif if (write) return 0; if (__raw_readl(&mdio_regs->mdio_status[3]) & 0x80) { - printk(KERN_ERR "%s: MII read failed\n", dev->name); - return 0; +#if DEBUG_MDIO + printk(KERN_DEBUG "%s #%i: MII read failed\n", bus->name, + phy_id); +#endif + return 0xFFFF; /* don't return error */ } return (__raw_readl(&mdio_regs->mdio_status[0]) & 0xFF) | - (__raw_readl(&mdio_regs->mdio_status[1]) << 8); + ((__raw_readl(&mdio_regs->mdio_status[1]) & 0xFF) << 8); } -static int mdio_read(struct net_device *dev, int phy_id, int location) +static int ixp4xx_mdio_read(struct mii_bus *bus, int phy_id, int location) { unsigned long flags; - u16 val; + int ret; spin_lock_irqsave(&mdio_lock, flags); - val = mdio_cmd(dev, phy_id, location, 0, 0); + ret = ixp4xx_mdio_cmd(bus, phy_id, location, 0, 0); spin_unlock_irqrestore(&mdio_lock, flags); - return val; +#if DEBUG_MDIO + printk(KERN_DEBUG "%s #%i: MII read [%i] -> 0x%X\n", bus->name, + phy_id, location, ret); +#endif + return ret; } -static void mdio_write(struct net_device *dev, int phy_id, int location, - int val) +static int ixp4xx_mdio_write(struct mii_bus *bus, int phy_id, int location, + u16 val) { unsigned long flags; + int ret; spin_lock_irqsave(&mdio_lock, flags); - mdio_cmd(dev, phy_id, location, 1, val); + ret = ixp4xx_mdio_cmd(bus, phy_id, location, 1, val); spin_unlock_irqrestore(&mdio_lock, flags); +#if DEBUG_MDIO + printk(KERN_DEBUG "%s #%i: MII read [%i] <- 0x%X, err = %i\n", + bus->name, phy_id, location, val, ret); +#endif + return ret; } -static void phy_reset(struct net_device *dev, int phy_id) +static int ixp4xx_mdio_register(void) { - struct port *port = netdev_priv(dev); - int cycles = 0; + int err; - mdio_write(dev, phy_id, MII_BMCR, port->mii_bmcr | BMCR_RESET); + if (!(mdio_bus = mdiobus_alloc())) + return -ENOMEM; - while (cycles < MAX_MII_RESET_RETRIES) { - if (!(mdio_read(dev, phy_id, MII_BMCR) & BMCR_RESET)) { -#if DEBUG_MDIO - printk(KERN_DEBUG "%s: phy_reset() took %i cycles\n", - dev->name, cycles); -#endif - return; - } - udelay(1); - cycles++; - } + /* All MII PHY accesses use NPE-B Ethernet registers */ + spin_lock_init(&mdio_lock); + mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; + __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control); + + mdio_bus->name = "IXP4xx MII Bus"; + mdio_bus->read = &ixp4xx_mdio_read; + mdio_bus->write = &ixp4xx_mdio_write; + strcpy(mdio_bus->id, "0"); - printk(KERN_ERR "%s: MII reset failed\n", dev->name); + if ((err = mdiobus_register(mdio_bus))) + mdiobus_free(mdio_bus); + return err; } -static void eth_set_duplex(struct port *port) +static void ixp4xx_mdio_remove(void) { - if (port->mii.full_duplex) - __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX, - &port->regs->tx_control[0]); - else - __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX, - &port->regs->tx_control[0]); + mdiobus_unregister(mdio_bus); + mdiobus_free(mdio_bus); } -static void phy_check_media(struct port *port, int init) +static void ixp4xx_adjust_link(struct net_device *dev) { - if (mii_check_media(&port->mii, 1, init)) - eth_set_duplex(port); - if (port->mii.force_media) { /* mii_check_media() doesn't work */ - struct net_device *dev = port->netdev; - int cur_link = mii_link_ok(&port->mii); - int prev_link = netif_carrier_ok(dev); - - if (!prev_link && cur_link) { - printk(KERN_INFO "%s: link up\n", dev->name); - netif_carrier_on(dev); - } else if (prev_link && !cur_link) { + struct port *port = netdev_priv(dev); + struct phy_device *phydev = port->phydev; + + if (!phydev->link) { + if (port->speed) { + port->speed = 0; printk(KERN_INFO "%s: link down\n", dev->name); - netif_carrier_off(dev); } + return; } -} + if (port->speed == phydev->speed && port->duplex == phydev->duplex) + return; -static void mdio_thread(struct work_struct *work) -{ - struct port *port = container_of(work, struct port, mdio_thread.work); + port->speed = phydev->speed; + port->duplex = phydev->duplex; + + if (port->duplex) + __raw_writel(DEFAULT_TX_CNTRL0 & ~TX_CNTRL0_HALFDUPLEX, + &port->regs->tx_control[0]); + else + __raw_writel(DEFAULT_TX_CNTRL0 | TX_CNTRL0_HALFDUPLEX, + &port->regs->tx_control[0]); - phy_check_media(port, 0); - schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL); + printk(KERN_INFO "%s: link up, speed %u Mb/s, %s duplex\n", + dev->name, port->speed, port->duplex ? "full" : "half"); } @@ -412,47 +422,13 @@ static inline void debug_desc(u32 phys, struct desc *desc) #endif } -static inline void debug_queue(unsigned int queue, int is_get, u32 phys) -{ -#if DEBUG_QUEUES - static struct { - int queue; - char *name; - } names[] = { - { TX_QUEUE(0x10), "TX#0 " }, - { TX_QUEUE(0x20), "TX#1 " }, - { TX_QUEUE(0x00), "TX#2 " }, - { RXFREE_QUEUE(0x10), "RX-free#0 " }, - { RXFREE_QUEUE(0x20), "RX-free#1 " }, - { RXFREE_QUEUE(0x00), "RX-free#2 " }, - { TXDONE_QUEUE, "TX-done " }, - }; - int i; - - for (i = 0; i < ARRAY_SIZE(names); i++) - if (names[i].queue == queue) - break; - - printk(KERN_DEBUG "Queue %i %s%s %X\n", queue, - i < ARRAY_SIZE(names) ? names[i].name : "", - is_get ? "->" : "<-", phys); -#endif -} - -static inline u32 queue_get_entry(unsigned int queue) -{ - u32 phys = qmgr_get_entry(queue); - debug_queue(queue, 1, phys); - return phys; -} - static inline int queue_get_desc(unsigned int queue, struct port *port, int is_tx) { u32 phys, tab_phys, n_desc; struct desc *tab; - if (!(phys = queue_get_entry(queue))) + if (!(phys = qmgr_get_entry(queue))) return -1; phys &= ~0x1F; /* mask out non-address bits */ @@ -468,7 +444,6 @@ static inline int queue_get_desc(unsigned int queue, struct port *port, static inline void queue_put_desc(unsigned int queue, u32 phys, struct desc *desc) { - debug_queue(queue, 0, phys); debug_desc(phys, desc); BUG_ON(phys & 0x1F); qmgr_put_entry(queue, phys); @@ -498,7 +473,7 @@ static void eth_rx_irq(void *pdev) printk(KERN_DEBUG "%s: eth_rx_irq\n", dev->name); #endif qmgr_disable_irq(port->plat->rxq); - netif_rx_schedule(dev, &port->napi); + netif_rx_schedule(&port->napi); } static int eth_poll(struct napi_struct *napi, int budget) @@ -526,7 +501,7 @@ static int eth_poll(struct napi_struct *napi, int budget) printk(KERN_DEBUG "%s: eth_poll netif_rx_complete\n", dev->name); #endif - netif_rx_complete(dev, napi); + netif_rx_complete(napi); qmgr_enable_irq(rxq); if (!qmgr_stat_empty(rxq) && netif_rx_reschedule(dev, napi)) { @@ -562,7 +537,7 @@ static int eth_poll(struct napi_struct *napi, int budget) #endif if (!skb) { - port->stat.rx_dropped++; + dev->stats.rx_dropped++; /* put the desc back on RX-ready queue */ desc->buf_len = MAX_MRU; desc->pkt_len = 0; @@ -588,9 +563,8 @@ static int eth_poll(struct napi_struct *napi, int budget) debug_pkt(dev, "eth_poll", skb->data, skb->len); skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; - port->stat.rx_packets++; - port->stat.rx_bytes += skb->len; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; netif_receive_skb(skb); /* put the new buffer on RX-free queue */ @@ -618,7 +592,7 @@ static void eth_txdone_irq(void *unused) #if DEBUG_TX printk(KERN_DEBUG DRV_NAME ": eth_txdone_irq\n"); #endif - while ((phys = queue_get_entry(TXDONE_QUEUE)) != 0) { + while ((phys = qmgr_get_entry(TXDONE_QUEUE)) != 0) { u32 npe_id, n_desc; struct port *port; struct desc *desc; @@ -635,8 +609,8 @@ static void eth_txdone_irq(void *unused) debug_desc(phys, desc); if (port->tx_buff_tab[n_desc]) { /* not the draining packet */ - port->stat.tx_packets++; - port->stat.tx_bytes += desc->pkt_len; + port->netdev->stats.tx_packets++; + port->netdev->stats.tx_bytes += desc->pkt_len; dma_unmap_tx(port, desc); #if DEBUG_TX @@ -674,7 +648,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(skb->len > MAX_MRU)) { dev_kfree_skb(skb); - port->stat.tx_errors++; + dev->stats.tx_errors++; return NETDEV_TX_OK; } @@ -690,7 +664,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) bytes = ALIGN(offset + len, 4); if (!(mem = kmalloc(bytes, GFP_ATOMIC))) { dev_kfree_skb(skb); - port->stat.tx_dropped++; + dev->stats.tx_dropped++; return NETDEV_TX_OK; } memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4); @@ -704,7 +678,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) #else kfree(mem); #endif - port->stat.tx_dropped++; + dev->stats.tx_dropped++; return NETDEV_TX_OK; } @@ -747,12 +721,6 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev) } -static struct net_device_stats *eth_stats(struct net_device *dev) -{ - struct port *port = netdev_priv(dev); - return &port->stat; -} - static void eth_set_mcast_list(struct net_device *dev) { struct port *port = netdev_priv(dev); @@ -786,41 +754,80 @@ static void eth_set_mcast_list(struct net_device *dev) static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd) { struct port *port = netdev_priv(dev); - unsigned int duplex_chg; - int err; if (!netif_running(dev)) return -EINVAL; - err = generic_mii_ioctl(&port->mii, if_mii(req), cmd, &duplex_chg); - if (duplex_chg) - eth_set_duplex(port); - return err; + return phy_mii_ioctl(port->phydev, if_mii(req), cmd); +} + +/* ethtool support */ + +static void ixp4xx_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + struct port *port = netdev_priv(dev); + strcpy(info->driver, DRV_NAME); + snprintf(info->fw_version, sizeof(info->fw_version), "%u:%u:%u:%u", + port->firmware[0], port->firmware[1], + port->firmware[2], port->firmware[3]); + strcpy(info->bus_info, "internal"); } +static int ixp4xx_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct port *port = netdev_priv(dev); + return phy_ethtool_gset(port->phydev, cmd); +} + +static int ixp4xx_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct port *port = netdev_priv(dev); + return phy_ethtool_sset(port->phydev, cmd); +} + +static int ixp4xx_nway_reset(struct net_device *dev) +{ + struct port *port = netdev_priv(dev); + return phy_start_aneg(port->phydev); +} + +static struct ethtool_ops ixp4xx_ethtool_ops = { + .get_drvinfo = ixp4xx_get_drvinfo, + .get_settings = ixp4xx_get_settings, + .set_settings = ixp4xx_set_settings, + .nway_reset = ixp4xx_nway_reset, + .get_link = ethtool_op_get_link, +}; + static int request_queues(struct port *port) { int err; - err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0); + err = qmgr_request_queue(RXFREE_QUEUE(port->id), RX_DESCS, 0, 0, + "%s:RX-free", port->netdev->name); if (err) return err; - err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0); + err = qmgr_request_queue(port->plat->rxq, RX_DESCS, 0, 0, + "%s:RX", port->netdev->name); if (err) goto rel_rxfree; - err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0); + err = qmgr_request_queue(TX_QUEUE(port->id), TX_DESCS, 0, 0, + "%s:TX", port->netdev->name); if (err) goto rel_rx; - err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0); + err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0, + "%s:TX-ready", port->netdev->name); if (err) goto rel_tx; /* TX-done queue handles skbs sent out by the NPEs */ if (!ports_open) { - err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0); + err = qmgr_request_queue(TXDONE_QUEUE, TXDONE_QUEUE_LEN, 0, 0, + "%s:TX-done", DRV_NAME); if (err) goto rel_txready; } @@ -944,10 +951,12 @@ static int eth_open(struct net_device *dev) npe_name(npe)); return -EIO; } + port->firmware[0] = msg.byte4; + port->firmware[1] = msg.byte5; + port->firmware[2] = msg.byte6; + port->firmware[3] = msg.byte7; } - mdio_write(dev, port->plat->phy, MII_BMCR, port->mii_bmcr); - memset(&msg, 0, sizeof(msg)); msg.cmd = NPE_VLAN_SETRXQOSENTRY; msg.eth_id = port->id; @@ -985,6 +994,9 @@ static int eth_open(struct net_device *dev) return err; } + port->speed = 0; /* force "link up" message */ + phy_start(port->phydev); + for (i = 0; i < ETH_ALEN; i++) __raw_writel(dev->dev_addr[i], &port->regs->hw_addr[i]); __raw_writel(0x08, &port->regs->random_seed); @@ -1012,10 +1024,8 @@ static int eth_open(struct net_device *dev) __raw_writel(DEFAULT_RX_CNTRL0, &port->regs->rx_control[0]); napi_enable(&port->napi); - phy_check_media(port, 1); eth_set_mcast_list(dev); netif_start_queue(dev); - schedule_delayed_work(&port->mdio_thread, MDIO_INTERVAL); qmgr_set_irq(port->plat->rxq, QUEUE_IRQ_SRC_NOT_EMPTY, eth_rx_irq, dev); @@ -1026,7 +1036,7 @@ static int eth_open(struct net_device *dev) } ports_open++; /* we may already have RX data, enables IRQ */ - netif_rx_schedule(dev, &port->napi); + netif_rx_schedule(&port->napi); return 0; } @@ -1106,25 +1116,31 @@ static int eth_close(struct net_device *dev) printk(KERN_CRIT "%s: unable to disable loopback\n", dev->name); - port->mii_bmcr = mdio_read(dev, port->plat->phy, MII_BMCR) & - ~(BMCR_RESET | BMCR_PDOWN); /* may have been altered */ - mdio_write(dev, port->plat->phy, MII_BMCR, - port->mii_bmcr | BMCR_PDOWN); + phy_stop(port->phydev); if (!ports_open) qmgr_disable_irq(TXDONE_QUEUE); - cancel_rearming_delayed_work(&port->mdio_thread); destroy_queues(port); release_queues(port); return 0; } +static const struct net_device_ops ixp4xx_netdev_ops = { + .ndo_open = eth_open, + .ndo_stop = eth_close, + .ndo_start_xmit = eth_xmit, + .ndo_set_multicast_list = eth_set_mcast_list, + .ndo_do_ioctl = eth_ioctl, + +}; + static int __devinit eth_init_one(struct platform_device *pdev) { struct port *port; struct net_device *dev; struct eth_plat_info *plat = pdev->dev.platform_data; u32 regs_phys; + char phy_id[BUS_ID_SIZE]; int err; if (!(dev = alloc_etherdev(sizeof(struct port)))) @@ -1153,12 +1169,8 @@ static int __devinit eth_init_one(struct platform_device *pdev) goto err_free; } - dev->open = eth_open; - dev->hard_start_xmit = eth_xmit; - dev->stop = eth_close; - dev->get_stats = eth_stats; - dev->do_ioctl = eth_ioctl; - dev->set_multicast_list = eth_set_mcast_list; + dev->netdev_ops = &ixp4xx_netdev_ops; + dev->ethtool_ops = &ixp4xx_ethtool_ops; dev->tx_queue_len = 100; netif_napi_add(dev, &port->napi, eth_poll, NAPI_WEIGHT); @@ -1191,22 +1203,19 @@ static int __devinit eth_init_one(struct platform_device *pdev) __raw_writel(DEFAULT_CORE_CNTRL, &port->regs->core_control); udelay(50); - port->mii.dev = dev; - port->mii.mdio_read = mdio_read; - port->mii.mdio_write = mdio_write; - port->mii.phy_id = plat->phy; - port->mii.phy_id_mask = 0x1F; - port->mii.reg_num_mask = 0x1F; + snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, "0", plat->phy); + port->phydev = phy_connect(dev, phy_id, &ixp4xx_adjust_link, 0, + PHY_INTERFACE_MODE_MII); + if (IS_ERR(port->phydev)) { + printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(port->phydev); + } + + port->phydev->irq = PHY_POLL; printk(KERN_INFO "%s: MII PHY %i on %s\n", dev->name, plat->phy, npe_name(port->npe)); - phy_reset(dev, plat->phy); - port->mii_bmcr = mdio_read(dev, plat->phy, MII_BMCR) & - ~(BMCR_RESET | BMCR_PDOWN); - mdio_write(dev, plat->phy, MII_BMCR, port->mii_bmcr | BMCR_PDOWN); - - INIT_DELAYED_WORK(&port->mdio_thread, mdio_thread); return 0; err_unreg: @@ -1232,7 +1241,7 @@ static int __devexit eth_remove_one(struct platform_device *pdev) return 0; } -static struct platform_driver drv = { +static struct platform_driver ixp4xx_eth_driver = { .driver.name = DRV_NAME, .probe = eth_init_one, .remove = eth_remove_one, @@ -1240,20 +1249,19 @@ static struct platform_driver drv = { static int __init eth_init_module(void) { + int err; if (!(ixp4xx_read_feature_bits() & IXP4XX_FEATURE_NPEB_ETH0)) return -ENOSYS; - /* All MII PHY accesses use NPE-B Ethernet registers */ - spin_lock_init(&mdio_lock); - mdio_regs = (struct eth_regs __iomem *)IXP4XX_EthB_BASE_VIRT; - __raw_writel(DEFAULT_CORE_CNTRL, &mdio_regs->core_control); - - return platform_driver_register(&drv); + if ((err = ixp4xx_mdio_register())) + return err; + return platform_driver_register(&ixp4xx_eth_driver); } static void __exit eth_cleanup_module(void) { - platform_driver_unregister(&drv); + platform_driver_unregister(&ixp4xx_eth_driver); + ixp4xx_mdio_remove(); } MODULE_AUTHOR("Krzysztof Halasa"); diff --git a/drivers/net/arm/ks8695net.c b/drivers/net/arm/ks8695net.c new file mode 100644 index 0000000000000000000000000000000000000000..592daee9dc2815cb7e6f6977dfcdad8485204224 --- /dev/null +++ b/drivers/net/arm/ks8695net.c @@ -0,0 +1,1676 @@ +/* + * Micrel KS8695 (Centaur) Ethernet. + * + * 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. + * + * Copyright 2008 Simtec Electronics + * Daniel Silverstone + * Vincent Sanders + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "ks8695net.h" + +#define MODULENAME "ks8695_ether" +#define MODULEVERSION "1.01" + +/* + * Transmit and device reset timeout, default 5 seconds. + */ +static int watchdog = 5000; + +/* Hardware structures */ + +/** + * struct rx_ring_desc - Receive descriptor ring element + * @status: The status of the descriptor element (E.g. who owns it) + * @length: The number of bytes in the block pointed to by data_ptr + * @data_ptr: The physical address of the data block to receive into + * @next_desc: The physical address of the next descriptor element. + */ +struct rx_ring_desc { + __le32 status; + __le32 length; + __le32 data_ptr; + __le32 next_desc; +}; + +/** + * struct tx_ring_desc - Transmit descriptor ring element + * @owner: Who owns the descriptor + * @status: The number of bytes in the block pointed to by data_ptr + * @data_ptr: The physical address of the data block to receive into + * @next_desc: The physical address of the next descriptor element. + */ +struct tx_ring_desc { + __le32 owner; + __le32 status; + __le32 data_ptr; + __le32 next_desc; +}; + +/** + * struct ks8695_skbuff - sk_buff wrapper for rx/tx rings. + * @skb: The buffer in the ring + * @dma_ptr: The mapped DMA pointer of the buffer + * @length: The number of bytes mapped to dma_ptr + */ +struct ks8695_skbuff { + struct sk_buff *skb; + dma_addr_t dma_ptr; + u32 length; +}; + +/* Private device structure */ + +#define MAX_TX_DESC 8 +#define MAX_TX_DESC_MASK 0x7 +#define MAX_RX_DESC 16 +#define MAX_RX_DESC_MASK 0xf + +#define MAX_RXBUF_SIZE 0x700 + +#define TX_RING_DMA_SIZE (sizeof(struct tx_ring_desc) * MAX_TX_DESC) +#define RX_RING_DMA_SIZE (sizeof(struct rx_ring_desc) * MAX_RX_DESC) +#define RING_DMA_SIZE (TX_RING_DMA_SIZE + RX_RING_DMA_SIZE) + +/** + * enum ks8695_dtype - Device type + * @KS8695_DTYPE_WAN: This device is a WAN interface + * @KS8695_DTYPE_LAN: This device is a LAN interface + * @KS8695_DTYPE_HPNA: This device is an HPNA interface + */ +enum ks8695_dtype { + KS8695_DTYPE_WAN, + KS8695_DTYPE_LAN, + KS8695_DTYPE_HPNA, +}; + +/** + * struct ks8695_priv - Private data for the KS8695 Ethernet + * @in_suspend: Flag to indicate if we're suspending/resuming + * @ndev: The net_device for this interface + * @dev: The platform device object for this interface + * @dtype: The type of this device + * @io_regs: The ioremapped registers for this interface + * @rx_irq_name: The textual name of the RX IRQ from the platform data + * @tx_irq_name: The textual name of the TX IRQ from the platform data + * @link_irq_name: The textual name of the link IRQ from the + * platform data if available + * @rx_irq: The IRQ number for the RX IRQ + * @tx_irq: The IRQ number for the TX IRQ + * @link_irq: The IRQ number for the link IRQ if available + * @regs_req: The resource request for the registers region + * @phyiface_req: The resource request for the phy/switch region + * if available + * @phyiface_regs: The ioremapped registers for the phy/switch if available + * @ring_base: The base pointer of the dma coherent memory for the rings + * @ring_base_dma: The DMA mapped equivalent of ring_base + * @tx_ring: The pointer in ring_base of the TX ring + * @tx_ring_used: The number of slots in the TX ring which are occupied + * @tx_ring_next_slot: The next slot to fill in the TX ring + * @tx_ring_dma: The DMA mapped equivalent of tx_ring + * @tx_buffers: The sk_buff mappings for the TX ring + * @txq_lock: A lock to protect the tx_buffers tx_ring_used etc variables + * @rx_ring: The pointer in ring_base of the RX ring + * @rx_ring_dma: The DMA mapped equivalent of rx_ring + * @rx_buffers: The sk_buff mappings for the RX ring + * @next_rx_desc_read: The next RX descriptor to read from on IRQ + * @msg_enable: The flags for which messages to emit + */ +struct ks8695_priv { + int in_suspend; + struct net_device *ndev; + struct device *dev; + enum ks8695_dtype dtype; + void __iomem *io_regs; + + const char *rx_irq_name, *tx_irq_name, *link_irq_name; + int rx_irq, tx_irq, link_irq; + + struct resource *regs_req, *phyiface_req; + void __iomem *phyiface_regs; + + void *ring_base; + dma_addr_t ring_base_dma; + + struct tx_ring_desc *tx_ring; + int tx_ring_used; + int tx_ring_next_slot; + dma_addr_t tx_ring_dma; + struct ks8695_skbuff tx_buffers[MAX_TX_DESC]; + spinlock_t txq_lock; + + struct rx_ring_desc *rx_ring; + dma_addr_t rx_ring_dma; + struct ks8695_skbuff rx_buffers[MAX_RX_DESC]; + int next_rx_desc_read; + + int msg_enable; +}; + +/* Register access */ + +/** + * ks8695_readreg - Read from a KS8695 ethernet register + * @ksp: The device to read from + * @reg: The register to read + */ +static inline u32 +ks8695_readreg(struct ks8695_priv *ksp, int reg) +{ + return readl(ksp->io_regs + reg); +} + +/** + * ks8695_writereg - Write to a KS8695 ethernet register + * @ksp: The device to write to + * @reg: The register to write + * @value: The value to write to the register + */ +static inline void +ks8695_writereg(struct ks8695_priv *ksp, int reg, u32 value) +{ + writel(value, ksp->io_regs + reg); +} + +/* Utility functions */ + +/** + * ks8695_port_type - Retrieve port-type as user-friendly string + * @ksp: The device to return the type for + * + * Returns a string indicating which of the WAN, LAN or HPNA + * ports this device is likely to represent. + */ +static const char * +ks8695_port_type(struct ks8695_priv *ksp) +{ + switch (ksp->dtype) { + case KS8695_DTYPE_LAN: + return "LAN"; + case KS8695_DTYPE_WAN: + return "WAN"; + case KS8695_DTYPE_HPNA: + return "HPNA"; + } + + return "UNKNOWN"; +} + +/** + * ks8695_update_mac - Update the MAC registers in the device + * @ksp: The device to update + * + * Updates the MAC registers in the KS8695 device from the address in the + * net_device structure associated with this interface. + */ +static void +ks8695_update_mac(struct ks8695_priv *ksp) +{ + /* Update the HW with the MAC from the net_device */ + struct net_device *ndev = ksp->ndev; + u32 machigh, maclow; + + maclow = ((ndev->dev_addr[2] << 24) | (ndev->dev_addr[3] << 16) | + (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5] << 0)); + machigh = ((ndev->dev_addr[0] << 8) | (ndev->dev_addr[1] << 0)); + + ks8695_writereg(ksp, KS8695_MAL, maclow); + ks8695_writereg(ksp, KS8695_MAH, machigh); + +} + +/** + * ks8695_refill_rxbuffers - Re-fill the RX buffer ring + * @ksp: The device to refill + * + * Iterates the RX ring of the device looking for empty slots. + * For each empty slot, we allocate and map a new SKB and give it + * to the hardware. + * This can be called from interrupt context safely. + */ +static void +ks8695_refill_rxbuffers(struct ks8695_priv *ksp) +{ + /* Run around the RX ring, filling in any missing sk_buff's */ + int buff_n; + + for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) { + if (!ksp->rx_buffers[buff_n].skb) { + struct sk_buff *skb = dev_alloc_skb(MAX_RXBUF_SIZE); + dma_addr_t mapping; + + ksp->rx_buffers[buff_n].skb = skb; + if (skb == NULL) { + /* Failed to allocate one, perhaps + * we'll try again later. + */ + break; + } + + mapping = dma_map_single(ksp->dev, skb->data, + MAX_RXBUF_SIZE, + DMA_FROM_DEVICE); + if (unlikely(dma_mapping_error(ksp->dev, mapping))) { + /* Failed to DMA map this SKB, try later */ + dev_kfree_skb_irq(skb); + ksp->rx_buffers[buff_n].skb = NULL; + break; + } + ksp->rx_buffers[buff_n].dma_ptr = mapping; + skb->dev = ksp->ndev; + ksp->rx_buffers[buff_n].length = MAX_RXBUF_SIZE; + + /* Record this into the DMA ring */ + ksp->rx_ring[buff_n].data_ptr = cpu_to_le32(mapping); + ksp->rx_ring[buff_n].length = + cpu_to_le32(MAX_RXBUF_SIZE); + + wmb(); + + /* And give ownership over to the hardware */ + ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN); + } + } +} + +/* Maximum number of multicast addresses which the KS8695 HW supports */ +#define KS8695_NR_ADDRESSES 16 + +/** + * ks8695_init_partial_multicast - Init the mcast addr registers + * @ksp: The device to initialise + * @addr: The multicast address list to use + * @nr_addr: The number of addresses in the list + * + * This routine is a helper for ks8695_set_multicast - it writes + * the additional-address registers in the KS8695 ethernet device + * and cleans up any others left behind. + */ +static void +ks8695_init_partial_multicast(struct ks8695_priv *ksp, + struct dev_mc_list *addr, + int nr_addr) +{ + u32 low, high; + int i; + + for (i = 0; i < nr_addr; i++, addr = addr->next) { + /* Ran out of addresses? */ + if (!addr) + break; + /* Ran out of space in chip? */ + BUG_ON(i == KS8695_NR_ADDRESSES); + + low = (addr->dmi_addr[2] << 24) | (addr->dmi_addr[3] << 16) | + (addr->dmi_addr[4] << 8) | (addr->dmi_addr[5]); + high = (addr->dmi_addr[0] << 8) | (addr->dmi_addr[1]); + + ks8695_writereg(ksp, KS8695_AAL_(i), low); + ks8695_writereg(ksp, KS8695_AAH_(i), AAH_E | high); + } + + /* Clear the remaining Additional Station Addresses */ + for (; i < KS8695_NR_ADDRESSES; i++) { + ks8695_writereg(ksp, KS8695_AAL_(i), 0); + ks8695_writereg(ksp, KS8695_AAH_(i), 0); + } +} + +/* Interrupt handling */ + +/** + * ks8695_tx_irq - Transmit IRQ handler + * @irq: The IRQ which went off (ignored) + * @dev_id: The net_device for the interrupt + * + * Process the TX ring, clearing out any transmitted slots. + * Allows the net_device to pass us new packets once slots are + * freed. + */ +static irqreturn_t +ks8695_tx_irq(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct ks8695_priv *ksp = netdev_priv(ndev); + int buff_n; + + for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) { + if (ksp->tx_buffers[buff_n].skb && + !(ksp->tx_ring[buff_n].owner & cpu_to_le32(TDES_OWN))) { + rmb(); + /* An SKB which is not owned by HW is present */ + /* Update the stats for the net_device */ + ndev->stats.tx_packets++; + ndev->stats.tx_bytes += ksp->tx_buffers[buff_n].length; + + /* Free the packet from the ring */ + ksp->tx_ring[buff_n].data_ptr = 0; + + /* Free the sk_buff */ + dma_unmap_single(ksp->dev, + ksp->tx_buffers[buff_n].dma_ptr, + ksp->tx_buffers[buff_n].length, + DMA_TO_DEVICE); + dev_kfree_skb_irq(ksp->tx_buffers[buff_n].skb); + ksp->tx_buffers[buff_n].skb = NULL; + ksp->tx_ring_used--; + } + } + + netif_wake_queue(ndev); + + return IRQ_HANDLED; +} + +/** + * ks8695_rx_irq - Receive IRQ handler + * @irq: The IRQ which went off (ignored) + * @dev_id: The net_device for the interrupt + * + * Process the RX ring, passing any received packets up to the + * host. If we received anything other than errors, we then + * refill the ring. + */ +static irqreturn_t +ks8695_rx_irq(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct ks8695_priv *ksp = netdev_priv(ndev); + struct sk_buff *skb; + int buff_n; + u32 flags; + int pktlen; + int last_rx_processed = -1; + + buff_n = ksp->next_rx_desc_read; + do { + if (ksp->rx_buffers[buff_n].skb && + !(ksp->rx_ring[buff_n].status & cpu_to_le32(RDES_OWN))) { + rmb(); + flags = le32_to_cpu(ksp->rx_ring[buff_n].status); + /* Found an SKB which we own, this means we + * received a packet + */ + if ((flags & (RDES_FS | RDES_LS)) != + (RDES_FS | RDES_LS)) { + /* This packet is not the first and + * the last segment. Therefore it is + * a "spanning" packet and we can't + * handle it + */ + goto rx_failure; + } + + if (flags & (RDES_ES | RDES_RE)) { + /* It's an error packet */ + ndev->stats.rx_errors++; + if (flags & RDES_TL) + ndev->stats.rx_length_errors++; + if (flags & RDES_RF) + ndev->stats.rx_length_errors++; + if (flags & RDES_CE) + ndev->stats.rx_crc_errors++; + if (flags & RDES_RE) + ndev->stats.rx_missed_errors++; + + goto rx_failure; + } + + pktlen = flags & RDES_FLEN; + pktlen -= 4; /* Drop the CRC */ + + /* Retrieve the sk_buff */ + skb = ksp->rx_buffers[buff_n].skb; + + /* Clear it from the ring */ + ksp->rx_buffers[buff_n].skb = NULL; + ksp->rx_ring[buff_n].data_ptr = 0; + + /* Unmap the SKB */ + dma_unmap_single(ksp->dev, + ksp->rx_buffers[buff_n].dma_ptr, + ksp->rx_buffers[buff_n].length, + DMA_FROM_DEVICE); + + /* Relinquish the SKB to the network layer */ + skb_put(skb, pktlen); + skb->protocol = eth_type_trans(skb, ndev); + netif_rx(skb); + + /* Record stats */ + ndev->last_rx = jiffies; + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += pktlen; + goto rx_finished; + +rx_failure: + /* This ring entry is an error, but we can + * re-use the skb + */ + /* Give the ring entry back to the hardware */ + ksp->rx_ring[buff_n].status = cpu_to_le32(RDES_OWN); +rx_finished: + /* And note this as processed so we can start + * from here next time + */ + last_rx_processed = buff_n; + } else { + /* Ran out of things to process, stop now */ + break; + } + buff_n = (buff_n + 1) & MAX_RX_DESC_MASK; + } while (buff_n != ksp->next_rx_desc_read); + + /* And note which RX descriptor we last did anything with */ + if (likely(last_rx_processed != -1)) + ksp->next_rx_desc_read = + (last_rx_processed + 1) & MAX_RX_DESC_MASK; + + /* And refill the buffers */ + ks8695_refill_rxbuffers(ksp); + + /* Kick the RX DMA engine, in case it became suspended */ + ks8695_writereg(ksp, KS8695_DRSC, 0); + + return IRQ_HANDLED; +} + +/** + * ks8695_link_irq - Link change IRQ handler + * @irq: The IRQ which went off (ignored) + * @dev_id: The net_device for the interrupt + * + * The WAN interface can generate an IRQ when the link changes, + * report this to the net layer and the user. + */ +static irqreturn_t +ks8695_link_irq(int irq, void *dev_id) +{ + struct net_device *ndev = (struct net_device *)dev_id; + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + if (ctrl & WMC_WLS) { + netif_carrier_on(ndev); + if (netif_msg_link(ksp)) + dev_info(ksp->dev, + "%s: Link is now up (10%sMbps/%s-duplex)\n", + ndev->name, + (ctrl & WMC_WSS) ? "0" : "", + (ctrl & WMC_WDS) ? "Full" : "Half"); + } else { + netif_carrier_off(ndev); + if (netif_msg_link(ksp)) + dev_info(ksp->dev, "%s: Link is now down.\n", + ndev->name); + } + + return IRQ_HANDLED; +} + + +/* KS8695 Device functions */ + +/** + * ks8695_reset - Reset a KS8695 ethernet interface + * @ksp: The interface to reset + * + * Perform an engine reset of the interface and re-program it + * with sensible defaults. + */ +static void +ks8695_reset(struct ks8695_priv *ksp) +{ + int reset_timeout = watchdog; + /* Issue the reset via the TX DMA control register */ + ks8695_writereg(ksp, KS8695_DTXC, DTXC_TRST); + while (reset_timeout--) { + if (!(ks8695_readreg(ksp, KS8695_DTXC) & DTXC_TRST)) + break; + msleep(1); + } + + if (reset_timeout == 0) { + dev_crit(ksp->dev, + "Timeout waiting for DMA engines to reset\n"); + /* And blithely carry on */ + } + + /* Definitely wait long enough before attempting to program + * the engines + */ + msleep(10); + + /* RX: unicast and broadcast */ + ks8695_writereg(ksp, KS8695_DRXC, DRXC_RU | DRXC_RB); + /* TX: pad and add CRC */ + ks8695_writereg(ksp, KS8695_DTXC, DTXC_TEP | DTXC_TAC); +} + +/** + * ks8695_shutdown - Shut down a KS8695 ethernet interface + * @ksp: The interface to shut down + * + * This disables packet RX/TX, cleans up IRQs, drains the rings, + * and basically places the interface into a clean shutdown + * state. + */ +static void +ks8695_shutdown(struct ks8695_priv *ksp) +{ + u32 ctrl; + int buff_n; + + /* Disable packet transmission */ + ctrl = ks8695_readreg(ksp, KS8695_DTXC); + ks8695_writereg(ksp, KS8695_DTXC, ctrl & ~DTXC_TE); + + /* Disable packet reception */ + ctrl = ks8695_readreg(ksp, KS8695_DRXC); + ks8695_writereg(ksp, KS8695_DRXC, ctrl & ~DRXC_RE); + + /* Release the IRQs */ + free_irq(ksp->rx_irq, ksp->ndev); + free_irq(ksp->tx_irq, ksp->ndev); + if (ksp->link_irq != -1) + free_irq(ksp->link_irq, ksp->ndev); + + /* Throw away any pending TX packets */ + for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) { + if (ksp->tx_buffers[buff_n].skb) { + /* Remove this SKB from the TX ring */ + ksp->tx_ring[buff_n].owner = 0; + ksp->tx_ring[buff_n].status = 0; + ksp->tx_ring[buff_n].data_ptr = 0; + + /* Unmap and bin this SKB */ + dma_unmap_single(ksp->dev, + ksp->tx_buffers[buff_n].dma_ptr, + ksp->tx_buffers[buff_n].length, + DMA_TO_DEVICE); + dev_kfree_skb_irq(ksp->tx_buffers[buff_n].skb); + ksp->tx_buffers[buff_n].skb = NULL; + } + } + + /* Purge the RX buffers */ + for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) { + if (ksp->rx_buffers[buff_n].skb) { + /* Remove the SKB from the RX ring */ + ksp->rx_ring[buff_n].status = 0; + ksp->rx_ring[buff_n].data_ptr = 0; + + /* Unmap and bin the SKB */ + dma_unmap_single(ksp->dev, + ksp->rx_buffers[buff_n].dma_ptr, + ksp->rx_buffers[buff_n].length, + DMA_FROM_DEVICE); + dev_kfree_skb_irq(ksp->rx_buffers[buff_n].skb); + ksp->rx_buffers[buff_n].skb = NULL; + } + } +} + + +/** + * ks8695_setup_irq - IRQ setup helper function + * @irq: The IRQ number to claim + * @irq_name: The name to give the IRQ claimant + * @handler: The function to call to handle the IRQ + * @ndev: The net_device to pass in as the dev_id argument to the handler + * + * Return 0 on success. + */ +static int +ks8695_setup_irq(int irq, const char *irq_name, + irq_handler_t handler, struct net_device *ndev) +{ + int ret; + + ret = request_irq(irq, handler, IRQF_SHARED, irq_name, ndev); + + if (ret) { + dev_err(&ndev->dev, "failure to request IRQ %d\n", irq); + return ret; + } + + return 0; +} + +/** + * ks8695_init_net - Initialise a KS8695 ethernet interface + * @ksp: The interface to initialise + * + * This routine fills the RX ring, initialises the DMA engines, + * allocates the IRQs and then starts the packet TX and RX + * engines. + */ +static int +ks8695_init_net(struct ks8695_priv *ksp) +{ + int ret; + u32 ctrl; + + ks8695_refill_rxbuffers(ksp); + + /* Initialise the DMA engines */ + ks8695_writereg(ksp, KS8695_RDLB, (u32) ksp->rx_ring_dma); + ks8695_writereg(ksp, KS8695_TDLB, (u32) ksp->tx_ring_dma); + + /* Request the IRQs */ + ret = ks8695_setup_irq(ksp->rx_irq, ksp->rx_irq_name, + ks8695_rx_irq, ksp->ndev); + if (ret) + return ret; + ret = ks8695_setup_irq(ksp->tx_irq, ksp->tx_irq_name, + ks8695_tx_irq, ksp->ndev); + if (ret) + return ret; + if (ksp->link_irq != -1) { + ret = ks8695_setup_irq(ksp->link_irq, ksp->link_irq_name, + ks8695_link_irq, ksp->ndev); + if (ret) + return ret; + } + + /* Set up the ring indices */ + ksp->next_rx_desc_read = 0; + ksp->tx_ring_next_slot = 0; + ksp->tx_ring_used = 0; + + /* Bring up transmission */ + ctrl = ks8695_readreg(ksp, KS8695_DTXC); + /* Enable packet transmission */ + ks8695_writereg(ksp, KS8695_DTXC, ctrl | DTXC_TE); + + /* Bring up the reception */ + ctrl = ks8695_readreg(ksp, KS8695_DRXC); + /* Enable packet reception */ + ks8695_writereg(ksp, KS8695_DRXC, ctrl | DRXC_RE); + /* And start the DMA engine */ + ks8695_writereg(ksp, KS8695_DRSC, 0); + + /* All done */ + return 0; +} + +/** + * ks8695_release_device - HW resource release for KS8695 e-net + * @ksp: The device to be freed + * + * This unallocates io memory regions, dma-coherent regions etc + * which were allocated in ks8695_probe. + */ +static void +ks8695_release_device(struct ks8695_priv *ksp) +{ + /* Unmap the registers */ + iounmap(ksp->io_regs); + if (ksp->phyiface_regs) + iounmap(ksp->phyiface_regs); + + /* And release the request */ + release_resource(ksp->regs_req); + kfree(ksp->regs_req); + if (ksp->phyiface_req) { + release_resource(ksp->phyiface_req); + kfree(ksp->phyiface_req); + } + + /* Free the ring buffers */ + dma_free_coherent(ksp->dev, RING_DMA_SIZE, + ksp->ring_base, ksp->ring_base_dma); +} + +/* Ethtool support */ + +/** + * ks8695_get_msglevel - Get the messages enabled for emission + * @ndev: The network device to read from + */ +static u32 +ks8695_get_msglevel(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + + return ksp->msg_enable; +} + +/** + * ks8695_set_msglevel - Set the messages enabled for emission + * @ndev: The network device to configure + * @value: The messages to set for emission + */ +static void +ks8695_set_msglevel(struct net_device *ndev, u32 value) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + + ksp->msg_enable = value; +} + +/** + * ks8695_get_settings - Get device-specific settings. + * @ndev: The network device to read settings from + * @cmd: The ethtool structure to read into + */ +static int +ks8695_get_settings(struct net_device *ndev, struct ethtool_cmd *cmd) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + /* All ports on the KS8695 support these... */ + cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | + SUPPORTED_TP | SUPPORTED_MII); + cmd->transceiver = XCVR_INTERNAL; + + /* Port specific extras */ + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + cmd->phy_address = 0; + /* not supported for HPNA */ + cmd->autoneg = AUTONEG_DISABLE; + + /* BUG: Erm, dtype hpna implies no phy regs */ + /* + ctrl = readl(KS8695_MISC_VA + KS8695_HMC); + cmd->speed = (ctrl & HMC_HSS) ? SPEED_100 : SPEED_10; + cmd->duplex = (ctrl & HMC_HDS) ? DUPLEX_FULL : DUPLEX_HALF; + */ + return -EOPNOTSUPP; + case KS8695_DTYPE_WAN: + cmd->advertising = ADVERTISED_TP | ADVERTISED_MII; + cmd->port = PORT_MII; + cmd->supported |= (SUPPORTED_Autoneg | SUPPORTED_Pause); + cmd->phy_address = 0; + + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + if ((ctrl & WMC_WAND) == 0) { + /* auto-negotiation is enabled */ + cmd->advertising |= ADVERTISED_Autoneg; + if (ctrl & WMC_WANA100F) + cmd->advertising |= ADVERTISED_100baseT_Full; + if (ctrl & WMC_WANA100H) + cmd->advertising |= ADVERTISED_100baseT_Half; + if (ctrl & WMC_WANA10F) + cmd->advertising |= ADVERTISED_10baseT_Full; + if (ctrl & WMC_WANA10H) + cmd->advertising |= ADVERTISED_10baseT_Half; + if (ctrl & WMC_WANAP) + cmd->advertising |= ADVERTISED_Pause; + cmd->autoneg = AUTONEG_ENABLE; + + cmd->speed = (ctrl & WMC_WSS) ? SPEED_100 : SPEED_10; + cmd->duplex = (ctrl & WMC_WDS) ? + DUPLEX_FULL : DUPLEX_HALF; + } else { + /* auto-negotiation is disabled */ + cmd->autoneg = AUTONEG_DISABLE; + + cmd->speed = (ctrl & WMC_WANF100) ? + SPEED_100 : SPEED_10; + cmd->duplex = (ctrl & WMC_WANFF) ? + DUPLEX_FULL : DUPLEX_HALF; + } + break; + case KS8695_DTYPE_LAN: + return -EOPNOTSUPP; + } + + return 0; +} + +/** + * ks8695_set_settings - Set device-specific settings. + * @ndev: The network device to configure + * @cmd: The settings to configure + */ +static int +ks8695_set_settings(struct net_device *ndev, struct ethtool_cmd *cmd) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + if ((cmd->speed != SPEED_10) && (cmd->speed != SPEED_100)) + return -EINVAL; + if ((cmd->duplex != DUPLEX_HALF) && (cmd->duplex != DUPLEX_FULL)) + return -EINVAL; + if (cmd->port != PORT_MII) + return -EINVAL; + if (cmd->transceiver != XCVR_INTERNAL) + return -EINVAL; + if ((cmd->autoneg != AUTONEG_DISABLE) && + (cmd->autoneg != AUTONEG_ENABLE)) + return -EINVAL; + + if (cmd->autoneg == AUTONEG_ENABLE) { + if ((cmd->advertising & (ADVERTISED_10baseT_Half | + ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | + ADVERTISED_100baseT_Full)) == 0) + return -EINVAL; + + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + /* HPNA does not support auto-negotiation. */ + return -EINVAL; + case KS8695_DTYPE_WAN: + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + + ctrl &= ~(WMC_WAND | WMC_WANA100F | WMC_WANA100H | + WMC_WANA10F | WMC_WANA10H); + if (cmd->advertising & ADVERTISED_100baseT_Full) + ctrl |= WMC_WANA100F; + if (cmd->advertising & ADVERTISED_100baseT_Half) + ctrl |= WMC_WANA100H; + if (cmd->advertising & ADVERTISED_10baseT_Full) + ctrl |= WMC_WANA10F; + if (cmd->advertising & ADVERTISED_10baseT_Half) + ctrl |= WMC_WANA10H; + + /* force a re-negotiation */ + ctrl |= WMC_WANR; + writel(ctrl, ksp->phyiface_regs + KS8695_WMC); + break; + case KS8695_DTYPE_LAN: + return -EOPNOTSUPP; + } + + } else { + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + /* BUG: dtype_hpna implies no phy registers */ + /* + ctrl = __raw_readl(KS8695_MISC_VA + KS8695_HMC); + + ctrl &= ~(HMC_HSS | HMC_HDS); + if (cmd->speed == SPEED_100) + ctrl |= HMC_HSS; + if (cmd->duplex == DUPLEX_FULL) + ctrl |= HMC_HDS; + + __raw_writel(ctrl, KS8695_MISC_VA + KS8695_HMC); + */ + return -EOPNOTSUPP; + case KS8695_DTYPE_WAN: + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + + /* disable auto-negotiation */ + ctrl |= WMC_WAND; + ctrl &= ~(WMC_WANF100 | WMC_WANFF); + + if (cmd->speed == SPEED_100) + ctrl |= WMC_WANF100; + if (cmd->duplex == DUPLEX_FULL) + ctrl |= WMC_WANFF; + + writel(ctrl, ksp->phyiface_regs + KS8695_WMC); + break; + case KS8695_DTYPE_LAN: + return -EOPNOTSUPP; + } + } + + return 0; +} + +/** + * ks8695_nwayreset - Restart the autonegotiation on the port. + * @ndev: The network device to restart autoneotiation on + */ +static int +ks8695_nwayreset(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + /* No phy means no autonegotiation on hpna */ + return -EINVAL; + case KS8695_DTYPE_WAN: + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + + if ((ctrl & WMC_WAND) == 0) + writel(ctrl | WMC_WANR, + ksp->phyiface_regs + KS8695_WMC); + else + /* auto-negotiation not enabled */ + return -EINVAL; + break; + case KS8695_DTYPE_LAN: + return -EOPNOTSUPP; + } + + return 0; +} + +/** + * ks8695_get_link - Retrieve link status of network interface + * @ndev: The network interface to retrive the link status of. + */ +static u32 +ks8695_get_link(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + /* HPNA always has link */ + return 1; + case KS8695_DTYPE_WAN: + /* WAN we can read the PHY for */ + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + return ctrl & WMC_WLS; + case KS8695_DTYPE_LAN: + return -EOPNOTSUPP; + } + return 0; +} + +/** + * ks8695_get_pause - Retrieve network pause/flow-control advertising + * @ndev: The device to retrieve settings from + * @param: The structure to fill out with the information + */ +static void +ks8695_get_pause(struct net_device *ndev, struct ethtool_pauseparam *param) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + switch (ksp->dtype) { + case KS8695_DTYPE_HPNA: + /* No phy link on hpna to configure */ + return; + case KS8695_DTYPE_WAN: + ctrl = readl(ksp->phyiface_regs + KS8695_WMC); + + /* advertise Pause */ + param->autoneg = (ctrl & WMC_WANAP); + + /* current Rx Flow-control */ + ctrl = ks8695_readreg(ksp, KS8695_DRXC); + param->rx_pause = (ctrl & DRXC_RFCE); + + /* current Tx Flow-control */ + ctrl = ks8695_readreg(ksp, KS8695_DTXC); + param->tx_pause = (ctrl & DTXC_TFCE); + break; + case KS8695_DTYPE_LAN: + /* The LAN's "phy" is a direct-attached switch */ + return; + } +} + +/** + * ks8695_set_pause - Configure pause/flow-control + * @ndev: The device to configure + * @param: The pause parameters to set + * + * TODO: Implement this + */ +static int +ks8695_set_pause(struct net_device *ndev, struct ethtool_pauseparam *param) +{ + return -EOPNOTSUPP; +} + +/** + * ks8695_get_drvinfo - Retrieve driver information + * @ndev: The network device to retrieve info about + * @info: The info structure to fill out. + */ +static void +ks8695_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, MODULENAME, sizeof(info->driver)); + strlcpy(info->version, MODULEVERSION, sizeof(info->version)); + strlcpy(info->bus_info, ndev->dev.parent->bus_id, + sizeof(info->bus_info)); +} + +static struct ethtool_ops ks8695_ethtool_ops = { + .get_msglevel = ks8695_get_msglevel, + .set_msglevel = ks8695_set_msglevel, + .get_settings = ks8695_get_settings, + .set_settings = ks8695_set_settings, + .nway_reset = ks8695_nwayreset, + .get_link = ks8695_get_link, + .get_pauseparam = ks8695_get_pause, + .set_pauseparam = ks8695_set_pause, + .get_drvinfo = ks8695_get_drvinfo, +}; + +/* Network device interface functions */ + +/** + * ks8695_set_mac - Update MAC in net dev and HW + * @ndev: The network device to update + * @addr: The new MAC address to set + */ +static int +ks8695_set_mac(struct net_device *ndev, void *addr) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + struct sockaddr *address = addr; + + if (!is_valid_ether_addr(address->sa_data)) + return -EADDRNOTAVAIL; + + memcpy(ndev->dev_addr, address->sa_data, ndev->addr_len); + + ks8695_update_mac(ksp); + + dev_dbg(ksp->dev, "%s: Updated MAC address to %pM\n", + ndev->name, ndev->dev_addr); + + return 0; +} + +/** + * ks8695_set_multicast - Set up the multicast behaviour of the interface + * @ndev: The net_device to configure + * + * This routine, called by the net layer, configures promiscuity + * and multicast reception behaviour for the interface. + */ +static void +ks8695_set_multicast(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + u32 ctrl; + + ctrl = ks8695_readreg(ksp, KS8695_DRXC); + + if (ndev->flags & IFF_PROMISC) { + /* enable promiscuous mode */ + ctrl |= DRXC_RA; + } else if (ndev->flags & ~IFF_PROMISC) { + /* disable promiscuous mode */ + ctrl &= ~DRXC_RA; + } + + if (ndev->flags & IFF_ALLMULTI) { + /* enable all multicast mode */ + ctrl |= DRXC_RM; + } else if (ndev->mc_count > KS8695_NR_ADDRESSES) { + /* more specific multicast addresses than can be + * handled in hardware + */ + ctrl |= DRXC_RM; + } else { + /* enable specific multicasts */ + ctrl &= ~DRXC_RM; + ks8695_init_partial_multicast(ksp, ndev->mc_list, + ndev->mc_count); + } + + ks8695_writereg(ksp, KS8695_DRXC, ctrl); +} + +/** + * ks8695_timeout - Handle a network tx/rx timeout. + * @ndev: The net_device which timed out. + * + * A network transaction timed out, reset the device. + */ +static void +ks8695_timeout(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + + netif_stop_queue(ndev); + ks8695_shutdown(ksp); + + ks8695_reset(ksp); + + ks8695_update_mac(ksp); + + /* We ignore the return from this since it managed to init + * before it probably will be okay to init again. + */ + ks8695_init_net(ksp); + + /* Reconfigure promiscuity etc */ + ks8695_set_multicast(ndev); + + /* And start the TX queue once more */ + netif_start_queue(ndev); +} + +/** + * ks8695_start_xmit - Start a packet transmission + * @skb: The packet to transmit + * @ndev: The network device to send the packet on + * + * This routine, called by the net layer, takes ownership of the + * sk_buff and adds it to the TX ring. It then kicks the TX DMA + * engine to ensure transmission begins. + */ +static int +ks8695_start_xmit(struct sk_buff *skb, struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + int buff_n; + dma_addr_t dmap; + + spin_lock_irq(&ksp->txq_lock); + + if (ksp->tx_ring_used == MAX_TX_DESC) { + /* Somehow we got entered when we have no room */ + spin_unlock_irq(&ksp->txq_lock); + return NETDEV_TX_BUSY; + } + + buff_n = ksp->tx_ring_next_slot; + + BUG_ON(ksp->tx_buffers[buff_n].skb); + + dmap = dma_map_single(ksp->dev, skb->data, skb->len, DMA_TO_DEVICE); + if (unlikely(dma_mapping_error(ksp->dev, dmap))) { + /* Failed to DMA map this SKB, give it back for now */ + spin_unlock_irq(&ksp->txq_lock); + dev_dbg(ksp->dev, "%s: Could not map DMA memory for "\ + "transmission, trying later\n", ndev->name); + return NETDEV_TX_BUSY; + } + + ksp->tx_buffers[buff_n].dma_ptr = dmap; + /* Mapped okay, store the buffer pointer and length for later */ + ksp->tx_buffers[buff_n].skb = skb; + ksp->tx_buffers[buff_n].length = skb->len; + + /* Fill out the TX descriptor */ + ksp->tx_ring[buff_n].data_ptr = + cpu_to_le32(ksp->tx_buffers[buff_n].dma_ptr); + ksp->tx_ring[buff_n].status = + cpu_to_le32(TDES_IC | TDES_FS | TDES_LS | + (skb->len & TDES_TBS)); + + wmb(); + + /* Hand it over to the hardware */ + ksp->tx_ring[buff_n].owner = cpu_to_le32(TDES_OWN); + + if (++ksp->tx_ring_used == MAX_TX_DESC) + netif_stop_queue(ndev); + + ndev->trans_start = jiffies; + + /* Kick the TX DMA in case it decided to go IDLE */ + ks8695_writereg(ksp, KS8695_DTSC, 0); + + /* And update the next ring slot */ + ksp->tx_ring_next_slot = (buff_n + 1) & MAX_TX_DESC_MASK; + + spin_unlock_irq(&ksp->txq_lock); + return NETDEV_TX_OK; +} + +/** + * ks8695_stop - Stop (shutdown) a KS8695 ethernet interface + * @ndev: The net_device to stop + * + * This disables the TX queue and cleans up a KS8695 ethernet + * device. + */ +static int +ks8695_stop(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + + netif_stop_queue(ndev); + netif_carrier_off(ndev); + + ks8695_shutdown(ksp); + + return 0; +} + +/** + * ks8695_open - Open (bring up) a KS8695 ethernet interface + * @ndev: The net_device to open + * + * This resets, configures the MAC, initialises the RX ring and + * DMA engines and starts the TX queue for a KS8695 ethernet + * device. + */ +static int +ks8695_open(struct net_device *ndev) +{ + struct ks8695_priv *ksp = netdev_priv(ndev); + int ret; + + if (!is_valid_ether_addr(ndev->dev_addr)) + return -EADDRNOTAVAIL; + + ks8695_reset(ksp); + + ks8695_update_mac(ksp); + + ret = ks8695_init_net(ksp); + if (ret) { + ks8695_shutdown(ksp); + return ret; + } + + netif_start_queue(ndev); + + return 0; +} + +/* Platform device driver */ + +/** + * ks8695_init_switch - Init LAN switch to known good defaults. + * @ksp: The device to initialise + * + * This initialises the LAN switch in the KS8695 to a known-good + * set of defaults. + */ +static void __devinit +ks8695_init_switch(struct ks8695_priv *ksp) +{ + u32 ctrl; + + /* Default value for SEC0 according to datasheet */ + ctrl = 0x40819e00; + + /* LED0 = Speed LED1 = Link/Activity */ + ctrl &= ~(SEC0_LLED1S | SEC0_LLED0S); + ctrl |= (LLED0S_LINK | LLED1S_LINK_ACTIVITY); + + /* Enable Switch */ + ctrl |= SEC0_ENABLE; + + writel(ctrl, ksp->phyiface_regs + KS8695_SEC0); + + /* Defaults for SEC1 */ + writel(0x9400100, ksp->phyiface_regs + KS8695_SEC1); +} + +/** + * ks8695_init_wan_phy - Initialise the WAN PHY to sensible defaults + * @ksp: The device to initialise + * + * This initialises a KS8695's WAN phy to sensible values for + * autonegotiation etc. + */ +static void __devinit +ks8695_init_wan_phy(struct ks8695_priv *ksp) +{ + u32 ctrl; + + /* Support auto-negotiation */ + ctrl = (WMC_WANAP | WMC_WANA100F | WMC_WANA100H | + WMC_WANA10F | WMC_WANA10H); + + /* LED0 = Activity , LED1 = Link */ + ctrl |= (WLED0S_ACTIVITY | WLED1S_LINK); + + /* Restart Auto-negotiation */ + ctrl |= WMC_WANR; + + writel(ctrl, ksp->phyiface_regs + KS8695_WMC); + + writel(0, ksp->phyiface_regs + KS8695_WPPM); + writel(0, ksp->phyiface_regs + KS8695_PPS); +} + +static const struct net_device_ops ks8695_netdev_ops = { + .ndo_open = ks8695_open, + .ndo_stop = ks8695_stop, + .ndo_start_xmit = ks8695_start_xmit, + .ndo_tx_timeout = ks8695_timeout, + .ndo_set_mac_address = ks8695_set_mac, + .ndo_set_multicast_list = ks8695_set_multicast, +}; + +/** + * ks8695_probe - Probe and initialise a KS8695 ethernet interface + * @pdev: The platform device to probe + * + * Initialise a KS8695 ethernet device from platform data. + * + * This driver requires at least one IORESOURCE_MEM for the + * registers and two IORESOURCE_IRQ for the RX and TX IRQs + * respectively. It can optionally take an additional + * IORESOURCE_MEM for the switch or phy in the case of the lan or + * wan ports, and an IORESOURCE_IRQ for the link IRQ for the wan + * port. + */ +static int __devinit +ks8695_probe(struct platform_device *pdev) +{ + struct ks8695_priv *ksp; + struct net_device *ndev; + struct resource *regs_res, *phyiface_res; + struct resource *rxirq_res, *txirq_res, *linkirq_res; + int ret = 0; + int buff_n; + u32 machigh, maclow; + + /* Initialise a net_device */ + ndev = alloc_etherdev(sizeof(struct ks8695_priv)); + if (!ndev) { + dev_err(&pdev->dev, "could not allocate device.\n"); + return -ENOMEM; + } + + SET_NETDEV_DEV(ndev, &pdev->dev); + + dev_dbg(&pdev->dev, "ks8695_probe() called\n"); + + /* Configure our private structure a little */ + ksp = netdev_priv(ndev); + memset(ksp, 0, sizeof(struct ks8695_priv)); + + ksp->dev = &pdev->dev; + ksp->ndev = ndev; + ksp->msg_enable = NETIF_MSG_LINK; + + /* Retrieve resources */ + regs_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + phyiface_res = platform_get_resource(pdev, IORESOURCE_MEM, 1); + + rxirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); + txirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 1); + linkirq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 2); + + if (!(regs_res && rxirq_res && txirq_res)) { + dev_err(ksp->dev, "insufficient resources\n"); + ret = -ENOENT; + goto failure; + } + + ksp->regs_req = request_mem_region(regs_res->start, + resource_size(regs_res), + pdev->name); + + if (!ksp->regs_req) { + dev_err(ksp->dev, "cannot claim register space\n"); + ret = -EIO; + goto failure; + } + + ksp->io_regs = ioremap(regs_res->start, resource_size(regs_res)); + + if (!ksp->io_regs) { + dev_err(ksp->dev, "failed to ioremap registers\n"); + ret = -EINVAL; + goto failure; + } + + if (phyiface_res) { + ksp->phyiface_req = + request_mem_region(phyiface_res->start, + resource_size(phyiface_res), + phyiface_res->name); + + if (!ksp->phyiface_req) { + dev_err(ksp->dev, + "cannot claim switch register space\n"); + ret = -EIO; + goto failure; + } + + ksp->phyiface_regs = ioremap(phyiface_res->start, + resource_size(phyiface_res)); + + if (!ksp->phyiface_regs) { + dev_err(ksp->dev, + "failed to ioremap switch registers\n"); + ret = -EINVAL; + goto failure; + } + } + + ksp->rx_irq = rxirq_res->start; + ksp->rx_irq_name = rxirq_res->name ? rxirq_res->name : "Ethernet RX"; + ksp->tx_irq = txirq_res->start; + ksp->tx_irq_name = txirq_res->name ? txirq_res->name : "Ethernet TX"; + ksp->link_irq = (linkirq_res ? linkirq_res->start : -1); + ksp->link_irq_name = (linkirq_res && linkirq_res->name) ? + linkirq_res->name : "Ethernet Link"; + + /* driver system setup */ + ndev->netdev_ops = &ks8695_netdev_ops; + SET_ETHTOOL_OPS(ndev, &ks8695_ethtool_ops); + ndev->watchdog_timeo = msecs_to_jiffies(watchdog); + + /* Retrieve the default MAC addr from the chip. */ + /* The bootloader should have left it in there for us. */ + + machigh = ks8695_readreg(ksp, KS8695_MAH); + maclow = ks8695_readreg(ksp, KS8695_MAL); + + ndev->dev_addr[0] = (machigh >> 8) & 0xFF; + ndev->dev_addr[1] = machigh & 0xFF; + ndev->dev_addr[2] = (maclow >> 24) & 0xFF; + ndev->dev_addr[3] = (maclow >> 16) & 0xFF; + ndev->dev_addr[4] = (maclow >> 8) & 0xFF; + ndev->dev_addr[5] = maclow & 0xFF; + + if (!is_valid_ether_addr(ndev->dev_addr)) + dev_warn(ksp->dev, "%s: Invalid ethernet MAC address. Please " + "set using ifconfig\n", ndev->name); + + /* In order to be efficient memory-wise, we allocate both + * rings in one go. + */ + ksp->ring_base = dma_alloc_coherent(&pdev->dev, RING_DMA_SIZE, + &ksp->ring_base_dma, GFP_KERNEL); + if (!ksp->ring_base) { + ret = -ENOMEM; + goto failure; + } + + /* Specify the TX DMA ring buffer */ + ksp->tx_ring = ksp->ring_base; + ksp->tx_ring_dma = ksp->ring_base_dma; + + /* And initialise the queue's lock */ + spin_lock_init(&ksp->txq_lock); + + /* Specify the RX DMA ring buffer */ + ksp->rx_ring = ksp->ring_base + TX_RING_DMA_SIZE; + ksp->rx_ring_dma = ksp->ring_base_dma + TX_RING_DMA_SIZE; + + /* Zero the descriptor rings */ + memset(ksp->tx_ring, 0, TX_RING_DMA_SIZE); + memset(ksp->rx_ring, 0, RX_RING_DMA_SIZE); + + /* Build the rings */ + for (buff_n = 0; buff_n < MAX_TX_DESC; ++buff_n) { + ksp->tx_ring[buff_n].next_desc = + cpu_to_le32(ksp->tx_ring_dma + + (sizeof(struct tx_ring_desc) * + ((buff_n + 1) & MAX_TX_DESC_MASK))); + } + + for (buff_n = 0; buff_n < MAX_RX_DESC; ++buff_n) { + ksp->rx_ring[buff_n].next_desc = + cpu_to_le32(ksp->rx_ring_dma + + (sizeof(struct rx_ring_desc) * + ((buff_n + 1) & MAX_RX_DESC_MASK))); + } + + /* Initialise the port (physically) */ + if (ksp->phyiface_regs && ksp->link_irq == -1) { + ks8695_init_switch(ksp); + ksp->dtype = KS8695_DTYPE_LAN; + } else if (ksp->phyiface_regs && ksp->link_irq != -1) { + ks8695_init_wan_phy(ksp); + ksp->dtype = KS8695_DTYPE_WAN; + } else { + /* No initialisation since HPNA does not have a PHY */ + ksp->dtype = KS8695_DTYPE_HPNA; + } + + /* And bring up the net_device with the net core */ + platform_set_drvdata(pdev, ndev); + ret = register_netdev(ndev); + + if (ret == 0) { + dev_info(ksp->dev, "ks8695 ethernet (%s) MAC: %pM\n", + ks8695_port_type(ksp), ndev->dev_addr); + } else { + /* Report the failure to register the net_device */ + dev_err(ksp->dev, "ks8695net: failed to register netdev.\n"); + goto failure; + } + + /* All is well */ + return 0; + + /* Error exit path */ +failure: + ks8695_release_device(ksp); + free_netdev(ndev); + + return ret; +} + +/** + * ks8695_drv_suspend - Suspend a KS8695 ethernet platform device. + * @pdev: The device to suspend + * @state: The suspend state + * + * This routine detaches and shuts down a KS8695 ethernet device. + */ +static int +ks8695_drv_suspend(struct platform_device *pdev, pm_message_t state) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct ks8695_priv *ksp = netdev_priv(ndev); + + ksp->in_suspend = 1; + + if (netif_running(ndev)) { + netif_device_detach(ndev); + ks8695_shutdown(ksp); + } + + return 0; +} + +/** + * ks8695_drv_resume - Resume a KS8695 ethernet platform device. + * @pdev: The device to resume + * + * This routine re-initialises and re-attaches a KS8695 ethernet + * device. + */ +static int +ks8695_drv_resume(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct ks8695_priv *ksp = netdev_priv(ndev); + + if (netif_running(ndev)) { + ks8695_reset(ksp); + ks8695_init_net(ksp); + ks8695_set_multicast(ndev); + netif_device_attach(ndev); + } + + ksp->in_suspend = 0; + + return 0; +} + +/** + * ks8695_drv_remove - Remove a KS8695 net device on driver unload. + * @pdev: The platform device to remove + * + * This unregisters and releases a KS8695 ethernet device. + */ +static int __devexit +ks8695_drv_remove(struct platform_device *pdev) +{ + struct net_device *ndev = platform_get_drvdata(pdev); + struct ks8695_priv *ksp = netdev_priv(ndev); + + platform_set_drvdata(pdev, NULL); + + unregister_netdev(ndev); + ks8695_release_device(ksp); + free_netdev(ndev); + + dev_dbg(&pdev->dev, "released and freed device\n"); + return 0; +} + +static struct platform_driver ks8695_driver = { + .driver = { + .name = MODULENAME, + .owner = THIS_MODULE, + }, + .probe = ks8695_probe, + .remove = __devexit_p(ks8695_drv_remove), + .suspend = ks8695_drv_suspend, + .resume = ks8695_drv_resume, +}; + +/* Module interface */ + +static int __init +ks8695_init(void) +{ + printk(KERN_INFO "%s Ethernet driver, V%s\n", + MODULENAME, MODULEVERSION); + + return platform_driver_register(&ks8695_driver); +} + +static void __exit +ks8695_cleanup(void) +{ + platform_driver_unregister(&ks8695_driver); +} + +module_init(ks8695_init); +module_exit(ks8695_cleanup); + +MODULE_AUTHOR("Simtec Electronics") +MODULE_DESCRIPTION("Micrel KS8695 (Centaur) Ethernet driver"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS("platform:" MODULENAME); + +module_param(watchdog, int, 0400); +MODULE_PARM_DESC(watchdog, "transmit timeout in milliseconds"); diff --git a/drivers/net/arm/ks8695net.h b/drivers/net/arm/ks8695net.h new file mode 100644 index 0000000000000000000000000000000000000000..80eff6ea51631a88097f86a0e71413e9e8ff012d --- /dev/null +++ b/drivers/net/arm/ks8695net.h @@ -0,0 +1,107 @@ +/* + * Micrel KS8695 (Centaur) Ethernet. + * + * Copyright 2008 Simtec Electronics + * Daniel Silverstone + * Vincent Sanders + */ + +#ifndef KS8695NET_H +#define KS8695NET_H + +/* Receive descriptor flags */ +#define RDES_OWN (1 << 31) /* Ownership */ +#define RDES_FS (1 << 30) /* First Descriptor */ +#define RDES_LS (1 << 29) /* Last Descriptor */ +#define RDES_IPE (1 << 28) /* IP Checksum error */ +#define RDES_TCPE (1 << 27) /* TCP Checksum error */ +#define RDES_UDPE (1 << 26) /* UDP Checksum error */ +#define RDES_ES (1 << 25) /* Error summary */ +#define RDES_MF (1 << 24) /* Multicast Frame */ +#define RDES_RE (1 << 19) /* MII Error reported */ +#define RDES_TL (1 << 18) /* Frame too Long */ +#define RDES_RF (1 << 17) /* Runt Frame */ +#define RDES_CE (1 << 16) /* CRC error */ +#define RDES_FT (1 << 15) /* Frame Type */ +#define RDES_FLEN (0x7ff) /* Frame Length */ + +#define RDES_RER (1 << 25) /* Receive End of Ring */ +#define RDES_RBS (0x7ff) /* Receive Buffer Size */ + +/* Transmit descriptor flags */ + +#define TDES_OWN (1 << 31) /* Ownership */ + +#define TDES_IC (1 << 31) /* Interrupt on Completion */ +#define TDES_FS (1 << 30) /* First Segment */ +#define TDES_LS (1 << 29) /* Last Segment */ +#define TDES_IPCKG (1 << 28) /* IP Checksum generate */ +#define TDES_TCPCKG (1 << 27) /* TCP Checksum generate */ +#define TDES_UDPCKG (1 << 26) /* UDP Checksum generate */ +#define TDES_TER (1 << 25) /* Transmit End of Ring */ +#define TDES_TBS (0x7ff) /* Transmit Buffer Size */ + +/* + * Network controller register offsets + */ +#define KS8695_DTXC (0x00) /* DMA Transmit Control */ +#define KS8695_DRXC (0x04) /* DMA Receive Control */ +#define KS8695_DTSC (0x08) /* DMA Transmit Start Command */ +#define KS8695_DRSC (0x0c) /* DMA Receive Start Command */ +#define KS8695_TDLB (0x10) /* Transmit Descriptor List + * Base Address + */ +#define KS8695_RDLB (0x14) /* Receive Descriptor List + * Base Address + */ +#define KS8695_MAL (0x18) /* MAC Station Address Low */ +#define KS8695_MAH (0x1c) /* MAC Station Address High */ +#define KS8695_AAL_(n) (0x80 + ((n)*8)) /* MAC Additional + * Station Address + * (0..15) Low + */ +#define KS8695_AAH_(n) (0x84 + ((n)*8)) /* MAC Additional + * Station Address + * (0..15) High + */ + + +/* DMA Transmit Control Register */ +#define DTXC_TRST (1 << 31) /* Soft Reset */ +#define DTXC_TBS (0x3f << 24) /* Transmit Burst Size */ +#define DTXC_TUCG (1 << 18) /* Transmit UDP + * Checksum Generate + */ +#define DTXC_TTCG (1 << 17) /* Transmit TCP + * Checksum Generate + */ +#define DTXC_TICG (1 << 16) /* Transmit IP + * Checksum Generate + */ +#define DTXC_TFCE (1 << 9) /* Transmit Flow + * Control Enable + */ +#define DTXC_TLB (1 << 8) /* Loopback mode */ +#define DTXC_TEP (1 << 2) /* Transmit Enable Padding */ +#define DTXC_TAC (1 << 1) /* Transmit Add CRC */ +#define DTXC_TE (1 << 0) /* TX Enable */ + +/* DMA Receive Control Register */ +#define DRXC_RBS (0x3f << 24) /* Receive Burst Size */ +#define DRXC_RUCC (1 << 18) /* Receive UDP Checksum check */ +#define DRXC_RTCG (1 << 17) /* Receive TCP Checksum check */ +#define DRXC_RICG (1 << 16) /* Receive IP Checksum check */ +#define DRXC_RFCE (1 << 9) /* Receive Flow Control + * Enable + */ +#define DRXC_RB (1 << 6) /* Receive Broadcast */ +#define DRXC_RM (1 << 5) /* Receive Multicast */ +#define DRXC_RU (1 << 4) /* Receive Unicast */ +#define DRXC_RERR (1 << 3) /* Receive Error Frame */ +#define DRXC_RA (1 << 2) /* Receive All */ +#define DRXC_RE (1 << 0) /* RX Enable */ + +/* Additional Station Address High */ +#define AAH_E (1 << 31) /* Address Enabled */ + +#endif /* KS8695NET_H */ diff --git a/drivers/net/at1700.c b/drivers/net/at1700.c index 7e874d485d24a36fbab6aee652eaf44c6cf72e78..72ea6e378f8dda5dec528cdad250c23cd6ce6677 100644 --- a/drivers/net/at1700.c +++ b/drivers/net/at1700.c @@ -265,7 +265,6 @@ static int __init at1700_probe1(struct net_device *dev, int ioaddr) unsigned int i, irq, is_fmv18x = 0, is_at1700 = 0; int slot, ret = -ENODEV; struct net_local *lp = netdev_priv(dev); - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, AT1700_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -397,7 +396,7 @@ found: dev->dev_addr[i] = val; } } - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); /* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals, rather than 150 ohm shielded twisted pair compensation. @@ -768,7 +767,6 @@ net_rx(struct net_device *dev) insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1); skb->protocol=eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -901,15 +899,3 @@ module_init(at1700_module_init); module_exit(at1700_module_exit); #endif /* MODULE */ MODULE_LICENSE("GPL"); - - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c" - * alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c" - * tab-width: 4 - * c-basic-offset: 4 - * c-indent-level: 4 - * End: - */ - diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 0860cc280b019c230e969c5b7efaac96ae4101f2..2d81f6afcb589075009d6e45bc0db9dcd4b40c00 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -466,7 +466,6 @@ static unsigned long __init lance_probe1( struct net_device *dev, int i; static int did_version; unsigned short save1, save2; - DECLARE_MAC_BUF(mac); PROBE_PRINT(( "Probing for Lance card at mem %#lx io %#lx\n", (long)memaddr, (long)ioaddr )); @@ -521,7 +520,7 @@ static unsigned long __init lance_probe1( struct net_device *dev, return( 0 ); probe_ok: - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); MEM = (struct lance_memory *)memaddr; IO = lp->iobase = (struct lance_ioreg *)ioaddr; dev->base_addr = (unsigned long)ioaddr; /* informational only */ @@ -595,7 +594,7 @@ static unsigned long __init lance_probe1( struct net_device *dev, i = IO->mem; break; } - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); if (lp->cardtype == OLD_RIEBL) { printk( "%s: Warning: This is a default ethernet address!\n", dev->name ); @@ -640,8 +639,8 @@ static unsigned long __init lance_probe1( struct net_device *dev, static int lance_open( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; int i; @@ -681,8 +680,8 @@ static int lance_open( struct net_device *dev ) /* Initialize the LANCE Rx and Tx rings. */ static void lance_init_ring( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); int i; unsigned offset; @@ -730,7 +729,7 @@ static void lance_init_ring( struct net_device *dev ) static void lance_tx_timeout (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; AREG = CSR0; @@ -772,14 +771,12 @@ static void lance_tx_timeout (struct net_device *dev) /* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; int entry, len; struct lance_tx_head *head; unsigned long flags; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); DPRINTK( 2, ( "%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, DREG )); @@ -802,12 +799,10 @@ static int lance_start_xmit( struct sk_buff *skb, struct net_device *dev ) /* Fill in a Tx ring entry */ if (lance_debug >= 3) { - printk( "%s: TX pkt type 0x%04x from " - "%s to %s" + printk( "%s: TX pkt type 0x%04x from %pM to %pM" " data at 0x%08x len %d\n", dev->name, ((u_short *)skb->data)[6], - print_mac(mac, &skb->data[6]), - print_mac(mac2, skb->data), + &skb->data[6], skb->data, (int)skb->data, (int)skb->len ); } @@ -865,7 +860,7 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id ) return IRQ_NONE; } - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); IO = lp->iobase; spin_lock (&lp->devlock); @@ -965,8 +960,8 @@ static irqreturn_t lance_interrupt( int irq, void *dev_id ) static int lance_rx( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); int entry = lp->cur_rx & RX_RING_MOD_MASK; int i; @@ -1019,14 +1014,12 @@ static int lance_rx( struct net_device *dev ) if (lance_debug >= 3) { u_char *data = PKTBUF_ADDR(head); - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %s to %s " + printk(KERN_DEBUG "%s: RX pkt type 0x%04x from %pM to %pM " "data %02x %02x %02x %02x %02x %02x %02x %02x " "len %d\n", dev->name, ((u_short *)data)[6], - print_mac(mac, &data[6]), print_mac(mac2, data), + &data[6], data, data[15], data[16], data[17], data[18], data[19], data[20], data[21], data[22], pkt_len); @@ -1037,7 +1030,6 @@ static int lance_rx( struct net_device *dev ) lp->memcpy_f( skb->data, PKTBUF_ADDR(head), pkt_len ); skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -1057,8 +1049,8 @@ static int lance_rx( struct net_device *dev ) static int lance_close( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; netif_stop_queue (dev); @@ -1084,8 +1076,8 @@ static int lance_close( struct net_device *dev ) */ static void set_multicast_list( struct net_device *dev ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); struct lance_ioreg *IO = lp->iobase; if (netif_running(dev)) @@ -1126,8 +1118,8 @@ static void set_multicast_list( struct net_device *dev ) /* This is needed for old RieblCards and possible for new RieblCards */ static int lance_set_mac_address( struct net_device *dev, void *addr ) - -{ struct lance_private *lp = (struct lance_private *)dev->priv; +{ + struct lance_private *lp = netdev_priv(dev); struct sockaddr *saddr = addr; int i; diff --git a/drivers/net/atl1e/atl1e_main.c b/drivers/net/atl1e/atl1e_main.c index 9b603528143d6dcee4da35059d74a7a0e8902964..bb9094d4cbc9014f2686033162cfde22fcc0d972 100644 --- a/drivers/net/atl1e/atl1e_main.c +++ b/drivers/net/atl1e/atl1e_main.c @@ -1326,9 +1326,9 @@ static irqreturn_t atl1e_intr(int irq, void *data) AT_WRITE_REG(hw, REG_IMR, IMR_NORMAL_MASK & ~ISR_RX_EVENT); AT_WRITE_FLUSH(hw); - if (likely(netif_rx_schedule_prep(netdev, + if (likely(netif_rx_schedule_prep( &adapter->napi))) - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } } while (--max_ints > 0); /* re-enable Interrupt*/ @@ -1460,7 +1460,6 @@ static void atl1e_clean_rx_irq(struct atl1e_adapter *adapter, u8 que, netif_receive_skb(skb); } - netdev->last_rx = jiffies; skip_pkt: /* skip current packet whether it's ok or not. */ rx_page->read_offset += @@ -1502,7 +1501,6 @@ static int atl1e_clean(struct napi_struct *napi, int budget) { struct atl1e_adapter *adapter = container_of(napi, struct atl1e_adapter, napi); - struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; u32 imr_data; int work_done = 0; @@ -1516,7 +1514,7 @@ static int atl1e_clean(struct napi_struct *napi, int budget) /* If no Tx and not enough Rx work done, exit the polling mode */ if (work_done < budget) { quit_polling: - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); imr_data = AT_READ_REG(&adapter->hw, REG_IMR); AT_WRITE_REG(&adapter->hw, REG_IMR, imr_data | ISR_RX_EVENT); /* test debug */ @@ -2254,26 +2252,33 @@ static void atl1e_shutdown(struct pci_dev *pdev) atl1e_suspend(pdev, PMSG_SUSPEND); } +static const struct net_device_ops atl1e_netdev_ops = { + .ndo_open = atl1e_open, + .ndo_stop = atl1e_close, + .ndo_start_xmit = atl1e_xmit_frame, + .ndo_get_stats = atl1e_get_stats, + .ndo_set_multicast_list = atl1e_set_multi, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = atl1e_set_mac_addr, + .ndo_change_mtu = atl1e_change_mtu, + .ndo_do_ioctl = atl1e_ioctl, + .ndo_tx_timeout = atl1e_tx_timeout, + .ndo_vlan_rx_register = atl1e_vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = atl1e_netpoll, +#endif + +}; + static int atl1e_init_netdev(struct net_device *netdev, struct pci_dev *pdev) { SET_NETDEV_DEV(netdev, &pdev->dev); pci_set_drvdata(pdev, netdev); netdev->irq = pdev->irq; - netdev->open = &atl1e_open; - netdev->stop = &atl1e_close; - netdev->hard_start_xmit = &atl1e_xmit_frame; - netdev->get_stats = &atl1e_get_stats; - netdev->set_multicast_list = &atl1e_set_multi; - netdev->set_mac_address = &atl1e_set_mac_addr; - netdev->change_mtu = &atl1e_change_mtu; - netdev->do_ioctl = &atl1e_ioctl; - netdev->tx_timeout = &atl1e_tx_timeout; + netdev->netdev_ops = &atl1e_netdev_ops; + netdev->watchdog_timeo = AT_TX_WATCHDOG; - netdev->vlan_rx_register = atl1e_vlan_rx_register; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = atl1e_netpoll; -#endif atl1e_set_ethtool_ops(netdev); netdev->features = NETIF_F_SG | NETIF_F_HW_CSUM | @@ -2488,7 +2493,7 @@ static pci_ers_result_t atl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); - struct atl1e_adapter *adapter = netdev->priv; + struct atl1e_adapter *adapter = netdev_priv(netdev); netif_device_detach(netdev); @@ -2511,7 +2516,7 @@ atl1e_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) static pci_ers_result_t atl1e_io_slot_reset(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct atl1e_adapter *adapter = netdev->priv; + struct atl1e_adapter *adapter = netdev_priv(netdev); if (pci_enable_device(pdev)) { dev_err(&pdev->dev, @@ -2539,7 +2544,7 @@ static pci_ers_result_t atl1e_io_slot_reset(struct pci_dev *pdev) static void atl1e_io_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct atl1e_adapter *adapter = netdev->priv; + struct atl1e_adapter *adapter = netdev_priv(netdev); if (netif_running(netdev)) { if (atl1e_up(adapter)) { diff --git a/drivers/net/atlx/atl1.c b/drivers/net/atlx/atl1.c index aef403d299eef1a5b04a4218070c0e51594fa288..c0ceee0d7c808ed4f4df1fdb12806239b37dad63 100644 --- a/drivers/net/atlx/atl1.c +++ b/drivers/net/atlx/atl1.c @@ -195,7 +195,7 @@ static int __devinit atl1_validate_option(int *value, struct atl1_option *opt, * value exists, a default value is used. The final value is stored * in a variable in the adapter structure. */ -void __devinit atl1_check_options(struct atl1_adapter *adapter) +static void __devinit atl1_check_options(struct atl1_adapter *adapter) { struct pci_dev *pdev = adapter->pdev; int bd = adapter->bd_number; @@ -523,7 +523,7 @@ static int atl1_get_permanent_address(struct atl1_hw *hw) * Reads the adapter's MAC address from the EEPROM * hw - Struct containing variables accessed by shared code */ -s32 atl1_read_mac_addr(struct atl1_hw *hw) +static s32 atl1_read_mac_addr(struct atl1_hw *hw) { u16 i; @@ -1390,7 +1390,8 @@ static u32 atl1_check_link(struct atl1_adapter *adapter) /* auto-neg, insert timer to re-config phy */ if (!adapter->phy_timer_pending) { adapter->phy_timer_pending = true; - mod_timer(&adapter->phy_config_timer, jiffies + 3 * HZ); + mod_timer(&adapter->phy_config_timer, + round_jiffies(jiffies + 3 * HZ)); } return 0; @@ -1662,6 +1663,7 @@ static void atl1_via_workaround(struct atl1_adapter *adapter) static void atl1_inc_smb(struct atl1_adapter *adapter) { + struct net_device *netdev = adapter->netdev; struct stats_msg_block *smb = adapter->smb.smb; /* Fill out the OS statistics structure */ @@ -1704,30 +1706,30 @@ static void atl1_inc_smb(struct atl1_adapter *adapter) adapter->soft_stats.tx_trunc += smb->tx_trunc; adapter->soft_stats.tx_pause += smb->tx_pause; - adapter->net_stats.rx_packets = adapter->soft_stats.rx_packets; - adapter->net_stats.tx_packets = adapter->soft_stats.tx_packets; - adapter->net_stats.rx_bytes = adapter->soft_stats.rx_bytes; - adapter->net_stats.tx_bytes = adapter->soft_stats.tx_bytes; - adapter->net_stats.multicast = adapter->soft_stats.multicast; - adapter->net_stats.collisions = adapter->soft_stats.collisions; - adapter->net_stats.rx_errors = adapter->soft_stats.rx_errors; - adapter->net_stats.rx_over_errors = + netdev->stats.rx_packets = adapter->soft_stats.rx_packets; + netdev->stats.tx_packets = adapter->soft_stats.tx_packets; + netdev->stats.rx_bytes = adapter->soft_stats.rx_bytes; + netdev->stats.tx_bytes = adapter->soft_stats.tx_bytes; + netdev->stats.multicast = adapter->soft_stats.multicast; + netdev->stats.collisions = adapter->soft_stats.collisions; + netdev->stats.rx_errors = adapter->soft_stats.rx_errors; + netdev->stats.rx_over_errors = adapter->soft_stats.rx_missed_errors; - adapter->net_stats.rx_length_errors = + netdev->stats.rx_length_errors = adapter->soft_stats.rx_length_errors; - adapter->net_stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors; - adapter->net_stats.rx_frame_errors = + netdev->stats.rx_crc_errors = adapter->soft_stats.rx_crc_errors; + netdev->stats.rx_frame_errors = adapter->soft_stats.rx_frame_errors; - adapter->net_stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors; - adapter->net_stats.rx_missed_errors = + netdev->stats.rx_fifo_errors = adapter->soft_stats.rx_fifo_errors; + netdev->stats.rx_missed_errors = adapter->soft_stats.rx_missed_errors; - adapter->net_stats.tx_errors = adapter->soft_stats.tx_errors; - adapter->net_stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors; - adapter->net_stats.tx_aborted_errors = + netdev->stats.tx_errors = adapter->soft_stats.tx_errors; + netdev->stats.tx_fifo_errors = adapter->soft_stats.tx_fifo_errors; + netdev->stats.tx_aborted_errors = adapter->soft_stats.tx_aborted_errors; - adapter->net_stats.tx_window_errors = + netdev->stats.tx_window_errors = adapter->soft_stats.tx_window_errors; - adapter->net_stats.tx_carrier_errors = + netdev->stats.tx_carrier_errors = adapter->soft_stats.tx_carrier_errors; } @@ -1860,7 +1862,7 @@ static u16 atl1_alloc_rx_buffers(struct atl1_adapter *adapter) adapter->rx_buffer_len + NET_IP_ALIGN); if (unlikely(!skb)) { /* Better luck next round */ - adapter->net_stats.rx_dropped++; + adapter->netdev->stats.rx_dropped++; break; } @@ -2026,8 +2028,6 @@ rrd_ok: buffer_info->skb = NULL; buffer_info->alloced = 0; rrd->xsz.valid = 0; - - adapter->netdev->last_rx = jiffies; } atomic_set(&rrd_ring->next_to_clean, rrd_next_to_clean); @@ -2524,17 +2524,6 @@ static irqreturn_t atl1_intr(int irq, void *data) return IRQ_HANDLED; } -/* - * atl1_watchdog - Timer Call-back - * @data: pointer to netdev cast into an unsigned long - */ -static void atl1_watchdog(unsigned long data) -{ - struct atl1_adapter *adapter = (struct atl1_adapter *)data; - - /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); -} /* * atl1_phy_config - Timer Call-back @@ -2607,7 +2596,6 @@ static s32 atl1_up(struct atl1_adapter *adapter) if (unlikely(err)) goto err_up; - mod_timer(&adapter->watchdog_timer, jiffies); atlx_irq_enable(adapter); atl1_check_link(adapter); netif_start_queue(netdev); @@ -2625,7 +2613,6 @@ static void atl1_down(struct atl1_adapter *adapter) struct net_device *netdev = adapter->netdev; netif_stop_queue(netdev); - del_timer_sync(&adapter->watchdog_timer); del_timer_sync(&adapter->phy_config_timer); adapter->phy_timer_pending = false; @@ -2893,6 +2880,22 @@ static void atl1_poll_controller(struct net_device *netdev) } #endif +static const struct net_device_ops atl1_netdev_ops = { + .ndo_open = atl1_open, + .ndo_stop = atl1_close, + .ndo_start_xmit = atl1_xmit_frame, + .ndo_set_multicast_list = atlx_set_multi, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = atl1_set_mac, + .ndo_change_mtu = atl1_change_mtu, + .ndo_do_ioctl = atlx_ioctl, + .ndo_tx_timeout = atlx_tx_timeout, + .ndo_vlan_rx_register = atlx_vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = atl1_poll_controller, +#endif +}; + /* * atl1_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -2980,20 +2983,8 @@ static int __devinit atl1_probe(struct pci_dev *pdev, adapter->mii.phy_id_mask = 0x1f; adapter->mii.reg_num_mask = 0x1f; - netdev->open = &atl1_open; - netdev->stop = &atl1_close; - netdev->hard_start_xmit = &atl1_xmit_frame; - netdev->get_stats = &atlx_get_stats; - netdev->set_multicast_list = &atlx_set_multi; - netdev->set_mac_address = &atl1_set_mac; - netdev->change_mtu = &atl1_change_mtu; - netdev->do_ioctl = &atlx_ioctl; - netdev->tx_timeout = &atlx_tx_timeout; + netdev->netdev_ops = &atl1_netdev_ops; netdev->watchdog_timeo = 5 * HZ; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = atl1_poll_controller; -#endif - netdev->vlan_rx_register = atlx_vlan_rx_register; netdev->ethtool_ops = &atl1_ethtool_ops; adapter->bd_number = cards_found; @@ -3049,13 +3040,8 @@ static int __devinit atl1_probe(struct pci_dev *pdev, netif_carrier_off(netdev); netif_stop_queue(netdev); - init_timer(&adapter->watchdog_timer); - adapter->watchdog_timer.function = &atl1_watchdog; - adapter->watchdog_timer.data = (unsigned long)adapter; - - init_timer(&adapter->phy_config_timer); - adapter->phy_config_timer.function = &atl1_phy_config; - adapter->phy_config_timer.data = (unsigned long)adapter; + setup_timer(&adapter->phy_config_timer, &atl1_phy_config, + (unsigned long)adapter); adapter->phy_timer_pending = false; INIT_WORK(&adapter->tx_timeout_task, atl1_tx_timeout_task); @@ -3173,8 +3159,6 @@ static struct atl1_stats atl1_gstrings_stats[] = { {"tx_bytes", ATL1_STAT(soft_stats.tx_bytes)}, {"rx_errors", ATL1_STAT(soft_stats.rx_errors)}, {"tx_errors", ATL1_STAT(soft_stats.tx_errors)}, - {"rx_dropped", ATL1_STAT(net_stats.rx_dropped)}, - {"tx_dropped", ATL1_STAT(net_stats.tx_dropped)}, {"multicast", ATL1_STAT(soft_stats.multicast)}, {"collisions", ATL1_STAT(soft_stats.collisions)}, {"rx_length_errors", ATL1_STAT(soft_stats.rx_length_errors)}, diff --git a/drivers/net/atlx/atl1.h b/drivers/net/atlx/atl1.h index ffa73fc8d95e6eca471ee18ec73986653bb492b3..146372fd66832843996b05216dd70d1e1d612c85 100644 --- a/drivers/net/atlx/atl1.h +++ b/drivers/net/atlx/atl1.h @@ -754,7 +754,7 @@ struct atl1_hw { struct atl1_adapter { struct net_device *netdev; struct pci_dev *pdev; - struct net_device_stats net_stats; + struct atl1_sft_stats soft_stats; struct vlan_group *vlgrp; u32 rx_buffer_len; @@ -765,7 +765,7 @@ struct atl1_adapter { struct work_struct tx_timeout_task; struct work_struct link_chg_task; struct work_struct pcie_dma_to_rst_task; - struct timer_list watchdog_timer; + struct timer_list phy_config_timer; bool phy_timer_pending; diff --git a/drivers/net/atlx/atl2.c b/drivers/net/atlx/atl2.c index 8571e8c0bc67b9973e16a8a85aa92b00049faed6..bc394491b63bb45397bc15df3d058987c0bec0d6 100644 --- a/drivers/net/atlx/atl2.c +++ b/drivers/net/atlx/atl2.c @@ -418,7 +418,7 @@ static void atl2_intr_rx(struct atl2_adapter *adapter) * Check that some rx space is free. If not, * free one and mark stats->rx_dropped++. */ - adapter->net_stats.rx_dropped++; + netdev->stats.rx_dropped++; break; } skb_reserve(skb, NET_IP_ALIGN); @@ -435,20 +435,19 @@ static void atl2_intr_rx(struct atl2_adapter *adapter) } else #endif netif_rx(skb); - adapter->net_stats.rx_bytes += rx_size; - adapter->net_stats.rx_packets++; - netdev->last_rx = jiffies; + netdev->stats.rx_bytes += rx_size; + netdev->stats.rx_packets++; } else { - adapter->net_stats.rx_errors++; + netdev->stats.rx_errors++; if (rxd->status.ok && rxd->status.pkt_size <= 60) - adapter->net_stats.rx_length_errors++; + netdev->stats.rx_length_errors++; if (rxd->status.mcast) - adapter->net_stats.multicast++; + netdev->stats.multicast++; if (rxd->status.crc) - adapter->net_stats.rx_crc_errors++; + netdev->stats.rx_crc_errors++; if (rxd->status.align) - adapter->net_stats.rx_frame_errors++; + netdev->stats.rx_frame_errors++; } /* advance write ptr */ @@ -463,6 +462,7 @@ static void atl2_intr_rx(struct atl2_adapter *adapter) static void atl2_intr_tx(struct atl2_adapter *adapter) { + struct net_device *netdev = adapter->netdev; u32 txd_read_ptr; u32 txs_write_ptr; struct tx_pkt_status *txs; @@ -522,20 +522,20 @@ static void atl2_intr_tx(struct atl2_adapter *adapter) /* tx statistics: */ if (txs->ok) { - adapter->net_stats.tx_bytes += txs->pkt_size; - adapter->net_stats.tx_packets++; + netdev->stats.tx_bytes += txs->pkt_size; + netdev->stats.tx_packets++; } else - adapter->net_stats.tx_errors++; + netdev->stats.tx_errors++; if (txs->defer) - adapter->net_stats.collisions++; + netdev->stats.collisions++; if (txs->abort_col) - adapter->net_stats.tx_aborted_errors++; + netdev->stats.tx_aborted_errors++; if (txs->late_col) - adapter->net_stats.tx_window_errors++; + netdev->stats.tx_window_errors++; if (txs->underun) - adapter->net_stats.tx_fifo_errors++; + netdev->stats.tx_fifo_errors++; } while (1); if (free_hole) { @@ -621,7 +621,7 @@ static irqreturn_t atl2_intr(int irq, void *data) /* link event */ if (status & (ISR_PHY | ISR_MANUAL)) { - adapter->net_stats.tx_carrier_errors++; + adapter->netdev->stats.tx_carrier_errors++; atl2_check_for_link(adapter); } @@ -644,7 +644,6 @@ static int atl2_request_irq(struct atl2_adapter *adapter) int flags, err = 0; flags = IRQF_SHARED; -#ifdef CONFIG_PCI_MSI adapter->have_msi = true; err = pci_enable_msi(adapter->pdev); if (err) @@ -652,7 +651,6 @@ static int atl2_request_irq(struct atl2_adapter *adapter) if (adapter->have_msi) flags &= ~IRQF_SHARED; -#endif return request_irq(adapter->pdev->irq, &atl2_intr, flags, netdev->name, netdev); @@ -723,7 +721,7 @@ static int atl2_open(struct net_device *netdev) clear_bit(__ATL2_DOWN, &adapter->flags); - mod_timer(&adapter->watchdog_timer, jiffies + 4*HZ); + mod_timer(&adapter->watchdog_timer, round_jiffies(jiffies + 4*HZ)); val = ATL2_READ_REG(&adapter->hw, REG_MASTER_CTRL); ATL2_WRITE_REG(&adapter->hw, REG_MASTER_CTRL, @@ -899,19 +897,6 @@ static int atl2_xmit_frame(struct sk_buff *skb, struct net_device *netdev) return NETDEV_TX_OK; } -/* - * atl2_get_stats - Get System Network Statistics - * @netdev: network interface device structure - * - * Returns the address of the device statistics structure. - * The statistics are actually updated from the timer callback. - */ -static struct net_device_stats *atl2_get_stats(struct net_device *netdev) -{ - struct atl2_adapter *adapter = netdev_priv(netdev); - return &adapter->net_stats; -} - /* * atl2_change_mtu - Change the Maximum Transfer Unit * @netdev: network interface device structure @@ -1050,18 +1035,21 @@ static void atl2_tx_timeout(struct net_device *netdev) static void atl2_watchdog(unsigned long data) { struct atl2_adapter *adapter = (struct atl2_adapter *) data; - u32 drop_rxd, drop_rxs; - unsigned long flags; if (!test_bit(__ATL2_DOWN, &adapter->flags)) { + u32 drop_rxd, drop_rxs; + unsigned long flags; + spin_lock_irqsave(&adapter->stats_lock, flags); drop_rxd = ATL2_READ_REG(&adapter->hw, REG_STS_RXD_OV); drop_rxs = ATL2_READ_REG(&adapter->hw, REG_STS_RXS_OV); - adapter->net_stats.rx_over_errors += (drop_rxd+drop_rxs); spin_unlock_irqrestore(&adapter->stats_lock, flags); + adapter->netdev->stats.rx_over_errors += drop_rxd + drop_rxs; + /* Reset the timer */ - mod_timer(&adapter->watchdog_timer, jiffies + 4 * HZ); + mod_timer(&adapter->watchdog_timer, + round_jiffies(jiffies + 4 * HZ)); } } @@ -1265,7 +1253,8 @@ static int atl2_check_link(struct atl2_adapter *adapter) * (if interval smaller than 5 seconds, something strange) */ if (!test_bit(__ATL2_DOWN, &adapter->flags)) { if (!test_and_set_bit(0, &adapter->cfg_phy)) - mod_timer(&adapter->phy_config_timer, jiffies + 5 * HZ); + mod_timer(&adapter->phy_config_timer, + round_jiffies(jiffies + 5 * HZ)); } return 0; @@ -1320,6 +1309,23 @@ static void atl2_poll_controller(struct net_device *netdev) } #endif + +static const struct net_device_ops atl2_netdev_ops = { + .ndo_open = atl2_open, + .ndo_stop = atl2_close, + .ndo_start_xmit = atl2_xmit_frame, + .ndo_set_multicast_list = atl2_set_multi, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = atl2_set_mac, + .ndo_change_mtu = atl2_change_mtu, + .ndo_do_ioctl = atl2_ioctl, + .ndo_tx_timeout = atl2_tx_timeout, + .ndo_vlan_rx_register = atl2_vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = atl2_poll_controller, +#endif +}; + /* * atl2_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -1393,26 +1399,9 @@ static int __devinit atl2_probe(struct pci_dev *pdev, atl2_setup_pcicmd(pdev); - netdev->open = &atl2_open; - netdev->stop = &atl2_close; - netdev->hard_start_xmit = &atl2_xmit_frame; - netdev->get_stats = &atl2_get_stats; - netdev->set_multicast_list = &atl2_set_multi; - netdev->set_mac_address = &atl2_set_mac; - netdev->change_mtu = &atl2_change_mtu; - netdev->do_ioctl = &atl2_ioctl; + netdev->netdev_ops = &atl2_netdev_ops; atl2_set_ethtool_ops(netdev); - -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = atl2_poll_controller; -#endif -#ifdef HAVE_TX_TIMEOUT - netdev->tx_timeout = &atl2_tx_timeout; netdev->watchdog_timeo = 5 * HZ; -#endif -#ifdef NETIF_F_HW_VLAN_TX - netdev->vlan_rx_register = atl2_vlan_rx_register; -#endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); netdev->mem_start = mmio_start; diff --git a/drivers/net/atlx/atl2.h b/drivers/net/atlx/atl2.h index 09974df76b1865d138d0ebac05319e3e8d7692cd..d918bbe621eae3d9e44dc1ad141fad8019a6f7fe 100644 --- a/drivers/net/atlx/atl2.h +++ b/drivers/net/atlx/atl2.h @@ -453,7 +453,6 @@ struct atl2_adapter { /* OS defined structs */ struct net_device *netdev; struct pci_dev *pdev; - struct net_device_stats net_stats; #ifdef NETIF_F_HW_VLAN_TX struct vlan_group *vlgrp; #endif diff --git a/drivers/net/atlx/atlx.c b/drivers/net/atlx/atlx.c index 3cc9d1089ca15b2c40ec80a88c124fe391116451..3dc01421567961450b6503f3bb2a98662bea2f07 100644 --- a/drivers/net/atlx/atlx.c +++ b/drivers/net/atlx/atlx.c @@ -181,19 +181,6 @@ static void atlx_clear_phy_int(struct atlx_adapter *adapter) spin_unlock_irqrestore(&adapter->lock, flags); } -/* - * atlx_get_stats - Get System Network Statistics - * @netdev: network interface device structure - * - * Returns the address of the device statistics structure. - * The statistics are actually updated from the timer callback. - */ -static struct net_device_stats *atlx_get_stats(struct net_device *netdev) -{ - struct atlx_adapter *adapter = netdev_priv(netdev); - return &adapter->net_stats; -} - /* * atlx_tx_timeout - Respond to a Tx Hang * @netdev: network interface device structure diff --git a/drivers/net/atp.c b/drivers/net/atp.c index c10cd8058e2303da73054ce892d52878123d225c..ea493ce23982abeb362f0d31618f4028495b9730 100644 --- a/drivers/net/atp.c +++ b/drivers/net/atp.c @@ -248,7 +248,6 @@ static int __init atp_probe1(long ioaddr) struct net_local *lp; int saved_ctrl_reg, status, i; int res; - DECLARE_MAC_BUF(mac); outb(0xff, ioaddr + PAR_DATA); /* Save the original value of the Control register, in case we guessed @@ -324,8 +323,8 @@ static int __init atp_probe1(long ioaddr) #endif printk(KERN_NOTICE "%s: Pocket adapter found at %#3lx, IRQ %d, " - "SAPROM %s.\n", - dev->name, dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr)); + "SAPROM %pM.\n", + dev->name, dev->base_addr, dev->irq, dev->dev_addr); /* Reset the ethernet hardware and activate the printer pass-through. */ write_reg_high(ioaddr, CMR1, CMR1h_RESET | CMR1h_MUX); @@ -421,7 +420,7 @@ static unsigned short __init eeprom_op(long ioaddr, u32 cmd) registers that "should" only need to be set once at boot, so that there is non-reboot way to recover if something goes wrong. - This is an attachable device: if there is no dev->priv entry then it wasn't + This is an attachable device: if there is no private entry then it wasn't probed for at boot-time, and we need to probe for it again. */ static int net_open(struct net_device *dev) @@ -803,21 +802,22 @@ static void net_rx(struct net_device *dev) static void read_block(long ioaddr, int length, unsigned char *p, int data_mode) { - if (data_mode <= 3) { /* Mode 0 or 1 */ outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); outb(length == 8 ? RdAddr | HNib | MAR : RdAddr | MAR, ioaddr + PAR_DATA); if (data_mode <= 1) { /* Mode 0 or 1 */ - do *p++ = read_byte_mode0(ioaddr); while (--length > 0); - } else /* Mode 2 or 3 */ - do *p++ = read_byte_mode2(ioaddr); while (--length > 0); - } else if (data_mode <= 5) - do *p++ = read_byte_mode4(ioaddr); while (--length > 0); - else - do *p++ = read_byte_mode6(ioaddr); while (--length > 0); + do { *p++ = read_byte_mode0(ioaddr); } while (--length > 0); + } else { /* Mode 2 or 3 */ + do { *p++ = read_byte_mode2(ioaddr); } while (--length > 0); + } + } else if (data_mode <= 5) { + do { *p++ = read_byte_mode4(ioaddr); } while (--length > 0); + } else { + do { *p++ = read_byte_mode6(ioaddr); } while (--length > 0); + } - outb(EOC+HNib+MAR, ioaddr + PAR_DATA); + outb(EOC+HNib+MAR, ioaddr + PAR_DATA); outb(Ctrl_SelData, ioaddr + PAR_CONTROL); } @@ -913,7 +913,8 @@ static void __exit atp_cleanup_module(void) { struct net_device *next_dev; while (root_atp_dev) { - next_dev = ((struct net_local *)root_atp_dev->priv)->next_module; + struct net_local *atp_local = netdev_priv(root_atp_dev); + next_dev = atp_local->next_module; unregister_netdev(root_atp_dev); /* No need to release_region(), since we never snarf it. */ free_netdev(root_atp_dev); diff --git a/drivers/net/au1000_eth.c b/drivers/net/au1000_eth.c index 019b13c08ae6ead71f5a0b976b1e087a3df87df7..9c875bb3f76c642f93203f9096942af72a0e3e53 100644 --- a/drivers/net/au1000_eth.c +++ b/drivers/net/au1000_eth.c @@ -193,7 +193,7 @@ struct au1000_private *au_macs[NUM_ETH_INTERFACES]; */ static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); volatile u32 *const mii_control_reg = &aup->mac->mii_control; volatile u32 *const mii_data_reg = &aup->mac->mii_data; u32 timedout = 20; @@ -228,7 +228,7 @@ static int au1000_mdio_read(struct net_device *dev, int phy_addr, int reg) static void au1000_mdio_write(struct net_device *dev, int phy_addr, int reg, u16 value) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); volatile u32 *const mii_control_reg = &aup->mac->mii_control; volatile u32 *const mii_data_reg = &aup->mac->mii_data; u32 timedout = 20; @@ -283,7 +283,7 @@ static int au1000_mdiobus_reset(struct mii_bus *bus) static int mii_probe (struct net_device *dev) { - struct au1000_private *const aup = (struct au1000_private *) dev->priv; + struct au1000_private *const aup = netdev_priv(dev); struct phy_device *phydev = NULL; #if defined(AU1XXX_PHY_STATIC_CONFIG) @@ -353,7 +353,6 @@ static int mii_probe (struct net_device *dev) } /* now we are supposed to have a proper phydev, to attach to... */ - BUG_ON(!phydev); BUG_ON(phydev->attached_dev); phydev = phy_connect(dev, phydev->dev.bus_id, &au1000_adjust_link, 0, @@ -415,7 +414,7 @@ void ReleaseDB(struct au1000_private *aup, db_dest_t *pDB) static void enable_rx_tx(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (au1000_debug > 4) printk(KERN_INFO "%s: enable_rx_tx\n", dev->name); @@ -426,7 +425,7 @@ static void enable_rx_tx(struct net_device *dev) static void hard_stop(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (au1000_debug > 4) printk(KERN_INFO "%s: hard stop\n", dev->name); @@ -438,7 +437,7 @@ static void hard_stop(struct net_device *dev) static void enable_mac(struct net_device *dev, int force_reset) { unsigned long flags; - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); spin_lock_irqsave(&aup->lock, flags); @@ -457,7 +456,7 @@ static void enable_mac(struct net_device *dev, int force_reset) static void reset_mac_unlocked(struct net_device *dev) { - struct au1000_private *const aup = (struct au1000_private *) dev->priv; + struct au1000_private *const aup = netdev_priv(dev); int i; hard_stop(dev); @@ -483,7 +482,7 @@ static void reset_mac_unlocked(struct net_device *dev) static void reset_mac(struct net_device *dev) { - struct au1000_private *const aup = (struct au1000_private *) dev->priv; + struct au1000_private *const aup = netdev_priv(dev); unsigned long flags; if (au1000_debug > 4) @@ -572,7 +571,7 @@ static int __init au1000_init_module(void) static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct au1000_private *aup = (struct au1000_private *)dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (aup->phy_dev) return phy_ethtool_gset(aup->phy_dev, cmd); @@ -582,7 +581,7 @@ static int au1000_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct au1000_private *aup = (struct au1000_private *)dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (!capable(CAP_NET_ADMIN)) return -EPERM; @@ -596,7 +595,7 @@ static int au1000_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static void au1000_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct au1000_private *aup = (struct au1000_private *)dev->priv; + struct au1000_private *aup = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -652,7 +651,7 @@ static struct net_device * au1000_probe(int port_num) printk("%s: Au1xx0 Ethernet found at 0x%x, irq %d\n", dev->name, base, irq); - aup = dev->priv; + aup = netdev_priv(dev); spin_lock_init(&aup->lock); @@ -817,7 +816,7 @@ err_out: */ static int au1000_init(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); unsigned long flags; int i; u32 control; @@ -868,7 +867,7 @@ static int au1000_init(struct net_device *dev) static void au1000_adjust_link(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); struct phy_device *phydev = aup->phy_dev; unsigned long flags; @@ -947,7 +946,7 @@ au1000_adjust_link(struct net_device *dev) static int au1000_open(struct net_device *dev) { int retval; - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (au1000_debug > 4) printk("%s: open: dev=%p\n", dev->name, dev); @@ -982,7 +981,7 @@ static int au1000_open(struct net_device *dev) static int au1000_close(struct net_device *dev) { unsigned long flags; - struct au1000_private *const aup = (struct au1000_private *) dev->priv; + struct au1000_private *const aup = netdev_priv(dev); if (au1000_debug > 4) printk("%s: close: dev=%p\n", dev->name, dev); @@ -1013,7 +1012,7 @@ static void __exit au1000_cleanup_module(void) for (i = 0; i < num_ifs; i++) { dev = iflist[i].dev; if (dev) { - aup = (struct au1000_private *) dev->priv; + aup = netdev_priv(dev); unregister_netdev(dev); mdiobus_unregister(aup->mii_bus); mdiobus_free(aup->mii_bus); @@ -1035,7 +1034,7 @@ static void __exit au1000_cleanup_module(void) static void update_tx_stats(struct net_device *dev, u32 status) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); struct net_device_stats *ps = &dev->stats; if (status & TX_FRAME_ABORTED) { @@ -1064,7 +1063,7 @@ static void update_tx_stats(struct net_device *dev, u32 status) */ static void au1000_tx_ack(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); volatile tx_dma_t *ptxd; ptxd = aup->tx_dma_ring[aup->tx_tail]; @@ -1091,7 +1090,7 @@ static void au1000_tx_ack(struct net_device *dev) */ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); struct net_device_stats *ps = &dev->stats; volatile tx_dma_t *ptxd; u32 buff_stat; @@ -1145,7 +1144,7 @@ static int au1000_tx(struct sk_buff *skb, struct net_device *dev) static inline void update_rx_stats(struct net_device *dev, u32 status) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); struct net_device_stats *ps = &dev->stats; ps->rx_packets++; @@ -1173,7 +1172,7 @@ static inline void update_rx_stats(struct net_device *dev, u32 status) */ static int au1000_rx(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); struct sk_buff *skb; volatile rx_dma_t *prxd; u32 buff_stat, status; @@ -1240,7 +1239,6 @@ static int au1000_rx(struct net_device *dev) /* next descriptor */ prxd = aup->rx_dma_ring[aup->rx_head]; buff_stat = prxd->buff_stat; - dev->last_rx = jiffies; } return 0; } @@ -1276,7 +1274,7 @@ static void au1000_tx_timeout(struct net_device *dev) static void set_rx_mode(struct net_device *dev) { - struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (au1000_debug > 4) printk("%s: set_rx_mode: flags=%x\n", dev->name, dev->flags); @@ -1308,7 +1306,7 @@ static void set_rx_mode(struct net_device *dev) static int au1000_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct au1000_private *aup = (struct au1000_private *)dev->priv; + struct au1000_private *aup = netdev_priv(dev); if (!netif_running(dev)) return -EINVAL; diff --git a/drivers/net/ax88796.c b/drivers/net/ax88796.c index 9a314d88e7b67aa16b74e60c442bc655242d9bf8..337488ec707cfc2aad6b14ae7aec63315510529c 100644 --- a/drivers/net/ax88796.c +++ b/drivers/net/ax88796.c @@ -758,13 +758,10 @@ static int ax_init_dev(struct net_device *dev, int first_init) #endif ax_NS8390_init(dev, 0); - if (first_init) { - DECLARE_MAC_BUF(mac); - - dev_info(&ax->dev->dev, "%dbit, irq %d, %lx, MAC: %s\n", + if (first_init) + dev_info(&ax->dev->dev, "%dbit, irq %d, %lx, MAC: %pM\n", ei_status.word16 ? 16:8, dev->irq, dev->base_addr, - print_mac(mac, dev->dev_addr)); - } + dev->dev_addr); ret = register_netdev(dev); if (ret) diff --git a/drivers/net/b44.c b/drivers/net/b44.c index c3bda5ce67c488dba1fc7f51469f16522c5b1080..0e7470a201f0ec18eb06c860495d5e6022679845 100644 --- a/drivers/net/b44.c +++ b/drivers/net/b44.c @@ -829,7 +829,6 @@ static int b44_rx(struct b44 *bp, int budget) skb->ip_summed = CHECKSUM_NONE; skb->protocol = eth_type_trans(skb, bp->dev); netif_receive_skb(skb); - bp->dev->last_rx = jiffies; received++; budget--; next_pkt: @@ -847,7 +846,6 @@ static int b44_rx(struct b44 *bp, int budget) static int b44_poll(struct napi_struct *napi, int budget) { struct b44 *bp = container_of(napi, struct b44, napi); - struct net_device *netdev = bp->dev; int work_done; spin_lock_irq(&bp->lock); @@ -876,7 +874,7 @@ static int b44_poll(struct napi_struct *napi, int budget) } if (work_done < budget) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); b44_enable_ints(bp); } @@ -908,13 +906,13 @@ static irqreturn_t b44_interrupt(int irq, void *dev_id) goto irq_ack; } - if (netif_rx_schedule_prep(dev, &bp->napi)) { + if (netif_rx_schedule_prep(&bp->napi)) { /* NOTE: These writes are posted by the readback of * the ISTAT register below. */ bp->istat = istat; __b44_disable_ints(bp); - __netif_rx_schedule(dev, &bp->napi); + __netif_rx_schedule(&bp->napi); } else { printk(KERN_ERR PFX "%s: Error, poll already scheduled\n", dev->name); @@ -2117,7 +2115,6 @@ static int __devinit b44_init_one(struct ssb_device *sdev, struct net_device *dev; struct b44 *bp; int err; - DECLARE_MAC_BUF(mac); instance++; @@ -2213,8 +2210,8 @@ static int __devinit b44_init_one(struct ssb_device *sdev, */ b44_chip_reset(bp, B44_CHIP_RESET_FULL); - printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Broadcom 44xx/47xx 10/100BaseT Ethernet %pM\n", + dev->name, dev->dev_addr); return 0; diff --git a/drivers/net/bfin_mac.c b/drivers/net/bfin_mac.c index b458d607a9c669215b48ffa831fe0c86cd4fde88..78e31aa861e020e461336e2323cea4647d7cb9c8 100644 --- a/drivers/net/bfin_mac.c +++ b/drivers/net/bfin_mac.c @@ -741,7 +741,6 @@ static void bfin_mac_rx(struct net_device *dev) blackfin_dcache_invalidate_range((unsigned long)skb->head, (unsigned long)skb->tail); - dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); #if defined(BFIN_MAC_CSUM_OFFLOAD) skb->csum = current_rx_ptr->status.ip_payload_csum; diff --git a/drivers/net/bmac.c b/drivers/net/bmac.c index a42bd19646d371e0ce75245280e446215495258e..8a546a33d58124fb39cf67ff673e305f7a7fd418 100644 --- a/drivers/net/bmac.c +++ b/drivers/net/bmac.c @@ -716,13 +716,11 @@ static irqreturn_t bmac_rxdma_intr(int irq, void *dev_id) skb_put(skb, nb); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; ++dev->stats.rx_packets; dev->stats.rx_bytes += nb; } else { ++dev->stats.rx_dropped; } - dev->last_rx = jiffies; if ((skb = bp->rx_bufs[i]) == NULL) { bp->rx_bufs[i] = skb = dev_alloc_skb(RX_BUFLEN+2); if (skb != NULL) @@ -1258,7 +1256,6 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i unsigned char addr[6]; struct net_device *dev; int is_bmac_plus = ((int)match->data) != 0; - DECLARE_MAC_BUF(mac); if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) { printk(KERN_ERR "BMAC: can't use, need 3 addrs and 3 intrs\n"); @@ -1368,8 +1365,8 @@ static int __devinit bmac_probe(struct macio_dev *mdev, const struct of_device_i goto err_out_irq2; } - printk(KERN_INFO "%s: BMAC%s at %s", - dev->name, (is_bmac_plus ? "+" : ""), print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: BMAC%s at %pM", + dev->name, (is_bmac_plus ? "+" : ""), dev->dev_addr); XXDEBUG((", base_addr=%#0lx", dev->base_addr)); printk("\n"); diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index 9e8222f9e90ee0f69416ffe985103d0f6b183df5..d4a3dac21dcfb83fdc7e6c2835705ac66433ec3c 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c @@ -57,8 +57,8 @@ #define DRV_MODULE_NAME "bnx2" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.8.1" -#define DRV_MODULE_RELDATE "Oct 7, 2008" +#define DRV_MODULE_VERSION "1.9.0" +#define DRV_MODULE_RELDATE "Dec 16, 2008" #define RUN_AT(x) (jiffies + (x)) @@ -89,6 +89,7 @@ typedef enum { BCM5709, BCM5709S, BCM5716, + BCM5716S, } board_t; /* indexed by board_t, above */ @@ -105,6 +106,7 @@ static struct { { "Broadcom NetXtreme II BCM5709 1000Base-T" }, { "Broadcom NetXtreme II BCM5709 1000Base-SX" }, { "Broadcom NetXtreme II BCM5716 1000Base-T" }, + { "Broadcom NetXtreme II BCM5716 1000Base-SX" }, }; static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = { @@ -128,6 +130,8 @@ static DEFINE_PCI_DEVICE_TABLE(bnx2_pci_tbl) = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5709S }, { PCI_VENDOR_ID_BROADCOM, 0x163b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716 }, + { PCI_VENDOR_ID_BROADCOM, 0x163c, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, BCM5716S }, { 0, } }; @@ -1652,7 +1656,7 @@ bnx2_setup_serdes_phy(struct bnx2 *bp, u8 port) * exchanging base pages plus 3 next pages and * normally completes in about 120 msec. */ - bp->current_interval = SERDES_AN_TIMEOUT; + bp->current_interval = BNX2_SERDES_AN_TIMEOUT; bp->serdes_an_pending = 1; mod_timer(&bp->timer, jiffies + bp->current_interval); } else { @@ -2274,7 +2278,7 @@ bnx2_fw_sync(struct bnx2 *bp, u32 msg_data, int ack, int silent) return 0; /* wait for an acknowledgement. */ - for (i = 0; i < (FW_ACK_TIME_OUT_MS / 10); i++) { + for (i = 0; i < (BNX2_FW_ACK_TIME_OUT_MS / 10); i++) { msleep(10); val = bnx2_shmem_rd(bp, BNX2_FW_MB); @@ -3000,7 +3004,6 @@ bnx2_rx_int(struct bnx2 *bp, struct bnx2_napi *bnapi, int budget) #endif netif_receive_skb(skb); - bp->dev->last_rx = jiffies; rx_pkt++; next_rx: @@ -3040,7 +3043,6 @@ bnx2_msi(int irq, void *dev_instance) { struct bnx2_napi *bnapi = dev_instance; struct bnx2 *bp = bnapi->bp; - struct net_device *dev = bp->dev; prefetch(bnapi->status_blk.msi); REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, @@ -3051,7 +3053,7 @@ bnx2_msi(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - netif_rx_schedule(dev, &bnapi->napi); + netif_rx_schedule(&bnapi->napi); return IRQ_HANDLED; } @@ -3061,7 +3063,6 @@ bnx2_msi_1shot(int irq, void *dev_instance) { struct bnx2_napi *bnapi = dev_instance; struct bnx2 *bp = bnapi->bp; - struct net_device *dev = bp->dev; prefetch(bnapi->status_blk.msi); @@ -3069,7 +3070,7 @@ bnx2_msi_1shot(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - netif_rx_schedule(dev, &bnapi->napi); + netif_rx_schedule(&bnapi->napi); return IRQ_HANDLED; } @@ -3079,7 +3080,6 @@ bnx2_interrupt(int irq, void *dev_instance) { struct bnx2_napi *bnapi = dev_instance; struct bnx2 *bp = bnapi->bp; - struct net_device *dev = bp->dev; struct status_block *sblk = bnapi->status_blk.msi; /* When using INTx, it is possible for the interrupt to arrive @@ -3106,9 +3106,9 @@ bnx2_interrupt(int irq, void *dev_instance) if (unlikely(atomic_read(&bp->intr_sem) != 0)) return IRQ_HANDLED; - if (netif_rx_schedule_prep(dev, &bnapi->napi)) { + if (netif_rx_schedule_prep(&bnapi->napi)) { bnapi->last_status_idx = sblk->status_idx; - __netif_rx_schedule(dev, &bnapi->napi); + __netif_rx_schedule(&bnapi->napi); } return IRQ_HANDLED; @@ -3218,7 +3218,7 @@ static int bnx2_poll_msix(struct napi_struct *napi, int budget) rmb(); if (likely(!bnx2_has_fast_work(bnapi))) { - netif_rx_complete(bp->dev, napi); + netif_rx_complete(napi); REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, bnapi->int_num | BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | bnapi->last_status_idx); @@ -3251,7 +3251,7 @@ static int bnx2_poll(struct napi_struct *napi, int budget) rmb(); if (likely(!bnx2_has_work(bnapi))) { - netif_rx_complete(bp->dev, napi); + netif_rx_complete(napi); if (likely(bp->flags & BNX2_FLAG_USING_MSI_OR_MSIX)) { REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | @@ -4493,7 +4493,7 @@ bnx2_reset_chip(struct bnx2 *bp, u32 reset_code) static int bnx2_init_chip(struct bnx2 *bp) { - u32 val; + u32 val, mtu; int rc, i; /* Make sure the interrupt is not active. */ @@ -4585,11 +4585,19 @@ bnx2_init_chip(struct bnx2 *bp) REG_WR(bp, BNX2_EMAC_BACKOFF_SEED, val); /* Program the MTU. Also include 4 bytes for CRC32. */ - val = bp->dev->mtu + ETH_HLEN + 4; + mtu = bp->dev->mtu; + val = mtu + ETH_HLEN + ETH_FCS_LEN; if (val > (MAX_ETHERNET_PACKET_SIZE + 4)) val |= BNX2_EMAC_RX_MTU_SIZE_JUMBO_ENA; REG_WR(bp, BNX2_EMAC_RX_MTU_SIZE, val); + if (mtu < 1500) + mtu = 1500; + + bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG, BNX2_RBUF_CONFIG_VAL(mtu)); + bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG2, BNX2_RBUF_CONFIG2_VAL(mtu)); + bnx2_reg_wr_ind(bp, BNX2_RBUF_CONFIG3, BNX2_RBUF_CONFIG3_VAL(mtu)); + for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) bp->bnx2_napi[i].last_status_idx = 0; @@ -5719,7 +5727,7 @@ bnx2_5708_serdes_timer(struct bnx2 *bp) bnx2_read_phy(bp, bp->mii_bmcr, &bmcr); if (bmcr & BMCR_ANENABLE) { bnx2_enable_forced_2g5(bp); - bp->current_interval = SERDES_FORCED_TIMEOUT; + bp->current_interval = BNX2_SERDES_FORCED_TIMEOUT; } else { bnx2_disable_forced_2g5(bp); bp->serdes_an_pending = 2; @@ -5816,6 +5824,8 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs) { int i, rc; struct msix_entry msix_ent[BNX2_MAX_MSIX_VEC]; + struct net_device *dev = bp->dev; + const int len = sizeof(bp->irq_tbl[0].name); bnx2_setup_msix_tbl(bp); REG_WR(bp, BNX2_PCI_MSIX_CONTROL, BNX2_MAX_MSIX_HW_VEC - 1); @@ -5826,7 +5836,7 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs) msix_ent[i].entry = i; msix_ent[i].vector = 0; - strcpy(bp->irq_tbl[i].name, bp->dev->name); + snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i); bp->irq_tbl[i].handler = bnx2_msi_1shot; } @@ -6173,7 +6183,7 @@ bnx2_get_stats(struct net_device *dev) { struct bnx2 *bp = netdev_priv(dev); struct statistics_block *stats_blk = bp->stats_blk; - struct net_device_stats *net_stats = &bp->net_stats; + struct net_device_stats *net_stats = &dev->stats; if (bp->stats_blk == NULL) { return net_stats; @@ -6540,7 +6550,7 @@ bnx2_nway_reset(struct net_device *dev) spin_lock_bh(&bp->phy_lock); - bp->current_interval = SERDES_AN_TIMEOUT; + bp->current_interval = BNX2_SERDES_AN_TIMEOUT; bp->serdes_an_pending = 1; mod_timer(&bp->timer, jiffies + bp->current_interval); } @@ -7615,7 +7625,8 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev) if ((CHIP_ID(bp) == CHIP_ID_5708_A0) || (CHIP_ID(bp) == CHIP_ID_5708_B0) || - (CHIP_ID(bp) == CHIP_ID_5708_B1)) { + (CHIP_ID(bp) == CHIP_ID_5708_B1) || + !(REG_RD(bp, BNX2_PCI_CONFIG_3) & BNX2_PCI_CONFIG_3_VAUX_PRESET)) { bp->flags |= BNX2_FLAG_NO_WOL; bp->wol = 0; } @@ -7724,6 +7735,25 @@ bnx2_init_napi(struct bnx2 *bp) } } +static const struct net_device_ops bnx2_netdev_ops = { + .ndo_open = bnx2_open, + .ndo_start_xmit = bnx2_start_xmit, + .ndo_stop = bnx2_close, + .ndo_get_stats = bnx2_get_stats, + .ndo_set_rx_mode = bnx2_set_rx_mode, + .ndo_do_ioctl = bnx2_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = bnx2_change_mac_addr, + .ndo_change_mtu = bnx2_change_mtu, + .ndo_tx_timeout = bnx2_tx_timeout, +#ifdef BCM_VLAN + .ndo_vlan_rx_register = bnx2_vlan_rx_register, +#endif +#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) + .ndo_poll_controller = poll_bnx2, +#endif +}; + static int __devinit bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -7732,7 +7762,6 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct bnx2 *bp; int rc; char str[40]; - DECLARE_MAC_BUF(mac); if (version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -7749,28 +7778,13 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) return rc; } - dev->open = bnx2_open; - dev->hard_start_xmit = bnx2_start_xmit; - dev->stop = bnx2_close; - dev->get_stats = bnx2_get_stats; - dev->set_rx_mode = bnx2_set_rx_mode; - dev->do_ioctl = bnx2_ioctl; - dev->set_mac_address = bnx2_change_mac_addr; - dev->change_mtu = bnx2_change_mtu; - dev->tx_timeout = bnx2_tx_timeout; + dev->netdev_ops = &bnx2_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef BCM_VLAN - dev->vlan_rx_register = bnx2_vlan_rx_register; -#endif dev->ethtool_ops = &bnx2_ethtool_ops; bp = netdev_priv(dev); bnx2_init_napi(bp); -#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) - dev->poll_controller = poll_bnx2; -#endif - pci_set_drvdata(pdev, dev); memcpy(dev->dev_addr, bp->mac_addr, 6); @@ -7799,14 +7813,14 @@ bnx2_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } printk(KERN_INFO "%s: %s (%c%d) %s found at mem %lx, " - "IRQ %d, node addr %s\n", + "IRQ %d, node addr %pM\n", dev->name, board_info[ent->driver_data].name, ((CHIP_ID(bp) & 0xf000) >> 12) + 'A', ((CHIP_ID(bp) & 0x0ff0) >> 4), bnx2_bus_string(bp, str), dev->base_addr, - bp->pdev->irq, print_mac(mac, dev->dev_addr)); + bp->pdev->irq, dev->dev_addr); return 0; } diff --git a/drivers/net/bnx2.h b/drivers/net/bnx2.h index 0b032c3c7b611c17cee29b12a62809839a1dae2b..900641ac63e04d4678d7f779fc4f0481e0b138af 100644 --- a/drivers/net/bnx2.h +++ b/drivers/net/bnx2.h @@ -4202,7 +4202,14 @@ struct l2_fhdr { #define BNX2_RBUF_CONFIG 0x0020000c #define BNX2_RBUF_CONFIG_XOFF_TRIP (0x3ffL<<0) +#define BNX2_RBUF_CONFIG_XOFF_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 31 / 1000) + 54) #define BNX2_RBUF_CONFIG_XON_TRIP (0x3ffL<<16) +#define BNX2_RBUF_CONFIG_XON_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 39 / 1000) + 66) +#define BNX2_RBUF_CONFIG_VAL(mtu) \ + (BNX2_RBUF_CONFIG_XOFF_TRIP_VAL(mtu) | \ + (BNX2_RBUF_CONFIG_XON_TRIP_VAL(mtu) << 16)) #define BNX2_RBUF_FW_BUF_ALLOC 0x00200010 #define BNX2_RBUF_FW_BUF_ALLOC_VALUE (0x1ffL<<7) @@ -4224,11 +4231,25 @@ struct l2_fhdr { #define BNX2_RBUF_CONFIG2 0x0020001c #define BNX2_RBUF_CONFIG2_MAC_DROP_TRIP (0x3ffL<<0) +#define BNX2_RBUF_CONFIG2_MAC_DROP_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 4 / 1000) + 5) #define BNX2_RBUF_CONFIG2_MAC_KEEP_TRIP (0x3ffL<<16) +#define BNX2_RBUF_CONFIG2_MAC_KEEP_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 2 / 100) + 30) +#define BNX2_RBUF_CONFIG2_VAL(mtu) \ + (BNX2_RBUF_CONFIG2_MAC_DROP_TRIP_VAL(mtu) | \ + (BNX2_RBUF_CONFIG2_MAC_KEEP_TRIP_VAL(mtu) << 16)) #define BNX2_RBUF_CONFIG3 0x00200020 #define BNX2_RBUF_CONFIG3_CU_DROP_TRIP (0x3ffL<<0) +#define BNX2_RBUF_CONFIG3_CU_DROP_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 12 / 1000) + 18) #define BNX2_RBUF_CONFIG3_CU_KEEP_TRIP (0x3ffL<<16) +#define BNX2_RBUF_CONFIG3_CU_KEEP_TRIP_VAL(mtu) \ + ((((mtu) - 1500) * 2 / 100) + 30) +#define BNX2_RBUF_CONFIG3_VAL(mtu) \ + (BNX2_RBUF_CONFIG3_CU_DROP_TRIP_VAL(mtu) | \ + (BNX2_RBUF_CONFIG3_CU_KEEP_TRIP_VAL(mtu) << 16)) #define BNX2_RBUF_PKT_DATA 0x00208000 #define BNX2_RBUF_CLIST_DATA 0x00210000 @@ -6606,7 +6627,7 @@ struct bnx2_irq { irq_handler_t handler; unsigned int vector; u8 requested; - char name[16]; + char name[IFNAMSIZ + 2]; }; struct bnx2_tx_ring_info { @@ -6661,8 +6682,6 @@ struct bnx2_napi { struct bnx2_tx_ring_info tx_ring; }; -#define BNX2_TIMER_INTERVAL HZ - struct bnx2 { /* Fields used in the tx and intr/napi performance paths are grouped */ /* together in the beginning of the structure. */ @@ -6710,7 +6729,11 @@ struct bnx2 { /* End of fields used in the performance code paths. */ - int current_interval; + unsigned int current_interval; +#define BNX2_TIMER_INTERVAL HZ +#define BNX2_SERDES_AN_TIMEOUT (HZ / 3) +#define BNX2_SERDES_FORCED_TIMEOUT (HZ / 10) + struct timer_list timer; struct work_struct reset_task; @@ -6825,9 +6848,6 @@ struct bnx2 { u8 flow_ctrl; /* actual flow ctrl settings */ /* may be different from */ /* req_flow_ctrl if autoneg */ -#define FLOW_CTRL_TX 1 -#define FLOW_CTRL_RX 2 - u32 advertising; u8 req_flow_ctrl; /* flow ctrl advertisement */ @@ -6842,8 +6862,6 @@ struct bnx2 { #define PHY_LOOPBACK 2 u8 serdes_an_pending; -#define SERDES_AN_TIMEOUT (HZ / 3) -#define SERDES_FORCED_TIMEOUT (HZ / 10) u8 mac_addr[8]; @@ -6854,8 +6872,6 @@ struct bnx2 { int pm_cap; int pcix_cap; - struct net_device_stats net_stats; - struct flash_spec *flash_info; u32 flash_size; @@ -6944,14 +6960,14 @@ struct fw_info { /* This value (in milliseconds) determines the frequency of the driver * issuing the PULSE message code. The firmware monitors this periodic * pulse to determine when to switch to an OS-absent mode. */ -#define DRV_PULSE_PERIOD_MS 250 +#define BNX2_DRV_PULSE_PERIOD_MS 250 /* This value (in milliseconds) determines how long the driver should * wait for an acknowledgement from the firmware before timing out. Once * the firmware has timed out, the driver will assume there is no firmware * running and there won't be any firmware-driver synchronization during a * driver reset. */ -#define FW_ACK_TIME_OUT_MS 1000 +#define BNX2_FW_ACK_TIME_OUT_MS 1000 #define BNX2_DRV_RESET_SIGNATURE 0x00000000 diff --git a/drivers/net/bnx2x_link.c b/drivers/net/bnx2x_link.c index 4ce7fe9c5251143745985b70cb449df9f394edfd..67de94f1f30e10c38beee7cfc0e3bdf2a5715962 100644 --- a/drivers/net/bnx2x_link.c +++ b/drivers/net/bnx2x_link.c @@ -289,7 +289,7 @@ static u8 bnx2x_emac_enable(struct link_params *params, /* pause enable/disable */ bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_RX_MODE, EMAC_RX_MODE_FLOW_EN); - if (vars->flow_ctrl & FLOW_CTRL_RX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_RX_MODE, EMAC_RX_MODE_FLOW_EN); @@ -297,7 +297,7 @@ static u8 bnx2x_emac_enable(struct link_params *params, bnx2x_bits_dis(bp, emac_base + EMAC_REG_EMAC_TX_MODE, (EMAC_TX_MODE_EXT_PAUSE_EN | EMAC_TX_MODE_FLOW_EN)); - if (vars->flow_ctrl & FLOW_CTRL_TX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) bnx2x_bits_en(bp, emac_base + EMAC_REG_EMAC_TX_MODE, (EMAC_TX_MODE_EXT_PAUSE_EN | @@ -333,7 +333,7 @@ static u8 bnx2x_emac_enable(struct link_params *params, /* enable the NIG in/out to the emac */ REG_WR(bp, NIG_REG_EMAC0_IN_EN + port*4, 0x1); val = 0; - if (vars->flow_ctrl & FLOW_CTRL_TX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) val = 1; REG_WR(bp, NIG_REG_EMAC0_PAUSE_OUT_EN + port*4, val); @@ -396,7 +396,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars, /* tx control */ val = 0xc0; - if (vars->flow_ctrl & FLOW_CTRL_TX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) val |= 0x800000; wb_data[0] = val; wb_data[1] = 0; @@ -423,7 +423,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars, /* rx control set to don't strip crc */ val = 0x14; - if (vars->flow_ctrl & FLOW_CTRL_RX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) val |= 0x20; wb_data[0] = val; wb_data[1] = 0; @@ -460,7 +460,7 @@ static u8 bnx2x_bmac_enable(struct link_params *params, struct link_vars *vars, REG_WR(bp, NIG_REG_XGXS_LANE_SEL_P0 + port*4, 0x0); REG_WR(bp, NIG_REG_EGRESS_EMAC0_PORT + port*4, 0x0); val = 0; - if (vars->flow_ctrl & FLOW_CTRL_TX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) val = 1; REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + port*4, val); REG_WR(bp, NIG_REG_EGRESS_EMAC0_OUT_EN + port*4, 0x0); @@ -580,14 +580,14 @@ void bnx2x_link_status_update(struct link_params *params, } if (vars->link_status & LINK_STATUS_TX_FLOW_CONTROL_ENABLED) - vars->flow_ctrl |= FLOW_CTRL_TX; + vars->flow_ctrl |= BNX2X_FLOW_CTRL_TX; else - vars->flow_ctrl &= ~FLOW_CTRL_TX; + vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_TX; if (vars->link_status & LINK_STATUS_RX_FLOW_CONTROL_ENABLED) - vars->flow_ctrl |= FLOW_CTRL_RX; + vars->flow_ctrl |= BNX2X_FLOW_CTRL_RX; else - vars->flow_ctrl &= ~FLOW_CTRL_RX; + vars->flow_ctrl &= ~BNX2X_FLOW_CTRL_RX; if (vars->phy_flags & PHY_XGXS_FLAG) { if (vars->line_speed && @@ -618,7 +618,7 @@ void bnx2x_link_status_update(struct link_params *params, vars->line_speed = 0; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; /* indicate no mac active */ vars->mac_type = MAC_TYPE_NONE; @@ -691,7 +691,7 @@ static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl, return -EINVAL; } - if (flow_ctrl & FLOW_CTRL_RX || + if (flow_ctrl & BNX2X_FLOW_CTRL_RX || line_speed == SPEED_10 || line_speed == SPEED_100 || line_speed == SPEED_1000 || @@ -1300,8 +1300,8 @@ static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) * Please refer to Table 28B-3 of the 802.3ab-1999 spec */ switch (params->req_flow_ctrl) { - case FLOW_CTRL_AUTO: - if (params->req_fc_auto_adv == FLOW_CTRL_BOTH) { + case BNX2X_FLOW_CTRL_AUTO: + if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH) { *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; } else { @@ -1309,17 +1309,17 @@ static void bnx2x_calc_ieee_aneg_adv(struct link_params *params, u32 *ieee_fc) MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; } break; - case FLOW_CTRL_TX: + case BNX2X_FLOW_CTRL_TX: *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC; break; - case FLOW_CTRL_RX: - case FLOW_CTRL_BOTH: + case BNX2X_FLOW_CTRL_RX: + case BNX2X_FLOW_CTRL_BOTH: *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH; break; - case FLOW_CTRL_NONE: + case BNX2X_FLOW_CTRL_NONE: default: *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE; break; @@ -1463,18 +1463,18 @@ static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result) { /* LD LP */ switch (pause_result) { /* ASYM P ASYM P */ case 0xb: /* 1 0 1 1 */ - vars->flow_ctrl = FLOW_CTRL_TX; + vars->flow_ctrl = BNX2X_FLOW_CTRL_TX; break; case 0xe: /* 1 1 1 0 */ - vars->flow_ctrl = FLOW_CTRL_RX; + vars->flow_ctrl = BNX2X_FLOW_CTRL_RX; break; case 0x5: /* 0 1 0 1 */ case 0x7: /* 0 1 1 1 */ case 0xd: /* 1 1 0 1 */ case 0xf: /* 1 1 1 1 */ - vars->flow_ctrl = FLOW_CTRL_BOTH; + vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH; break; default: @@ -1531,7 +1531,7 @@ static u8 bnx2x_ext_phy_resove_fc(struct link_params *params, DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x \n", pause_result); bnx2x_pause_resolve(vars, pause_result); - if (vars->flow_ctrl == FLOW_CTRL_NONE && + if (vars->flow_ctrl == BNX2X_FLOW_CTRL_NONE && ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073) { bnx2x_cl45_read(bp, port, ext_phy_type, @@ -1567,10 +1567,10 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, u16 lp_pause; /* link partner */ u16 pause_result; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; /* resolve from gp_status in case of AN complete and not sgmii */ - if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) && + if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && (gp_status & MDIO_AN_CL73_OR_37_COMPLETE) && (!(vars->phy_flags & PHY_SGMII_FLAG)) && (XGXS_EXT_PHY_TYPE(params->ext_phy_config) == @@ -1591,11 +1591,11 @@ static void bnx2x_flow_ctrl_resolve(struct link_params *params, MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_MASK)>>7; DP(NETIF_MSG_LINK, "pause_result 0x%x\n", pause_result); bnx2x_pause_resolve(vars, pause_result); - } else if ((params->req_flow_ctrl == FLOW_CTRL_AUTO) && + } else if ((params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && (bnx2x_ext_phy_resove_fc(params, vars))) { return; } else { - if (params->req_flow_ctrl == FLOW_CTRL_AUTO) + if (params->req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) vars->flow_ctrl = params->req_fc_auto_adv; else vars->flow_ctrl = params->req_flow_ctrl; @@ -1728,11 +1728,11 @@ static u8 bnx2x_link_settings_status(struct link_params *params, LINK_STATUS_PARALLEL_DETECTION_USED; } - if (vars->flow_ctrl & FLOW_CTRL_TX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_TX) vars->link_status |= LINK_STATUS_TX_FLOW_CONTROL_ENABLED; - if (vars->flow_ctrl & FLOW_CTRL_RX) + if (vars->flow_ctrl & BNX2X_FLOW_CTRL_RX) vars->link_status |= LINK_STATUS_RX_FLOW_CONTROL_ENABLED; @@ -1742,7 +1742,7 @@ static u8 bnx2x_link_settings_status(struct link_params *params, vars->phy_link_up = 0; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->autoneg = AUTO_NEG_DISABLED; vars->mac_type = MAC_TYPE_NONE; } @@ -3924,7 +3924,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 0; vars->line_speed = 0; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->mac_type = MAC_TYPE_NONE; if (params->switch_cfg == SWITCH_CFG_1G) @@ -3946,12 +3946,12 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD); /* enable on E1.5 FPGA */ if (CHIP_IS_E1H(bp)) { vars->flow_ctrl |= - (FLOW_CTRL_TX | FLOW_CTRL_RX); + (BNX2X_FLOW_CTRL_TX | BNX2X_FLOW_CTRL_RX); vars->link_status |= (LINK_STATUS_TX_FLOW_CONTROL_ENABLED | LINK_STATUS_RX_FLOW_CONTROL_ENABLED); @@ -3974,7 +3974,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->link_status = (LINK_STATUS_LINK_UP | LINK_10GTFD); bnx2x_bmac_enable(params, vars, 0); @@ -3994,7 +3994,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->mac_type = MAC_TYPE_BMAC; vars->phy_flags = PHY_XGXS_FLAG; @@ -4009,7 +4009,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 1; vars->line_speed = SPEED_1000; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->mac_type = MAC_TYPE_EMAC; vars->phy_flags = PHY_XGXS_FLAG; @@ -4026,7 +4026,7 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars) vars->link_up = 1; vars->line_speed = SPEED_10000; vars->duplex = DUPLEX_FULL; - vars->flow_ctrl = FLOW_CTRL_NONE; + vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE; vars->phy_flags = PHY_XGXS_FLAG; diff --git a/drivers/net/bnx2x_link.h b/drivers/net/bnx2x_link.h index 86d54a17b41127c7bcb278d7e3b971305c6a3b27..47cb585f4278a8680b0eba010eeb8f145d040b8d 100644 --- a/drivers/net/bnx2x_link.h +++ b/drivers/net/bnx2x_link.h @@ -26,11 +26,11 @@ -#define FLOW_CTRL_AUTO PORT_FEATURE_FLOW_CONTROL_AUTO -#define FLOW_CTRL_TX PORT_FEATURE_FLOW_CONTROL_TX -#define FLOW_CTRL_RX PORT_FEATURE_FLOW_CONTROL_RX -#define FLOW_CTRL_BOTH PORT_FEATURE_FLOW_CONTROL_BOTH -#define FLOW_CTRL_NONE PORT_FEATURE_FLOW_CONTROL_NONE +#define BNX2X_FLOW_CTRL_AUTO PORT_FEATURE_FLOW_CONTROL_AUTO +#define BNX2X_FLOW_CTRL_TX PORT_FEATURE_FLOW_CONTROL_TX +#define BNX2X_FLOW_CTRL_RX PORT_FEATURE_FLOW_CONTROL_RX +#define BNX2X_FLOW_CTRL_BOTH PORT_FEATURE_FLOW_CONTROL_BOTH +#define BNX2X_FLOW_CTRL_NONE PORT_FEATURE_FLOW_CONTROL_NONE #define SPEED_AUTO_NEG 0 #define SPEED_12000 12000 diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c index 600210d7eff95da4f60840b530f149cec8259e45..ef8103b3523e0e80695caf1d032034c6ff3c9b6b 100644 --- a/drivers/net/bnx2x_main.c +++ b/drivers/net/bnx2x_main.c @@ -1328,7 +1328,6 @@ static void bnx2x_tpa_stop(struct bnx2x *bp, struct bnx2x_fastpath *fp, dev_kfree_skb(skb); } - bp->dev->last_rx = jiffies; /* put new skb in bin */ fp->tpa_pool[queue].skb = new_skb; @@ -1557,7 +1556,6 @@ reuse_rx: #endif netif_receive_skb(skb); - bp->dev->last_rx = jiffies; next_rx: rx_buf->skb = NULL; @@ -1594,7 +1592,6 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) { struct bnx2x_fastpath *fp = fp_cookie; struct bnx2x *bp = fp->bp; - struct net_device *dev = bp->dev; int index = FP_IDX(fp); /* Return here if interrupt is disabled */ @@ -1617,7 +1614,7 @@ static irqreturn_t bnx2x_msix_fp_int(int irq, void *fp_cookie) prefetch(&fp->status_blk->c_status_block.status_block_index); prefetch(&fp->status_blk->u_status_block.status_block_index); - netif_rx_schedule(dev, &bnx2x_fp(bp, index, napi)); + netif_rx_schedule(&bnx2x_fp(bp, index, napi)); return IRQ_HANDLED; } @@ -1656,7 +1653,7 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance) prefetch(&fp->status_blk->c_status_block.status_block_index); prefetch(&fp->status_blk->u_status_block.status_block_index); - netif_rx_schedule(dev, &bnx2x_fp(bp, 0, napi)); + netif_rx_schedule(&bnx2x_fp(bp, 0, napi)); status &= ~mask; } @@ -1923,10 +1920,10 @@ static void bnx2x_link_report(struct bnx2x *bp) else printk("half duplex"); - if (bp->link_vars.flow_ctrl != FLOW_CTRL_NONE) { - if (bp->link_vars.flow_ctrl & FLOW_CTRL_RX) { + if (bp->link_vars.flow_ctrl != BNX2X_FLOW_CTRL_NONE) { + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) { printk(", receive "); - if (bp->link_vars.flow_ctrl & FLOW_CTRL_TX) + if (bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) printk("& transmit "); } else { printk(", transmit "); @@ -1950,11 +1947,11 @@ static u8 bnx2x_initial_phy_init(struct bnx2x *bp) /* It is recommended to turn off RX FC for jumbo frames for better performance */ if (IS_E1HMF(bp)) - bp->link_params.req_fc_auto_adv = FLOW_CTRL_BOTH; + bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH; else if (bp->dev->mtu > 5000) - bp->link_params.req_fc_auto_adv = FLOW_CTRL_TX; + bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_TX; else - bp->link_params.req_fc_auto_adv = FLOW_CTRL_BOTH; + bp->link_params.req_fc_auto_adv = BNX2X_FLOW_CTRL_BOTH; bnx2x_acquire_phy_lock(bp); rc = bnx2x_phy_init(&bp->link_params, &bp->link_vars); @@ -7364,9 +7361,9 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp) bp->link_params.req_flow_ctrl = (bp->port.link_config & PORT_FEATURE_FLOW_CONTROL_MASK); - if ((bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) && + if ((bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && !(bp->port.supported & SUPPORTED_Autoneg)) - bp->link_params.req_flow_ctrl = FLOW_CTRL_NONE; + bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE; BNX2X_DEV_INFO("req_line_speed %d req_duplex %d req_flow_ctrl 0x%x" " advertising 0x%x\n", @@ -8355,13 +8352,13 @@ static void bnx2x_get_pauseparam(struct net_device *dev, { struct bnx2x *bp = netdev_priv(dev); - epause->autoneg = (bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) && + epause->autoneg = (bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) && (bp->link_params.req_line_speed == SPEED_AUTO_NEG); - epause->rx_pause = ((bp->link_vars.flow_ctrl & FLOW_CTRL_RX) == - FLOW_CTRL_RX); - epause->tx_pause = ((bp->link_vars.flow_ctrl & FLOW_CTRL_TX) == - FLOW_CTRL_TX); + epause->rx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_RX) == + BNX2X_FLOW_CTRL_RX); + epause->tx_pause = ((bp->link_vars.flow_ctrl & BNX2X_FLOW_CTRL_TX) == + BNX2X_FLOW_CTRL_TX); DP(NETIF_MSG_LINK, "ethtool_pauseparam: cmd %d\n" DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", @@ -8380,16 +8377,16 @@ static int bnx2x_set_pauseparam(struct net_device *dev, DP_LEVEL " autoneg %d rx_pause %d tx_pause %d\n", epause->cmd, epause->autoneg, epause->rx_pause, epause->tx_pause); - bp->link_params.req_flow_ctrl = FLOW_CTRL_AUTO; + bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO; if (epause->rx_pause) - bp->link_params.req_flow_ctrl |= FLOW_CTRL_RX; + bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_RX; if (epause->tx_pause) - bp->link_params.req_flow_ctrl |= FLOW_CTRL_TX; + bp->link_params.req_flow_ctrl |= BNX2X_FLOW_CTRL_TX; - if (bp->link_params.req_flow_ctrl == FLOW_CTRL_AUTO) - bp->link_params.req_flow_ctrl = FLOW_CTRL_NONE; + if (bp->link_params.req_flow_ctrl == BNX2X_FLOW_CTRL_AUTO) + bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_NONE; if (epause->autoneg) { if (!(bp->port.supported & SUPPORTED_Autoneg)) { @@ -8398,7 +8395,7 @@ static int bnx2x_set_pauseparam(struct net_device *dev, } if (bp->link_params.req_line_speed == SPEED_AUTO_NEG) - bp->link_params.req_flow_ctrl = FLOW_CTRL_AUTO; + bp->link_params.req_flow_ctrl = BNX2X_FLOW_CTRL_AUTO; } DP(NETIF_MSG_LINK, @@ -8769,7 +8766,6 @@ static int bnx2x_run_loopback(struct bnx2x *bp, int loopback_mode, u8 link_up) rc = 0; test_loopback_rx_exit: - bp->dev->last_rx = jiffies; fp->rx_bd_cons = NEXT_RX_IDX(fp->rx_bd_cons); fp->rx_bd_prod = NEXT_RX_IDX(fp->rx_bd_prod); @@ -9287,7 +9283,7 @@ static int bnx2x_poll(struct napi_struct *napi, int budget) #ifdef BNX2X_STOP_ON_ERROR poll_panic: #endif - netif_rx_complete(bp->dev, napi); + netif_rx_complete(napi); bnx2x_ack_sb(bp, FP_SB_ID(fp), USTORM_ID, le16_to_cpu(fp->fp_u_idx), IGU_INT_NOP, 1); @@ -9853,11 +9849,8 @@ static void bnx2x_set_rx_mode(struct net_device *dev) mclist && (i < dev->mc_count); i++, mclist = mclist->next) { - DP(NETIF_MSG_IFUP, "Adding mcast MAC: " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - mclist->dmi_addr[0], mclist->dmi_addr[1], - mclist->dmi_addr[2], mclist->dmi_addr[3], - mclist->dmi_addr[4], mclist->dmi_addr[5]); + DP(NETIF_MSG_IFUP, "Adding mcast MAC: %pM\n", + mclist->dmi_addr); crc = crc32c_le(0, mclist->dmi_addr, ETH_ALEN); bit = (crc >> 24) & 0xff; @@ -10008,6 +10001,25 @@ static void poll_bnx2x(struct net_device *dev) } #endif +static const struct net_device_ops bnx2x_netdev_ops = { + .ndo_open = bnx2x_open, + .ndo_stop = bnx2x_close, + .ndo_start_xmit = bnx2x_start_xmit, + .ndo_set_multicast_list = bnx2x_set_rx_mode, + .ndo_set_mac_address = bnx2x_change_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = bnx2x_ioctl, + .ndo_change_mtu = bnx2x_change_mtu, + .ndo_tx_timeout = bnx2x_tx_timeout, +#ifdef BCM_VLAN + .ndo_vlan_rx_register = bnx2x_vlan_rx_register, +#endif +#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) + .ndo_poll_controller = poll_bnx2x, +#endif +}; + + static int __devinit bnx2x_init_dev(struct pci_dev *pdev, struct net_device *dev) { @@ -10092,8 +10104,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, dev->irq = pdev->irq; - bp->regview = ioremap_nocache(dev->base_addr, - pci_resource_len(pdev, 0)); + bp->regview = pci_ioremap_bar(pdev, 0); if (!bp->regview) { printk(KERN_ERR PFX "Cannot map register space, aborting\n"); rc = -ENOMEM; @@ -10119,23 +10130,10 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev, REG_WR(bp, PXP2_REG_PGL_ADDR_90_F0 + BP_PORT(bp)*16, 0); REG_WR(bp, PXP2_REG_PGL_ADDR_94_F0 + BP_PORT(bp)*16, 0); - dev->hard_start_xmit = bnx2x_start_xmit; dev->watchdog_timeo = TX_TIMEOUT; + dev->netdev_ops = &bnx2x_netdev_ops; dev->ethtool_ops = &bnx2x_ethtool_ops; - dev->open = bnx2x_open; - dev->stop = bnx2x_close; - dev->set_multicast_list = bnx2x_set_rx_mode; - dev->set_mac_address = bnx2x_change_mac_addr; - dev->do_ioctl = bnx2x_ioctl; - dev->change_mtu = bnx2x_change_mtu; - dev->tx_timeout = bnx2x_tx_timeout; -#ifdef BCM_VLAN - dev->vlan_rx_register = bnx2x_vlan_rx_register; -#endif -#if defined(HAVE_POLL_CONTROLLER) || defined(CONFIG_NET_POLL_CONTROLLER) - dev->poll_controller = poll_bnx2x; -#endif dev->features |= NETIF_F_SG; dev->features |= NETIF_F_HW_CSUM; if (bp->flags & USING_DAC_FLAG) @@ -10194,7 +10192,6 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, struct net_device *dev = NULL; struct bnx2x *bp; int rc; - DECLARE_MAC_BUF(mac); if (version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -10238,7 +10235,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev, bnx2x_get_pcie_width(bp), (bnx2x_get_pcie_speed(bp) == 2) ? "5GHz (Gen2)" : "2.5GHz", dev->base_addr, bp->pdev->irq); - printk(KERN_CONT "node addr %s\n", print_mac(mac, dev->dev_addr)); + printk(KERN_CONT "node addr %pM\n", dev->dev_addr); return 0; init_one_exit: diff --git a/drivers/net/bonding/Makefile b/drivers/net/bonding/Makefile index 5cdae2bc055a9c27d679af0793d97bce459c0fd1..6f9c6faef24c4079741128e2e88f18c2cea3f979 100644 --- a/drivers/net/bonding/Makefile +++ b/drivers/net/bonding/Makefile @@ -6,3 +6,6 @@ obj-$(CONFIG_BONDING) += bonding.o bonding-objs := bond_main.o bond_3ad.o bond_alb.o bond_sysfs.o +ipv6-$(subst m,y,$(CONFIG_IPV6)) += bond_ipv6.o +bonding-objs += $(ipv6-y) + diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c index 6106660a4a44b9a68f7a5b9a9c9c26a5b45ee689..8c2e5ab51f08fd35265eacd0b8881998fae8e6a8 100644 --- a/drivers/net/bonding/bond_3ad.c +++ b/drivers/net/bonding/bond_3ad.c @@ -20,13 +20,12 @@ * */ -//#define BONDING_DEBUG 1 - #include #include #include #include #include +#include #include #include #include @@ -96,33 +95,7 @@ static struct mac_addr null_mac_addr = {{0, 0, 0, 0, 0, 0}}; static u16 ad_ticks_per_sec; static const int ad_delta_in_ticks = (AD_TIMER_INTERVAL * HZ) / 1000; -// ================= 3AD api to bonding and kernel code ================== -static u16 __get_link_speed(struct port *port); -static u8 __get_duplex(struct port *port); -static inline void __initialize_port_locks(struct port *port); -//conversions -static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par); - - -// ================= ad code helper functions ================== -//needed by ad_rx_machine(...) -static void __record_pdu(struct lacpdu *lacpdu, struct port *port); -static void __record_default(struct port *port); -static void __update_selected(struct lacpdu *lacpdu, struct port *port); -static void __update_default_selected(struct port *port); -static void __choose_matched(struct lacpdu *lacpdu, struct port *port); -static void __update_ntt(struct lacpdu *lacpdu, struct port *port); - -//needed for ad_mux_machine(..) -static void __attach_bond_to_agg(struct port *port); -static void __detach_bond_from_agg(struct port *port); -static int __agg_ports_are_ready(struct aggregator *aggregator); -static void __set_agg_ports_ready(struct aggregator *aggregator, int val); - -//needed for ad_agg_selection_logic(...) -static u32 __get_agg_bandwidth(struct aggregator *aggregator); -static struct aggregator *__get_active_agg(struct aggregator *aggregator); - +static const u8 lacpdu_mcast_addr[ETH_ALEN] = MULTICAST_LACPDU_ADDR; // ================= main 802.3ad protocol functions ================== static int ad_lacpdu_send(struct port *port); @@ -136,7 +109,6 @@ static void ad_agg_selection_logic(struct aggregator *aggregator); static void ad_clear_agg(struct aggregator *aggregator); static void ad_initialize_agg(struct aggregator *aggregator); static void ad_initialize_port(struct port *port, int lacp_fast); -static void ad_initialize_lacpdu(struct lacpdu *Lacpdu); static void ad_enable_collecting_distributing(struct port *port); static void ad_disable_collecting_distributing(struct port *port); static void ad_marker_info_received(struct bond_marker *marker_info, struct port *port); @@ -236,6 +208,17 @@ static inline struct aggregator *__get_next_agg(struct aggregator *aggregator) return &(SLAVE_AD_INFO(slave->next).aggregator); } +/* + * __agg_has_partner + * + * Return nonzero if aggregator has a partner (denoted by a non-zero ether + * address for the partner). Return 0 if not. + */ +static inline int __agg_has_partner(struct aggregator *agg) +{ + return !is_zero_ether_addr(agg->partner_system.mac_addr_value); +} + /** * __disable_port - disable the port's slave * @port: the port we're looking at @@ -274,14 +257,14 @@ static inline int __port_is_enabled(struct port *port) * __get_agg_selection_mode - get the aggregator selection mode * @port: the port we're looking at * - * Get the aggregator selection mode. Can be %BANDWIDTH or %COUNT. + * Get the aggregator selection mode. Can be %STABLE, %BANDWIDTH or %COUNT. */ static inline u32 __get_agg_selection_mode(struct port *port) { struct bonding *bond = __get_bond_by_port(port); if (bond == NULL) { - return AD_BANDWIDTH; + return BOND_AD_STABLE; } return BOND_AD_INFO(bond).agg_select_mode; @@ -369,7 +352,7 @@ static u16 __get_link_speed(struct port *port) } } - dprintk("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed); + pr_debug("Port %d Received link speed %d update from adapter\n", port->actor_port_number, speed); return speed; } @@ -395,12 +378,12 @@ static u8 __get_duplex(struct port *port) switch (slave->duplex) { case DUPLEX_FULL: retval=0x1; - dprintk("Port %d Received status full duplex update from adapter\n", port->actor_port_number); + pr_debug("Port %d Received status full duplex update from adapter\n", port->actor_port_number); break; case DUPLEX_HALF: default: retval=0x0; - dprintk("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number); + pr_debug("Port %d Received status NOT full duplex update from adapter\n", port->actor_port_number); break; } } @@ -473,33 +456,25 @@ static u16 __ad_timer_to_ticks(u16 timer_type, u16 par) */ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) { - // validate lacpdu and port if (lacpdu && port) { + struct port_params *partner = &port->partner_oper; + // record the new parameter values for the partner operational - port->partner_oper_port_number = ntohs(lacpdu->actor_port); - port->partner_oper_port_priority = ntohs(lacpdu->actor_port_priority); - port->partner_oper_system = lacpdu->actor_system; - port->partner_oper_system_priority = ntohs(lacpdu->actor_system_priority); - port->partner_oper_key = ntohs(lacpdu->actor_key); - // zero partener's lase states - port->partner_oper_port_state = 0; - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_TIMEOUT); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_AGGREGATION); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_COLLECTING); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_DISTRIBUTING); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_DEFAULTED); - port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_EXPIRED); + partner->port_number = ntohs(lacpdu->actor_port); + partner->port_priority = ntohs(lacpdu->actor_port_priority); + partner->system = lacpdu->actor_system; + partner->system_priority = ntohs(lacpdu->actor_system_priority); + partner->key = ntohs(lacpdu->actor_key); + partner->port_state = lacpdu->actor_state; // set actor_oper_port_state.defaulted to FALSE port->actor_oper_port_state &= ~AD_STATE_DEFAULTED; // set the partner sync. to on if the partner is sync. and the port is matched if ((port->sm_vars & AD_PORT_MATCHED) && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) { - port->partner_oper_port_state |= AD_STATE_SYNCHRONIZATION; + partner->port_state |= AD_STATE_SYNCHRONIZATION; } else { - port->partner_oper_port_state &= ~AD_STATE_SYNCHRONIZATION; + partner->port_state &= ~AD_STATE_SYNCHRONIZATION; } } } @@ -514,15 +489,10 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port) */ static void __record_default(struct port *port) { - // validate the port if (port) { // record the partner admin parameters - port->partner_oper_port_number = port->partner_admin_port_number; - port->partner_oper_port_priority = port->partner_admin_port_priority; - port->partner_oper_system = port->partner_admin_system; - port->partner_oper_system_priority = port->partner_admin_system_priority; - port->partner_oper_key = port->partner_admin_key; - port->partner_oper_port_state = port->partner_admin_port_state; + memcpy(&port->partner_oper, &port->partner_admin, + sizeof(struct port_params)); // set actor_oper_port_state.defaulted to true port->actor_oper_port_state |= AD_STATE_DEFAULTED; @@ -544,16 +514,16 @@ static void __record_default(struct port *port) */ static void __update_selected(struct lacpdu *lacpdu, struct port *port) { - // validate lacpdu and port if (lacpdu && port) { + const struct port_params *partner = &port->partner_oper; + // check if any parameter is different - if ((ntohs(lacpdu->actor_port) != port->partner_oper_port_number) || - (ntohs(lacpdu->actor_port_priority) != port->partner_oper_port_priority) || - MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) || - (ntohs(lacpdu->actor_system_priority) != port->partner_oper_system_priority) || - (ntohs(lacpdu->actor_key) != port->partner_oper_key) || - ((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION)) - ) { + if (ntohs(lacpdu->actor_port) != partner->port_number + || ntohs(lacpdu->actor_port_priority) != partner->port_priority + || MAC_ADDRESS_COMPARE(&lacpdu->actor_system, &partner->system) + || ntohs(lacpdu->actor_system_priority) != partner->system_priority + || ntohs(lacpdu->actor_key) != partner->key + || (lacpdu->actor_state & AD_STATE_AGGREGATION) != (partner->port_state & AD_STATE_AGGREGATION)) { // update the state machine Selected variable port->sm_vars &= ~AD_PORT_SELECTED; } @@ -574,16 +544,18 @@ static void __update_selected(struct lacpdu *lacpdu, struct port *port) */ static void __update_default_selected(struct port *port) { - // validate the port if (port) { + const struct port_params *admin = &port->partner_admin; + const struct port_params *oper = &port->partner_oper; + // check if any parameter is different - if ((port->partner_admin_port_number != port->partner_oper_port_number) || - (port->partner_admin_port_priority != port->partner_oper_port_priority) || - MAC_ADDRESS_COMPARE(&(port->partner_admin_system), &(port->partner_oper_system)) || - (port->partner_admin_system_priority != port->partner_oper_system_priority) || - (port->partner_admin_key != port->partner_oper_key) || - ((port->partner_admin_port_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION)) - ) { + if (admin->port_number != oper->port_number + || admin->port_priority != oper->port_priority + || MAC_ADDRESS_COMPARE(&admin->system, &oper->system) + || admin->system_priority != oper->system_priority + || admin->key != oper->key + || (admin->port_state & AD_STATE_AGGREGATION) + != (oper->port_state & AD_STATE_AGGREGATION)) { // update the state machine Selected variable port->sm_vars &= ~AD_PORT_SELECTED; } @@ -658,8 +630,8 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port) ((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) || ((lacpdu->partner_state & AD_STATE_AGGREGATION) != (port->actor_oper_port_state & AD_STATE_AGGREGATION)) ) { - // set ntt to be TRUE - port->ntt = 1; + + port->ntt = true; } } } @@ -798,6 +770,7 @@ static struct aggregator *__get_active_agg(struct aggregator *aggregator) static inline void __update_lacpdu_from_port(struct port *port) { struct lacpdu *lacpdu = &port->lacpdu; + const struct port_params *partner = &port->partner_oper; /* update current actual Actor parameters */ /* lacpdu->subtype initialized @@ -818,12 +791,12 @@ static inline void __update_lacpdu_from_port(struct port *port) * lacpdu->partner_information_length initialized */ - lacpdu->partner_system_priority = htons(port->partner_oper_system_priority); - lacpdu->partner_system = port->partner_oper_system; - lacpdu->partner_key = htons(port->partner_oper_key); - lacpdu->partner_port_priority = htons(port->partner_oper_port_priority); - lacpdu->partner_port = htons(port->partner_oper_port_number); - lacpdu->partner_state = port->partner_oper_port_state; + lacpdu->partner_system_priority = htons(partner->system_priority); + lacpdu->partner_system = partner->system; + lacpdu->partner_key = htons(partner->key); + lacpdu->partner_port_priority = htons(partner->port_priority); + lacpdu->partner_port = htons(partner->port_number); + lacpdu->partner_state = partner->port_state; /* lacpdu->reserved_3_2 initialized * lacpdu->tlv_type_collector_info initialized @@ -853,7 +826,6 @@ static int ad_lacpdu_send(struct port *port) struct sk_buff *skb; struct lacpdu_header *lacpdu_header; int length = sizeof(struct lacpdu_header); - struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR; skb = dev_alloc_skb(length); if (!skb) { @@ -868,11 +840,11 @@ static int ad_lacpdu_send(struct port *port) lacpdu_header = (struct lacpdu_header *)skb_put(skb, length); - lacpdu_header->ad_header.destination_address = lacpdu_multicast_address; - /* Note: source addres is set to be the member's PERMANENT address, because we use it - to identify loopback lacpdus in receive. */ - lacpdu_header->ad_header.source_address = *((struct mac_addr *)(slave->perm_hwaddr)); - lacpdu_header->ad_header.length_type = PKT_TYPE_LACPDU; + memcpy(lacpdu_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); + /* Note: source addres is set to be the member's PERMANENT address, + because we use it to identify loopback lacpdus in receive. */ + memcpy(lacpdu_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); + lacpdu_header->hdr.h_proto = PKT_TYPE_LACPDU; lacpdu_header->lacpdu = port->lacpdu; // struct copy @@ -895,7 +867,6 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) struct sk_buff *skb; struct bond_marker_header *marker_header; int length = sizeof(struct bond_marker_header); - struct mac_addr lacpdu_multicast_address = AD_MULTICAST_LACPDU_ADDR; skb = dev_alloc_skb(length + 16); if (!skb) { @@ -911,11 +882,11 @@ static int ad_marker_send(struct port *port, struct bond_marker *marker) marker_header = (struct bond_marker_header *)skb_put(skb, length); - marker_header->ad_header.destination_address = lacpdu_multicast_address; - /* Note: source addres is set to be the member's PERMANENT address, because we use it - to identify loopback MARKERs in receive. */ - marker_header->ad_header.source_address = *((struct mac_addr *)(slave->perm_hwaddr)); - marker_header->ad_header.length_type = PKT_TYPE_LACPDU; + memcpy(marker_header->hdr.h_dest, lacpdu_mcast_addr, ETH_ALEN); + /* Note: source addres is set to be the member's PERMANENT address, + because we use it to identify loopback MARKERs in receive. */ + memcpy(marker_header->hdr.h_source, slave->perm_hwaddr, ETH_ALEN); + marker_header->hdr.h_proto = PKT_TYPE_LACPDU; marker_header->marker = *marker; // struct copy @@ -972,7 +943,7 @@ static void ad_mux_machine(struct port *port) break; case AD_MUX_ATTACHED: // check also if agg_select_timer expired(so the edable port will take place only after this timer) - if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper_port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) { + if ((port->sm_vars & AD_PORT_SELECTED) && (port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) && !__check_agg_selection_timer(port)) { port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING;// next state } else if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY)) { // if UNSELECTED or STANDBY port->sm_vars &= ~AD_PORT_READY_N; @@ -984,7 +955,7 @@ static void ad_mux_machine(struct port *port) break; case AD_MUX_COLLECTING_DISTRIBUTING: if (!(port->sm_vars & AD_PORT_SELECTED) || (port->sm_vars & AD_PORT_STANDBY) || - !(port->partner_oper_port_state & AD_STATE_SYNCHRONIZATION) + !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) ) { port->sm_mux_state = AD_MUX_ATTACHED;// next state @@ -1007,7 +978,7 @@ static void ad_mux_machine(struct port *port) // check if the state machine was changed if (port->sm_mux_state != last_state) { - dprintk("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state); + pr_debug("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_mux_state); switch (port->sm_mux_state) { case AD_MUX_DETACHED: __detach_bond_from_agg(port); @@ -1015,7 +986,7 @@ static void ad_mux_machine(struct port *port) ad_disable_collecting_distributing(port); port->actor_oper_port_state &= ~AD_STATE_COLLECTING; port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING; - port->ntt = 1; + port->ntt = true; break; case AD_MUX_WAITING: port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0); @@ -1026,13 +997,13 @@ static void ad_mux_machine(struct port *port) port->actor_oper_port_state &= ~AD_STATE_COLLECTING; port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING; ad_disable_collecting_distributing(port); - port->ntt = 1; + port->ntt = true; break; case AD_MUX_COLLECTING_DISTRIBUTING: port->actor_oper_port_state |= AD_STATE_COLLECTING; port->actor_oper_port_state |= AD_STATE_DISTRIBUTING; ad_enable_collecting_distributing(port); - port->ntt = 1; + port->ntt = true; break; default: //to silence the compiler break; @@ -1106,7 +1077,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) // check if the State machine was changed or new lacpdu arrived if ((port->sm_rx_state != last_state) || (lacpdu)) { - dprintk("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state); + pr_debug("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_rx_state); switch (port->sm_rx_state) { case AD_RX_INITIALIZE: if (!(port->actor_oper_port_key & AD_DUPLEX_KEY_BITS)) { @@ -1128,7 +1099,7 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) case AD_RX_LACP_DISABLED: port->sm_vars &= ~AD_PORT_SELECTED; __record_default(port); - port->partner_oper_port_state &= ~AD_STATE_AGGREGATION; + port->partner_oper.port_state &= ~AD_STATE_AGGREGATION; port->sm_vars |= AD_PORT_MATCHED; port->actor_oper_port_state &= ~AD_STATE_EXPIRED; break; @@ -1136,9 +1107,9 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port) //Reset of the Synchronization flag. (Standard 43.4.12) //This reset cause to disable this port in the COLLECTING_DISTRIBUTING state of the //mux machine in case of EXPIRED even if LINK_DOWN didn't arrive for the port. - port->partner_oper_port_state &= ~AD_STATE_SYNCHRONIZATION; + port->partner_oper.port_state &= ~AD_STATE_SYNCHRONIZATION; port->sm_vars &= ~AD_PORT_MATCHED; - port->partner_oper_port_state |= AD_SHORT_TIMEOUT; + port->partner_oper.port_state |= AD_SHORT_TIMEOUT; port->sm_rx_timer_counter = __ad_timer_to_ticks(AD_CURRENT_WHILE_TIMER, (u16)(AD_SHORT_TIMEOUT)); port->actor_oper_port_state |= AD_STATE_EXPIRED; break; @@ -1191,11 +1162,13 @@ static void ad_tx_machine(struct port *port) // check if there is something to send if (port->ntt && (port->sm_vars & AD_PORT_LACP_ENABLED)) { __update_lacpdu_from_port(port); - // send the lacpdu + if (ad_lacpdu_send(port) >= 0) { - dprintk("Sent LACPDU on port %d\n", port->actor_port_number); - // mark ntt as false, so it will not be sent again until demanded - port->ntt = 0; + pr_debug("Sent LACPDU on port %d\n", port->actor_port_number); + + /* mark ntt as false, so it will not be sent again until + demanded */ + port->ntt = false; } } // restart tx timer(to verify that we will not exceed AD_MAX_TX_IN_SECOND @@ -1218,7 +1191,7 @@ static void ad_periodic_machine(struct port *port) // check if port was reinitialized if (((port->sm_vars & AD_PORT_BEGIN) || !(port->sm_vars & AD_PORT_LACP_ENABLED) || !port->is_enabled) || - (!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper_port_state & AD_STATE_LACP_ACTIVITY)) + (!(port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY) && !(port->partner_oper.port_state & AD_STATE_LACP_ACTIVITY)) ) { port->sm_periodic_state = AD_NO_PERIODIC; // next state } @@ -1232,12 +1205,12 @@ static void ad_periodic_machine(struct port *port) // If not expired, check if there is some new timeout parameter from the partner state switch (port->sm_periodic_state) { case AD_FAST_PERIODIC: - if (!(port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) { + if (!(port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) { port->sm_periodic_state = AD_SLOW_PERIODIC; // next state } break; case AD_SLOW_PERIODIC: - if ((port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) { + if ((port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) { // stop current timer port->sm_periodic_timer_counter = 0; port->sm_periodic_state = AD_PERIODIC_TX; // next state @@ -1253,7 +1226,7 @@ static void ad_periodic_machine(struct port *port) port->sm_periodic_state = AD_FAST_PERIODIC; // next state break; case AD_PERIODIC_TX: - if (!(port->partner_oper_port_state & AD_STATE_LACP_TIMEOUT)) { + if (!(port->partner_oper.port_state & AD_STATE_LACP_TIMEOUT)) { port->sm_periodic_state = AD_SLOW_PERIODIC; // next state } else { port->sm_periodic_state = AD_FAST_PERIODIC; // next state @@ -1266,7 +1239,7 @@ static void ad_periodic_machine(struct port *port) // check if the state machine was changed if (port->sm_periodic_state != last_state) { - dprintk("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state); + pr_debug("Periodic Machine: Port=%d, Last State=%d, Curr State=%d\n", port->actor_port_number, last_state, port->sm_periodic_state); switch (port->sm_periodic_state) { case AD_NO_PERIODIC: port->sm_periodic_timer_counter = 0; // zero timer @@ -1278,7 +1251,7 @@ static void ad_periodic_machine(struct port *port) port->sm_periodic_timer_counter = __ad_timer_to_ticks(AD_PERIODIC_TIMER, (u16)(AD_SLOW_PERIODIC_TIME))-1; // decrement 1 tick we lost in the PERIODIC_TX cycle break; case AD_PERIODIC_TX: - port->ntt = 1; + port->ntt = true; break; default: //to silence the compiler break; @@ -1323,7 +1296,7 @@ static void ad_port_selection_logic(struct port *port) port->next_port_in_aggregator=NULL; port->actor_port_aggregator_identifier=0; - dprintk("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier); + pr_debug("Port %d left LAG %d\n", port->actor_port_number, temp_aggregator->aggregator_identifier); // if the aggregator is empty, clear its parameters, and set it ready to be attached if (!temp_aggregator->lag_ports) { ad_clear_agg(temp_aggregator); @@ -1352,11 +1325,11 @@ static void ad_port_selection_logic(struct port *port) } // check if current aggregator suits us if (((aggregator->actor_oper_aggregator_key == port->actor_oper_port_key) && // if all parameters match AND - !MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(port->partner_oper_system)) && - (aggregator->partner_system_priority == port->partner_oper_system_priority) && - (aggregator->partner_oper_aggregator_key == port->partner_oper_key) + !MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(port->partner_oper.system)) && + (aggregator->partner_system_priority == port->partner_oper.system_priority) && + (aggregator->partner_oper_aggregator_key == port->partner_oper.key) ) && - ((MAC_ADDRESS_COMPARE(&(port->partner_oper_system), &(null_mac_addr)) && // partner answers + ((MAC_ADDRESS_COMPARE(&(port->partner_oper.system), &(null_mac_addr)) && // partner answers !aggregator->is_individual) // but is not individual OR ) ) { @@ -1366,7 +1339,7 @@ static void ad_port_selection_logic(struct port *port) port->next_port_in_aggregator=aggregator->lag_ports; port->aggregator->num_of_ports++; aggregator->lag_ports=port; - dprintk("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); + pr_debug("Port %d joined LAG %d(existing LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; @@ -1385,16 +1358,16 @@ static void ad_port_selection_logic(struct port *port) // update the new aggregator's parameters // if port was responsed from the end-user if (port->actor_oper_port_key & AD_DUPLEX_KEY_BITS) {// if port is full duplex - port->aggregator->is_individual = 0; + port->aggregator->is_individual = false; } else { - port->aggregator->is_individual = 1; + port->aggregator->is_individual = true; } port->aggregator->actor_admin_aggregator_key = port->actor_admin_port_key; port->aggregator->actor_oper_aggregator_key = port->actor_oper_port_key; - port->aggregator->partner_system=port->partner_oper_system; - port->aggregator->partner_system_priority = port->partner_oper_system_priority; - port->aggregator->partner_oper_aggregator_key = port->partner_oper_key; + port->aggregator->partner_system=port->partner_oper.system; + port->aggregator->partner_system_priority = port->partner_oper.system_priority; + port->aggregator->partner_oper_aggregator_key = port->partner_oper.key; port->aggregator->receive_state = 1; port->aggregator->transmit_state = 1; port->aggregator->lag_ports = port; @@ -1403,7 +1376,7 @@ static void ad_port_selection_logic(struct port *port) // mark this port as selected port->sm_vars |= AD_PORT_SELECTED; - dprintk("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); + pr_debug("Port %d joined LAG %d(new LAG)\n", port->actor_port_number, port->aggregator->aggregator_identifier); } else { printk(KERN_ERR DRV_NAME ": %s: Port %d (on %s) did not find a suitable aggregator\n", port->slave->dev->master->name, @@ -1414,9 +1387,82 @@ static void ad_port_selection_logic(struct port *port) // else set ready=FALSE in all aggregator's ports __set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator)); - if (!__check_agg_selection_timer(port) && (aggregator = __get_first_agg(port))) { - ad_agg_selection_logic(aggregator); + aggregator = __get_first_agg(port); + ad_agg_selection_logic(aggregator); +} + +/* + * Decide if "agg" is a better choice for the new active aggregator that + * the current best, according to the ad_select policy. + */ +static struct aggregator *ad_agg_selection_test(struct aggregator *best, + struct aggregator *curr) +{ + /* + * 0. If no best, select current. + * + * 1. If the current agg is not individual, and the best is + * individual, select current. + * + * 2. If current agg is individual and the best is not, keep best. + * + * 3. Therefore, current and best are both individual or both not + * individual, so: + * + * 3a. If current agg partner replied, and best agg partner did not, + * select current. + * + * 3b. If current agg partner did not reply and best agg partner + * did reply, keep best. + * + * 4. Therefore, current and best both have partner replies or + * both do not, so perform selection policy: + * + * BOND_AD_COUNT: Select by count of ports. If count is equal, + * select by bandwidth. + * + * BOND_AD_STABLE, BOND_AD_BANDWIDTH: Select by bandwidth. + */ + if (!best) + return curr; + + if (!curr->is_individual && best->is_individual) + return curr; + + if (curr->is_individual && !best->is_individual) + return best; + + if (__agg_has_partner(curr) && !__agg_has_partner(best)) + return curr; + + if (!__agg_has_partner(curr) && __agg_has_partner(best)) + return best; + + switch (__get_agg_selection_mode(curr->lag_ports)) { + case BOND_AD_COUNT: + if (curr->num_of_ports > best->num_of_ports) + return curr; + + if (curr->num_of_ports < best->num_of_ports) + return best; + + /*FALLTHROUGH*/ + case BOND_AD_STABLE: + case BOND_AD_BANDWIDTH: + if (__get_agg_bandwidth(curr) > __get_agg_bandwidth(best)) + return curr; + + break; + + default: + printk(KERN_WARNING DRV_NAME + ": %s: Impossible agg select mode %d\n", + curr->slave->dev->master->name, + __get_agg_selection_mode(curr->lag_ports)); + break; } + + return best; } /** @@ -1424,156 +1470,138 @@ static void ad_port_selection_logic(struct port *port) * @aggregator: the aggregator we're looking at * * It is assumed that only one aggregator may be selected for a team. - * The logic of this function is to select (at first time) the aggregator with - * the most ports attached to it, and to reselect the active aggregator only if - * the previous aggregator has no more ports related to it. + * + * The logic of this function is to select the aggregator according to + * the ad_select policy: + * + * BOND_AD_STABLE: select the aggregator with the most ports attached to + * it, and to reselect the active aggregator only if the previous + * aggregator has no more ports related to it. + * + * BOND_AD_BANDWIDTH: select the aggregator with the highest total + * bandwidth, and reselect whenever a link state change takes place or the + * set of slaves in the bond changes. + * + * BOND_AD_COUNT: select the aggregator with largest number of ports + * (slaves), and reselect whenever a link state change takes place or the + * set of slaves in the bond changes. * * FIXME: this function MUST be called with the first agg in the bond, or * __get_active_agg() won't work correctly. This function should be better * called with the bond itself, and retrieve the first agg from it. */ -static void ad_agg_selection_logic(struct aggregator *aggregator) +static void ad_agg_selection_logic(struct aggregator *agg) { - struct aggregator *best_aggregator = NULL, *active_aggregator = NULL; - struct aggregator *last_active_aggregator = NULL, *origin_aggregator; + struct aggregator *best, *active, *origin; struct port *port; - u16 num_of_aggs=0; - origin_aggregator = aggregator; + origin = agg; - //get current active aggregator - last_active_aggregator = __get_active_agg(aggregator); + active = __get_active_agg(agg); + best = active; - // search for the aggregator with the most ports attached to it. do { - // count how many candidate lag's we have - if (aggregator->lag_ports) { - num_of_aggs++; - } - if (aggregator->is_active && !aggregator->is_individual && // if current aggregator is the active aggregator - MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr))) { // and partner answers to 802.3ad PDUs - if (aggregator->num_of_ports) { // if any ports attached to the current aggregator - best_aggregator=NULL; // disregard the best aggregator that was chosen by now - break; // stop the selection of other aggregator if there are any ports attached to this active aggregator - } else { // no ports attached to this active aggregator - aggregator->is_active = 0; // mark this aggregator as not active anymore - } - } - if (aggregator->num_of_ports) { // if any ports attached - if (best_aggregator) { // if there is a candidte aggregator - //The reasons for choosing new best aggregator: - // 1. if current agg is NOT individual and the best agg chosen so far is individual OR - // current and best aggs are both individual or both not individual, AND - // 2a. current agg partner reply but best agg partner do not reply OR - // 2b. current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply AND - // current has more ports/bandwidth, or same amount of ports but current has faster ports, THEN - // current agg become best agg so far - - //if current agg is NOT individual and the best agg chosen so far is individual change best_aggregator - if (!aggregator->is_individual && best_aggregator->is_individual) { - best_aggregator=aggregator; - } - // current and best aggs are both individual or both not individual - else if ((aggregator->is_individual && best_aggregator->is_individual) || - (!aggregator->is_individual && !best_aggregator->is_individual)) { - // current and best aggs are both individual or both not individual AND - // current agg partner reply but best agg partner do not reply - if ((MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) && - !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) { - best_aggregator=aggregator; - } - // current agg partner reply OR current agg partner do not reply AND best agg partner also do not reply - else if (! (!MAC_ADDRESS_COMPARE(&(aggregator->partner_system), &(null_mac_addr)) && - MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) { - if ((__get_agg_selection_mode(aggregator->lag_ports) == AD_BANDWIDTH)&& - (__get_agg_bandwidth(aggregator) > __get_agg_bandwidth(best_aggregator))) { - best_aggregator=aggregator; - } else if (__get_agg_selection_mode(aggregator->lag_ports) == AD_COUNT) { - if (((aggregator->num_of_ports > best_aggregator->num_of_ports) && - (aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS))|| - ((aggregator->num_of_ports == best_aggregator->num_of_ports) && - ((u16)(aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS) > - (u16)(best_aggregator->actor_oper_aggregator_key & AD_SPEED_KEY_BITS)))) { - best_aggregator=aggregator; - } - } - } - } - } else { - best_aggregator=aggregator; + agg->is_active = 0; + + if (agg->num_of_ports) + best = ad_agg_selection_test(best, agg); + + } while ((agg = __get_next_agg(agg))); + + if (best && + __get_agg_selection_mode(best->lag_ports) == BOND_AD_STABLE) { + /* + * For the STABLE policy, don't replace the old active + * aggregator if it's still active (it has an answering + * partner) or if both the best and active don't have an + * answering partner. + */ + if (active && active->lag_ports && + active->lag_ports->is_enabled && + (__agg_has_partner(active) || + (!__agg_has_partner(active) && !__agg_has_partner(best)))) { + if (!(!active->actor_oper_aggregator_key && + best->actor_oper_aggregator_key)) { + best = NULL; + active->is_active = 1; } } - aggregator->is_active = 0; // mark all aggregators as not active anymore - } while ((aggregator = __get_next_agg(aggregator))); - - // if we have new aggregator selected, don't replace the old aggregator if it has an answering partner, - // or if both old aggregator and new aggregator don't have answering partner - if (best_aggregator) { - if (last_active_aggregator && last_active_aggregator->lag_ports && last_active_aggregator->lag_ports->is_enabled && - (MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) || // partner answers OR - (!MAC_ADDRESS_COMPARE(&(last_active_aggregator->partner_system), &(null_mac_addr)) && // both old and new - !MAC_ADDRESS_COMPARE(&(best_aggregator->partner_system), &(null_mac_addr)))) // partner do not answer - ) { - // if new aggregator has link, and old aggregator does not, replace old aggregator.(do nothing) - // -> don't replace otherwise. - if (!(!last_active_aggregator->actor_oper_aggregator_key && best_aggregator->actor_oper_aggregator_key)) { - best_aggregator=NULL; - last_active_aggregator->is_active = 1; // don't replace good old aggregator + } - } - } + if (best && (best == active)) { + best = NULL; + active->is_active = 1; } // if there is new best aggregator, activate it - if (best_aggregator) { - for (aggregator = __get_first_agg(best_aggregator->lag_ports); - aggregator; - aggregator = __get_next_agg(aggregator)) { - - dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", - aggregator->aggregator_identifier, aggregator->num_of_ports, - aggregator->actor_oper_aggregator_key, aggregator->partner_oper_aggregator_key, - aggregator->is_individual, aggregator->is_active); + if (best) { + pr_debug("best Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", + best->aggregator_identifier, best->num_of_ports, + best->actor_oper_aggregator_key, + best->partner_oper_aggregator_key, + best->is_individual, best->is_active); + pr_debug("best ports %p slave %p %s\n", + best->lag_ports, best->slave, + best->slave ? best->slave->dev->name : "NULL"); + + for (agg = __get_first_agg(best->lag_ports); agg; + agg = __get_next_agg(agg)) { + + pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", + agg->aggregator_identifier, agg->num_of_ports, + agg->actor_oper_aggregator_key, + agg->partner_oper_aggregator_key, + agg->is_individual, agg->is_active); } // check if any partner replys - if (best_aggregator->is_individual) { - printk(KERN_WARNING DRV_NAME ": %s: Warning: No 802.3ad response from " - "the link partner for any adapters in the bond\n", - best_aggregator->slave->dev->master->name); + if (best->is_individual) { + printk(KERN_WARNING DRV_NAME ": %s: Warning: No 802.3ad" + " response from the link partner for any" + " adapters in the bond\n", + best->slave->dev->master->name); } - // check if there are more than one aggregator - if (num_of_aggs > 1) { - dprintk("Warning: More than one Link Aggregation Group was " - "found in the bond. Only one group will function in the bond\n"); - } - - best_aggregator->is_active = 1; - dprintk("LAG %d choosed as the active LAG\n", best_aggregator->aggregator_identifier); - dprintk("Agg=%d; Ports=%d; a key=%d; p key=%d; Indiv=%d; Active=%d\n", - best_aggregator->aggregator_identifier, best_aggregator->num_of_ports, - best_aggregator->actor_oper_aggregator_key, best_aggregator->partner_oper_aggregator_key, - best_aggregator->is_individual, best_aggregator->is_active); + best->is_active = 1; + pr_debug("LAG %d chosen as the active LAG\n", + best->aggregator_identifier); + pr_debug("Agg=%d; P=%d; a k=%d; p k=%d; Ind=%d; Act=%d\n", + best->aggregator_identifier, best->num_of_ports, + best->actor_oper_aggregator_key, + best->partner_oper_aggregator_key, + best->is_individual, best->is_active); // disable the ports that were related to the former active_aggregator - if (last_active_aggregator) { - for (port=last_active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) { + if (active) { + for (port = active->lag_ports; port; + port = port->next_port_in_aggregator) { __disable_port(port); } } } - // if the selected aggregator is of join individuals(partner_system is NULL), enable their ports - active_aggregator = __get_active_agg(origin_aggregator); + /* + * if the selected aggregator is of join individuals + * (partner_system is NULL), enable their ports + */ + active = __get_active_agg(origin); - if (active_aggregator) { - if (!MAC_ADDRESS_COMPARE(&(active_aggregator->partner_system), &(null_mac_addr))) { - for (port=active_aggregator->lag_ports; port; port=port->next_port_in_aggregator) { + if (active) { + if (!__agg_has_partner(active)) { + for (port = active->lag_ports; port; + port = port->next_port_in_aggregator) { __enable_port(port); } } } + + if (origin->slave) { + struct bonding *bond; + + bond = bond_get_bond_by_slave(origin->slave); + if (bond) + bond_3ad_set_carrier(bond); + } } /** @@ -1584,7 +1612,7 @@ static void ad_agg_selection_logic(struct aggregator *aggregator) static void ad_clear_agg(struct aggregator *aggregator) { if (aggregator) { - aggregator->is_individual = 0; + aggregator->is_individual = false; aggregator->actor_admin_aggregator_key = 0; aggregator->actor_oper_aggregator_key = 0; aggregator->partner_system = null_mac_addr; @@ -1595,7 +1623,7 @@ static void ad_clear_agg(struct aggregator *aggregator) aggregator->lag_ports = NULL; aggregator->is_active = 0; aggregator->num_of_ports = 0; - dprintk("LAG %d was cleared\n", aggregator->aggregator_identifier); + pr_debug("LAG %d was cleared\n", aggregator->aggregator_identifier); } } @@ -1623,13 +1651,32 @@ static void ad_initialize_agg(struct aggregator *aggregator) */ static void ad_initialize_port(struct port *port, int lacp_fast) { + static const struct port_params tmpl = { + .system_priority = 0xffff, + .key = 1, + .port_number = 1, + .port_priority = 0xff, + .port_state = 1, + }; + static const struct lacpdu lacpdu = { + .subtype = 0x01, + .version_number = 0x01, + .tlv_type_actor_info = 0x01, + .actor_information_length = 0x14, + .tlv_type_partner_info = 0x02, + .partner_information_length = 0x14, + .tlv_type_collector_info = 0x03, + .collector_information_length = 0x10, + .collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY), + }; + if (port) { port->actor_port_number = 1; port->actor_port_priority = 0xff; port->actor_system = null_mac_addr; port->actor_system_priority = 0xffff; port->actor_port_aggregator_identifier = 0; - port->ntt = 0; + port->ntt = false; port->actor_admin_port_key = 1; port->actor_oper_port_key = 1; port->actor_admin_port_state = AD_STATE_AGGREGATION | AD_STATE_LACP_ACTIVITY; @@ -1639,19 +1686,10 @@ static void ad_initialize_port(struct port *port, int lacp_fast) port->actor_oper_port_state |= AD_STATE_LACP_TIMEOUT; } - port->partner_admin_system = null_mac_addr; - port->partner_oper_system = null_mac_addr; - port->partner_admin_system_priority = 0xffff; - port->partner_oper_system_priority = 0xffff; - port->partner_admin_key = 1; - port->partner_oper_key = 1; - port->partner_admin_port_number = 1; - port->partner_oper_port_number = 1; - port->partner_admin_port_priority = 0xff; - port->partner_oper_port_priority = 0xff; - port->partner_admin_port_state = 1; - port->partner_oper_port_state = 1; - port->is_enabled = 1; + memcpy(&port->partner_admin, &tmpl, sizeof(tmpl)); + memcpy(&port->partner_oper, &tmpl, sizeof(tmpl)); + + port->is_enabled = true; // ****** private parameters ****** port->sm_vars = 0x3; port->sm_rx_state = 0; @@ -1667,7 +1705,7 @@ static void ad_initialize_port(struct port *port, int lacp_fast) port->next_port_in_aggregator = NULL; port->transaction_id = 0; - ad_initialize_lacpdu(&(port->lacpdu)); + memcpy(&port->lacpdu, &lacpdu, sizeof(lacpdu)); } } @@ -1680,7 +1718,7 @@ static void ad_initialize_port(struct port *port, int lacp_fast) static void ad_enable_collecting_distributing(struct port *port) { if (port->aggregator->is_active) { - dprintk("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); + pr_debug("Enabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __enable_port(port); } } @@ -1693,7 +1731,7 @@ static void ad_enable_collecting_distributing(struct port *port) static void ad_disable_collecting_distributing(struct port *port) { if (port->aggregator && MAC_ADDRESS_COMPARE(&(port->aggregator->partner_system), &(null_mac_addr))) { - dprintk("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); + pr_debug("Disabling port %d(LAG %d)\n", port->actor_port_number, port->aggregator->aggregator_identifier); __disable_port(port); } } @@ -1731,7 +1769,7 @@ static void ad_marker_info_send(struct port *port) // send the marker information if (ad_marker_send(port, &marker) >= 0) { - dprintk("Sent Marker Information on port %d\n", port->actor_port_number); + pr_debug("Sent Marker Information on port %d\n", port->actor_port_number); } } #endif @@ -1755,7 +1793,7 @@ static void ad_marker_info_received(struct bond_marker *marker_info, // send the marker response if (ad_marker_send(port, &marker) >= 0) { - dprintk("Sent Marker Response on port %d\n", port->actor_port_number); + pr_debug("Sent Marker Response on port %d\n", port->actor_port_number); } } @@ -1776,53 +1814,6 @@ static void ad_marker_response_received(struct bond_marker *marker, // DO NOTHING, SINCE WE DECIDED NOT TO IMPLEMENT THIS FEATURE FOR NOW } -/** - * ad_initialize_lacpdu - initialize a given lacpdu structure - * @lacpdu: lacpdu structure to initialize - * - */ -static void ad_initialize_lacpdu(struct lacpdu *lacpdu) -{ - u16 index; - - // initialize lacpdu data - lacpdu->subtype = 0x01; - lacpdu->version_number = 0x01; - lacpdu->tlv_type_actor_info = 0x01; - lacpdu->actor_information_length = 0x14; - // lacpdu->actor_system_priority updated on send - // lacpdu->actor_system updated on send - // lacpdu->actor_key updated on send - // lacpdu->actor_port_priority updated on send - // lacpdu->actor_port updated on send - // lacpdu->actor_state updated on send - lacpdu->tlv_type_partner_info = 0x02; - lacpdu->partner_information_length = 0x14; - for (index=0; index<=2; index++) { - lacpdu->reserved_3_1[index]=0; - } - // lacpdu->partner_system_priority updated on send - // lacpdu->partner_system updated on send - // lacpdu->partner_key updated on send - // lacpdu->partner_port_priority updated on send - // lacpdu->partner_port updated on send - // lacpdu->partner_state updated on send - for (index=0; index<=2; index++) { - lacpdu->reserved_3_2[index]=0; - } - lacpdu->tlv_type_collector_info = 0x03; - lacpdu->collector_information_length= 0x10; - lacpdu->collector_max_delay = htons(AD_COLLECTOR_MAX_DELAY); - for (index=0; index<=11; index++) { - lacpdu->reserved_12[index]=0; - } - lacpdu->tlv_type_terminator = 0x00; - lacpdu->terminator_length = 0; - for (index=0; index<=49; index++) { - lacpdu->reserved_50[index]=0; - } -} - ////////////////////////////////////////////////////////////////////////////////////// // ================= AD exported functions to the main bonding code ================== ////////////////////////////////////////////////////////////////////////////////////// @@ -1830,6 +1821,19 @@ static void ad_initialize_lacpdu(struct lacpdu *lacpdu) // Check aggregators status in team every T seconds #define AD_AGGREGATOR_SELECTION_TIMER 8 +/* + * bond_3ad_initiate_agg_selection(struct bonding *bond) + * + * Set the aggregation selection timer, to initiate an agg selection in + * the very near future. Called during first initialization, and during + * any down to up transitions of the bond. + */ +void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout) +{ + BOND_AD_INFO(bond).agg_select_timer = timeout; + BOND_AD_INFO(bond).agg_select_mode = bond->params.ad_select; +} + static u16 aggregator_identifier; /** @@ -1854,9 +1858,9 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fas // initialize how many times this module is called in one second(should be about every 100ms) ad_ticks_per_sec = tick_resolution; - // initialize the aggregator selection timer(to activate an aggregation selection after initialize) - BOND_AD_INFO(bond).agg_select_timer = (AD_AGGREGATOR_SELECTION_TIMER * ad_ticks_per_sec); - BOND_AD_INFO(bond).agg_select_mode = AD_BANDWIDTH; + bond_3ad_initiate_agg_selection(bond, + AD_AGGREGATOR_SELECTION_TIMER * + ad_ticks_per_sec); } } @@ -1956,7 +1960,7 @@ void bond_3ad_unbind_slave(struct slave *slave) return; } - dprintk("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier); + pr_debug("Unbinding Link Aggregation Group %d\n", aggregator->aggregator_identifier); /* Tell the partner that this port is not suitable for aggregation */ port->actor_oper_port_state &= ~AD_STATE_AGGREGATION; @@ -1980,7 +1984,7 @@ void bond_3ad_unbind_slave(struct slave *slave) // if new aggregator found, copy the aggregator's parameters // and connect the related lag_ports to the new aggregator if ((new_aggregator) && ((!new_aggregator->lag_ports) || ((new_aggregator->lag_ports == port) && !new_aggregator->lag_ports->next_port_in_aggregator))) { - dprintk("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); + pr_debug("Some port(s) related to LAG %d - replaceing with LAG %d\n", aggregator->aggregator_identifier, new_aggregator->aggregator_identifier); if ((new_aggregator->lag_ports == port) && new_aggregator->is_active) { printk(KERN_INFO DRV_NAME ": %s: Removing an active aggregator\n", @@ -2031,7 +2035,7 @@ void bond_3ad_unbind_slave(struct slave *slave) } } - dprintk("Unbinding port %d\n", port->actor_port_number); + pr_debug("Unbinding port %d\n", port->actor_port_number); // find the aggregator that this port is connected to temp_aggregator = __get_first_agg(port); for (; temp_aggregator; temp_aggregator = __get_next_agg(temp_aggregator)) { @@ -2162,7 +2166,7 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u switch (lacpdu->subtype) { case AD_TYPE_LACPDU: - dprintk("Received LACPDU on port %d\n", port->actor_port_number); + pr_debug("Received LACPDU on port %d\n", port->actor_port_number); ad_rx_machine(lacpdu, port); break; @@ -2171,17 +2175,17 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u switch (((struct bond_marker *)lacpdu)->tlv_type) { case AD_MARKER_INFORMATION_SUBTYPE: - dprintk("Received Marker Information on port %d\n", port->actor_port_number); + pr_debug("Received Marker Information on port %d\n", port->actor_port_number); ad_marker_info_received((struct bond_marker *)lacpdu, port); break; case AD_MARKER_RESPONSE_SUBTYPE: - dprintk("Received Marker Response on port %d\n", port->actor_port_number); + pr_debug("Received Marker Response on port %d\n", port->actor_port_number); ad_marker_response_received((struct bond_marker *)lacpdu, port); break; default: - dprintk("Received an unknown Marker subtype on slot %d\n", port->actor_port_number); + pr_debug("Received an unknown Marker subtype on slot %d\n", port->actor_port_number); } } } @@ -2209,7 +2213,7 @@ void bond_3ad_adapter_speed_changed(struct slave *slave) port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1); - dprintk("Port %d changed speed\n", port->actor_port_number); + pr_debug("Port %d changed speed\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2237,7 +2241,7 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave) port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port); - dprintk("Port %d changed duplex\n", port->actor_port_number); + pr_debug("Port %d changed duplex\n", port->actor_port_number); // there is no need to reselect a new aggregator, just signal the // state machines to reinitialize port->sm_vars |= AD_PORT_BEGIN; @@ -2267,14 +2271,14 @@ void bond_3ad_handle_link_change(struct slave *slave, char link) // on link down we are zeroing duplex and speed since some of the adaptors(ce1000.lan) report full duplex/speed instead of N/A(duplex) / 0(speed) // on link up we are forcing recheck on the duplex and speed since some of he adaptors(ce1000.lan) report if (link == BOND_LINK_UP) { - port->is_enabled = 1; + port->is_enabled = true; port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= __get_duplex(port); port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS; port->actor_oper_port_key=port->actor_admin_port_key |= (__get_link_speed(port) << 1); } else { /* link has failed */ - port->is_enabled = 0; + port->is_enabled = false; port->actor_admin_port_key &= ~AD_DUPLEX_KEY_BITS; port->actor_oper_port_key= (port->actor_admin_port_key &= ~AD_SPEED_KEY_BITS); } @@ -2346,7 +2350,7 @@ int bond_3ad_get_active_agg_info(struct bonding *bond, struct ad_info *ad_info) int bond_3ad_xmit_xor(struct sk_buff *skb, struct net_device *dev) { struct slave *slave, *start_at; - struct bonding *bond = dev->priv; + struct bonding *bond = netdev_priv(dev); int slave_agg_no; int slaves_in_agg; int agg_id; @@ -2426,7 +2430,7 @@ out: int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type* ptype, struct net_device *orig_dev) { - struct bonding *bond = dev->priv; + struct bonding *bond = netdev_priv(dev); struct slave *slave = NULL; int ret = NET_RX_DROP; @@ -2437,7 +2441,8 @@ int bond_3ad_lacpdu_recv(struct sk_buff *skb, struct net_device *dev, struct pac goto out; read_lock(&bond->lock); - slave = bond_get_slave_by_dev((struct bonding *)dev->priv, orig_dev); + slave = bond_get_slave_by_dev((struct bonding *)netdev_priv(dev), + orig_dev); if (!slave) goto out_unlock; diff --git a/drivers/net/bonding/bond_3ad.h b/drivers/net/bonding/bond_3ad.h index b5ee45f6d55a41fec6bd93c890c75415d04e6de3..8a83eb283c21c8abecb64047be80a72faaa611b5 100644 --- a/drivers/net/bonding/bond_3ad.h +++ b/drivers/net/bonding/bond_3ad.h @@ -33,7 +33,6 @@ #define AD_TIMER_INTERVAL 100 /*msec*/ #define MULTICAST_LACPDU_ADDR {0x01, 0x80, 0xC2, 0x00, 0x00, 0x02} -#define AD_MULTICAST_LACPDU_ADDR {MULTICAST_LACPDU_ADDR} #define AD_LACP_SLOW 0 #define AD_LACP_FAST 1 @@ -42,10 +41,11 @@ typedef struct mac_addr { u8 mac_addr_value[ETH_ALEN]; } mac_addr_t; -typedef enum { - AD_BANDWIDTH = 0, - AD_COUNT -} agg_selection_t; +enum { + BOND_AD_STABLE = 0, + BOND_AD_BANDWIDTH = 1, + BOND_AD_COUNT = 2, +}; // rx machine states(43.4.11 in the 802.3ad standard) typedef enum { @@ -105,12 +105,6 @@ typedef enum { #pragma pack(1) -typedef struct ad_header { - struct mac_addr destination_address; - struct mac_addr source_address; - __be16 length_type; -} ad_header_t; - // Link Aggregation Control Protocol(LACP) data unit structure(43.4.2.2 in the 802.3ad standard) typedef struct lacpdu { u8 subtype; // = LACP(= 0x01) @@ -143,7 +137,7 @@ typedef struct lacpdu { } lacpdu_t; typedef struct lacpdu_header { - struct ad_header ad_header; + struct ethhdr hdr; struct lacpdu lacpdu; } lacpdu_header_t; @@ -164,7 +158,7 @@ typedef struct bond_marker { } bond_marker_t; typedef struct bond_marker_header { - struct ad_header ad_header; + struct ethhdr hdr; struct bond_marker marker; } bond_marker_header_t; @@ -183,7 +177,7 @@ struct port; typedef struct aggregator { struct mac_addr aggregator_mac_address; u16 aggregator_identifier; - u16 is_individual; // BOOLEAN + bool is_individual; u16 actor_admin_aggregator_key; u16 actor_oper_aggregator_key; struct mac_addr partner_system; @@ -198,6 +192,15 @@ typedef struct aggregator { u16 num_of_ports; } aggregator_t; +struct port_params { + struct mac_addr system; + u16 system_priority; + u16 key; + u16 port_number; + u16 port_priority; + u16 port_state; +}; + // port structure(43.4.6 in the 802.3ad standard) typedef struct port { u16 actor_port_number; @@ -205,24 +208,17 @@ typedef struct port { struct mac_addr actor_system; // This parameter is added here although it is not specified in the standard, just for simplification u16 actor_system_priority; // This parameter is added here although it is not specified in the standard, just for simplification u16 actor_port_aggregator_identifier; - u16 ntt; // BOOLEAN + bool ntt; u16 actor_admin_port_key; u16 actor_oper_port_key; u8 actor_admin_port_state; u8 actor_oper_port_state; - struct mac_addr partner_admin_system; - struct mac_addr partner_oper_system; - u16 partner_admin_system_priority; - u16 partner_oper_system_priority; - u16 partner_admin_key; - u16 partner_oper_key; - u16 partner_admin_port_number; - u16 partner_oper_port_number; - u16 partner_admin_port_priority; - u16 partner_oper_port_priority; - u8 partner_admin_port_state; - u8 partner_oper_port_state; - u16 is_enabled; // BOOLEAN + + struct port_params partner_admin; + struct port_params partner_oper; + + bool is_enabled; + // ****** PRIVATE PARAMETERS ****** u16 sm_vars; // all state machines variables for this port rx_states_t sm_rx_state; // state machine rx state @@ -241,10 +237,10 @@ typedef struct port { } port_t; // system structure -typedef struct ad_system { +struct ad_system { u16 sys_priority; struct mac_addr sys_mac_addr; -} ad_system_t; +}; #ifdef __ia64__ #pragma pack() @@ -255,7 +251,7 @@ typedef struct ad_system { #define SLAVE_AD_INFO(slave) ((slave)->ad_info) struct ad_bond_info { - ad_system_t system; // 802.3ad system structure + struct ad_system system; /* 802.3ad system structure */ u32 agg_select_timer; // Timer to select aggregator after all adapter's hand shakes u32 agg_select_mode; // Mode of selection of active aggregator(bandwidth/count) int lacp_fast; /* whether fast periodic tx should be @@ -277,6 +273,7 @@ void bond_3ad_initialize(struct bonding *bond, u16 tick_resolution, int lacp_fas int bond_3ad_bind_slave(struct slave *slave); void bond_3ad_unbind_slave(struct slave *slave); void bond_3ad_state_machine_handler(struct work_struct *); +void bond_3ad_initiate_agg_selection(struct bonding *bond, int timeout); void bond_3ad_adapter_speed_changed(struct slave *slave); void bond_3ad_adapter_duplex_changed(struct slave *slave); void bond_3ad_handle_link_change(struct slave *slave, char link); diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c index 87437c788476ab8a05df31a0f7fd1887ffeef497..27fb7f5c21cf57029b62d830ada44b6f26904dac 100644 --- a/drivers/net/bonding/bond_alb.c +++ b/drivers/net/bonding/bond_alb.c @@ -20,8 +20,6 @@ * */ -//#define BONDING_DEBUG 1 - #include #include #include @@ -346,30 +344,37 @@ static void rlb_update_entry_from_arp(struct bonding *bond, struct arp_pkt *arp) static int rlb_arp_recv(struct sk_buff *skb, struct net_device *bond_dev, struct packet_type *ptype, struct net_device *orig_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond; struct arp_pkt *arp = (struct arp_pkt *)skb->data; int res = NET_RX_DROP; if (dev_net(bond_dev) != &init_net) goto out; - if (!(bond_dev->flags & IFF_MASTER)) + while (bond_dev->priv_flags & IFF_802_1Q_VLAN) + bond_dev = vlan_dev_real_dev(bond_dev); + + if (!(bond_dev->priv_flags & IFF_BONDING) || + !(bond_dev->flags & IFF_MASTER)) goto out; if (!arp) { - dprintk("Packet has no ARP data\n"); + pr_debug("Packet has no ARP data\n"); goto out; } if (skb->len < sizeof(struct arp_pkt)) { - dprintk("Packet is too small to be an ARP\n"); + pr_debug("Packet is too small to be an ARP\n"); goto out; } if (arp->op_code == htons(ARPOP_REPLY)) { /* update rx hash table for this ARP */ + printk("rar: update orig %s bond_dev %s\n", orig_dev->name, + bond_dev->name); + bond = netdev_priv(bond_dev); rlb_update_entry_from_arp(bond, arp); - dprintk("Server received an ARP Reply from client\n"); + pr_debug("Server received an ARP Reply from client\n"); } res = NET_RX_SUCCESS; @@ -723,7 +728,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) if (tx_slave) { memcpy(arp->mac_src,tx_slave->dev->dev_addr, ETH_ALEN); } - dprintk("Server sent ARP Reply packet\n"); + pr_debug("Server sent ARP Reply packet\n"); } else if (arp->op_code == htons(ARPOP_REQUEST)) { /* Create an entry in the rx_hashtbl for this client as a * place holder. @@ -743,7 +748,7 @@ static struct slave *rlb_arp_xmit(struct sk_buff *skb, struct bonding *bond) * updated with their assigned mac. */ rlb_req_update_subnet_clients(bond, arp->ip_src); - dprintk("Server sent ARP Request packet\n"); + pr_debug("Server sent ARP Request packet\n"); } return tx_slave; @@ -818,7 +823,7 @@ static int rlb_initialize(struct bonding *bond) /*initialize packet type*/ pk_type->type = __constant_htons(ETH_P_ARP); - pk_type->dev = bond->dev; + pk_type->dev = NULL; pk_type->func = rlb_arp_recv; /* register to receive ARPs */ @@ -1211,11 +1216,6 @@ static int alb_set_mac_address(struct bonding *bond, void *addr) } bond_for_each_slave(bond, slave, i) { - if (slave->dev->set_mac_address == NULL) { - res = -EOPNOTSUPP; - goto unwind; - } - /* save net_device's current hw address */ memcpy(tmp_addr, slave->dev->dev_addr, ETH_ALEN); @@ -1224,9 +1224,8 @@ static int alb_set_mac_address(struct bonding *bond, void *addr) /* restore net_device's hw address */ memcpy(slave->dev->dev_addr, tmp_addr, ETH_ALEN); - if (res) { + if (res) goto unwind; - } } return 0; @@ -1285,7 +1284,7 @@ void bond_alb_deinitialize(struct bonding *bond) int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct ethhdr *eth_data; struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; @@ -1706,7 +1705,7 @@ void bond_alb_handle_active_change(struct bonding *bond, struct slave *new_slave */ int bond_alb_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct sockaddr *sa = addr; struct slave *slave, *swap_slave; int res; diff --git a/drivers/net/bonding/bond_ipv6.c b/drivers/net/bonding/bond_ipv6.c new file mode 100644 index 0000000000000000000000000000000000000000..0d73bf5ac5a5b1014be49e17193b2be6b216809f --- /dev/null +++ b/drivers/net/bonding/bond_ipv6.c @@ -0,0 +1,216 @@ +/* + * Copyright(c) 2008 Hewlett-Packard Development Company, L.P. + * + * 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. + * + * The full GNU General Public License is included in this distribution in the + * file called LICENSE. + * + */ + +#include +#include +#include +#include +#include +#include "bonding.h" + +/* + * Assign bond->master_ipv6 to the next IPv6 address in the list, or + * zero it out if there are none. + */ +static void bond_glean_dev_ipv6(struct net_device *dev, struct in6_addr *addr) +{ + struct inet6_dev *idev; + struct inet6_ifaddr *ifa; + + if (!dev) + return; + + idev = in6_dev_get(dev); + if (!idev) + return; + + read_lock_bh(&idev->lock); + ifa = idev->addr_list; + if (ifa) + ipv6_addr_copy(addr, &ifa->addr); + else + ipv6_addr_set(addr, 0, 0, 0, 0); + + read_unlock_bh(&idev->lock); + + in6_dev_put(idev); +} + +static void bond_na_send(struct net_device *slave_dev, + struct in6_addr *daddr, + int router, + unsigned short vlan_id) +{ + struct in6_addr mcaddr; + struct icmp6hdr icmp6h = { + .icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT, + }; + struct sk_buff *skb; + + icmp6h.icmp6_router = router; + icmp6h.icmp6_solicited = 0; + icmp6h.icmp6_override = 1; + + addrconf_addr_solict_mult(daddr, &mcaddr); + + pr_debug("ipv6 na on slave %s: dest %pI6, src %pI6\n", + slave_dev->name, &mcaddr, daddr); + + skb = ndisc_build_skb(slave_dev, &mcaddr, daddr, &icmp6h, daddr, + ND_OPT_TARGET_LL_ADDR); + + if (!skb) { + printk(KERN_ERR DRV_NAME ": NA packet allocation failed\n"); + return; + } + + if (vlan_id) { + skb = vlan_put_tag(skb, vlan_id); + if (!skb) { + printk(KERN_ERR DRV_NAME ": failed to insert VLAN tag\n"); + return; + } + } + + ndisc_send_skb(skb, slave_dev, NULL, &mcaddr, daddr, &icmp6h); +} + +/* + * Kick out an unsolicited Neighbor Advertisement for an IPv6 address on + * the bonding master. This will help the switch learn our address + * if in active-backup mode. + * + * Caller must hold curr_slave_lock for read or better + */ +void bond_send_unsolicited_na(struct bonding *bond) +{ + struct slave *slave = bond->curr_active_slave; + struct vlan_entry *vlan; + struct inet6_dev *idev; + int is_router; + + pr_debug("bond_send_unsol_na: bond %s slave %s\n", bond->dev->name, + slave ? slave->dev->name : "NULL"); + + if (!slave || !bond->send_unsol_na || + test_bit(__LINK_STATE_LINKWATCH_PENDING, &slave->dev->state)) + return; + + bond->send_unsol_na--; + + idev = in6_dev_get(bond->dev); + if (!idev) + return; + + is_router = !!idev->cnf.forwarding; + + in6_dev_put(idev); + + if (!ipv6_addr_any(&bond->master_ipv6)) + bond_na_send(slave->dev, &bond->master_ipv6, is_router, 0); + + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { + if (!ipv6_addr_any(&vlan->vlan_ipv6)) { + bond_na_send(slave->dev, &vlan->vlan_ipv6, is_router, + vlan->vlan_id); + } + } +} + +/* + * bond_inet6addr_event: handle inet6addr notifier chain events. + * + * We keep track of device IPv6 addresses primarily to use as source + * addresses in NS probes. + * + * We track one IPv6 for the main device (if it has one). + */ +static int bond_inet6addr_event(struct notifier_block *this, + unsigned long event, + void *ptr) +{ + struct inet6_ifaddr *ifa = ptr; + struct net_device *vlan_dev, *event_dev = ifa->idev->dev; + struct bonding *bond; + struct vlan_entry *vlan; + + if (dev_net(event_dev) != &init_net) + return NOTIFY_DONE; + + list_for_each_entry(bond, &bond_dev_list, bond_list) { + if (bond->dev == event_dev) { + switch (event) { + case NETDEV_UP: + if (ipv6_addr_any(&bond->master_ipv6)) + ipv6_addr_copy(&bond->master_ipv6, + &ifa->addr); + return NOTIFY_OK; + case NETDEV_DOWN: + if (ipv6_addr_equal(&bond->master_ipv6, + &ifa->addr)) + bond_glean_dev_ipv6(bond->dev, + &bond->master_ipv6); + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } + } + + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { + vlan_dev = vlan_group_get_device(bond->vlgrp, + vlan->vlan_id); + if (vlan_dev == event_dev) { + switch (event) { + case NETDEV_UP: + if (ipv6_addr_any(&vlan->vlan_ipv6)) + ipv6_addr_copy(&vlan->vlan_ipv6, + &ifa->addr); + return NOTIFY_OK; + case NETDEV_DOWN: + if (ipv6_addr_equal(&vlan->vlan_ipv6, + &ifa->addr)) + bond_glean_dev_ipv6(vlan_dev, + &vlan->vlan_ipv6); + return NOTIFY_OK; + default: + return NOTIFY_DONE; + } + } + } + } + return NOTIFY_DONE; +} + +static struct notifier_block bond_inet6addr_notifier = { + .notifier_call = bond_inet6addr_event, +}; + +void bond_register_ipv6_notifier(void) +{ + register_inet6addr_notifier(&bond_inet6addr_notifier); +} + +void bond_unregister_ipv6_notifier(void) +{ + unregister_inet6addr_notifier(&bond_inet6addr_notifier); +} + diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index a3efba59eee98daa96aeae7dd1278865a31c6db6..460c2cad2755d2c5df58b626eceb280619271632 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -31,8 +31,6 @@ * */ -//#define BONDING_DEBUG 1 - #include #include #include @@ -89,6 +87,7 @@ static int max_bonds = BOND_DEFAULT_MAX_BONDS; static int num_grat_arp = 1; +static int num_unsol_na = 1; static int miimon = BOND_LINK_MON_INTERV; static int updelay = 0; static int downdelay = 0; @@ -96,6 +95,7 @@ static int use_carrier = 1; static char *mode = NULL; static char *primary = NULL; static char *lacp_rate = NULL; +static char *ad_select = NULL; static char *xmit_hash_policy = NULL; static int arp_interval = BOND_LINK_ARP_INTERV; static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, }; @@ -107,6 +107,8 @@ module_param(max_bonds, int, 0); MODULE_PARM_DESC(max_bonds, "Max number of bonded devices"); module_param(num_grat_arp, int, 0644); MODULE_PARM_DESC(num_grat_arp, "Number of gratuitous ARP packets to send on failover event"); +module_param(num_unsol_na, int, 0644); +MODULE_PARM_DESC(num_unsol_na, "Number of unsolicited IPv6 Neighbor Advertisements packets to send on failover event"); module_param(miimon, int, 0); MODULE_PARM_DESC(miimon, "Link check interval in milliseconds"); module_param(updelay, int, 0); @@ -127,6 +129,8 @@ MODULE_PARM_DESC(primary, "Primary network device to use"); module_param(lacp_rate, charp, 0); MODULE_PARM_DESC(lacp_rate, "LACPDU tx rate to request from 802.3ad partner " "(slow/fast)"); +module_param(ad_select, charp, 0); +MODULE_PARM_DESC(ad_select, "803.ad aggregation selection logic: stable (0, default), bandwidth (1), count (2)"); module_param(xmit_hash_policy, charp, 0); MODULE_PARM_DESC(xmit_hash_policy, "XOR hashing method: 0 for layer 2 (default)" ", 1 for layer 3+4"); @@ -150,7 +154,6 @@ LIST_HEAD(bond_dev_list); static struct proc_dir_entry *bond_proc_dir = NULL; #endif -extern struct rw_semaphore bonding_rwsem; static __be32 arp_target[BOND_MAX_ARP_TARGETS] = { 0, } ; static int arp_ip_count = 0; static int bond_mode = BOND_MODE_ROUNDROBIN; @@ -158,13 +161,13 @@ static int xmit_hashtype= BOND_XMIT_POLICY_LAYER2; static int lacp_fast = 0; -struct bond_parm_tbl bond_lacp_tbl[] = { +const struct bond_parm_tbl bond_lacp_tbl[] = { { "slow", AD_LACP_SLOW}, { "fast", AD_LACP_FAST}, { NULL, -1}, }; -struct bond_parm_tbl bond_mode_tbl[] = { +const struct bond_parm_tbl bond_mode_tbl[] = { { "balance-rr", BOND_MODE_ROUNDROBIN}, { "active-backup", BOND_MODE_ACTIVEBACKUP}, { "balance-xor", BOND_MODE_XOR}, @@ -175,14 +178,14 @@ struct bond_parm_tbl bond_mode_tbl[] = { { NULL, -1}, }; -struct bond_parm_tbl xmit_hashtype_tbl[] = { +const struct bond_parm_tbl xmit_hashtype_tbl[] = { { "layer2", BOND_XMIT_POLICY_LAYER2}, { "layer3+4", BOND_XMIT_POLICY_LAYER34}, { "layer2+3", BOND_XMIT_POLICY_LAYER23}, { NULL, -1}, }; -struct bond_parm_tbl arp_validate_tbl[] = { +const struct bond_parm_tbl arp_validate_tbl[] = { { "none", BOND_ARP_VALIDATE_NONE}, { "active", BOND_ARP_VALIDATE_ACTIVE}, { "backup", BOND_ARP_VALIDATE_BACKUP}, @@ -190,13 +193,20 @@ struct bond_parm_tbl arp_validate_tbl[] = { { NULL, -1}, }; -struct bond_parm_tbl fail_over_mac_tbl[] = { +const struct bond_parm_tbl fail_over_mac_tbl[] = { { "none", BOND_FOM_NONE}, { "active", BOND_FOM_ACTIVE}, { "follow", BOND_FOM_FOLLOW}, { NULL, -1}, }; +struct bond_parm_tbl ad_select_tbl[] = { +{ "stable", BOND_AD_STABLE}, +{ "bandwidth", BOND_AD_BANDWIDTH}, +{ "count", BOND_AD_COUNT}, +{ NULL, -1}, +}; + /*-------------------------- Forward declarations ---------------------------*/ static void bond_send_gratuitous_arp(struct bonding *bond); @@ -206,24 +216,20 @@ static void bond_deinit(struct net_device *bond_dev); static const char *bond_mode_name(int mode) { - switch (mode) { - case BOND_MODE_ROUNDROBIN : - return "load balancing (round-robin)"; - case BOND_MODE_ACTIVEBACKUP : - return "fault-tolerance (active-backup)"; - case BOND_MODE_XOR : - return "load balancing (xor)"; - case BOND_MODE_BROADCAST : - return "fault-tolerance (broadcast)"; - case BOND_MODE_8023AD: - return "IEEE 802.3ad Dynamic link aggregation"; - case BOND_MODE_TLB: - return "transmit load balancing"; - case BOND_MODE_ALB: - return "adaptive load balancing"; - default: + static const char *names[] = { + [BOND_MODE_ROUNDROBIN] = "load balancing (round-robin)", + [BOND_MODE_ACTIVEBACKUP] = "fault-tolerance (active-backup)", + [BOND_MODE_XOR] = "load balancing (xor)", + [BOND_MODE_BROADCAST] = "fault-tolerance (broadcast)", + [BOND_MODE_8023AD]= "IEEE 802.3ad Dynamic link aggregation", + [BOND_MODE_TLB] = "transmit load balancing", + [BOND_MODE_ALB] = "adaptive load balancing", + }; + + if (mode < 0 || mode > BOND_MODE_ALB) return "unknown"; - } + + return names[mode]; } /*---------------------------------- VLAN -----------------------------------*/ @@ -239,17 +245,16 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id) { struct vlan_entry *vlan; - dprintk("bond: %s, vlan id %d\n", + pr_debug("bond: %s, vlan id %d\n", (bond ? bond->dev->name: "None"), vlan_id); - vlan = kmalloc(sizeof(struct vlan_entry), GFP_KERNEL); + vlan = kzalloc(sizeof(struct vlan_entry), GFP_KERNEL); if (!vlan) { return -ENOMEM; } INIT_LIST_HEAD(&vlan->vlan_list); vlan->vlan_id = vlan_id; - vlan->vlan_ip = 0; write_lock_bh(&bond->lock); @@ -257,7 +262,7 @@ static int bond_add_vlan(struct bonding *bond, unsigned short vlan_id) write_unlock_bh(&bond->lock); - dprintk("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name); + pr_debug("added VLAN ID %d on bond %s\n", vlan_id, bond->dev->name); return 0; } @@ -274,7 +279,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) struct vlan_entry *vlan; int res = -ENODEV; - dprintk("bond: %s, vlan id %d\n", bond->dev->name, vlan_id); + pr_debug("bond: %s, vlan id %d\n", bond->dev->name, vlan_id); write_lock_bh(&bond->lock); @@ -282,12 +287,10 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) if (vlan->vlan_id == vlan_id) { list_del(&vlan->vlan_list); - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) bond_alb_clear_vlan(bond, vlan_id); - } - dprintk("removed VLAN ID %d from bond %s\n", vlan_id, + pr_debug("removed VLAN ID %d from bond %s\n", vlan_id, bond->dev->name); kfree(vlan); @@ -307,7 +310,7 @@ static int bond_del_vlan(struct bonding *bond, unsigned short vlan_id) } } - dprintk("couldn't find VLAN ID %d in bond %s\n", vlan_id, + pr_debug("couldn't find VLAN ID %d in bond %s\n", vlan_id, bond->dev->name); out: @@ -331,13 +334,13 @@ static int bond_has_challenged_slaves(struct bonding *bond) bond_for_each_slave(bond, slave, i) { if (slave->dev->features & NETIF_F_VLAN_CHALLENGED) { - dprintk("found VLAN challenged slave - %s\n", + pr_debug("found VLAN challenged slave - %s\n", slave->dev->name); return 1; } } - dprintk("no VLAN challenged slaves found\n"); + pr_debug("no VLAN challenged slaves found\n"); return 0; } @@ -442,7 +445,7 @@ int bond_dev_queue_xmit(struct bonding *bond, struct sk_buff *skb, struct net_de */ static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group *grp) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; int i; @@ -450,10 +453,11 @@ static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group bond_for_each_slave(bond, slave, i) { struct net_device *slave_dev = slave->dev; + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && - slave_dev->vlan_rx_register) { - slave_dev->vlan_rx_register(slave_dev, grp); + slave_ops->ndo_vlan_rx_register) { + slave_ops->ndo_vlan_rx_register(slave_dev, grp); } } } @@ -465,16 +469,17 @@ static void bond_vlan_rx_register(struct net_device *bond_dev, struct vlan_group */ static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; int i, res; bond_for_each_slave(bond, slave, i) { struct net_device *slave_dev = slave->dev; + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && - slave_dev->vlan_rx_add_vid) { - slave_dev->vlan_rx_add_vid(slave_dev, vid); + slave_ops->ndo_vlan_rx_add_vid) { + slave_ops->ndo_vlan_rx_add_vid(slave_dev, vid); } } @@ -493,21 +498,22 @@ static void bond_vlan_rx_add_vid(struct net_device *bond_dev, uint16_t vid) */ static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; struct net_device *vlan_dev; int i, res; bond_for_each_slave(bond, slave, i) { struct net_device *slave_dev = slave->dev; + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; if ((slave_dev->features & NETIF_F_HW_VLAN_FILTER) && - slave_dev->vlan_rx_kill_vid) { + slave_ops->ndo_vlan_rx_kill_vid) { /* Save and then restore vlan_dev in the grp array, * since the slave's driver might clear it. */ vlan_dev = vlan_group_get_device(bond->vlgrp, vid); - slave_dev->vlan_rx_kill_vid(slave_dev, vid); + slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vid); vlan_group_set_device(bond->vlgrp, vid, vlan_dev); } } @@ -523,26 +529,23 @@ static void bond_vlan_rx_kill_vid(struct net_device *bond_dev, uint16_t vid) static void bond_add_vlans_on_slave(struct bonding *bond, struct net_device *slave_dev) { struct vlan_entry *vlan; + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; write_lock_bh(&bond->lock); - if (list_empty(&bond->vlan_list)) { + if (list_empty(&bond->vlan_list)) goto out; - } if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && - slave_dev->vlan_rx_register) { - slave_dev->vlan_rx_register(slave_dev, bond->vlgrp); - } + slave_ops->ndo_vlan_rx_register) + slave_ops->ndo_vlan_rx_register(slave_dev, bond->vlgrp); if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || - !(slave_dev->vlan_rx_add_vid)) { + !(slave_ops->ndo_vlan_rx_add_vid)) goto out; - } - list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { - slave_dev->vlan_rx_add_vid(slave_dev, vlan->vlan_id); - } + list_for_each_entry(vlan, &bond->vlan_list, vlan_list) + slave_ops->ndo_vlan_rx_add_vid(slave_dev, vlan->vlan_id); out: write_unlock_bh(&bond->lock); @@ -550,34 +553,32 @@ out: static void bond_del_vlans_from_slave(struct bonding *bond, struct net_device *slave_dev) { + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; struct vlan_entry *vlan; struct net_device *vlan_dev; write_lock_bh(&bond->lock); - if (list_empty(&bond->vlan_list)) { + if (list_empty(&bond->vlan_list)) goto out; - } if (!(slave_dev->features & NETIF_F_HW_VLAN_FILTER) || - !(slave_dev->vlan_rx_kill_vid)) { + !(slave_ops->ndo_vlan_rx_kill_vid)) goto unreg; - } list_for_each_entry(vlan, &bond->vlan_list, vlan_list) { /* Save and then restore vlan_dev in the grp array, * since the slave's driver might clear it. */ vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); - slave_dev->vlan_rx_kill_vid(slave_dev, vlan->vlan_id); + slave_ops->ndo_vlan_rx_kill_vid(slave_dev, vlan->vlan_id); vlan_group_set_device(bond->vlgrp, vlan->vlan_id, vlan_dev); } unreg: if ((slave_dev->features & NETIF_F_HW_VLAN_RX) && - slave_dev->vlan_rx_register) { - slave_dev->vlan_rx_register(slave_dev, NULL); - } + slave_ops->ndo_vlan_rx_register) + slave_ops->ndo_vlan_rx_register(slave_dev, NULL); out: write_unlock_bh(&bond->lock); @@ -686,15 +687,15 @@ static int bond_update_speed_duplex(struct slave *slave) */ static int bond_check_dev_link(struct bonding *bond, struct net_device *slave_dev, int reporting) { + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; static int (* ioctl)(struct net_device *, struct ifreq *, int); struct ifreq ifr; struct mii_ioctl_data *mii; - if (bond->params.use_carrier) { + if (bond->params.use_carrier) return netif_carrier_ok(slave_dev) ? BMSR_LSTATUS : 0; - } - ioctl = slave_dev->do_ioctl; + ioctl = slave_ops->ndo_do_ioctl; if (ioctl) { /* TODO: set pointer to correct ioctl on a per team member */ /* bases to make this more efficient. that is, once */ @@ -927,7 +928,7 @@ static int bond_mc_list_copy(struct dev_mc_list *mc_list, struct bonding *bond, */ static void bond_mc_list_flush(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct dev_mc_list *dmi; for (dmi = bond_dev->mc_list; dmi; dmi = dmi->next) { @@ -1164,10 +1165,8 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_3ad_handle_link_change(new_active, BOND_LINK_UP); } - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) bond_alb_handle_link_change(bond, new_active, BOND_LINK_UP); - } } else { if (USES_PRIMARY(bond->params.mode)) { printk(KERN_INFO DRV_NAME @@ -1182,8 +1181,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond_mc_swap(bond, new_active, old_active); } - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { bond_alb_handle_active_change(bond, new_active); if (old_active) bond_set_slave_inactive_flags(old_active); @@ -1208,6 +1206,9 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active) bond->send_grat_arp = bond->params.num_grat_arp; bond_send_gratuitous_arp(bond); + bond->send_unsol_na = bond->params.num_unsol_na; + bond_send_unsolicited_na(bond); + write_unlock_bh(&bond->curr_slave_lock); read_unlock(&bond->lock); @@ -1315,9 +1316,9 @@ static void bond_detach_slave(struct bonding *bond, struct slave *slave) static int bond_sethwaddr(struct net_device *bond_dev, struct net_device *slave_dev) { - dprintk("bond_dev=%p\n", bond_dev); - dprintk("slave_dev=%p\n", slave_dev); - dprintk("slave_dev->addr_len=%d\n", slave_dev->addr_len); + pr_debug("bond_dev=%p\n", bond_dev); + pr_debug("slave_dev=%p\n", slave_dev); + pr_debug("slave_dev->addr_len=%d\n", slave_dev->addr_len); memcpy(bond_dev->dev_addr, slave_dev->dev_addr, slave_dev->addr_len); return 0; } @@ -1364,14 +1365,12 @@ done: return 0; } - static void bond_setup_by_slave(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); - bond_dev->neigh_setup = slave_dev->neigh_setup; - bond_dev->header_ops = slave_dev->header_ops; + bond_dev->header_ops = slave_dev->header_ops; bond_dev->type = slave_dev->type; bond_dev->hard_header_len = slave_dev->hard_header_len; @@ -1385,7 +1384,8 @@ static void bond_setup_by_slave(struct net_device *bond_dev, /* enslave device to bond device */ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); + const struct net_device_ops *slave_ops = slave_dev->netdev_ops; struct slave *new_slave = NULL; struct dev_mc_list *dmi; struct sockaddr addr; @@ -1394,7 +1394,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) int res = 0; if (!bond->params.use_carrier && slave_dev->ethtool_ops == NULL && - slave_dev->do_ioctl == NULL) { + slave_ops->ndo_do_ioctl == NULL) { printk(KERN_WARNING DRV_NAME ": %s: Warning: no link monitoring support for %s\n", bond_dev->name, slave_dev->name); @@ -1409,14 +1409,14 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) /* already enslaved */ if (slave_dev->flags & IFF_SLAVE) { - dprintk("Error, Device was already enslaved\n"); + pr_debug("Error, Device was already enslaved\n"); return -EBUSY; } /* vlan challenged mutual exclusion */ /* no need to lock since we're protected by rtnl_lock */ if (slave_dev->features & NETIF_F_VLAN_CHALLENGED) { - dprintk("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); + pr_debug("%s: NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); if (!list_empty(&bond->vlan_list)) { printk(KERN_ERR DRV_NAME ": %s: Error: cannot enslave VLAN " @@ -1434,7 +1434,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_dev->features |= NETIF_F_VLAN_CHALLENGED; } } else { - dprintk("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); + pr_debug("%s: ! NETIF_F_VLAN_CHALLENGED\n", slave_dev->name); if (bond->slave_cnt == 0) { /* First slave, and it is not VLAN challenged, * so remove the block of adding VLANs over the bond. @@ -1476,7 +1476,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) goto err_undo_flags; } - if (slave_dev->set_mac_address == NULL) { + if (slave_ops->ndo_set_mac_address == NULL) { if (bond->slave_cnt == 0) { printk(KERN_WARNING DRV_NAME ": %s: Warning: The first slave device " @@ -1522,28 +1522,27 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) addr.sa_family = slave_dev->type; res = dev_set_mac_address(slave_dev, &addr); if (res) { - dprintk("Error %d calling set_mac_address\n", res); + pr_debug("Error %d calling set_mac_address\n", res); goto err_free; } } res = netdev_set_master(slave_dev, bond_dev); if (res) { - dprintk("Error %d calling netdev_set_master\n", res); + pr_debug("Error %d calling netdev_set_master\n", res); goto err_restore_mac; } /* open the slave since the application closed it */ res = dev_open(slave_dev); if (res) { - dprintk("Openning slave %s failed\n", slave_dev->name); + pr_debug("Openning slave %s failed\n", slave_dev->name); goto err_unset_master; } new_slave->dev = slave_dev; slave_dev->priv_flags |= IFF_BONDING; - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { /* bond_alb_init_slave() must be called before all other stages since * it might fail and we do not want to have to undo everything */ @@ -1641,18 +1640,18 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) if (!bond->params.miimon || (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS)) { if (bond->params.updelay) { - dprintk("Initial state of slave_dev is " + pr_debug("Initial state of slave_dev is " "BOND_LINK_BACK\n"); new_slave->link = BOND_LINK_BACK; new_slave->delay = bond->params.updelay; } else { - dprintk("Initial state of slave_dev is " + pr_debug("Initial state of slave_dev is " "BOND_LINK_UP\n"); new_slave->link = BOND_LINK_UP; } new_slave->jiffies = jiffies; } else { - dprintk("Initial state of slave_dev is " + pr_debug("Initial state of slave_dev is " "BOND_LINK_DOWN\n"); new_slave->link = BOND_LINK_DOWN; } @@ -1713,7 +1712,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) bond_set_slave_inactive_flags(new_slave); break; default: - dprintk("This slave is always active in trunk mode\n"); + pr_debug("This slave is always active in trunk mode\n"); /* always active in trunk mode */ new_slave->state = BOND_STATE_ACTIVE; @@ -1787,11 +1786,10 @@ err_undo_flags: */ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *oldcurrent; struct sockaddr addr; int mac_addr_differ; - DECLARE_MAC_BUF(mac); /* slave is not a slave or master is not master of this slave */ if (!(slave_dev->flags & IFF_SLAVE) || @@ -1820,11 +1818,11 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) if (!mac_addr_differ && (bond->slave_cnt > 1)) printk(KERN_WARNING DRV_NAME ": %s: Warning: the permanent HWaddr of %s - " - "%s - is still in use by %s. " + "%pM - is still in use by %s. " "Set the HWaddr of %s to a different address " "to avoid conflicts.\n", bond_dev->name, slave_dev->name, - print_mac(mac, slave->perm_hwaddr), + slave->perm_hwaddr, bond_dev->name, slave_dev->name); } @@ -1860,8 +1858,7 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev) bond_change_active_slave(bond, NULL); } - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { /* Must be called only after the slave has been * detached from the list and the curr_active_slave * has been cleared (if our_slave == old_current), @@ -1981,7 +1978,7 @@ void bond_destroy(struct bonding *bond) static void bond_destructor(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); if (bond->wq) destroy_workqueue(bond->wq); @@ -1999,7 +1996,7 @@ static void bond_destructor(struct net_device *bond_dev) */ int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); int ret; ret = bond_release(bond_dev, slave_dev); @@ -2016,7 +2013,7 @@ int bond_release_and_destroy(struct net_device *bond_dev, struct net_device *sl */ static int bond_release_all(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; struct net_device *slave_dev; struct sockaddr addr; @@ -2050,8 +2047,7 @@ static int bond_release_all(struct net_device *bond_dev) */ write_unlock_bh(&bond->lock); - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { /* must be called only after the slave * has been detached from the list */ @@ -2147,7 +2143,7 @@ out: */ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_device *slave_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *old_active = NULL; struct slave *new_active = NULL; int res = 0; @@ -2196,7 +2192,7 @@ static int bond_ioctl_change_active(struct net_device *bond_dev, struct net_devi static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); info->bond_mode = bond->params.mode; info->miimon = bond->params.miimon; @@ -2210,7 +2206,7 @@ static int bond_info_query(struct net_device *bond_dev, struct ifbond *info) static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *info) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave; int i, found = 0; @@ -2378,8 +2374,7 @@ static void bond_miimon_commit(struct bonding *bond) if (bond->params.mode == BOND_MODE_8023AD) bond_3ad_handle_link_change(slave, BOND_LINK_UP); - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) + if (bond_is_lb(bond)) bond_alb_handle_link_change(bond, slave, BOND_LINK_UP); @@ -2464,6 +2459,12 @@ void bond_mii_monitor(struct work_struct *work) read_unlock(&bond->curr_slave_lock); } + if (bond->send_unsol_na) { + read_lock(&bond->curr_slave_lock); + bond_send_unsolicited_na(bond); + read_unlock(&bond->curr_slave_lock); + } + if (bond_miimon_inspect(bond)) { read_unlock(&bond->lock); rtnl_lock(); @@ -2532,7 +2533,7 @@ static void bond_arp_send(struct net_device *slave_dev, int arp_op, __be32 dest_ { struct sk_buff *skb; - dprintk("arp %d on slave %s: dst %x src %x vid %d\n", arp_op, + pr_debug("arp %d on slave %s: dst %x src %x vid %d\n", arp_op, slave_dev->name, dest_ip, src_ip, vlan_id); skb = arp_create(arp_op, ETH_P_ARP, dest_ip, slave_dev, src_ip, @@ -2565,9 +2566,9 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { if (!targets[i]) continue; - dprintk("basa: target %x\n", targets[i]); + pr_debug("basa: target %x\n", targets[i]); if (list_empty(&bond->vlan_list)) { - dprintk("basa: empty vlan: arp_send\n"); + pr_debug("basa: empty vlan: arp_send\n"); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], bond->master_ip, 0); continue; @@ -2586,8 +2587,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) if (rv) { if (net_ratelimit()) { printk(KERN_WARNING DRV_NAME - ": %s: no route to arp_ip_target %u.%u.%u.%u\n", - bond->dev->name, NIPQUAD(fl.fl4_dst)); + ": %s: no route to arp_ip_target %pI4\n", + bond->dev->name, &fl.fl4_dst); } continue; } @@ -2597,7 +2598,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) */ if (rt->u.dst.dev == bond->dev) { ip_rt_put(rt); - dprintk("basa: rtdev == bond->dev: arp_send\n"); + pr_debug("basa: rtdev == bond->dev: arp_send\n"); bond_arp_send(slave->dev, ARPOP_REQUEST, targets[i], bond->master_ip, 0); continue; @@ -2608,7 +2609,7 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) vlan_dev = vlan_group_get_device(bond->vlgrp, vlan->vlan_id); if (vlan_dev == rt->u.dst.dev) { vlan_id = vlan->vlan_id; - dprintk("basa: vlan match on %s %d\n", + pr_debug("basa: vlan match on %s %d\n", vlan_dev->name, vlan_id); break; } @@ -2623,8 +2624,8 @@ static void bond_arp_send_all(struct bonding *bond, struct slave *slave) if (net_ratelimit()) { printk(KERN_WARNING DRV_NAME - ": %s: no path to arp_ip_target %u.%u.%u.%u via rt.dev %s\n", - bond->dev->name, NIPQUAD(fl.fl4_dst), + ": %s: no path to arp_ip_target %pI4 via rt.dev %s\n", + bond->dev->name, &fl.fl4_dst, rt->u.dst.dev ? rt->u.dst.dev->name : "NULL"); } ip_rt_put(rt); @@ -2643,7 +2644,7 @@ static void bond_send_gratuitous_arp(struct bonding *bond) struct vlan_entry *vlan; struct net_device *vlan_dev; - dprintk("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name, + pr_debug("bond_send_grat_arp: bond %s slave %s\n", bond->dev->name, slave ? slave->dev->name : "NULL"); if (!slave || !bond->send_grat_arp || @@ -2673,10 +2674,8 @@ static void bond_validate_arp(struct bonding *bond, struct slave *slave, __be32 targets = bond->params.arp_targets; for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) { - dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] " - "%u.%u.%u.%u bhti(tip) %d\n", - NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]), - bond_has_this_ip(bond, tip)); + pr_debug("bva: sip %pI4 tip %pI4 t[%d] %pI4 bhti(tip) %d\n", + &sip, &tip, i, &targets[i], bond_has_this_ip(bond, tip)); if (sip == targets[i]) { if (bond_has_this_ip(bond, tip)) slave->last_arp_rx = jiffies; @@ -2699,10 +2698,10 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER)) goto out; - bond = dev->priv; + bond = netdev_priv(dev); read_lock(&bond->lock); - dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n", + pr_debug("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n", bond->dev->name, skb->dev ? skb->dev->name : "NULL", orig_dev ? orig_dev->name : "NULL"); @@ -2728,10 +2727,10 @@ static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct pack arp_ptr += 4 + dev->addr_len; memcpy(&tip, arp_ptr, 4); - dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u" - " tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name, - slave->state, bond->params.arp_validate, - slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip)); + pr_debug("bond_arp_rcv: %s %s/%d av %d sv %d sip %pI4 tip %pI4\n", + bond->dev->name, slave->dev->name, slave->state, + bond->params.arp_validate, slave_do_arp_validate(bond, slave), + &sip, &tip); /* * Backup slaves won't see the ARP reply, but do come through @@ -3161,6 +3160,12 @@ void bond_activebackup_arp_mon(struct work_struct *work) read_unlock(&bond->curr_slave_lock); } + if (bond->send_unsol_na) { + read_lock(&bond->curr_slave_lock); + bond_send_unsolicited_na(bond); + read_unlock(&bond->curr_slave_lock); + } + if (bond_ab_arp_inspect(bond, delta_in_ticks)) { read_unlock(&bond->lock); rtnl_lock(); @@ -3239,7 +3244,6 @@ static void bond_info_show_master(struct seq_file *seq) struct bonding *bond = seq->private; struct slave *curr; int i; - u32 target; read_lock(&bond->curr_slave_lock); curr = bond->curr_active_slave; @@ -3293,8 +3297,7 @@ static void bond_info_show_master(struct seq_file *seq) continue; if (printed) seq_printf(seq, ","); - target = ntohl(bond->params.arp_targets[i]); - seq_printf(seq, " %d.%d.%d.%d", HIPQUAD(target)); + seq_printf(seq, " %pI4", &bond->params.arp_targets[i]); printed = 1; } seq_printf(seq, "\n"); @@ -3302,11 +3305,12 @@ static void bond_info_show_master(struct seq_file *seq) if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; - DECLARE_MAC_BUF(mac); seq_puts(seq, "\n802.3ad info\n"); seq_printf(seq, "LACP rate: %s\n", (bond->params.lacp_fast) ? "fast" : "slow"); + seq_printf(seq, "Aggregator selection policy (ad_select): %s\n", + ad_select_tbl[bond->params.ad_select].modename); if (bond_3ad_get_active_agg_info(bond, &ad_info)) { seq_printf(seq, "bond %s has no active aggregator\n", @@ -3322,8 +3326,8 @@ static void bond_info_show_master(struct seq_file *seq) ad_info.actor_key); seq_printf(seq, "\tPartner Key: %d\n", ad_info.partner_key); - seq_printf(seq, "\tPartner Mac Address: %s\n", - print_mac(mac, ad_info.partner_system)); + seq_printf(seq, "\tPartner Mac Address: %pM\n", + ad_info.partner_system); } } } @@ -3331,7 +3335,6 @@ static void bond_info_show_master(struct seq_file *seq) static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave) { struct bonding *bond = seq->private; - DECLARE_MAC_BUF(mac); seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", @@ -3339,9 +3342,7 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave seq_printf(seq, "Link Failure Count: %u\n", slave->link_failure_count); - seq_printf(seq, - "Permanent HW addr: %s\n", - print_mac(mac, slave->perm_hwaddr)); + seq_printf(seq, "Permanent HW addr: %pM\n", slave->perm_hwaddr); if (bond->params.mode == BOND_MODE_8023AD) { const struct aggregator *agg @@ -3506,7 +3507,7 @@ static int bond_event_changename(struct bonding *bond) static int bond_master_netdev_event(unsigned long event, struct net_device *bond_dev) { - struct bonding *event_bond = bond_dev->priv; + struct bonding *event_bond = netdev_priv(bond_dev); switch (event) { case NETDEV_CHANGENAME: @@ -3524,7 +3525,7 @@ static int bond_master_netdev_event(unsigned long event, struct net_device *bond static int bond_slave_netdev_event(unsigned long event, struct net_device *slave_dev) { struct net_device *bond_dev = slave_dev->master; - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); switch (event) { case NETDEV_UNREGISTER: @@ -3591,7 +3592,7 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v if (dev_net(event_dev) != &init_net) return NOTIFY_DONE; - dprintk("event_dev: %s, event: %lx\n", + pr_debug("event_dev: %s, event: %lx\n", (event_dev ? event_dev->name : "None"), event); @@ -3599,12 +3600,12 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v return NOTIFY_DONE; if (event_dev->flags & IFF_MASTER) { - dprintk("IFF_MASTER\n"); + pr_debug("IFF_MASTER\n"); return bond_master_netdev_event(event, event_dev); } if (event_dev->flags & IFF_SLAVE) { - dprintk("IFF_SLAVE\n"); + pr_debug("IFF_SLAVE\n"); return bond_slave_netdev_event(event, event_dev); } @@ -3775,12 +3776,11 @@ static int bond_xmit_hash_policy_l2(struct sk_buff *skb, static int bond_open(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); bond->kill_timers = 0; - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { /* bond_alb_initialize must be called before the timer * is started. */ @@ -3816,6 +3816,7 @@ static int bond_open(struct net_device *bond_dev) queue_delayed_work(bond->wq, &bond->ad_work, 0); /* register to receive LACPDUs */ bond_register_lacpdu(bond); + bond_3ad_initiate_agg_selection(bond, 1); } return 0; @@ -3823,7 +3824,7 @@ static int bond_open(struct net_device *bond_dev) static int bond_close(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); if (bond->params.mode == BOND_MODE_8023AD) { /* Unregister the receive of LACPDUs */ @@ -3836,6 +3837,7 @@ static int bond_close(struct net_device *bond_dev) write_lock_bh(&bond->lock); bond->send_grat_arp = 0; + bond->send_unsol_na = 0; /* signal timers not to re-arm */ bond->kill_timers = 1; @@ -3863,8 +3865,7 @@ static int bond_close(struct net_device *bond_dev) } - if ((bond->params.mode == BOND_MODE_TLB) || - (bond->params.mode == BOND_MODE_ALB)) { + if (bond_is_lb(bond)) { /* Must be called only after all * slaves have been released */ @@ -3876,8 +3877,8 @@ static int bond_close(struct net_device *bond_dev) static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; - struct net_device_stats *stats = &(bond->stats), *sstats; + struct bonding *bond = netdev_priv(bond_dev); + struct net_device_stats *stats = &bond->stats; struct net_device_stats local_stats; struct slave *slave; int i; @@ -3887,7 +3888,8 @@ static struct net_device_stats *bond_get_stats(struct net_device *bond_dev) read_lock_bh(&bond->lock); bond_for_each_slave(bond, slave, i) { - sstats = slave->dev->get_stats(slave->dev); + const struct net_device_stats *sstats = dev_get_stats(slave->dev); + local_stats.rx_packets += sstats->rx_packets; local_stats.rx_bytes += sstats->rx_bytes; local_stats.rx_errors += sstats->rx_errors; @@ -3932,7 +3934,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd struct mii_ioctl_data *mii = NULL; int res = 0; - dprintk("bond_ioctl: master=%s, cmd=%d\n", + pr_debug("bond_ioctl: master=%s, cmd=%d\n", bond_dev->name, cmd); switch (cmd) { @@ -3954,7 +3956,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd } if (mii->reg_num == 1) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); mii->val_out = 0; read_lock(&bond->lock); read_lock(&bond->curr_slave_lock); @@ -4010,12 +4012,12 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd down_write(&(bonding_rwsem)); slave_dev = dev_get_by_name(&init_net, ifr->ifr_slave); - dprintk("slave_dev=%p: \n", slave_dev); + pr_debug("slave_dev=%p: \n", slave_dev); if (!slave_dev) { res = -ENODEV; } else { - dprintk("slave_dev->name=%s: \n", slave_dev->name); + pr_debug("slave_dev->name=%s: \n", slave_dev->name); switch (cmd) { case BOND_ENSLAVE_OLD: case SIOCBONDENSLAVE: @@ -4046,7 +4048,7 @@ static int bond_do_ioctl(struct net_device *bond_dev, struct ifreq *ifr, int cmd static void bond_set_multicast_list(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct dev_mc_list *dmi; /* @@ -4102,17 +4104,31 @@ static void bond_set_multicast_list(struct net_device *bond_dev) read_unlock(&bond->lock); } +static int bond_neigh_setup(struct net_device *dev, struct neigh_parms *parms) +{ + struct bonding *bond = netdev_priv(dev); + struct slave *slave = bond->first_slave; + + if (slave) { + const struct net_device_ops *slave_ops + = slave->dev->netdev_ops; + if (slave_ops->ndo_neigh_setup) + return slave_ops->ndo_neigh_setup(dev, parms); + } + return 0; +} + /* * Change the MTU of all of a master's slaves to match the master */ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *stop_at; int res = 0; int i; - dprintk("bond=%p, name=%s, new_mtu=%d\n", bond, + pr_debug("bond=%p, name=%s, new_mtu=%d\n", bond, (bond_dev ? bond_dev->name : "None"), new_mtu); /* Can't hold bond->lock with bh disabled here since @@ -4131,7 +4147,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) */ bond_for_each_slave(bond, slave, i) { - dprintk("s %p s->p %p c_m %p\n", slave, + pr_debug("s %p s->p %p c_m %p\n", slave, slave->prev, slave->dev->change_mtu); res = dev_set_mtu(slave->dev, new_mtu); @@ -4145,7 +4161,7 @@ static int bond_change_mtu(struct net_device *bond_dev, int new_mtu) * means changing their mtu from timer context, which * is probably not a good idea. */ - dprintk("err %d %s\n", res, slave->dev->name); + pr_debug("err %d %s\n", res, slave->dev->name); goto unwind; } } @@ -4162,7 +4178,7 @@ unwind: tmp_res = dev_set_mtu(slave->dev, bond_dev->mtu); if (tmp_res) { - dprintk("unwind err %d dev %s\n", tmp_res, + pr_debug("unwind err %d dev %s\n", tmp_res, slave->dev->name); } } @@ -4179,13 +4195,17 @@ unwind: */ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct sockaddr *sa = addr, tmp_sa; struct slave *slave, *stop_at; int res = 0; int i; - dprintk("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); + if (bond->params.mode == BOND_MODE_ALB) + return bond_alb_set_mac_address(bond_dev, addr); + + + pr_debug("bond=%p, name=%s\n", bond, (bond_dev ? bond_dev->name : "None")); /* * If fail_over_mac is set to active, do nothing and return @@ -4214,11 +4234,12 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) */ bond_for_each_slave(bond, slave, i) { - dprintk("slave %p %s\n", slave, slave->dev->name); + const struct net_device_ops *slave_ops = slave->dev->netdev_ops; + pr_debug("slave %p %s\n", slave, slave->dev->name); - if (slave->dev->set_mac_address == NULL) { + if (slave_ops->ndo_set_mac_address == NULL) { res = -EOPNOTSUPP; - dprintk("EOPNOTSUPP %s\n", slave->dev->name); + pr_debug("EOPNOTSUPP %s\n", slave->dev->name); goto unwind; } @@ -4230,7 +4251,7 @@ static int bond_set_mac_address(struct net_device *bond_dev, void *addr) * breakage anyway until ARP finish * updating, so... */ - dprintk("err %d %s\n", res, slave->dev->name); + pr_debug("err %d %s\n", res, slave->dev->name); goto unwind; } } @@ -4250,7 +4271,7 @@ unwind: tmp_res = dev_set_mac_address(slave->dev, &tmp_sa); if (tmp_res) { - dprintk("unwind err %d dev %s\n", tmp_res, + pr_debug("unwind err %d dev %s\n", tmp_res, slave->dev->name); } } @@ -4260,7 +4281,7 @@ unwind: static int bond_xmit_roundrobin(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *start_at; int i, slave_no, res = 1; @@ -4309,7 +4330,7 @@ out: */ static int bond_xmit_activebackup(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); int res = 1; read_lock(&bond->lock); @@ -4341,7 +4362,7 @@ out: */ static int bond_xmit_xor(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *start_at; int slave_no; int i; @@ -4387,7 +4408,7 @@ out: */ static int bond_xmit_broadcast(struct sk_buff *skb, struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); struct slave *slave, *start_at; struct net_device *tx_dev = NULL; int i; @@ -4463,6 +4484,35 @@ static void bond_set_xmit_hash_policy(struct bonding *bond) } } +static int bond_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + const struct bonding *bond = netdev_priv(dev); + + switch (bond->params.mode) { + case BOND_MODE_ROUNDROBIN: + return bond_xmit_roundrobin(skb, dev); + case BOND_MODE_ACTIVEBACKUP: + return bond_xmit_activebackup(skb, dev); + case BOND_MODE_XOR: + return bond_xmit_xor(skb, dev); + case BOND_MODE_BROADCAST: + return bond_xmit_broadcast(skb, dev); + case BOND_MODE_8023AD: + return bond_3ad_xmit_xor(skb, dev); + case BOND_MODE_ALB: + case BOND_MODE_TLB: + return bond_alb_xmit(skb, dev); + default: + /* Should never happen, mode already checked */ + printk(KERN_ERR DRV_NAME ": %s: Error: Unknown bonding mode %d\n", + dev->name, bond->params.mode); + WARN_ON_ONCE(1); + dev_kfree_skb(skb); + return NETDEV_TX_OK; + } +} + + /* * set bond mode specific net device operations */ @@ -4472,29 +4522,22 @@ void bond_set_mode_ops(struct bonding *bond, int mode) switch (mode) { case BOND_MODE_ROUNDROBIN: - bond_dev->hard_start_xmit = bond_xmit_roundrobin; break; case BOND_MODE_ACTIVEBACKUP: - bond_dev->hard_start_xmit = bond_xmit_activebackup; break; case BOND_MODE_XOR: - bond_dev->hard_start_xmit = bond_xmit_xor; bond_set_xmit_hash_policy(bond); break; case BOND_MODE_BROADCAST: - bond_dev->hard_start_xmit = bond_xmit_broadcast; break; case BOND_MODE_8023AD: bond_set_master_3ad_flags(bond); - bond_dev->hard_start_xmit = bond_3ad_xmit_xor; bond_set_xmit_hash_policy(bond); break; case BOND_MODE_ALB: bond_set_master_alb_flags(bond); /* FALLTHRU */ case BOND_MODE_TLB: - bond_dev->hard_start_xmit = bond_alb_xmit; - bond_dev->set_mac_address = bond_alb_set_mac_address; break; default: /* Should never happen, mode already checked */ @@ -4524,15 +4567,30 @@ static const struct ethtool_ops bond_ethtool_ops = { .get_flags = ethtool_op_get_flags, }; +static const struct net_device_ops bond_netdev_ops = { + .ndo_open = bond_open, + .ndo_stop = bond_close, + .ndo_start_xmit = bond_start_xmit, + .ndo_get_stats = bond_get_stats, + .ndo_do_ioctl = bond_do_ioctl, + .ndo_set_multicast_list = bond_set_multicast_list, + .ndo_change_mtu = bond_change_mtu, + .ndo_set_mac_address = bond_set_mac_address, + .ndo_neigh_setup = bond_neigh_setup, + .ndo_vlan_rx_register = bond_vlan_rx_register, + .ndo_vlan_rx_add_vid = bond_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = bond_vlan_rx_kill_vid, +}; + /* * Does not allocate but creates a /proc entry. * Allowed to fail. */ static int bond_init(struct net_device *bond_dev, struct bond_params *params) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); - dprintk("Begin bond_init for %s\n", bond_dev->name); + pr_debug("Begin bond_init for %s\n", bond_dev->name); /* initialize rwlocks */ rwlock_init(&bond->lock); @@ -4551,20 +4609,13 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) bond->primary_slave = NULL; bond->dev = bond_dev; bond->send_grat_arp = 0; + bond->send_unsol_na = 0; bond->setup_by_slave = 0; INIT_LIST_HEAD(&bond->vlan_list); /* Initialize the device entry points */ - bond_dev->open = bond_open; - bond_dev->stop = bond_close; - bond_dev->get_stats = bond_get_stats; - bond_dev->do_ioctl = bond_do_ioctl; + bond_dev->netdev_ops = &bond_netdev_ops; bond_dev->ethtool_ops = &bond_ethtool_ops; - bond_dev->set_multicast_list = bond_set_multicast_list; - bond_dev->change_mtu = bond_change_mtu; - bond_dev->set_mac_address = bond_set_mac_address; - bond_dev->validate_addr = NULL; - bond_set_mode_ops(bond, bond->params.mode); bond_dev->destructor = bond_destructor; @@ -4573,6 +4624,8 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) bond_dev->tx_queue_len = 0; bond_dev->flags |= IFF_MASTER|IFF_MULTICAST; bond_dev->priv_flags |= IFF_BONDING; + if (bond->params.arp_interval) + bond_dev->priv_flags |= IFF_MASTER_ARPMON; /* At first, we block adding VLANs. That's the only way to * prevent problems that occur when adding VLANs over an @@ -4591,9 +4644,6 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params) * when there are slaves that are not hw accel * capable */ - bond_dev->vlan_rx_register = bond_vlan_rx_register; - bond_dev->vlan_rx_add_vid = bond_vlan_rx_add_vid; - bond_dev->vlan_rx_kill_vid = bond_vlan_rx_kill_vid; bond_dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER); @@ -4632,7 +4682,7 @@ static void bond_work_cancel_all(struct bonding *bond) */ static void bond_deinit(struct net_device *bond_dev) { - struct bonding *bond = bond_dev->priv; + struct bonding *bond = netdev_priv(bond_dev); list_del(&bond->bond_list); @@ -4672,7 +4722,7 @@ static void bond_free_all(void) * some mode names are substrings of other names, and calls from sysfs * may have whitespace in the name (trailing newlines, for example). */ -int bond_parse_parm(const char *buf, struct bond_parm_tbl *tbl) +int bond_parse_parm(const char *buf, const struct bond_parm_tbl *tbl) { int mode = -1, i, rv; char *p, modestr[BOND_MAX_MODENAME_LEN + 1] = { 0, }; @@ -4751,6 +4801,23 @@ static int bond_check_params(struct bond_params *params) } } + if (ad_select) { + params->ad_select = bond_parse_parm(ad_select, ad_select_tbl); + if (params->ad_select == -1) { + printk(KERN_ERR DRV_NAME + ": Error: Invalid ad_select \"%s\"\n", + ad_select == NULL ? "NULL" : ad_select); + return -EINVAL; + } + + if (bond_mode != BOND_MODE_8023AD) { + printk(KERN_WARNING DRV_NAME + ": ad_select param only affects 802.3ad mode\n"); + } + } else { + params->ad_select = BOND_AD_STABLE; + } + if (max_bonds < 0 || max_bonds > INT_MAX) { printk(KERN_WARNING DRV_NAME ": Warning: max_bonds (%d) not in range %d-%d, so it " @@ -4798,6 +4865,13 @@ static int bond_check_params(struct bond_params *params) num_grat_arp = 1; } + if (num_unsol_na < 0 || num_unsol_na > 255) { + printk(KERN_WARNING DRV_NAME + ": Warning: num_unsol_na (%d) not in range 0-255 so it " + "was reset to 1 \n", num_unsol_na); + num_unsol_na = 1; + } + /* reset values for 802.3ad */ if (bond_mode == BOND_MODE_8023AD) { if (!miimon) { @@ -4999,6 +5073,7 @@ static int bond_check_params(struct bond_params *params) params->xmit_policy = xmit_hashtype; params->miimon = miimon; params->num_grat_arp = num_grat_arp; + params->num_unsol_na = num_unsol_na; params->arp_interval = arp_interval; params->arp_validate = arp_validate_value; params->updelay = updelay; @@ -5099,7 +5174,7 @@ int bond_create(char *name, struct bond_params *params) up_write(&bonding_rwsem); rtnl_unlock(); /* allows sysfs registration of net device */ - res = bond_create_sysfs_entry(bond_dev->priv); + res = bond_create_sysfs_entry(netdev_priv(bond_dev)); if (res < 0) { rtnl_lock(); down_write(&bonding_rwsem); @@ -5151,6 +5226,7 @@ static int __init bonding_init(void) register_netdevice_notifier(&bond_netdev_notifier); register_inetaddr_notifier(&bond_inetaddr_notifier); + bond_register_ipv6_notifier(); goto out; err: @@ -5173,6 +5249,7 @@ static void __exit bonding_exit(void) { unregister_netdevice_notifier(&bond_netdev_notifier); unregister_inetaddr_notifier(&bond_inetaddr_notifier); + bond_unregister_ipv6_notifier(); bond_destroy_sysfs(); diff --git a/drivers/net/bonding/bond_sysfs.c b/drivers/net/bonding/bond_sysfs.c index 3bdb47382521149010c7e478039fd190cb6b3868..18cf4787874cadb1b3671aa1d2419d76a81c7020 100644 --- a/drivers/net/bonding/bond_sysfs.c +++ b/drivers/net/bonding/bond_sysfs.c @@ -36,22 +36,13 @@ #include #include -/* #define BONDING_DEBUG 1 */ #include "bonding.h" + #define to_dev(obj) container_of(obj,struct device,kobj) -#define to_bond(cd) ((struct bonding *)(to_net_dev(cd)->priv)) +#define to_bond(cd) ((struct bonding *)(netdev_priv(to_net_dev(cd)))) /*---------------------------- Declarations -------------------------------*/ - -extern struct list_head bond_dev_list; -extern struct bond_params bonding_defaults; -extern struct bond_parm_tbl bond_mode_tbl[]; -extern struct bond_parm_tbl bond_lacp_tbl[]; -extern struct bond_parm_tbl xmit_hashtype_tbl[]; -extern struct bond_parm_tbl arp_validate_tbl[]; -extern struct bond_parm_tbl fail_over_mac_tbl[]; - static int expected_refcount = -1; /*--------------------------- Data Structures -----------------------------*/ @@ -316,18 +307,12 @@ static ssize_t bonding_store_slaves(struct device *d, /* Set the slave's MTU to match the bond */ original_mtu = dev->mtu; - if (dev->mtu != bond->dev->mtu) { - if (dev->change_mtu) { - res = dev->change_mtu(dev, - bond->dev->mtu); - if (res) { - ret = res; - goto out; - } - } else { - dev->mtu = bond->dev->mtu; - } + res = dev_set_mtu(dev, bond->dev->mtu); + if (res) { + ret = res; + goto out; } + res = bond_enslave(bond->dev, dev); bond_for_each_slave(bond, slave, i) if (strnicmp(slave->dev->name, ifname, IFNAMSIZ) == 0) @@ -356,11 +341,7 @@ static ssize_t bonding_store_slaves(struct device *d, goto out; } /* set the slave MTU to the default */ - if (dev->change_mtu) { - dev->change_mtu(dev, original_mtu); - } else { - dev->mtu = original_mtu; - } + dev_set_mtu(dev, original_mtu); } else { printk(KERN_ERR DRV_NAME ": unable to remove non-existent slave %s for bond %s.\n", @@ -620,6 +601,8 @@ static ssize_t bonding_store_arp_interval(struct device *d, ": %s: Setting ARP monitoring interval to %d.\n", bond->dev->name, new_value); bond->params.arp_interval = new_value; + if (bond->params.arp_interval) + bond->dev->priv_flags |= IFF_MASTER_ARPMON; if (bond->params.miimon) { printk(KERN_INFO DRV_NAME ": %s: ARP monitoring cannot be used with MII monitoring. " @@ -672,8 +655,8 @@ static ssize_t bonding_show_arp_targets(struct device *d, for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) { if (bond->params.arp_targets[i]) - res += sprintf(buf + res, "%u.%u.%u.%u ", - NIPQUAD(bond->params.arp_targets[i])); + res += sprintf(buf + res, "%pI4 ", + &bond->params.arp_targets[i]); } if (res) buf[res-1] = '\n'; /* eat the leftover space */ @@ -695,8 +678,8 @@ static ssize_t bonding_store_arp_targets(struct device *d, if (buf[0] == '+') { if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { printk(KERN_ERR DRV_NAME - ": %s: invalid ARP target %u.%u.%u.%u specified for addition\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: invalid ARP target %pI4 specified for addition\n", + bond->dev->name, &newtarget); ret = -EINVAL; goto out; } @@ -704,8 +687,8 @@ static ssize_t bonding_store_arp_targets(struct device *d, for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { if (targets[i] == newtarget) { /* duplicate */ printk(KERN_ERR DRV_NAME - ": %s: ARP target %u.%u.%u.%u is already present\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: ARP target %pI4 is already present\n", + bond->dev->name, &newtarget); if (done) targets[i] = 0; ret = -EINVAL; @@ -713,8 +696,8 @@ static ssize_t bonding_store_arp_targets(struct device *d, } if (targets[i] == 0 && !done) { printk(KERN_INFO DRV_NAME - ": %s: adding ARP target %d.%d.%d.%d.\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: adding ARP target %pI4.\n", + bond->dev->name, &newtarget); done = 1; targets[i] = newtarget; } @@ -731,8 +714,8 @@ static ssize_t bonding_store_arp_targets(struct device *d, else if (buf[0] == '-') { if ((newtarget == 0) || (newtarget == htonl(INADDR_BROADCAST))) { printk(KERN_ERR DRV_NAME - ": %s: invalid ARP target %d.%d.%d.%d specified for removal\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: invalid ARP target %pI4 specified for removal\n", + bond->dev->name, &newtarget); ret = -EINVAL; goto out; } @@ -740,16 +723,16 @@ static ssize_t bonding_store_arp_targets(struct device *d, for (i = 0; (i < BOND_MAX_ARP_TARGETS); i++) { if (targets[i] == newtarget) { printk(KERN_INFO DRV_NAME - ": %s: removing ARP target %d.%d.%d.%d.\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: removing ARP target %pI4.\n", + bond->dev->name, &newtarget); targets[i] = 0; done = 1; } } if (!done) { printk(KERN_INFO DRV_NAME - ": %s: unable to remove nonexistent ARP target %d.%d.%d.%d.\n", - bond->dev->name, NIPQUAD(newtarget)); + ": %s: unable to remove nonexistent ARP target %pI4.\n", + bond->dev->name, &newtarget); ret = -EINVAL; goto out; } @@ -942,6 +925,53 @@ out: } static DEVICE_ATTR(lacp_rate, S_IRUGO | S_IWUSR, bonding_show_lacp, bonding_store_lacp); +static ssize_t bonding_show_ad_select(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + return sprintf(buf, "%s %d\n", + ad_select_tbl[bond->params.ad_select].modename, + bond->params.ad_select); +} + + +static ssize_t bonding_store_ad_select(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int new_value, ret = count; + struct bonding *bond = to_bond(d); + + if (bond->dev->flags & IFF_UP) { + printk(KERN_ERR DRV_NAME + ": %s: Unable to update ad_select because interface " + "is up.\n", bond->dev->name); + ret = -EPERM; + goto out; + } + + new_value = bond_parse_parm(buf, ad_select_tbl); + + if (new_value != -1) { + bond->params.ad_select = new_value; + printk(KERN_INFO DRV_NAME + ": %s: Setting ad_select to %s (%d).\n", + bond->dev->name, ad_select_tbl[new_value].modename, + new_value); + } else { + printk(KERN_ERR DRV_NAME + ": %s: Ignoring invalid ad_select value %.*s.\n", + bond->dev->name, (int)strlen(buf) - 1, buf); + ret = -EINVAL; + } +out: + return ret; +} + +static DEVICE_ATTR(ad_select, S_IRUGO | S_IWUSR, bonding_show_ad_select, bonding_store_ad_select); + /* * Show and set the number of grat ARP to send after a failover event. */ @@ -981,6 +1011,47 @@ out: return ret; } static DEVICE_ATTR(num_grat_arp, S_IRUGO | S_IWUSR, bonding_show_n_grat_arp, bonding_store_n_grat_arp); + +/* + * Show and set the number of unsolicted NA's to send after a failover event. + */ +static ssize_t bonding_show_n_unsol_na(struct device *d, + struct device_attribute *attr, + char *buf) +{ + struct bonding *bond = to_bond(d); + + return sprintf(buf, "%d\n", bond->params.num_unsol_na); +} + +static ssize_t bonding_store_n_unsol_na(struct device *d, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int new_value, ret = count; + struct bonding *bond = to_bond(d); + + if (sscanf(buf, "%d", &new_value) != 1) { + printk(KERN_ERR DRV_NAME + ": %s: no num_unsol_na value specified.\n", + bond->dev->name); + ret = -EINVAL; + goto out; + } + if (new_value < 0 || new_value > 255) { + printk(KERN_ERR DRV_NAME + ": %s: Invalid num_unsol_na value %d not in range 0-255; rejected.\n", + bond->dev->name, new_value); + ret = -EINVAL; + goto out; + } else { + bond->params.num_unsol_na = new_value; + } +out: + return ret; +} +static DEVICE_ATTR(num_unsol_na, S_IRUGO | S_IWUSR, bonding_show_n_unsol_na, bonding_store_n_unsol_na); + /* * Show and set the MII monitor interval. There are two tricky bits * here. First, if MII monitoring is activated, then we must disable @@ -1039,6 +1110,7 @@ static ssize_t bonding_store_miimon(struct device *d, "ARP monitoring. Disabling ARP monitoring...\n", bond->dev->name); bond->params.arp_interval = 0; + bond->dev->priv_flags &= ~IFF_MASTER_ARPMON; if (bond->params.arp_validate) { bond_unregister_arp(bond); bond->params.arp_validate = @@ -1391,13 +1463,11 @@ static ssize_t bonding_show_ad_partner_mac(struct device *d, { int count = 0; struct bonding *bond = to_bond(d); - DECLARE_MAC_BUF(mac); if (bond->params.mode == BOND_MODE_8023AD) { struct ad_info ad_info; if (!bond_3ad_get_active_agg_info(bond, &ad_info)) { - count = sprintf(buf,"%s\n", - print_mac(mac, ad_info.partner_system)); + count = sprintf(buf, "%pM\n", ad_info.partner_system); } } @@ -1417,8 +1487,10 @@ static struct attribute *per_bond_attrs[] = { &dev_attr_downdelay.attr, &dev_attr_updelay.attr, &dev_attr_lacp_rate.attr, + &dev_attr_ad_select.attr, &dev_attr_xmit_hash_policy.attr, &dev_attr_num_grat_arp.attr, + &dev_attr_num_unsol_na.attr, &dev_attr_miimon.attr, &dev_attr_primary.attr, &dev_attr_use_carrier.attr, diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h index ffb668dd6d3b00eddbc328513b785e42c31d492d..ca849d2adf98d7a79861b6c333a6f0357fe789cf 100644 --- a/drivers/net/bonding/bonding.h +++ b/drivers/net/bonding/bonding.h @@ -19,23 +19,18 @@ #include #include #include +#include #include "bond_3ad.h" #include "bond_alb.h" -#define DRV_VERSION "3.3.0" -#define DRV_RELDATE "June 10, 2008" +#define DRV_VERSION "3.5.0" +#define DRV_RELDATE "November 4, 2008" #define DRV_NAME "bonding" #define DRV_DESCRIPTION "Ethernet Channel Bonding Driver" #define BOND_MAX_ARP_TARGETS 16 -#ifdef BONDING_DEBUG -#define dprintk(fmt, args...) \ - printk(KERN_DEBUG \ - DRV_NAME ": %s() %d: " fmt, __func__, __LINE__ , ## args ) -#else -#define dprintk(fmt, args...) -#endif /* BONDING_DEBUG */ +extern struct list_head bond_dev_list; #define IS_UP(dev) \ ((((dev)->flags & IFF_UP) == IFF_UP) && \ @@ -126,6 +121,7 @@ struct bond_params { int xmit_policy; int miimon; int num_grat_arp; + int num_unsol_na; int arp_interval; int arp_validate; int use_carrier; @@ -133,6 +129,7 @@ struct bond_params { int updelay; int downdelay; int lacp_fast; + int ad_select; char primary[IFNAMSIZ]; __be32 arp_targets[BOND_MAX_ARP_TARGETS]; }; @@ -148,6 +145,9 @@ struct vlan_entry { struct list_head vlan_list; __be32 vlan_ip; unsigned short vlan_id; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct in6_addr vlan_ipv6; +#endif }; struct slave { @@ -195,6 +195,7 @@ struct bonding { rwlock_t curr_slave_lock; s8 kill_timers; s8 send_grat_arp; + s8 send_unsol_na; s8 setup_by_slave; struct net_device_stats stats; #ifdef CONFIG_PROC_FS @@ -218,6 +219,9 @@ struct bonding { struct delayed_work arp_work; struct delayed_work alb_work; struct delayed_work ad_work; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + struct in6_addr master_ipv6; +#endif }; /** @@ -245,7 +249,13 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave) return NULL; } - return (struct bonding *)slave->dev->master->priv; + return (struct bonding *)netdev_priv(slave->dev->master); +} + +static inline bool bond_is_lb(const struct bonding *bond) +{ + return bond->params.mode == BOND_MODE_TLB + || bond->params.mode == BOND_MODE_ALB; } #define BOND_FOM_NONE 0 @@ -275,7 +285,7 @@ static inline unsigned long slave_last_rx(struct bonding *bond, static inline void bond_set_slave_inactive_flags(struct slave *slave) { - struct bonding *bond = slave->dev->master->priv; + struct bonding *bond = netdev_priv(slave->dev->master); if (bond->params.mode != BOND_MODE_TLB && bond->params.mode != BOND_MODE_ALB) slave->state = BOND_STATE_BACKUP; @@ -327,7 +337,7 @@ void bond_mii_monitor(struct work_struct *); void bond_loadbalance_arp_mon(struct work_struct *); void bond_activebackup_arp_mon(struct work_struct *); void bond_set_mode_ops(struct bonding *bond, int mode); -int bond_parse_parm(const char *mode_arg, struct bond_parm_tbl *tbl); +int bond_parse_parm(const char *mode_arg, const struct bond_parm_tbl *tbl); void bond_select_active_slave(struct bonding *bond); void bond_change_active_slave(struct bonding *bond, struct slave *new_active); void bond_register_arp(struct bonding *); @@ -335,11 +345,35 @@ void bond_unregister_arp(struct bonding *); /* exported from bond_main.c */ extern struct list_head bond_dev_list; -extern struct bond_parm_tbl bond_lacp_tbl[]; -extern struct bond_parm_tbl bond_mode_tbl[]; -extern struct bond_parm_tbl xmit_hashtype_tbl[]; -extern struct bond_parm_tbl arp_validate_tbl[]; -extern struct bond_parm_tbl fail_over_mac_tbl[]; +extern const struct bond_parm_tbl bond_lacp_tbl[]; +extern const struct bond_parm_tbl bond_mode_tbl[]; +extern const struct bond_parm_tbl xmit_hashtype_tbl[]; +extern const struct bond_parm_tbl arp_validate_tbl[]; +extern const struct bond_parm_tbl fail_over_mac_tbl[]; +extern struct bond_params bonding_defaults; +extern struct bond_parm_tbl ad_select_tbl[]; + +/* exported from bond_sysfs.c */ +extern struct rw_semaphore bonding_rwsem; + +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +void bond_send_unsolicited_na(struct bonding *bond); +void bond_register_ipv6_notifier(void); +void bond_unregister_ipv6_notifier(void); +#else +static inline void bond_send_unsolicited_na(struct bonding *bond) +{ + return; +} +static inline void bond_register_ipv6_notifier(void) +{ + return; +} +static inline void bond_unregister_ipv6_notifier(void) +{ + return; +} +#endif #endif /* _LINUX_BONDING_H */ diff --git a/drivers/net/can/vcan.c b/drivers/net/can/vcan.c index 103f0f1df28065e9b30fab934f1f43184f654293..a10c1d7b3b0a6383a0fd255d1132dfabe49cbeca 100644 --- a/drivers/net/can/vcan.c +++ b/drivers/net/can/vcan.c @@ -128,26 +128,30 @@ static int vcan_tx(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } +static const struct net_device_ops vcan_netdev_ops = { + .ndo_start_xmit = vcan_tx, +}; + static void vcan_setup(struct net_device *dev) { - dev->type = ARPHRD_CAN; - dev->mtu = sizeof(struct can_frame); - dev->hard_header_len = 0; - dev->addr_len = 0; - dev->tx_queue_len = 0; - dev->flags = IFF_NOARP; + dev->type = ARPHRD_CAN; + dev->mtu = sizeof(struct can_frame); + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->tx_queue_len = 0; + dev->flags = IFF_NOARP; /* set flags according to driver capabilities */ if (echo) dev->flags |= IFF_ECHO; - dev->hard_start_xmit = vcan_tx; - dev->destructor = free_netdev; + dev->netdev_ops = &vcan_netdev_ops; + dev->destructor = free_netdev; } static struct rtnl_link_ops vcan_link_ops __read_mostly = { - .kind = "vcan", - .setup = vcan_setup, + .kind = "vcan", + .setup = vcan_setup, }; static __init int vcan_init_module(void) diff --git a/drivers/net/cassini.c b/drivers/net/cassini.c index 86909cfb14de77b458131940110d290e76c6197f..321f43d9f0e2caf56a2fb4263e338bc34a80f94e 100644 --- a/drivers/net/cassini.c +++ b/drivers/net/cassini.c @@ -2347,7 +2347,7 @@ static int cas_rx_ringN(struct cas *cp, int ring, int budget) drops = 0; while (1) { struct cas_rx_comp *rxc = rxcs + entry; - struct sk_buff *skb; + struct sk_buff *uninitialized_var(skb); int type, len; u64 words[4]; int i, dring; @@ -2405,7 +2405,6 @@ static int cas_rx_ringN(struct cas *cp, int ring, int budget) cp->net_stats[ring].rx_packets++; cp->net_stats[ring].rx_bytes += len; spin_unlock(&cp->stat_lock[ring]); - cp->dev->last_rx = jiffies; next: npackets++; @@ -2507,7 +2506,7 @@ static irqreturn_t cas_interruptN(int irq, void *dev_id) if (status & INTR_RX_DONE_ALT) { /* handle rx separately */ #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev, &cp->napi); + netif_rx_schedule(&cp->napi); #else cas_rx_ringN(cp, ring, 0); #endif @@ -2558,7 +2557,7 @@ static irqreturn_t cas_interrupt1(int irq, void *dev_id) if (status & INTR_RX_DONE_ALT) { /* handle rx separately */ #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev, &cp->napi); + netif_rx_schedule(&cp->napi); #else cas_rx_ringN(cp, 1, 0); #endif @@ -2614,7 +2613,7 @@ static irqreturn_t cas_interrupt(int irq, void *dev_id) if (status & INTR_RX_DONE) { #ifdef USE_NAPI cas_mask_intr(cp); - netif_rx_schedule(dev, &cp->napi); + netif_rx_schedule(&cp->napi); #else cas_rx_ringN(cp, 0, 0); #endif @@ -2692,7 +2691,7 @@ rx_comp: #endif spin_unlock_irqrestore(&cp->lock, flags); if (enable_intr) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); cas_unmask_intr(cp); } return credits; @@ -4988,7 +4987,6 @@ static int __devinit cas_init_one(struct pci_dev *pdev, int i, err, pci_using_dac; u16 pci_cmd; u8 orig_cacheline_size = 0, cas_cacheline_size = 0; - DECLARE_MAC_BUF(mac); if (cas_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -5201,12 +5199,12 @@ static int __devinit cas_init_one(struct pci_dev *pdev, i = readl(cp->regs + REG_BIM_CFG); printk(KERN_INFO "%s: Sun Cassini%s (%sbit/%sMHz PCI/%s) " - "Ethernet[%d] %s\n", dev->name, + "Ethernet[%d] %pM\n", dev->name, (cp->cas_flags & CAS_FLAG_REG_PLUS) ? "+" : "", (i & BIM_CFG_32BIT) ? "32" : "64", (i & BIM_CFG_66MHZ) ? "66" : "33", (cp->phy_type == CAS_PHY_SERDES) ? "Fi" : "Cu", pdev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); pci_set_drvdata(pdev, dev); cp->hw_running = 1; diff --git a/drivers/net/chelsio/cxgb2.c b/drivers/net/chelsio/cxgb2.c index 638c9a27a7a64902f00dd2251382ed4ff8b1de55..9b6011e7678e3552d51b9692d53aad4477724519 100644 --- a/drivers/net/chelsio/cxgb2.c +++ b/drivers/net/chelsio/cxgb2.c @@ -120,7 +120,7 @@ static const char pci_speed[][4] = { */ static void t1_set_rxmode(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct cmac *mac = adapter->port[dev->if_port].mac; struct t1_rx_mode rm; @@ -252,7 +252,7 @@ static void cxgb_down(struct adapter *adapter) static int cxgb_open(struct net_device *dev) { int err; - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; int other_ports = adapter->open_device_map & PORT_MASK; napi_enable(&adapter->napi); @@ -272,7 +272,7 @@ static int cxgb_open(struct net_device *dev) static int cxgb_close(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; struct cmac *mac = p->mac; @@ -298,7 +298,7 @@ static int cxgb_close(struct net_device *dev) static struct net_device_stats *t1_get_stats(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; struct net_device_stats *ns = &p->netstats; const struct cmac_statistics *pstats; @@ -346,14 +346,14 @@ static struct net_device_stats *t1_get_stats(struct net_device *dev) static u32 get_msglevel(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; return adapter->msg_enable; } static void set_msglevel(struct net_device *dev, u32 val) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; adapter->msg_enable = val; } @@ -434,7 +434,7 @@ static int get_regs_len(struct net_device *dev) static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -461,7 +461,7 @@ static void get_strings(struct net_device *dev, u32 stringset, u8 *data) static void get_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct cmac *mac = adapter->port[dev->if_port].mac; const struct cmac_statistics *s; const struct sge_intr_counts *t; @@ -552,7 +552,7 @@ static inline void reg_block_dump(struct adapter *ap, void *buf, static void get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf) { - struct adapter *ap = dev->priv; + struct adapter *ap = dev->ml_priv; /* * Version scheme: bits 0..9: chip version, bits 10..15: chip revision @@ -574,7 +574,7 @@ static void get_regs(struct net_device *dev, struct ethtool_regs *regs, static int get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; cmd->supported = p->link_config.supported; @@ -634,7 +634,7 @@ static int speed_duplex_to_caps(int speed, int duplex) static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; struct link_config *lc = &p->link_config; @@ -669,7 +669,7 @@ static int set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static void get_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; epause->autoneg = (p->link_config.requested_fc & PAUSE_AUTONEG) != 0; @@ -680,7 +680,7 @@ static void get_pauseparam(struct net_device *dev, static int set_pauseparam(struct net_device *dev, struct ethtool_pauseparam *epause) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct port_info *p = &adapter->port[dev->if_port]; struct link_config *lc = &p->link_config; @@ -709,14 +709,14 @@ static int set_pauseparam(struct net_device *dev, static u32 get_rx_csum(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; return (adapter->flags & RX_CSUM_ENABLED) != 0; } static int set_rx_csum(struct net_device *dev, u32 data) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; if (data) adapter->flags |= RX_CSUM_ENABLED; @@ -727,7 +727,7 @@ static int set_rx_csum(struct net_device *dev, u32 data) static int set_tso(struct net_device *dev, u32 value) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; if (!(adapter->flags & TSO_CAPABLE)) return value ? -EOPNOTSUPP : 0; @@ -736,7 +736,7 @@ static int set_tso(struct net_device *dev, u32 value) static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; e->rx_max_pending = MAX_RX_BUFFERS; @@ -752,7 +752,7 @@ static void get_sge_param(struct net_device *dev, struct ethtool_ringparam *e) static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; int jumbo_fl = t1_is_T1B(adapter) ? 1 : 0; if (e->rx_pending > MAX_RX_BUFFERS || e->rx_mini_pending || @@ -776,7 +776,7 @@ static int set_sge_param(struct net_device *dev, struct ethtool_ringparam *e) static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; adapter->params.sge.rx_coalesce_usecs = c->rx_coalesce_usecs; adapter->params.sge.coalesce_enable = c->use_adaptive_rx_coalesce; @@ -787,7 +787,7 @@ static int set_coalesce(struct net_device *dev, struct ethtool_coalesce *c) static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; c->rx_coalesce_usecs = adapter->params.sge.rx_coalesce_usecs; c->rate_sample_interval = adapter->params.sge.sample_interval_usecs; @@ -797,7 +797,7 @@ static int get_coalesce(struct net_device *dev, struct ethtool_coalesce *c) static int get_eeprom_len(struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; return t1_is_asic(adapter) ? EEPROM_SIZE : 0; } @@ -810,7 +810,7 @@ static int get_eeprom(struct net_device *dev, struct ethtool_eeprom *e, { int i; u8 buf[EEPROM_SIZE] __attribute__((aligned(4))); - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; e->magic = EEPROM_MAGIC(adapter); for (i = e->offset & ~3; i < e->offset + e->len; i += sizeof(u32)) @@ -848,7 +848,7 @@ static const struct ethtool_ops t1_ethtool_ops = { static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct mii_ioctl_data *data = if_mii(req); switch (cmd) { @@ -887,7 +887,7 @@ static int t1_ioctl(struct net_device *dev, struct ifreq *req, int cmd) static int t1_change_mtu(struct net_device *dev, int new_mtu) { int ret; - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct cmac *mac = adapter->port[dev->if_port].mac; if (!mac->ops->set_mtu) @@ -902,7 +902,7 @@ static int t1_change_mtu(struct net_device *dev, int new_mtu) static int t1_set_mac_addr(struct net_device *dev, void *p) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct cmac *mac = adapter->port[dev->if_port].mac; struct sockaddr *addr = p; @@ -915,10 +915,10 @@ static int t1_set_mac_addr(struct net_device *dev, void *p) } #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) -static void vlan_rx_register(struct net_device *dev, +static void t1_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; spin_lock_irq(&adapter->async_lock); adapter->vlan_grp = grp; @@ -931,7 +931,7 @@ static void vlan_rx_register(struct net_device *dev, static void t1_netpoll(struct net_device *dev) { unsigned long flags; - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; local_irq_save(flags); t1_interrupt(adapter->pdev->irq, adapter); @@ -1010,6 +1010,24 @@ void t1_fatal_err(struct adapter *adapter) adapter->name); } +static const struct net_device_ops cxgb_netdev_ops = { + .ndo_open = cxgb_open, + .ndo_stop = cxgb_close, + .ndo_start_xmit = t1_start_xmit, + .ndo_get_stats = t1_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = t1_set_rxmode, + .ndo_do_ioctl = t1_ioctl, + .ndo_change_mtu = t1_change_mtu, + .ndo_set_mac_address = t1_set_mac_addr, +#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) + .ndo_vlan_rx_register = t1_vlan_rx_register, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = t1_netpoll, +#endif +}; + static int __devinit init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1077,7 +1095,7 @@ static int __devinit init_one(struct pci_dev *pdev, SET_NETDEV_DEV(netdev, &pdev->dev); if (!adapter) { - adapter = netdev->priv; + adapter = netdev_priv(netdev); adapter->pdev = pdev; adapter->port[0].dev = netdev; /* so we don't leak it */ @@ -1118,7 +1136,7 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->if_port = i; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; - netdev->priv = adapter; + netdev->ml_priv = adapter; netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; netdev->features |= NETIF_F_LLTX; @@ -1130,7 +1148,6 @@ static int __devinit init_one(struct pci_dev *pdev, adapter->flags |= VLAN_ACCEL_CAPABLE; netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->vlan_rx_register = vlan_rx_register; #endif /* T204: disable TSO */ @@ -1140,19 +1157,10 @@ static int __devinit init_one(struct pci_dev *pdev, } } - netdev->open = cxgb_open; - netdev->stop = cxgb_close; - netdev->hard_start_xmit = t1_start_xmit; + netdev->netdev_ops = &cxgb_netdev_ops; netdev->hard_header_len += (adapter->flags & TSO_CAPABLE) ? sizeof(struct cpl_tx_pkt_lso) : sizeof(struct cpl_tx_pkt); - netdev->get_stats = t1_get_stats; - netdev->set_multicast_list = t1_set_rxmode; - netdev->do_ioctl = t1_ioctl; - netdev->change_mtu = t1_change_mtu; - netdev->set_mac_address = t1_set_mac_addr; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = t1_netpoll; -#endif + netif_napi_add(netdev, &adapter->napi, t1_poll, 64); SET_ETHTOOL_OPS(netdev, &t1_ethtool_ops); @@ -1382,7 +1390,7 @@ static inline void t1_sw_reset(struct pci_dev *pdev) static void __devexit remove_one(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; int i; for_each_port(adapter, i) { diff --git a/drivers/net/chelsio/sge.c b/drivers/net/chelsio/sge.c index 7092df50ff784007f34f72b74aac85d6a437a42e..d984b799576373f1c7a7064d8180f476f8870f48 100644 --- a/drivers/net/chelsio/sge.c +++ b/drivers/net/chelsio/sge.c @@ -1381,7 +1381,6 @@ static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) st = per_cpu_ptr(sge->port_stats[p->iff], smp_processor_id()); skb->protocol = eth_type_trans(skb, adapter->port[p->iff].dev); - skb->dev->last_rx = jiffies; if ((adapter->flags & RX_CSUM_ENABLED) && p->csum == 0xffff && skb->protocol == htons(ETH_P_IP) && (skb->data[9] == IPPROTO_TCP || skb->data[9] == IPPROTO_UDP)) { @@ -1610,11 +1609,10 @@ static int process_pure_responses(struct adapter *adapter) int t1_poll(struct napi_struct *napi, int budget) { struct adapter *adapter = container_of(napi, struct adapter, napi); - struct net_device *dev = adapter->port[0].dev; int work_done = process_responses(adapter, budget); if (likely(work_done < budget)) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); } @@ -1628,13 +1626,11 @@ irqreturn_t t1_interrupt(int irq, void *data) int handled; if (likely(responses_pending(adapter))) { - struct net_device *dev = sge->netdev; - writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); if (napi_schedule_prep(&adapter->napi)) { if (process_pure_responses(adapter)) - __netif_rx_schedule(dev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); else { /* no data, no NAPI needed */ writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); @@ -1782,7 +1778,7 @@ static inline int eth_hdr_len(const void *data) */ int t1_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct adapter *adapter = dev->priv; + struct adapter *adapter = dev->ml_priv; struct sge *sge = adapter->sge; struct sge_port_stats *st = per_cpu_ptr(sge->port_stats[dev->if_port], smp_processor_id()); diff --git a/drivers/net/cpmac.c b/drivers/net/cpmac.c index 017a5361b980c2f37b8ff1e6b05ac1d8c90a158b..f66548751c384c1bf111f69b995dd701aa60b713 100644 --- a/drivers/net/cpmac.c +++ b/drivers/net/cpmac.c @@ -428,7 +428,7 @@ static int cpmac_poll(struct napi_struct *napi, int budget) printk(KERN_WARNING "%s: rx: polling, but no queue\n", priv->dev->name); spin_unlock(&priv->rx_lock); - netif_rx_complete(priv->dev, napi); + netif_rx_complete(napi); return 0; } @@ -514,7 +514,7 @@ static int cpmac_poll(struct napi_struct *napi, int budget) if (processed == 0) { /* we ran out of packets to read, * revert to interrupt-driven mode */ - netif_rx_complete(priv->dev, napi); + netif_rx_complete(napi); cpmac_write(priv->regs, CPMAC_RX_INT_ENABLE, 1); return 0; } @@ -536,7 +536,7 @@ fatal_error: } spin_unlock(&priv->rx_lock); - netif_rx_complete(priv->dev, napi); + netif_rx_complete(napi); netif_tx_stop_all_queues(priv->dev); napi_disable(&priv->napi); @@ -802,9 +802,9 @@ static irqreturn_t cpmac_irq(int irq, void *dev_id) if (status & MAC_INT_RX) { queue = (status >> 8) & 7; - if (netif_rx_schedule_prep(dev, &priv->napi)) { + if (netif_rx_schedule_prep(&priv->napi)) { cpmac_write(priv->regs, CPMAC_RX_INT_CLEAR, 1 << queue); - __netif_rx_schedule(dev, &priv->napi); + __netif_rx_schedule(&priv->napi); } } @@ -1103,7 +1103,6 @@ static int __devinit cpmac_probe(struct platform_device *pdev) struct cpmac_priv *priv; struct net_device *dev; struct plat_cpmac_data *pdata; - DECLARE_MAC_BUF(mac); pdata = pdev->dev.platform_data; @@ -1180,8 +1179,8 @@ static int __devinit cpmac_probe(struct platform_device *pdev) if (netif_msg_probe(priv)) { printk(KERN_INFO "cpmac: device %s (regs: %p, irq: %d, phy: %s, " - "mac: %s)\n", dev->name, (void *)mem->start, dev->irq, - priv->phy_name, print_mac(mac, dev->dev_addr)); + "mac: %pM)\n", dev->name, (void *)mem->start, dev->irq, + priv->phy_name, dev->dev_addr); } return 0; diff --git a/drivers/net/cris/eth_v10.c b/drivers/net/cris/eth_v10.c index 7e8a63106bdf42f2aa3ba4e4303e9920fab56713..c9806c58b2fde2644505fde1409dbf6af24674fd 100644 --- a/drivers/net/cris/eth_v10.c +++ b/drivers/net/cris/eth_v10.c @@ -419,7 +419,6 @@ e100_set_mac_address(struct net_device *dev, void *p) { struct net_local *np = netdev_priv(dev); struct sockaddr *addr = p; - DECLARE_MAC_BUF(mac); spin_lock(&np->lock); /* preemption protection */ @@ -440,8 +439,7 @@ e100_set_mac_address(struct net_device *dev, void *p) /* show it in the log as well */ - printk(KERN_INFO "%s: changed MAC to %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: changed MAC to %pM\n", dev->name, dev->dev_addr); spin_unlock(&np->lock); diff --git a/drivers/net/cs89x0.c b/drivers/net/cs89x0.c index 7107620f615dfd0d17bef1b06fce245ef12411f0..d548a45d59d563f837b1634335547950210aa043 100644 --- a/drivers/net/cs89x0.c +++ b/drivers/net/cs89x0.c @@ -521,7 +521,6 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) unsigned rev_type = 0; int eeprom_buff[CHKSUM_LEN]; int retval; - DECLARE_MAC_BUF(mac); /* Initialize the device structure. */ if (!modular) { @@ -846,7 +845,7 @@ cs89x0_probe1(struct net_device *dev, int ioaddr, int modular) } /* print the ethernet address. */ - printk(", MAC %s", print_mac(mac, dev->dev_addr)); + printk(", MAC %pM", dev->dev_addr); dev->open = net_open; dev->stop = net_close; @@ -1025,14 +1024,13 @@ skip_this_frame: } skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += length; } #endif /* ALLOW_DMA */ -void __init reset_chip(struct net_device *dev) +static void __init reset_chip(struct net_device *dev) { #if !defined(CONFIG_MACH_MX31ADS) #if !defined(CONFIG_MACH_IXDP2351) && !defined(CONFIG_ARCH_IXDP2X01) @@ -1719,7 +1717,6 @@ net_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += length; } @@ -1817,11 +1814,10 @@ static int set_mac_address(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - if (net_debug) { - DECLARE_MAC_BUF(mac); - printk("%s: Setting MAC address to %s.\n", - dev->name, print_mac(mac, dev->dev_addr)); - } + if (net_debug) + printk("%s: Setting MAC address to %pM.\n", + dev->name, dev->dev_addr); + /* set the Ethernet address */ for (i=0; i < ETH_ALEN/2; i++) writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); diff --git a/drivers/net/cxgb3/adapter.h b/drivers/net/cxgb3/adapter.h index bc8e2413abd25d6c5106bcc83d10098fde44489d..5b346f9eaa8b482c556351a6d7eedf8c4fcce9ba 100644 --- a/drivers/net/cxgb3/adapter.h +++ b/drivers/net/cxgb3/adapter.h @@ -63,6 +63,7 @@ struct port_info { struct link_config link_config; struct net_device_stats netstats; int activity; + __be32 iscsi_ipv4addr; }; enum { /* adapter flags */ @@ -196,6 +197,7 @@ struct sge_qset { /* an SGE queue set */ int lro_frag_len; void *lro_va; struct net_device *netdev; + struct netdev_queue *tx_q; /* associated netdev TX queue */ unsigned long txq_stopped; /* which Tx queues are stopped */ struct timer_list tx_reclaim_timer; /* reclaims TX buffers */ unsigned long port_stats[SGE_PSTAT_MAX]; @@ -294,7 +296,8 @@ int t3_mgmt_tx(struct adapter *adap, struct sk_buff *skb); void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p); int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, int irq_vec_idx, const struct qset_params *p, - int ntxq, struct net_device *dev); + int ntxq, struct net_device *dev, + struct netdev_queue *netdevq); int t3_get_desc(const struct sge_qset *qs, unsigned int qnum, unsigned int idx, unsigned char *data); irqreturn_t t3_sge_intr_msix(int irq, void *cookie); diff --git a/drivers/net/cxgb3/common.h b/drivers/net/cxgb3/common.h index e312d315a42d4e5ded041e3c1d8c717ae6ae02a6..db4f4f575b6a1e153a8be1e4056ddf3e97da4870 100644 --- a/drivers/net/cxgb3/common.h +++ b/drivers/net/cxgb3/common.h @@ -714,7 +714,7 @@ int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data); int t3_seeprom_write(struct adapter *adapter, u32 addr, __le32 data); int t3_seeprom_wp(struct adapter *adapter, int enable); int t3_get_tp_version(struct adapter *adapter, u32 *vers); -int t3_check_tpsram_version(struct adapter *adapter, int *must_load); +int t3_check_tpsram_version(struct adapter *adapter); int t3_check_tpsram(struct adapter *adapter, const u8 *tp_ram, unsigned int size); int t3_set_proto_sram(struct adapter *adap, const u8 *data); @@ -722,7 +722,7 @@ int t3_read_flash(struct adapter *adapter, unsigned int addr, unsigned int nwords, u32 *data, int byte_oriented); int t3_load_fw(struct adapter *adapter, const u8 * fw_data, unsigned int size); int t3_get_fw_version(struct adapter *adapter, u32 *vers); -int t3_check_fw_version(struct adapter *adapter, int *must_load); +int t3_check_fw_version(struct adapter *adapter); int t3_init_hw(struct adapter *adapter, u32 fw_params); void mac_prep(struct cmac *mac, struct adapter *adapter, int index); void early_hw_init(struct adapter *adapter, const struct adapter_info *ai); diff --git a/drivers/net/cxgb3/cxgb3_ctl_defs.h b/drivers/net/cxgb3/cxgb3_ctl_defs.h index 1d8d46eb3c960e0efd3725d731f947abb02b438f..369fe711fd7f0dc8e974c99acbd912add1bdb773 100644 --- a/drivers/net/cxgb3/cxgb3_ctl_defs.h +++ b/drivers/net/cxgb3/cxgb3_ctl_defs.h @@ -57,6 +57,9 @@ enum { RDMA_GET_MIB = 19, GET_RX_PAGE_INFO = 50, + GET_ISCSI_IPV4ADDR = 51, + + GET_EMBEDDED_INFO = 70, }; /* @@ -86,6 +89,12 @@ struct iff_mac { u16 vlan_tag; }; +/* Structure used to request a port's iSCSI IPv4 address */ +struct iscsi_ipv4addr { + struct net_device *dev; /* the net_device */ + __be32 ipv4addr; /* the return iSCSI IPv4 address */ +}; + struct pci_dev; /* @@ -169,4 +178,12 @@ struct ofld_page_info { unsigned int page_size; /* Page size, should be a power of 2 */ unsigned int num; /* Number of pages */ }; + +/* + * Structure used to get firmware and protocol engine versions. + */ +struct ch_embedded_info { + u32 fw_vers; + u32 tp_vers; +}; #endif /* _CXGB3_OFFLOAD_CTL_DEFS_H */ diff --git a/drivers/net/cxgb3/cxgb3_main.c b/drivers/net/cxgb3/cxgb3_main.c index 2c341f83d3270e8d32a42d24e1a472fffd945599..2847f947499d9f9edcdaaf672c9f876d3602d571 100644 --- a/drivers/net/cxgb3/cxgb3_main.c +++ b/drivers/net/cxgb3/cxgb3_main.c @@ -493,6 +493,36 @@ static void enable_all_napi(struct adapter *adap) napi_enable(&adap->sge.qs[i].napi); } +/** + * set_qset_lro - Turn a queue set's LRO capability on and off + * @dev: the device the qset is attached to + * @qset_idx: the queue set index + * @val: the LRO switch + * + * Sets LRO on or off for a particular queue set. + * the device's features flag is updated to reflect the LRO + * capability when all queues belonging to the device are + * in the same state. + */ +static void set_qset_lro(struct net_device *dev, int qset_idx, int val) +{ + struct port_info *pi = netdev_priv(dev); + struct adapter *adapter = pi->adapter; + int i, lro_on = 1; + + adapter->params.sge.qset[qset_idx].lro = !!val; + adapter->sge.qs[qset_idx].lro_enabled = !!val; + + /* let ethtool report LRO on only if all queues are LRO enabled */ + for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; ++i) + lro_on &= adapter->params.sge.qset[i].lro; + + if (lro_on) + dev->features |= NETIF_F_LRO; + else + dev->features &= ~NETIF_F_LRO; +} + /** * setup_sge_qsets - configure SGE Tx/Rx/response queues * @adap: the adapter @@ -516,12 +546,12 @@ static int setup_sge_qsets(struct adapter *adap) pi->qs = &adap->sge.qs[pi->first_qset]; for (j = pi->first_qset; j < pi->first_qset + pi->nqsets; ++j, ++qset_idx) { - if (!pi->rx_csum_offload) - adap->params.sge.qset[qset_idx].lro = 0; + set_qset_lro(dev, qset_idx, pi->rx_csum_offload); err = t3_sge_alloc_qset(adap, qset_idx, 1, (adap->flags & USING_MSIX) ? qset_idx + 1 : irq_idx, - &adap->params.sge.qset[qset_idx], ntxq, dev); + &adap->params.sge.qset[qset_idx], ntxq, dev, + netdev_get_tx_queue(dev, j)); if (err) { t3_stop_sge_timers(adap); t3_free_sge_resources(adap); @@ -824,8 +854,8 @@ static int bind_qsets(struct adapter *adap) return err; } -#define FW_FNAME "t3fw-%d.%d.%d.bin" -#define TPSRAM_NAME "t3%c_protocol_sram-%d.%d.%d.bin" +#define FW_FNAME "cxgb3/t3fw-%d.%d.%d.bin" +#define TPSRAM_NAME "cxgb3/t3%c_psram-%d.%d.%d.bin" static int upgrade_fw(struct adapter *adap) { @@ -928,21 +958,22 @@ release_tpsram: static int cxgb_up(struct adapter *adap) { int err; - int must_load; if (!(adap->flags & FULL_INIT_DONE)) { - err = t3_check_fw_version(adap, &must_load); + err = t3_check_fw_version(adap); if (err == -EINVAL) { err = upgrade_fw(adap); - if (err && must_load) - goto out; + CH_WARN(adap, "FW upgrade to %d.%d.%d %s\n", + FW_VERSION_MAJOR, FW_VERSION_MINOR, + FW_VERSION_MICRO, err ? "failed" : "succeeded"); } - err = t3_check_tpsram_version(adap, &must_load); + err = t3_check_tpsram_version(adap); if (err == -EINVAL) { err = update_tpsram(adap); - if (err && must_load) - goto out; + CH_WARN(adap, "TP upgrade to %d.%d.%d %s\n", + TP_VERSION_MAJOR, TP_VERSION_MINOR, + TP_VERSION_MICRO, err ? "failed" : "succeeded"); } /* @@ -1136,9 +1167,10 @@ static int cxgb_open(struct net_device *dev) "Could not initialize offload capabilities\n"); } + dev->real_num_tx_queues = pi->nqsets; link_start(dev); t3_port_intr_enable(adapter, pi->port_id); - netif_start_queue(dev); + netif_tx_start_all_queues(dev); if (!other_ports) schedule_chk_task(adapter); @@ -1151,7 +1183,7 @@ static int cxgb_close(struct net_device *dev) struct adapter *adapter = pi->adapter; t3_port_intr_disable(adapter, pi->port_id); - netif_stop_queue(dev); + netif_tx_stop_all_queues(dev); pi->phy.ops->power_down(&pi->phy, 1); netif_carrier_off(dev); t3_mac_disable(&pi->mac, MAC_DIRECTION_TX | MAC_DIRECTION_RX); @@ -1634,13 +1666,10 @@ static int set_rx_csum(struct net_device *dev, u32 data) p->rx_csum_offload = data; if (!data) { - struct adapter *adap = p->adapter; int i; - for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) { - adap->params.sge.qset[i].lro = 0; - adap->sge.qs[i].lro_enabled = 0; - } + for (i = p->first_qset; i < p->first_qset + p->nqsets; i++) + set_qset_lro(dev, i, 0); } return 0; } @@ -1795,6 +1824,25 @@ static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) memset(&wol->sopass, 0, sizeof(wol->sopass)); } +static int cxgb3_set_flags(struct net_device *dev, u32 data) +{ + struct port_info *pi = netdev_priv(dev); + int i; + + if (data & ETH_FLAG_LRO) { + if (!pi->rx_csum_offload) + return -EINVAL; + + for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) + set_qset_lro(dev, i, 1); + + } else + for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++) + set_qset_lro(dev, i, 0); + + return 0; +} + static const struct ethtool_ops cxgb_ethtool_ops = { .get_settings = get_settings, .set_settings = set_settings, @@ -1824,6 +1872,8 @@ static const struct ethtool_ops cxgb_ethtool_ops = { .get_regs = get_regs, .get_wol = get_wol, .set_tso = ethtool_op_set_tso, + .get_flags = ethtool_op_get_flags, + .set_flags = cxgb3_set_flags, }; static int in_range(int val, int lo, int hi) @@ -1940,11 +1990,9 @@ static int cxgb_extension_ioctl(struct net_device *dev, void __user *useraddr) } } } - if (t.lro >= 0) { - struct sge_qset *qs = &adapter->sge.qs[t.qset_idx]; - q->lro = t.lro; - qs->lro_enabled = t.lro; - } + if (t.lro >= 0) + set_qset_lro(dev, t.qset_idx, t.lro); + break; } case CHELSIO_GET_QSET_PARAMS:{ @@ -2783,6 +2831,22 @@ static void __devinit print_port_info(struct adapter *adap, } } +static const struct net_device_ops cxgb_netdev_ops = { + .ndo_open = cxgb_open, + .ndo_stop = cxgb_close, + .ndo_start_xmit = t3_eth_xmit, + .ndo_get_stats = cxgb_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = cxgb_set_rxmode, + .ndo_do_ioctl = cxgb_ioctl, + .ndo_change_mtu = cxgb_change_mtu, + .ndo_set_mac_address = cxgb_set_mac_addr, + .ndo_vlan_rx_register = vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = cxgb_netpoll, +#endif +}; + static int __devinit init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -2871,7 +2935,7 @@ static int __devinit init_one(struct pci_dev *pdev, for (i = 0; i < ai->nports; ++i) { struct net_device *netdev; - netdev = alloc_etherdev(sizeof(struct port_info)); + netdev = alloc_etherdev_mq(sizeof(struct port_info), SGE_QSETS); if (!netdev) { err = -ENOMEM; goto out_free_dev; @@ -2885,6 +2949,7 @@ static int __devinit init_one(struct pci_dev *pdev, pi->rx_csum_offload = 1; pi->port_id = i; netif_carrier_off(netdev); + netif_tx_stop_all_queues(netdev); netdev->irq = pdev->irq; netdev->mem_start = mmio_start; netdev->mem_end = mmio_start + mmio_len - 1; @@ -2894,20 +2959,7 @@ static int __devinit init_one(struct pci_dev *pdev, netdev->features |= NETIF_F_HIGHDMA; netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - netdev->vlan_rx_register = vlan_rx_register; - - netdev->open = cxgb_open; - netdev->stop = cxgb_close; - netdev->hard_start_xmit = t3_eth_xmit; - netdev->get_stats = cxgb_get_stats; - netdev->set_multicast_list = cxgb_set_rxmode; - netdev->do_ioctl = cxgb_ioctl; - netdev->change_mtu = cxgb_change_mtu; - netdev->set_mac_address = cxgb_set_mac_addr; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = cxgb_netpoll; -#endif - + netdev->netdev_ops = &cxgb_netdev_ops; SET_ETHTOOL_OPS(netdev, &cxgb_ethtool_ops); } diff --git a/drivers/net/cxgb3/cxgb3_offload.c b/drivers/net/cxgb3/cxgb3_offload.c index 265aa8a15afaed2eb5a61177917d07cd6649b476..2d7f69aff1d949a47e952997932800593444338e 100644 --- a/drivers/net/cxgb3/cxgb3_offload.c +++ b/drivers/net/cxgb3/cxgb3_offload.c @@ -182,7 +182,9 @@ static struct net_device *get_iff_from_mac(struct adapter *adapter, static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req, void *data) { + int i; int ret = 0; + unsigned int val = 0; struct ulp_iscsi_info *uiip = data; switch (req) { @@ -191,32 +193,55 @@ static int cxgb_ulp_iscsi_ctl(struct adapter *adapter, unsigned int req, uiip->llimit = t3_read_reg(adapter, A_ULPRX_ISCSI_LLIMIT); uiip->ulimit = t3_read_reg(adapter, A_ULPRX_ISCSI_ULIMIT); uiip->tagmask = t3_read_reg(adapter, A_ULPRX_ISCSI_TAGMASK); + + val = t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ); + for (i = 0; i < 4; i++, val >>= 8) + uiip->pgsz_factor[i] = val & 0xFF; + + val = t3_read_reg(adapter, A_TP_PARA_REG7); + uiip->max_txsz = + uiip->max_rxsz = min((val >> S_PMMAXXFERLEN0)&M_PMMAXXFERLEN0, + (val >> S_PMMAXXFERLEN1)&M_PMMAXXFERLEN1); /* * On tx, the iscsi pdu has to be <= tx page size and has to * fit into the Tx PM FIFO. */ - uiip->max_txsz = min(adapter->params.tp.tx_pg_size, - t3_read_reg(adapter, A_PM1_TX_CFG) >> 17); - /* on rx, the iscsi pdu has to be < rx page size and the - whole pdu + cpl headers has to fit into one sge buffer */ - uiip->max_rxsz = min_t(unsigned int, - adapter->params.tp.rx_pg_size, - (adapter->sge.qs[0].fl[1].buf_size - - sizeof(struct cpl_rx_data) * 2 - - sizeof(struct cpl_rx_data_ddp))); + val = min(adapter->params.tp.tx_pg_size, + t3_read_reg(adapter, A_PM1_TX_CFG) >> 17); + uiip->max_txsz = min(val, uiip->max_txsz); + + /* set MaxRxData to 16224 */ + val = t3_read_reg(adapter, A_TP_PARA_REG2); + if ((val >> S_MAXRXDATA) != 0x3f60) { + val &= (M_RXCOALESCESIZE << S_RXCOALESCESIZE); + val |= V_MAXRXDATA(0x3f60); + printk(KERN_INFO + "%s, iscsi set MaxRxData to 16224 (0x%x).\n", + adapter->name, val); + t3_write_reg(adapter, A_TP_PARA_REG2, val); + } + + /* + * on rx, the iscsi pdu has to be < rx page size and the + * the max rx data length programmed in TP + */ + val = min(adapter->params.tp.rx_pg_size, + ((t3_read_reg(adapter, A_TP_PARA_REG2)) >> + S_MAXRXDATA) & M_MAXRXDATA); + uiip->max_rxsz = min(val, uiip->max_rxsz); break; case ULP_ISCSI_SET_PARAMS: t3_write_reg(adapter, A_ULPRX_ISCSI_TAGMASK, uiip->tagmask); - /* set MaxRxData and MaxCoalesceSize to 16224 */ - t3_write_reg(adapter, A_TP_PARA_REG2, 0x3f603f60); /* program the ddp page sizes */ - { - int i; - unsigned int val = 0; - for (i = 0; i < 4; i++) - val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i); - if (val) - t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val); + for (i = 0; i < 4; i++) + val |= (uiip->pgsz_factor[i] & 0xF) << (8 * i); + if (val && (val != t3_read_reg(adapter, A_ULPRX_ISCSI_PSZ))) { + printk(KERN_INFO + "%s, setting iscsi pgsz 0x%x, %u,%u,%u,%u.\n", + adapter->name, val, uiip->pgsz_factor[0], + uiip->pgsz_factor[1], uiip->pgsz_factor[2], + uiip->pgsz_factor[3]); + t3_write_reg(adapter, A_ULPRX_ISCSI_PSZ, val); } break; default: @@ -407,6 +432,21 @@ static int cxgb_offload_ctl(struct t3cdev *tdev, unsigned int req, void *data) rx_page_info->page_size = tp->rx_pg_size; rx_page_info->num = tp->rx_num_pgs; break; + case GET_ISCSI_IPV4ADDR: { + struct iscsi_ipv4addr *p = data; + struct port_info *pi = netdev_priv(p->dev); + p->ipv4addr = pi->iscsi_ipv4addr; + break; + } + case GET_EMBEDDED_INFO: { + struct ch_embedded_info *e = data; + + spin_lock(&adapter->stats_lock); + t3_get_fw_version(adapter, &e->fw_vers); + t3_get_tp_version(adapter, &e->tp_vers); + spin_unlock(&adapter->stats_lock); + break; + } default: return -EOPNOTSUPP; } diff --git a/drivers/net/cxgb3/sge.c b/drivers/net/cxgb3/sge.c index c6480be0bc1f7ed033b9a9ed0d856d12b4490255..6c641a889471012b5e6db7bac57da040d9f36ed8 100644 --- a/drivers/net/cxgb3/sge.c +++ b/drivers/net/cxgb3/sge.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "common.h" #include "regs.h" #include "sge_defs.h" @@ -549,16 +550,15 @@ static void *alloc_ring(struct pci_dev *pdev, size_t nelem, size_t elem_size, if (!p) return NULL; - if (sw_size) { + if (sw_size && metadata) { s = kcalloc(nelem, sw_size, GFP_KERNEL); if (!s) { dma_free_coherent(&pdev->dev, len, p, *phys); return NULL; } - } - if (metadata) *(void **)metadata = s; + } memset(p, 0, len); return p; } @@ -1121,10 +1121,10 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb, htonl(V_WR_TID(q->token))); } -static inline void t3_stop_queue(struct net_device *dev, struct sge_qset *qs, - struct sge_txq *q) +static inline void t3_stop_tx_queue(struct netdev_queue *txq, + struct sge_qset *qs, struct sge_txq *q) { - netif_stop_queue(dev); + netif_tx_stop_queue(txq); set_bit(TXQ_ETH, &qs->txq_stopped); q->stops++; } @@ -1138,11 +1138,13 @@ static inline void t3_stop_queue(struct net_device *dev, struct sge_qset *qs, */ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) { + int qidx; unsigned int ndesc, pidx, credits, gen, compl; const struct port_info *pi = netdev_priv(dev); struct adapter *adap = pi->adapter; - struct sge_qset *qs = pi->qs; - struct sge_txq *q = &qs->txq[TXQ_ETH]; + struct netdev_queue *txq; + struct sge_qset *qs; + struct sge_txq *q; /* * The chip min packet length is 9 octets but play safe and reject @@ -1153,6 +1155,11 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) return NETDEV_TX_OK; } + qidx = skb_get_queue_mapping(skb); + qs = &pi->qs[qidx]; + q = &qs->txq[TXQ_ETH]; + txq = netdev_get_tx_queue(dev, qidx); + spin_lock(&q->lock); reclaim_completed_tx(adap, q); @@ -1160,7 +1167,7 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) ndesc = calc_tx_descs(skb); if (unlikely(credits < ndesc)) { - t3_stop_queue(dev, qs, q); + t3_stop_tx_queue(txq, qs, q); dev_err(&adap->pdev->dev, "%s: Tx ring %u full while queue awake!\n", dev->name, q->cntxt_id & 7); @@ -1170,12 +1177,12 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev) q->in_use += ndesc; if (unlikely(credits - ndesc < q->stop_thres)) { - t3_stop_queue(dev, qs, q); + t3_stop_tx_queue(txq, qs, q); if (should_restart_tx(q) && test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { q->restarts++; - netif_wake_queue(dev); + netif_tx_wake_queue(txq); } } @@ -1839,7 +1846,7 @@ static void restart_tx(struct sge_qset *qs) test_and_clear_bit(TXQ_ETH, &qs->txq_stopped)) { qs->txq[TXQ_ETH].restarts++; if (netif_running(qs->netdev)) - netif_wake_queue(qs->netdev); + netif_tx_wake_queue(qs->tx_q); } if (test_bit(TXQ_OFLD, &qs->txq_stopped) && @@ -1856,6 +1863,54 @@ static void restart_tx(struct sge_qset *qs) } } +/** + * cxgb3_arp_process - process an ARP request probing a private IP address + * @adapter: the adapter + * @skb: the skbuff containing the ARP request + * + * Check if the ARP request is probing the private IP address + * dedicated to iSCSI, generate an ARP reply if so. + */ +static void cxgb3_arp_process(struct adapter *adapter, struct sk_buff *skb) +{ + struct net_device *dev = skb->dev; + struct port_info *pi; + struct arphdr *arp; + unsigned char *arp_ptr; + unsigned char *sha; + __be32 sip, tip; + + if (!dev) + return; + + skb_reset_network_header(skb); + arp = arp_hdr(skb); + + if (arp->ar_op != htons(ARPOP_REQUEST)) + return; + + arp_ptr = (unsigned char *)(arp + 1); + sha = arp_ptr; + arp_ptr += dev->addr_len; + memcpy(&sip, arp_ptr, sizeof(sip)); + arp_ptr += sizeof(sip); + arp_ptr += dev->addr_len; + memcpy(&tip, arp_ptr, sizeof(tip)); + + pi = netdev_priv(dev); + if (tip != pi->iscsi_ipv4addr) + return; + + arp_send(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, sha, + dev->dev_addr, sha); + +} + +static inline int is_arp(struct sk_buff *skb) +{ + return skb->protocol == htons(ETH_P_ARP); +} + /** * rx_eth - process an ingress ethernet packet * @adap: the adapter @@ -1876,11 +1931,10 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, skb_pull(skb, sizeof(*p) + pad); skb->protocol = eth_type_trans(skb, adap->port[p->iff]); - skb->dev->last_rx = jiffies; pi = netdev_priv(skb->dev); if (pi->rx_csum_offload && p->csum_valid && p->csum == htons(0xffff) && !p->fragment) { - rspq_to_qset(rq)->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; + qs->port_stats[SGE_PSTAT_RX_CSUM_GOOD]++; skb->ip_summed = CHECKSUM_UNNECESSARY; } else skb->ip_summed = CHECKSUM_NONE; @@ -1895,16 +1949,28 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq, grp, ntohs(p->vlan), p); - else + else { + if (unlikely(pi->iscsi_ipv4addr && + is_arp(skb))) { + unsigned short vtag = ntohs(p->vlan) & + VLAN_VID_MASK; + skb->dev = vlan_group_get_device(grp, + vtag); + cxgb3_arp_process(adap, skb); + } __vlan_hwaccel_rx(skb, grp, ntohs(p->vlan), rq->polling); + } else dev_kfree_skb_any(skb); } else if (rq->polling) { if (lro) lro_receive_skb(&qs->lro_mgr, skb, p); - else + else { + if (unlikely(pi->iscsi_ipv4addr && is_arp(skb))) + cxgb3_arp_process(adap, skb); netif_receive_skb(skb); + } } else netif_rx(skb); } @@ -2308,7 +2374,7 @@ next_fl: static inline int is_pure_response(const struct rsp_desc *r) { - u32 n = ntohl(r->flags) & (F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID); + __be32 n = r->flags & htonl(F_RSPD_ASYNC_NOTIF | F_RSPD_IMM_DATA_VALID); return (n | r->len_cq) == 0; } @@ -2826,6 +2892,7 @@ void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) * @p: configuration parameters for this queue set * @ntxq: number of Tx queues for the queue set * @netdev: net device associated with this queue set + * @netdevq: net device TX queue associated with this queue set * * Allocate resources and initialize an SGE queue set. A queue set * comprises a response queue, two Rx free-buffer queues, and up to 3 @@ -2834,7 +2901,8 @@ void t3_update_qset_coalesce(struct sge_qset *qs, const struct qset_params *p) */ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, int irq_vec_idx, const struct qset_params *p, - int ntxq, struct net_device *dev) + int ntxq, struct net_device *dev, + struct netdev_queue *netdevq) { int i, avail, ret = -ENOMEM; struct sge_qset *q = &adapter->sge.qs[id]; @@ -2970,6 +3038,7 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports, q->adap = adapter; q->netdev = dev; + q->tx_q = netdevq; t3_update_qset_coalesce(q, p); init_lro_mgr(q, lro_mgr); diff --git a/drivers/net/cxgb3/t3_hw.c b/drivers/net/cxgb3/t3_hw.c index 9a0898b0dbcef2e8d214046c3ac9137de1ccfb23..2d1433077a8ee992a71ed1e89210ebf8749de816 100644 --- a/drivers/net/cxgb3/t3_hw.c +++ b/drivers/net/cxgb3/t3_hw.c @@ -925,11 +925,10 @@ int t3_get_tp_version(struct adapter *adapter, u32 *vers) /** * t3_check_tpsram_version - read the tp sram version * @adapter: the adapter - * @must_load: set to 1 if loading a new microcode image is required * * Reads the protocol sram version from flash. */ -int t3_check_tpsram_version(struct adapter *adapter, int *must_load) +int t3_check_tpsram_version(struct adapter *adapter) { int ret; u32 vers; @@ -938,7 +937,6 @@ int t3_check_tpsram_version(struct adapter *adapter, int *must_load) if (adapter->params.rev == T3_REV_A) return 0; - *must_load = 1; ret = t3_get_tp_version(adapter, &vers); if (ret) @@ -949,13 +947,7 @@ int t3_check_tpsram_version(struct adapter *adapter, int *must_load) if (major == TP_VERSION_MAJOR && minor == TP_VERSION_MINOR) return 0; - - if (major != TP_VERSION_MAJOR) - CH_ERR(adapter, "found wrong TP version (%u.%u), " - "driver needs version %d.%d\n", major, minor, - TP_VERSION_MAJOR, TP_VERSION_MINOR); else { - *must_load = 0; CH_ERR(adapter, "found wrong TP version (%u.%u), " "driver compiled for version %d.%d\n", major, minor, TP_VERSION_MAJOR, TP_VERSION_MINOR); @@ -1012,18 +1004,16 @@ int t3_get_fw_version(struct adapter *adapter, u32 *vers) /** * t3_check_fw_version - check if the FW is compatible with this driver * @adapter: the adapter - * @must_load: set to 1 if loading a new FW image is required - + * * Checks if an adapter's FW is compatible with the driver. Returns 0 * if the versions are compatible, a negative error otherwise. */ -int t3_check_fw_version(struct adapter *adapter, int *must_load) +int t3_check_fw_version(struct adapter *adapter) { int ret; u32 vers; unsigned int type, major, minor; - *must_load = 1; ret = t3_get_fw_version(adapter, &vers); if (ret) return ret; @@ -1035,17 +1025,11 @@ int t3_check_fw_version(struct adapter *adapter, int *must_load) if (type == FW_VERSION_T3 && major == FW_VERSION_MAJOR && minor == FW_VERSION_MINOR) return 0; - - if (major != FW_VERSION_MAJOR) - CH_ERR(adapter, "found wrong FW version(%u.%u), " - "driver needs version %u.%u\n", major, minor, - FW_VERSION_MAJOR, FW_VERSION_MINOR); - else if (minor < FW_VERSION_MINOR) { - *must_load = 0; + else if (major != FW_VERSION_MAJOR || minor < FW_VERSION_MINOR) CH_WARN(adapter, "found old FW minor version(%u.%u), " "driver compiled for version %u.%u\n", major, minor, FW_VERSION_MAJOR, FW_VERSION_MINOR); - } else { + else { CH_WARN(adapter, "found newer FW version(%u.%u), " "driver compiled for version %u.%u\n", major, minor, FW_VERSION_MAJOR, FW_VERSION_MINOR); diff --git a/drivers/net/cxgb3/version.h b/drivers/net/cxgb3/version.h index bb8698a867545384842032a10d330c3ee785cc0b..b1b25c37aa1062099cbb38dbeafc0a6ce2d476de 100644 --- a/drivers/net/cxgb3/version.h +++ b/drivers/net/cxgb3/version.h @@ -35,7 +35,7 @@ #define DRV_DESC "Chelsio T3 Network Driver" #define DRV_NAME "cxgb3" /* Driver version */ -#define DRV_VERSION "1.1.0-ko" +#define DRV_VERSION "1.1.1-ko" /* Firmware version */ #define FW_VERSION_MAJOR 7 diff --git a/drivers/net/cxgb3/vsc8211.c b/drivers/net/cxgb3/vsc8211.c index 33f956bd6b59b8f96134c9e09cc23149f4556b77..d07130971b8f4bba321784ce079d51c54e905ec4 100644 --- a/drivers/net/cxgb3/vsc8211.c +++ b/drivers/net/cxgb3/vsc8211.c @@ -262,6 +262,7 @@ static int vsc8211_get_link_status_fiber(struct cphy *cphy, int *link_ok, return 0; } +#ifdef UNUSED /* * Enable/disable auto MDI/MDI-X in forced link speed mode. */ @@ -301,6 +302,7 @@ int vsc8211_set_speed_duplex(struct cphy *phy, int speed, int duplex) err = vsc8211_set_automdi(phy, 1); return err; } +#endif /* UNUSED */ static int vsc8211_power_down(struct cphy *cphy, int enable) { diff --git a/drivers/net/de600.c b/drivers/net/de600.c index cb849b091f980c9521e45ed0ac227420fa835c30..970f820ba814fc3b71d1f09401d74da5f0fa0b6a 100644 --- a/drivers/net/de600.c +++ b/drivers/net/de600.c @@ -369,7 +369,6 @@ static void de600_rx_intr(struct net_device *dev) netif_rx(skb); /* update stats */ - dev->last_rx = jiffies; dev->stats.rx_packets++; /* count all receives */ dev->stats.rx_bytes += size; /* count all received bytes */ @@ -384,7 +383,6 @@ static struct net_device * __init de600_probe(void) int i; struct net_device *dev; int err; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(0); if (!dev) @@ -439,7 +437,7 @@ static struct net_device * __init de600_probe(void) goto out1; } - printk(", Ethernet Address: %s\n", print_mac(mac, dev->dev_addr)); + printk(", Ethernet Address: %pM\n", dev->dev_addr); dev->open = de600_open; dev->stop = de600_close; diff --git a/drivers/net/de620.c b/drivers/net/de620.c index d454e143483ee39ad64ba0724753af67053527c0..bdfa89403389cb1470a3c1e1fa1bc6ab8f73a508 100644 --- a/drivers/net/de620.c +++ b/drivers/net/de620.c @@ -686,7 +686,6 @@ static int de620_rx_intr(struct net_device *dev) PRINTK(("Read %d bytes\n", size)); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); /* deliver it "upstairs" */ - dev->last_rx = jiffies; /* count all receives */ dev->stats.rx_packets++; dev->stats.rx_bytes += size; @@ -800,7 +799,6 @@ struct net_device * __init de620_probe(int unit) struct net_device *dev; int err = -ENOMEM; int i; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(0); if (!dev) @@ -853,7 +851,7 @@ struct net_device * __init de620_probe(int unit) dev->broadcast[i] = 0xff; } - printk(", Ethernet Address: %s", print_mac(mac, dev->dev_addr)); + printk(", Ethernet Address: %pM", dev->dev_addr); printk(" (%dk RAM,", (nic_data.RAM_Size) ? (nic_data.RAM_Size >> 2) : 64); @@ -876,10 +874,7 @@ struct net_device * __init de620_probe(int unit) if (de620_debug) { printk("\nEEPROM contents:\n"); printk("RAM_Size = 0x%02X\n", nic_data.RAM_Size); - printk("NodeID = %02X:%02X:%02X:%02X:%02X:%02X\n", - nic_data.NodeID[0], nic_data.NodeID[1], - nic_data.NodeID[2], nic_data.NodeID[3], - nic_data.NodeID[4], nic_data.NodeID[5]); + printk("NodeID = %pM\n", nic_data.NodeID); printk("Model = %d\n", nic_data.Model); printk("Media = %d\n", nic_data.Media); printk("SCR = 0x%02x\n", nic_data.SCR); @@ -1008,20 +1003,3 @@ void cleanup_module(void) } #endif /* MODULE */ MODULE_LICENSE("GPL"); - - -/* - * (add '-DMODULE' when compiling as loadable module) - * - * compile-command: - * gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O2 \ - * -fomit-frame-pointer -m486 \ - * -I/usr/src/linux/include -I../../net/inet -c de620.c -*/ -/* - * Local variables: - * kernel-compile-command: "gcc -D__KERNEL__ -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de620.c" - * module-compile-command: "gcc -D__KERNEL__ -DMODULE -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de620.c" - * compile-command: "gcc -D__KERNEL__ -DMODULE -Ilinux/include -I../../net/inet -Wall -Wstrict-prototypes -O2 -m486 -c de620.c" - * End: - */ diff --git a/drivers/net/declance.c b/drivers/net/declance.c index 3e3506411ac08a50501e8049bb6f0b74af9a0363..7ce3053530f9c62279f38dd17340e89167b6044b 100644 --- a/drivers/net/declance.c +++ b/drivers/net/declance.c @@ -622,7 +622,6 @@ static int lance_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } @@ -1023,7 +1022,6 @@ static int __init dec_lance_probe(struct device *bdev, const int type) int i, ret; unsigned long esar_base; unsigned char *esar; - DECLARE_MAC_BUF(mac); if (dec_lance_debug && version_printed++ == 0) printk(version); @@ -1035,7 +1033,7 @@ static int __init dec_lance_probe(struct device *bdev, const int type) dev = root_lance_dev; while (dev) { i++; - lp = (struct lance_private *)dev->priv; + lp = netdev_priv(dev); dev = lp->next; } snprintf(name, sizeof(name), fmt, i); @@ -1223,8 +1221,7 @@ static int __init dec_lance_probe(struct device *bdev, const int type) for (i = 0; i < 6; i++) dev->dev_addr[i] = esar[i * 4]; - printk(", addr = %s, irq = %d\n", - print_mac(mac, dev->dev_addr), dev->irq); + printk(", addr = %pM, irq = %d\n", dev->dev_addr, dev->irq); dev->open = &lance_open; dev->stop = &lance_close; diff --git a/drivers/net/defxx.c b/drivers/net/defxx.c index c062aacf229ce2b23e773e45584734184d6e3ffa..6445cedd586844ad6f544c9e1f34af3d3212d0eb 100644 --- a/drivers/net/defxx.c +++ b/drivers/net/defxx.c @@ -477,6 +477,15 @@ static void dfx_get_bars(struct device *bdev, } } +static const struct net_device_ops dfx_netdev_ops = { + .ndo_open = dfx_open, + .ndo_stop = dfx_close, + .ndo_start_xmit = dfx_xmt_queue_pkt, + .ndo_get_stats = dfx_ctl_get_stats, + .ndo_set_multicast_list = dfx_ctl_set_multicast_list, + .ndo_set_mac_address = dfx_ctl_set_mac_address, +}; + /* * ================ * = dfx_register = @@ -511,7 +520,7 @@ static int __devinit dfx_register(struct device *bdev) int dfx_bus_pci = DFX_BUS_PCI(bdev); int dfx_bus_tc = DFX_BUS_TC(bdev); int dfx_use_mmio = DFX_MMIO || dfx_bus_tc; - char *print_name = bdev->bus_id; + const char *print_name = dev_name(bdev); struct net_device *dev; DFX_board_t *bp; /* board pointer */ resource_size_t bar_start = 0; /* pointer to port */ @@ -573,13 +582,7 @@ static int __devinit dfx_register(struct device *bdev) } /* Initialize new device structure */ - - dev->get_stats = dfx_ctl_get_stats; - dev->open = dfx_open; - dev->stop = dfx_close; - dev->hard_start_xmit = dfx_xmt_queue_pkt; - dev->set_multicast_list = dfx_ctl_set_multicast_list; - dev->set_mac_address = dfx_ctl_set_mac_address; + dev->netdev_ops = &dfx_netdev_ops; if (dfx_bus_pci) pci_set_master(to_pci_dev(bdev)); @@ -3103,7 +3106,6 @@ static void dfx_rcv_queue_process( netif_rx(skb); /* Update the rcv counters */ - bp->dev->last_rx = jiffies; bp->rcv_total_frames++; if (*(p_buff + RCV_BUFF_K_DA) & 0x01) bp->rcv_multicast_frames++; @@ -3741,10 +3743,3 @@ MODULE_AUTHOR("Lawrence V. Stefani"); MODULE_DESCRIPTION("DEC FDDIcontroller TC/EISA/PCI (DEFTA/DEFEA/DEFPA) driver " DRV_VERSION " " DRV_RELDATE); MODULE_LICENSE("GPL"); - - -/* - * Local variables: - * kernel-compile-command: "gcc -D__KERNEL__ -I/root/linux/include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -c defxx.c" - * End: - */ diff --git a/drivers/net/depca.c b/drivers/net/depca.c index ace39ec0a367c121be87001b4e44bde930c0633f..e4cef491dc73fc8d6486b98976d9b937b12399ad 100644 --- a/drivers/net/depca.c +++ b/drivers/net/depca.c @@ -573,7 +573,6 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) s16 nicsr; u_long ioaddr; u_long mem_start; - DECLARE_MAC_BUF(mac); /* * We are now supposed to enter this function with the @@ -601,7 +600,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) return -ENXIO; } - lp = (struct depca_private *) dev->priv; + lp = netdev_priv(dev); mem_start = lp->mem_start; if (!mem_start || lp->adapter < DEPCA || lp->adapter >=unknown) @@ -633,7 +632,7 @@ static int __init depca_hw_init (struct net_device *dev, struct device *device) printk(", h/w address "); status = get_hw_addr(dev); - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); if (status != 0) { printk(" which has an Ethernet PROM CRC error.\n"); return -ENXIO; @@ -821,7 +820,7 @@ out_priv: static int depca_open(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; s16 nicsr; int status = 0; @@ -866,7 +865,7 @@ static int depca_open(struct net_device *dev) /* Initialize the lance Rx and Tx descriptor rings. */ static void depca_init_ring(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_int i; u_long offset; @@ -924,7 +923,7 @@ static void depca_tx_timeout(struct net_device *dev) */ static int depca_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; int status = 0; @@ -972,7 +971,7 @@ static irqreturn_t depca_interrupt(int irq, void *dev_id) return IRQ_NONE; } - lp = (struct depca_private *) dev->priv; + lp = netdev_priv(dev); ioaddr = dev->base_addr; spin_lock(&lp->lock); @@ -1010,7 +1009,7 @@ static irqreturn_t depca_interrupt(int irq, void *dev_id) /* Called with lp->lock held */ static int depca_rx(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); int i, entry; s32 status; @@ -1057,7 +1056,6 @@ static int depca_rx(struct net_device *dev) /* ** Update stats */ - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; for (i = 1; i < DEPCA_PKT_STAT_SZ - 1; i++) { @@ -1108,7 +1106,7 @@ static int depca_rx(struct net_device *dev) */ static int depca_tx(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); int entry; s32 status; u_long ioaddr = dev->base_addr; @@ -1149,7 +1147,7 @@ static int depca_tx(struct net_device *dev) static int depca_close(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); s16 nicsr; u_long ioaddr = dev->base_addr; @@ -1185,7 +1183,7 @@ static int depca_close(struct net_device *dev) static void LoadCSRs(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */ @@ -1202,7 +1200,7 @@ static void LoadCSRs(struct net_device *dev) static int InitRestartDepca(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; int i, status = 0; @@ -1234,7 +1232,7 @@ static int InitRestartDepca(struct net_device *dev) */ static void set_multicast_list(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; netif_stop_queue(dev); @@ -1263,7 +1261,7 @@ static void set_multicast_list(struct net_device *dev) */ static void SetMulticastFilter(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); struct dev_mc_list *dmi = dev->mc_list; char *addrs; int i, j, bit, byte; @@ -1431,7 +1429,7 @@ static int __init depca_mca_probe(struct device *device) dev->irq = irq; dev->base_addr = iobase; - lp = dev->priv; + lp = netdev_priv(dev); lp->depca_bus = DEPCA_BUS_MCA; lp->adapter = depca_mca_adapter_type[mdev->index]; lp->mem_start = mem_start; @@ -1534,7 +1532,7 @@ static int __init depca_isa_probe (struct platform_device *device) dev->base_addr = ioaddr; dev->irq = irq; /* Use whatever value the user gave * us, and 0 if he didn't. */ - lp = dev->priv; + lp = netdev_priv(dev); lp->depca_bus = DEPCA_BUS_ISA; lp->adapter = adapter; lp->mem_start = mem_start; @@ -1558,6 +1556,7 @@ static int __init depca_isa_probe (struct platform_device *device) #ifdef CONFIG_EISA static int __init depca_eisa_probe (struct device *device) { + enum depca_type adapter = unknown; struct eisa_device *edev; struct net_device *dev; struct depca_private *lp; @@ -1576,11 +1575,15 @@ static int __init depca_eisa_probe (struct device *device) * the EISA configuration structures (yet... :-), just rely on * the ISA probing to sort it out... */ - depca_shmem_probe (&mem_start); + adapter = depca_shmem_probe (&mem_start); + if (adapter == unknown) { + status = -ENODEV; + goto out_free; + } dev->base_addr = ioaddr; dev->irq = irq; - lp = dev->priv; + lp = netdev_priv(dev); lp->depca_bus = DEPCA_BUS_EISA; lp->adapter = edev->id.driver_data; lp->mem_start = mem_start; @@ -1605,7 +1608,7 @@ static int __devexit depca_device_remove (struct device *device) int bus; dev = device->driver_data; - lp = dev->priv; + lp = netdev_priv(dev); unregister_netdev (dev); iounmap (lp->sh_mem); @@ -1747,7 +1750,7 @@ static int __init DevicePresent(u_long ioaddr) static int __init get_hw_addr(struct net_device *dev) { u_long ioaddr = dev->base_addr; - struct depca_private *lp = dev->priv; + struct depca_private *lp = netdev_priv(dev); int i, k, tmp, status = 0; u_short j, x, chksum; @@ -1782,7 +1785,7 @@ static int __init get_hw_addr(struct net_device *dev) */ static int load_packet(struct net_device *dev, struct sk_buff *skb) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); int i, entry, end, len, status = 0; entry = lp->tx_new; /* Ring around buffer number. */ @@ -1837,11 +1840,10 @@ static int load_packet(struct net_device *dev, struct sk_buff *skb) static void depca_dbg_open(struct net_device *dev) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; struct depca_init *p = &lp->init_block; int i; - DECLARE_MAC_BUF(mac); if (depca_debug > 1) { /* Do not copy the shadow init block into shared memory */ @@ -1880,7 +1882,7 @@ static void depca_dbg_open(struct net_device *dev) printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base)); printk("Initialisation block at 0x%8.8lx(Phys)\n", lp->mem_start); printk(" mode: 0x%4.4x\n", p->mode); - printk(" physical address: %s\n", print_mac(mac, p->phys_addr)); + printk(" physical address: %pM\n", p->phys_addr); printk(" multicast hash table: "); for (i = 0; i < (HASH_TABLE_LEN >> 3) - 1; i++) { printk("%2.2x:", p->mcast_table[i]); @@ -1909,7 +1911,7 @@ static void depca_dbg_open(struct net_device *dev) */ static int depca_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct depca_private *lp = (struct depca_private *) dev->priv; + struct depca_private *lp = netdev_priv(dev); struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_ifru; int i, status = 0; u_long ioaddr = dev->base_addr; diff --git a/drivers/net/dl2k.c b/drivers/net/dl2k.c index f8037110a522e3eb2616414908cacdaafa363c8f..c749e9fb47ef9d99922946f42013ab21951b5eb4 100644 --- a/drivers/net/dl2k.c +++ b/drivers/net/dl2k.c @@ -85,6 +85,19 @@ static int mii_write (struct net_device *dev, int phy_addr, int reg_num, static const struct ethtool_ops ethtool_ops; +static const struct net_device_ops netdev_ops = { + .ndo_open = rio_open, + .ndo_start_xmit = start_xmit, + .ndo_stop = rio_close, + .ndo_get_stats = get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_set_multicast_list = set_multicast, + .ndo_do_ioctl = rio_ioctl, + .ndo_tx_timeout = rio_tx_timeout, + .ndo_change_mtu = change_mtu, +}; + static int __devinit rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -97,7 +110,6 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) static int version_printed; void *ring_space; dma_addr_t ring_dma; - DECLARE_MAC_BUF(mac); if (!version_printed++) printk ("%s", version); @@ -198,15 +210,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) else if (tx_coalesce > TX_RING_SIZE-1) tx_coalesce = TX_RING_SIZE - 1; } - dev->open = &rio_open; - dev->hard_start_xmit = &start_xmit; - dev->stop = &rio_close; - dev->get_stats = &get_stats; - dev->set_multicast_list = &set_multicast; - dev->do_ioctl = &rio_ioctl; - dev->tx_timeout = &rio_tx_timeout; + dev->netdev_ops = &netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; - dev->change_mtu = &change_mtu; SET_ETHTOOL_OPS(dev, ðtool_ops); #if 0 dev->features = NETIF_F_IP_CSUM; @@ -257,8 +262,8 @@ rio_probe1 (struct pci_dev *pdev, const struct pci_device_id *ent) card_idx++; - printk (KERN_INFO "%s: %s, %s, IRQ %d\n", - dev->name, np->name, print_mac(mac, dev->dev_addr), irq); + printk (KERN_INFO "%s: %s, %pM, IRQ %d\n", + dev->name, np->name, dev->dev_addr, irq); if (tx_coalesce > 1) printk(KERN_INFO "tx_coalesce:\t%d packets\n", tx_coalesce); @@ -892,7 +897,6 @@ receive_packet (struct net_device *dev) } #endif netif_rx (skb); - dev->last_rx = jiffies; } entry = (entry + 1) % RX_RING_SIZE; } diff --git a/drivers/net/dm9000.c b/drivers/net/dm9000.c index 5a9083e3f443b81f0b744cac37f3b36d274b88ff..bcf92917bbf3192504bd90e48e4165716615208d 100644 --- a/drivers/net/dm9000.c +++ b/drivers/net/dm9000.c @@ -137,7 +137,7 @@ typedef struct board_info { static inline board_info_t *to_dm9000_board(struct net_device *dev) { - return dev->priv; + return netdev_priv(dev); } /* DM9000 network board routine ---------------------------- */ @@ -626,7 +626,7 @@ static unsigned char dm9000_type_to_char(enum dm9000_type type) static void dm9000_hash_table(struct net_device *dev) { - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = netdev_priv(dev); struct dev_mc_list *mcptr = dev->mc_list; int mc_cnt = dev->mc_count; int i, oft; @@ -677,7 +677,7 @@ dm9000_hash_table(struct net_device *dev) static void dm9000_init_dm9000(struct net_device *dev) { - board_info_t *db = dev->priv; + board_info_t *db = netdev_priv(dev); unsigned int imr; dm9000_dbg(db, 1, "entering %s\n", __func__); @@ -723,7 +723,7 @@ dm9000_init_dm9000(struct net_device *dev) /* Our watchdog timed out. Called by the networking layer */ static void dm9000_timeout(struct net_device *dev) { - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = netdev_priv(dev); u8 reg_save; unsigned long flags; @@ -751,7 +751,7 @@ static int dm9000_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; - board_info_t *db = dev->priv; + board_info_t *db = netdev_priv(dev); dm9000_dbg(db, 3, "%s:\n", __func__); @@ -831,7 +831,7 @@ struct dm9000_rxhdr { static void dm9000_rx(struct net_device *dev) { - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = netdev_priv(dev); struct dm9000_rxhdr rxhdr; struct sk_buff *skb; u8 rxbyte, *rdptr; @@ -928,7 +928,7 @@ dm9000_rx(struct net_device *dev) static irqreturn_t dm9000_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - board_info_t *db = dev->priv; + board_info_t *db = netdev_priv(dev); int int_status; u8 reg_save; @@ -996,7 +996,7 @@ static void dm9000_poll_controller(struct net_device *dev) static int dm9000_open(struct net_device *dev) { - board_info_t *db = dev->priv; + board_info_t *db = netdev_priv(dev); unsigned long irqflags = db->irq_res->flags & IRQF_TRIGGER_MASK; if (netif_msg_ifup(db)) @@ -1046,7 +1046,7 @@ static void dm9000_msleep(board_info_t *db, unsigned int ms) static int dm9000_phy_read(struct net_device *dev, int phy_reg_unused, int reg) { - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = netdev_priv(dev); unsigned long flags; unsigned int reg_save; int ret; @@ -1093,7 +1093,7 @@ static void dm9000_phy_write(struct net_device *dev, int phyaddr_unused, int reg, int value) { - board_info_t *db = (board_info_t *) dev->priv; + board_info_t *db = netdev_priv(dev); unsigned long flags; unsigned long reg_save; @@ -1134,7 +1134,7 @@ dm9000_phy_write(struct net_device *dev, static void dm9000_shutdown(struct net_device *dev) { - board_info_t *db = dev->priv; + board_info_t *db = netdev_priv(dev); /* RESET device */ dm9000_phy_write(dev, 0, MII_BMCR, BMCR_RESET); /* PHY RESET */ @@ -1150,7 +1150,7 @@ dm9000_shutdown(struct net_device *dev) static int dm9000_stop(struct net_device *ndev) { - board_info_t *db = ndev->priv; + board_info_t *db = netdev_priv(ndev); if (netif_msg_ifdown(db)) dev_dbg(db->dev, "shutting down %s\n", ndev->name); @@ -1197,7 +1197,7 @@ dm9000_probe(struct platform_device *pdev) dev_dbg(&pdev->dev, "dm9000_probe()\n"); /* setup board info structure */ - db = ndev->priv; + db = netdev_priv(ndev); memset(db, 0, sizeof(*db)); db->dev = &pdev->dev; @@ -1385,13 +1385,11 @@ dm9000_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ndev); ret = register_netdev(ndev); - if (ret == 0) { - DECLARE_MAC_BUF(mac); - printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %s (%s)\n", + if (ret == 0) + printk(KERN_INFO "%s: dm9000%c at %p,%p IRQ %d MAC: %pM (%s)\n", ndev->name, dm9000_type_to_char(db->type), db->io_addr, db->io_data, ndev->irq, - print_mac(mac, ndev->dev_addr), mac_src); - } + ndev->dev_addr, mac_src); return 0; out: @@ -1410,7 +1408,7 @@ dm9000_drv_suspend(struct platform_device *dev, pm_message_t state) board_info_t *db; if (ndev) { - db = (board_info_t *) ndev->priv; + db = netdev_priv(ndev); db->in_suspend = 1; if (netif_running(ndev)) { @@ -1425,7 +1423,7 @@ static int dm9000_drv_resume(struct platform_device *dev) { struct net_device *ndev = platform_get_drvdata(dev); - board_info_t *db = (board_info_t *) ndev->priv; + board_info_t *db = netdev_priv(ndev); if (ndev) { @@ -1449,7 +1447,7 @@ dm9000_drv_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); unregister_netdev(ndev); - dm9000_release_board(pdev, (board_info_t *) ndev->priv); + dm9000_release_board(pdev, (board_info_t *) netdev_priv(ndev)); free_netdev(ndev); /* free device structure */ dev_dbg(&pdev->dev, "released and freed device\n"); diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 84e14f397d9ae1f5322dd0614855b6a53b5e3980..8ebd7d78940569054f5bab34b28b3db4e2c4eeae 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c @@ -57,18 +57,23 @@ static void set_multicast_list(struct net_device *dev) { } +static const struct net_device_ops dummy_netdev_ops = { + .ndo_start_xmit = dummy_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = set_multicast_list, + .ndo_set_mac_address = dummy_set_address, +}; + static void dummy_setup(struct net_device *dev) { + ether_setup(dev); + /* Initialize the device structure. */ - dev->hard_start_xmit = dummy_xmit; - dev->set_multicast_list = set_multicast_list; - dev->set_mac_address = dummy_set_address; + dev->netdev_ops = &dummy_netdev_ops; dev->destructor = free_netdev; /* Fill in device structure with ethernet-generic values. */ - ether_setup(dev); dev->tx_queue_len = 0; - dev->change_mtu = NULL; dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; random_ether_addr(dev->dev_addr); diff --git a/drivers/net/e100.c b/drivers/net/e100.c index e8bfcce6b319da95be67ecc44e211b7f8ed7ac38..9f38b16ccbbd1b58f308225d15e59f94f1585a1c 100644 --- a/drivers/net/e100.c +++ b/drivers/net/e100.c @@ -1580,11 +1580,13 @@ static void e100_watchdog(unsigned long data) mii_ethtool_gset(&nic->mii, &cmd); if(mii_link_ok(&nic->mii) && !netif_carrier_ok(nic->netdev)) { - DPRINTK(LINK, INFO, "link up, %sMbps, %s-duplex\n", - cmd.speed == SPEED_100 ? "100" : "10", - cmd.duplex == DUPLEX_FULL ? "full" : "half"); + printk(KERN_INFO "e100: %s NIC Link is Up %s Mbps %s Duplex\n", + nic->netdev->name, + cmd.speed == SPEED_100 ? "100" : "10", + cmd.duplex == DUPLEX_FULL ? "Full" : "Half"); } else if(!mii_link_ok(&nic->mii) && netif_carrier_ok(nic->netdev)) { - DPRINTK(LINK, INFO, "link down\n"); + printk(KERN_INFO "e100: %s NIC Link is Down\n", + nic->netdev->name); } mii_check_link(&nic->mii); @@ -1880,7 +1882,6 @@ static int e100_rx_indicate(struct nic *nic, struct rx *rx, } else { dev->stats.rx_packets++; dev->stats.rx_bytes += actual_size; - nic->netdev->last_rx = jiffies; netif_receive_skb(skb); if(work_done) (*work_done)++; @@ -2048,9 +2049,9 @@ static irqreturn_t e100_intr(int irq, void *dev_id) if(stat_ack & stat_ack_rnr) nic->ru_running = RU_SUSPENDED; - if(likely(netif_rx_schedule_prep(netdev, &nic->napi))) { + if(likely(netif_rx_schedule_prep(&nic->napi))) { e100_disable_irq(nic); - __netif_rx_schedule(netdev, &nic->napi); + __netif_rx_schedule(&nic->napi); } return IRQ_HANDLED; @@ -2059,7 +2060,6 @@ static irqreturn_t e100_intr(int irq, void *dev_id) static int e100_poll(struct napi_struct *napi, int budget) { struct nic *nic = container_of(napi, struct nic, napi); - struct net_device *netdev = nic->netdev; unsigned int work_done = 0; e100_rx_clean(nic, &work_done, budget); @@ -2067,7 +2067,7 @@ static int e100_poll(struct napi_struct *napi, int budget) /* If budget not fully consumed, exit the polling mode */ if (work_done < budget) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); e100_enable_irq(nic); } @@ -2322,7 +2322,8 @@ static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { struct nic *nic = netdev_priv(netdev); - if(wol->wolopts != WAKE_MAGIC && wol->wolopts != 0) + if ((wol->wolopts && wol->wolopts != WAKE_MAGIC) || + !device_can_wakeup(&nic->pdev->dev)) return -EOPNOTSUPP; if(wol->wolopts) @@ -2330,6 +2331,8 @@ static int e100_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) else nic->flags &= ~wol_magic; + device_set_wakeup_enable(&nic->pdev->dev, wol->wolopts); + e100_exec_cb(nic, NULL, e100_configure); return 0; @@ -2610,13 +2613,27 @@ static int e100_close(struct net_device *netdev) return 0; } +static const struct net_device_ops e100_netdev_ops = { + .ndo_open = e100_open, + .ndo_stop = e100_close, + .ndo_start_xmit = e100_xmit_frame, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = e100_set_multicast_list, + .ndo_set_mac_address = e100_set_mac_address, + .ndo_change_mtu = e100_change_mtu, + .ndo_do_ioctl = e100_do_ioctl, + .ndo_tx_timeout = e100_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = e100_netpoll, +#endif +}; + static int __devinit e100_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; struct nic *nic; int err; - DECLARE_MAC_BUF(mac); if(!(netdev = alloc_etherdev(sizeof(struct nic)))) { if(((1 << debug) - 1) & NETIF_MSG_PROBE) @@ -2624,19 +2641,9 @@ static int __devinit e100_probe(struct pci_dev *pdev, return -ENOMEM; } - netdev->open = e100_open; - netdev->stop = e100_close; - netdev->hard_start_xmit = e100_xmit_frame; - netdev->set_multicast_list = e100_set_multicast_list; - netdev->set_mac_address = e100_set_mac_address; - netdev->change_mtu = e100_change_mtu; - netdev->do_ioctl = e100_do_ioctl; + netdev->netdev_ops = &e100_netdev_ops; SET_ETHTOOL_OPS(netdev, &e100_ethtool_ops); - netdev->tx_timeout = e100_tx_timeout; netdev->watchdog_timeo = E100_WATCHDOG_PERIOD; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = e100_netpoll; -#endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); nic = netdev_priv(netdev); @@ -2734,8 +2741,10 @@ static int __devinit e100_probe(struct pci_dev *pdev, /* Wol magic packet can be enabled from eeprom */ if((nic->mac >= mac_82558_D101_A4) && - (nic->eeprom[eeprom_id] & eeprom_id_wol)) + (nic->eeprom[eeprom_id] & eeprom_id_wol)) { nic->flags |= wol_magic; + device_set_wakeup_enable(&pdev->dev, true); + } /* ack any pending wake events, disable PME */ pci_pme_active(pdev, false); @@ -2746,9 +2755,9 @@ static int __devinit e100_probe(struct pci_dev *pdev, goto err_out_free; } - DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %s\n", + DPRINTK(PROBE, INFO, "addr 0x%llx, irq %d, MAC addr %pM\n", (unsigned long long)pci_resource_start(pdev, use_io ? 1 : 0), - pdev->irq, print_mac(mac, netdev->dev_addr)); + pdev->irq, netdev->dev_addr); return 0; @@ -2794,11 +2803,10 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state) pci_save_state(pdev); if ((nic->flags & wol_magic) | e100_asf(nic)) { - pci_enable_wake(pdev, PCI_D3hot, 1); - pci_enable_wake(pdev, PCI_D3cold, 1); + if (pci_enable_wake(pdev, PCI_D3cold, true)) + pci_enable_wake(pdev, PCI_D3hot, true); } else { - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + pci_enable_wake(pdev, PCI_D3hot, false); } pci_disable_device(pdev); @@ -2843,7 +2851,7 @@ static pci_ers_result_t e100_io_error_detected(struct pci_dev *pdev, pci_channel struct nic *nic = netdev_priv(netdev); /* Similar to calling e100_down(), but avoids adapter I/O. */ - netdev->stop(netdev); + e100_close(netdev); /* Detach; put netif into a state similar to hotplug unplug. */ napi_enable(&nic->napi); diff --git a/drivers/net/e1000/e1000.h b/drivers/net/e1000/e1000.h index 62f62970f978a4bc32bdc1c987a236056c9b6b84..f5581de04757701df1c0205980018361459da7a0 100644 --- a/drivers/net/e1000/e1000.h +++ b/drivers/net/e1000/e1000.h @@ -284,7 +284,6 @@ struct e1000_adapter { int cleaned_count); struct e1000_rx_ring *rx_ring; /* One per active queue */ struct napi_struct napi; - struct net_device *polling_netdev; /* One per active queue */ int num_tx_queues; int num_rx_queues; diff --git a/drivers/net/e1000/e1000_main.c b/drivers/net/e1000/e1000_main.c index 872799b746f501a3af4264c13b4674dbb8802382..26474c92193f705a3b66e413fa5773da38ce87f2 100644 --- a/drivers/net/e1000/e1000_main.c +++ b/drivers/net/e1000/e1000_main.c @@ -888,6 +888,26 @@ static int e1000_is_need_ioport(struct pci_dev *pdev) } } +static const struct net_device_ops e1000_netdev_ops = { + .ndo_open = e1000_open, + .ndo_stop = e1000_close, + .ndo_start_xmit = e1000_xmit_frame, + .ndo_get_stats = e1000_get_stats, + .ndo_set_rx_mode = e1000_set_rx_mode, + .ndo_set_mac_address = e1000_set_mac, + .ndo_tx_timeout = e1000_tx_timeout, + .ndo_change_mtu = e1000_change_mtu, + .ndo_do_ioctl = e1000_ioctl, + .ndo_validate_addr = eth_validate_addr, + + .ndo_vlan_rx_register = e1000_vlan_rx_register, + .ndo_vlan_rx_add_vid = e1000_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = e1000_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = e1000_netpoll, +#endif +}; + /** * e1000_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -912,7 +932,6 @@ static int __devinit e1000_probe(struct pci_dev *pdev, u16 eeprom_data = 0; u16 eeprom_apme_mask = E1000_EEPROM_APME; int bars, need_ioport; - DECLARE_MAC_BUF(mac); /* do not allocate ioport bars when not needed */ need_ioport = e1000_is_need_ioport(pdev); @@ -967,8 +986,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, hw->back = adapter; err = -EIO; - hw->hw_addr = ioremap(pci_resource_start(pdev, BAR_0), - pci_resource_len(pdev, BAR_0)); + hw->hw_addr = pci_ioremap_bar(pdev, BAR_0); if (!hw->hw_addr) goto err_ioremap; @@ -983,24 +1001,11 @@ static int __devinit e1000_probe(struct pci_dev *pdev, } } - netdev->open = &e1000_open; - netdev->stop = &e1000_close; - netdev->hard_start_xmit = &e1000_xmit_frame; - netdev->get_stats = &e1000_get_stats; - netdev->set_rx_mode = &e1000_set_rx_mode; - netdev->set_mac_address = &e1000_set_mac; - netdev->change_mtu = &e1000_change_mtu; - netdev->do_ioctl = &e1000_ioctl; + netdev->netdev_ops = &e1000_netdev_ops; e1000_set_ethtool_ops(netdev); - netdev->tx_timeout = &e1000_tx_timeout; netdev->watchdog_timeo = 5 * HZ; netif_napi_add(netdev, &adapter->napi, e1000_clean, 64); - netdev->vlan_rx_register = e1000_vlan_rx_register; - netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = e1000_netpoll; -#endif + strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); adapter->bd_number = cards_found; @@ -1016,9 +1021,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, * because it depends on mac_type */ if ((hw->mac_type == e1000_ich8lan) && (pci_resource_flags(pdev, 1) & IORESOURCE_MEM)) { - hw->flash_address = - ioremap(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1)); + hw->flash_address = pci_ioremap_bar(pdev, 1); if (!hw->flash_address) goto err_flashmap; } @@ -1195,7 +1198,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, (hw->bus_width == e1000_bus_width_pciex_1) ? "Width x1" : "32-bit")); - printk("%s\n", print_mac(mac, netdev->dev_addr)); + printk("%pM\n", netdev->dev_addr); if (hw->bus_type == e1000_bus_type_pci_express) { DPRINTK(PROBE, WARNING, "This device (id %04x:%04x) will no " @@ -1239,12 +1242,8 @@ err_eeprom: if (hw->flash_address) iounmap(hw->flash_address); err_flashmap: - for (i = 0; i < adapter->num_rx_queues; i++) - dev_put(&adapter->polling_netdev[i]); - kfree(adapter->tx_ring); kfree(adapter->rx_ring); - kfree(adapter->polling_netdev); err_sw_init: iounmap(hw->hw_addr); err_ioremap: @@ -1272,7 +1271,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; - int i; cancel_work_sync(&adapter->reset_task); @@ -1282,9 +1280,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev) * would have already happened in close and is redundant. */ e1000_release_hw_control(adapter); - for (i = 0; i < adapter->num_rx_queues; i++) - dev_put(&adapter->polling_netdev[i]); - unregister_netdev(netdev); if (!e1000_check_phy_reset_block(hw)) @@ -1292,7 +1287,6 @@ static void __devexit e1000_remove(struct pci_dev *pdev) kfree(adapter->tx_ring); kfree(adapter->rx_ring); - kfree(adapter->polling_netdev); iounmap(hw->hw_addr); if (hw->flash_address) @@ -1318,7 +1312,6 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; - int i; /* PCI config space info */ @@ -1375,11 +1368,6 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter) return -ENOMEM; } - for (i = 0; i < adapter->num_rx_queues; i++) { - adapter->polling_netdev[i].priv = adapter; - dev_hold(&adapter->polling_netdev[i]); - set_bit(__LINK_STATE_START, &adapter->polling_netdev[i].state); - } spin_lock_init(&adapter->tx_queue_lock); /* Explicitly disable IRQ since the NIC can be in any state. */ @@ -1397,8 +1385,7 @@ static int __devinit e1000_sw_init(struct e1000_adapter *adapter) * @adapter: board private structure to initialize * * We allocate one ring per queue at run-time since we don't know the - * number of queues at compile-time. The polling_netdev array is - * intended for Multiqueue, but should work fine with a single queue. + * number of queues at compile-time. **/ static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter) @@ -1415,15 +1402,6 @@ static int __devinit e1000_alloc_queues(struct e1000_adapter *adapter) return -ENOMEM; } - adapter->polling_netdev = kcalloc(adapter->num_rx_queues, - sizeof(struct net_device), - GFP_KERNEL); - if (!adapter->polling_netdev) { - kfree(adapter->tx_ring); - kfree(adapter->rx_ring); - return -ENOMEM; - } - return E1000_SUCCESS; } @@ -2521,10 +2499,11 @@ static void e1000_watchdog(unsigned long data) &adapter->link_duplex); ctrl = er32(CTRL); - DPRINTK(LINK, INFO, "NIC Link is Up %d Mbps %s, " - "Flow Control: %s\n", - adapter->link_speed, - adapter->link_duplex == FULL_DUPLEX ? + printk(KERN_INFO "e1000: %s NIC Link is Up %d Mbps %s, " + "Flow Control: %s\n", + netdev->name, + adapter->link_speed, + adapter->link_duplex == FULL_DUPLEX ? "Full Duplex" : "Half Duplex", ((ctrl & E1000_CTRL_TFCE) && (ctrl & E1000_CTRL_RFCE)) ? "RX/TX" : ((ctrl & @@ -2600,7 +2579,8 @@ static void e1000_watchdog(unsigned long data) if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; - DPRINTK(LINK, INFO, "NIC Link is Down\n"); + printk(KERN_INFO "e1000: %s NIC Link is Down\n", + netdev->name); netif_carrier_off(netdev); netif_stop_queue(netdev); mod_timer(&adapter->phy_info_timer, round_jiffies(jiffies + 2 * HZ)); @@ -3707,12 +3687,12 @@ static irqreturn_t e1000_intr_msi(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { + if (likely(netif_rx_schedule_prep(&adapter->napi))) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } else e1000_irq_enable(adapter); @@ -3767,12 +3747,12 @@ static irqreturn_t e1000_intr(int irq, void *data) ew32(IMC, ~0); E1000_WRITE_FLUSH(); } - if (likely(netif_rx_schedule_prep(netdev, &adapter->napi))) { + if (likely(netif_rx_schedule_prep(&adapter->napi))) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } else /* this really should not happen! if it does it is basically a * bug, but not a hard error, so enable ints and continue */ @@ -3791,8 +3771,7 @@ static int e1000_clean(struct napi_struct *napi, int budget) struct net_device *poll_dev = adapter->netdev; int tx_cleaned = 0, work_done = 0; - /* Must NOT use netdev_priv macro here. */ - adapter = poll_dev->priv; + adapter = netdev_priv(poll_dev); /* e1000_clean is called per-cpu. This lock protects * tx_ring[0] from being cleaned by multiple cpus @@ -3814,7 +3793,7 @@ static int e1000_clean(struct napi_struct *napi, int budget) if (work_done < budget) { if (likely(adapter->itr_setting & 3)) e1000_set_itr(adapter); - netif_rx_complete(poll_dev, napi); + netif_rx_complete(napi); e1000_irq_enable(adapter); } @@ -4104,8 +4083,6 @@ static bool e1000_clean_rx_irq(struct e1000_adapter *adapter, netif_receive_skb(skb); } - netdev->last_rx = jiffies; - next_desc: rx_desc->status = 0; @@ -4789,7 +4766,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); - struct e1000_adapter *adapter = netdev->priv; + struct e1000_adapter *adapter = netdev_priv(netdev); netif_device_detach(netdev); @@ -4811,7 +4788,7 @@ static pci_ers_result_t e1000_io_error_detected(struct pci_dev *pdev, static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct e1000_adapter *adapter = netdev->priv; + struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; int err; @@ -4845,7 +4822,7 @@ static pci_ers_result_t e1000_io_slot_reset(struct pci_dev *pdev) static void e1000_io_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct e1000_adapter *adapter = netdev->priv; + struct e1000_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; e1000_init_manageability(adapter); diff --git a/drivers/net/e1000e/82571.c b/drivers/net/e1000e/82571.c index b2c910c52df9756717246d21bdf2b115ab475d2c..cf43ee743b3cde3af28e061c61f57a1a1bc3936f 100644 --- a/drivers/net/e1000e/82571.c +++ b/drivers/net/e1000e/82571.c @@ -28,6 +28,7 @@ /* * 82571EB Gigabit Ethernet Controller + * 82571EB Gigabit Ethernet Controller (Copper) * 82571EB Gigabit Ethernet Controller (Fiber) * 82571EB Dual Port Gigabit Mezzanine Adapter * 82571EB Quad Port Gigabit Mezzanine Adapter @@ -331,8 +332,9 @@ static s32 e1000_get_variants_82571(struct e1000_adapter *adapter) case e1000_82573: if (pdev->device == E1000_DEV_ID_82573L) { - e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1, - &eeprom_data); + if (e1000_read_nvm(&adapter->hw, NVM_INIT_3GIO_3, 1, + &eeprom_data) < 0) + break; if (eeprom_data & NVM_WORD1A_ASPM_MASK) adapter->flags &= ~FLAG_HAS_JUMBO_FRAMES; } @@ -973,6 +975,12 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw) ew32(CTRL_EXT, reg); } + if (hw->mac.type == e1000_82571) { + reg = er32(PBA_ECC); + reg |= E1000_PBA_ECC_CORR_EN; + ew32(PBA_ECC, reg); + } + /* PCI-Ex Control Register */ if (hw->mac.type == e1000_82574) { reg = er32(GCR); @@ -1111,8 +1119,8 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw) * set it to full. */ if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) && - hw->fc.type == e1000_fc_default) - hw->fc.type = e1000_fc_full; + hw->fc.requested_mode == e1000_fc_default) + hw->fc.requested_mode = e1000_fc_full; return e1000e_setup_link(hw); } @@ -1387,6 +1395,7 @@ static struct e1000_phy_operations e82_phy_ops_igp = { .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, .set_d3_lplu_state = e1000e_set_d3_lplu_state, .write_phy_reg = e1000e_write_phy_reg_igp, + .cfg_on_link_up = NULL, }; static struct e1000_phy_operations e82_phy_ops_m88 = { @@ -1403,6 +1412,7 @@ static struct e1000_phy_operations e82_phy_ops_m88 = { .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, .set_d3_lplu_state = e1000e_set_d3_lplu_state, .write_phy_reg = e1000e_write_phy_reg_m88, + .cfg_on_link_up = NULL, }; static struct e1000_phy_operations e82_phy_ops_bm = { @@ -1419,6 +1429,7 @@ static struct e1000_phy_operations e82_phy_ops_bm = { .set_d0_lplu_state = e1000_set_d0_lplu_state_82571, .set_d3_lplu_state = e1000e_set_d3_lplu_state, .write_phy_reg = e1000e_write_phy_reg_bm2, + .cfg_on_link_up = NULL, }; static struct e1000_nvm_operations e82571_nvm_ops = { diff --git a/drivers/net/e1000e/defines.h b/drivers/net/e1000e/defines.h index 48f79ecb82a035e424c7ffa855bd9e92595087ba..e6caf29d42522b8302e480bcbdc6115a0f971635 100644 --- a/drivers/net/e1000e/defines.h +++ b/drivers/net/e1000e/defines.h @@ -372,6 +372,13 @@ #define E1000_ICR_TXQ1 0x00800000 /* Tx Queue 1 Interrupt */ #define E1000_ICR_OTHER 0x01000000 /* Other Interrupts */ +/* PBA ECC Register */ +#define E1000_PBA_ECC_COUNTER_MASK 0xFFF00000 /* ECC counter mask */ +#define E1000_PBA_ECC_COUNTER_SHIFT 20 /* ECC counter shift value */ +#define E1000_PBA_ECC_CORR_EN 0x00000001 /* ECC correction enable */ +#define E1000_PBA_ECC_STAT_CLR 0x00000002 /* Clear ECC error counter */ +#define E1000_PBA_ECC_INT_EN 0x00000004 /* Enable ICR bit 5 for ECC */ + /* * This defines the bits that are set in the Interrupt Mask * Set/Read Register. Each bit is documented below: @@ -565,6 +572,7 @@ #define E1000_EECD_FLUPD 0x00080000 /* Update FLASH */ #define E1000_EECD_AUPDEN 0x00100000 /* Enable Autonomous FLASH update */ #define E1000_EECD_SEC1VAL 0x00400000 /* Sector One Valid */ +#define E1000_EECD_SEC1VAL_VALID_MASK (E1000_EECD_AUTO_RD | E1000_EECD_PRES) #define E1000_NVM_RW_REG_DATA 16 /* Offset to data in NVM read/write registers */ #define E1000_NVM_RW_REG_DONE 2 /* Offset to READ/WRITE done bit */ diff --git a/drivers/net/e1000e/e1000.h b/drivers/net/e1000e/e1000.h index c55fd6fdb91c16bcf0fba6049b1ef0d6ea3064ff..37bcb190eef80856c89caa08e3e93df1380b38e7 100644 --- a/drivers/net/e1000e/e1000.h +++ b/drivers/net/e1000e/e1000.h @@ -193,6 +193,7 @@ struct e1000_adapter { u16 mng_vlan_id; u16 link_speed; u16 link_duplex; + u16 eeprom_vers; spinlock_t tx_queue_lock; /* prevent concurrent tail updates */ @@ -388,6 +389,7 @@ extern int e1000e_setup_tx_resources(struct e1000_adapter *adapter); extern void e1000e_free_rx_resources(struct e1000_adapter *adapter); extern void e1000e_free_tx_resources(struct e1000_adapter *adapter); extern void e1000e_update_stats(struct e1000_adapter *adapter); +extern bool e1000_has_link(struct e1000_adapter *adapter); extern void e1000e_set_interrupt_capability(struct e1000_adapter *adapter); extern void e1000e_reset_interrupt_capability(struct e1000_adapter *adapter); diff --git a/drivers/net/e1000e/es2lan.c b/drivers/net/e1000e/es2lan.c index da9c09c248ede89e2a9096d9919fff6bbe6a3860..8964838c686b7fcb83fcd745574fc453cddb246d 100644 --- a/drivers/net/e1000e/es2lan.c +++ b/drivers/net/e1000e/es2lan.c @@ -112,6 +112,11 @@ static void e1000_initialize_hw_bits_80003es2lan(struct e1000_hw *hw); static void e1000_clear_hw_cntrs_80003es2lan(struct e1000_hw *hw); static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw); static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex); +static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw); +static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, + u16 *data); +static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, + u16 data); /** * e1000_init_phy_params_80003es2lan - Init ESB2 PHY func ptrs. @@ -275,8 +280,6 @@ static s32 e1000_acquire_phy_80003es2lan(struct e1000_hw *hw) u16 mask; mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; - mask |= E1000_SWFW_CSR_SM; - return e1000_acquire_swfw_sync_80003es2lan(hw, mask); } @@ -292,7 +295,36 @@ static void e1000_release_phy_80003es2lan(struct e1000_hw *hw) u16 mask; mask = hw->bus.func ? E1000_SWFW_PHY1_SM : E1000_SWFW_PHY0_SM; - mask |= E1000_SWFW_CSR_SM; + e1000_release_swfw_sync_80003es2lan(hw, mask); +} + +/** + * e1000_acquire_mac_csr_80003es2lan - Acquire rights to access Kumeran register + * @hw: pointer to the HW structure + * + * Acquire the semaphore to access the Kumeran interface. + * + **/ +static s32 e1000_acquire_mac_csr_80003es2lan(struct e1000_hw *hw) +{ + u16 mask; + + mask = E1000_SWFW_CSR_SM; + + return e1000_acquire_swfw_sync_80003es2lan(hw, mask); +} + +/** + * e1000_release_mac_csr_80003es2lan - Release rights to access Kumeran Register + * @hw: pointer to the HW structure + * + * Release the semaphore used to access the Kumeran interface + **/ +static void e1000_release_mac_csr_80003es2lan(struct e1000_hw *hw) +{ + u16 mask; + + mask = E1000_SWFW_CSR_SM; e1000_release_swfw_sync_80003es2lan(hw, mask); } @@ -347,7 +379,7 @@ static s32 e1000_acquire_swfw_sync_80003es2lan(struct e1000_hw *hw, u16 mask) u32 swmask = mask; u32 fwmask = mask << 16; s32 i = 0; - s32 timeout = 200; + s32 timeout = 50; while (i < timeout) { if (e1000e_get_hw_semaphore(hw)) @@ -715,13 +747,7 @@ static s32 e1000_get_link_up_info_80003es2lan(struct e1000_hw *hw, u16 *speed, ret_val = e1000e_get_speed_and_duplex_copper(hw, speed, duplex); - if (ret_val) - return ret_val; - if (*speed == SPEED_1000) - ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw); - else - ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, - *duplex); + hw->phy.ops.cfg_on_link_up(hw); } else { ret_val = e1000e_get_speed_and_duplex_fiber_serdes(hw, speed, @@ -763,8 +789,10 @@ static s32 e1000_reset_hw_80003es2lan(struct e1000_hw *hw) ctrl = er32(CTRL); + ret_val = e1000_acquire_phy_80003es2lan(hw); hw_dbg(hw, "Issuing a global reset to MAC\n"); ew32(CTRL, ctrl | E1000_CTRL_RST); + e1000_release_phy_80003es2lan(hw); ret_val = e1000e_get_auto_rd_done(hw); if (ret_val) @@ -907,8 +935,7 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) struct e1000_phy_info *phy = &hw->phy; s32 ret_val; u32 ctrl_ext; - u32 i = 0; - u16 data, data2; + u16 data; ret_val = e1e_rphy(hw, GG82563_PHY_MAC_SPEC_CTRL, &data); if (ret_val) @@ -972,19 +999,20 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) } /* Bypass Rx and Tx FIFO's */ - ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL, + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, + E1000_KMRNCTRLSTA_OFFSET_FIFO_CTRL, E1000_KMRNCTRLSTA_FIFO_CTRL_RX_BYPASS | E1000_KMRNCTRLSTA_FIFO_CTRL_TX_BYPASS); if (ret_val) return ret_val; - ret_val = e1000e_read_kmrn_reg(hw, + ret_val = e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, &data); if (ret_val) return ret_val; data |= E1000_KMRNCTRLSTA_OPMODE_E_IDLE; - ret_val = e1000e_write_kmrn_reg(hw, + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_OFFSET_MAC2PHY_OPMODE, data); if (ret_val) @@ -1019,18 +1047,9 @@ static s32 e1000_copper_link_setup_gg82563_80003es2lan(struct e1000_hw *hw) if (ret_val) return ret_val; - do { - ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, - &data); - if (ret_val) - return ret_val; - - ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, - &data2); - if (ret_val) - return ret_val; - i++; - } while ((data != data2) && (i < GG82563_MAX_KMRN_RETRY)); + ret_val = e1e_rphy(hw, GG82563_PHY_KMRN_MODE_CTRL, &data); + if (ret_val) + return ret_val; data &= ~GG82563_KMCR_PASS_FALSE_CARRIER; ret_val = e1e_wphy(hw, GG82563_PHY_KMRN_MODE_CTRL, data); @@ -1077,23 +1096,27 @@ static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw) * iteration and increase the max iterations when * polling the phy; this fixes erroneous timeouts at 10Mbps. */ - ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 4), 0xFFFF); + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 4), + 0xFFFF); if (ret_val) return ret_val; - ret_val = e1000e_read_kmrn_reg(hw, GG82563_REG(0x34, 9), ®_data); + ret_val = e1000_read_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9), + ®_data); if (ret_val) return ret_val; reg_data |= 0x3F; - ret_val = e1000e_write_kmrn_reg(hw, GG82563_REG(0x34, 9), reg_data); + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, GG82563_REG(0x34, 9), + reg_data); if (ret_val) return ret_val; - ret_val = e1000e_read_kmrn_reg(hw, + ret_val = e1000_read_kmrn_reg_80003es2lan(hw, E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, ®_data); if (ret_val) return ret_val; reg_data |= E1000_KMRNCTRLSTA_INB_CTRL_DIS_PADDING; - ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, + E1000_KMRNCTRLSTA_OFFSET_INB_CTRL, reg_data); if (ret_val) return ret_val; @@ -1107,6 +1130,35 @@ static s32 e1000_setup_copper_link_80003es2lan(struct e1000_hw *hw) return 0; } +/** + * e1000_cfg_on_link_up_80003es2lan - es2 link configuration after link-up + * @hw: pointer to the HW structure + * @duplex: current duplex setting + * + * Configure the KMRN interface by applying last minute quirks for + * 10/100 operation. + **/ +static s32 e1000_cfg_on_link_up_80003es2lan(struct e1000_hw *hw) +{ + s32 ret_val = 0; + u16 speed; + u16 duplex; + + if (hw->phy.media_type == e1000_media_type_copper) { + ret_val = e1000e_get_speed_and_duplex_copper(hw, &speed, + &duplex); + if (ret_val) + return ret_val; + + if (speed == SPEED_1000) + ret_val = e1000_cfg_kmrn_1000_80003es2lan(hw); + else + ret_val = e1000_cfg_kmrn_10_100_80003es2lan(hw, duplex); + } + + return ret_val; +} + /** * e1000_cfg_kmrn_10_100_80003es2lan - Apply "quirks" for 10/100 operation * @hw: pointer to the HW structure @@ -1123,8 +1175,9 @@ static s32 e1000_cfg_kmrn_10_100_80003es2lan(struct e1000_hw *hw, u16 duplex) u16 reg_data, reg_data2; reg_data = E1000_KMRNCTRLSTA_HD_CTRL_10_100_DEFAULT; - ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, - reg_data); + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, + E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, + reg_data); if (ret_val) return ret_val; @@ -1170,8 +1223,9 @@ static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) u32 i = 0; reg_data = E1000_KMRNCTRLSTA_HD_CTRL_1000_DEFAULT; - ret_val = e1000e_write_kmrn_reg(hw, E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, - reg_data); + ret_val = e1000_write_kmrn_reg_80003es2lan(hw, + E1000_KMRNCTRLSTA_OFFSET_HD_CTRL, + reg_data); if (ret_val) return ret_val; @@ -1198,6 +1252,71 @@ static s32 e1000_cfg_kmrn_1000_80003es2lan(struct e1000_hw *hw) return ret_val; } +/** + * e1000_read_kmrn_reg_80003es2lan - Read kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to be read + * @data: pointer to the read data + * + * Acquire semaphore, then read the PHY register at offset + * using the kumeran interface. The information retrieved is stored in data. + * Release the semaphore before exiting. + **/ +static s32 e1000_read_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, + u16 *data) +{ + u32 kmrnctrlsta; + s32 ret_val = 0; + + ret_val = e1000_acquire_mac_csr_80003es2lan(hw); + if (ret_val) + return ret_val; + + kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & + E1000_KMRNCTRLSTA_OFFSET) | E1000_KMRNCTRLSTA_REN; + ew32(KMRNCTRLSTA, kmrnctrlsta); + + udelay(2); + + kmrnctrlsta = er32(KMRNCTRLSTA); + *data = (u16)kmrnctrlsta; + + e1000_release_mac_csr_80003es2lan(hw); + + return ret_val; +} + +/** + * e1000_write_kmrn_reg_80003es2lan - Write kumeran register + * @hw: pointer to the HW structure + * @offset: register offset to write to + * @data: data to write at register offset + * + * Acquire semaphore, then write the data to PHY register + * at the offset using the kumeran interface. Release semaphore + * before exiting. + **/ +static s32 e1000_write_kmrn_reg_80003es2lan(struct e1000_hw *hw, u32 offset, + u16 data) +{ + u32 kmrnctrlsta; + s32 ret_val = 0; + + ret_val = e1000_acquire_mac_csr_80003es2lan(hw); + if (ret_val) + return ret_val; + + kmrnctrlsta = ((offset << E1000_KMRNCTRLSTA_OFFSET_SHIFT) & + E1000_KMRNCTRLSTA_OFFSET) | data; + ew32(KMRNCTRLSTA, kmrnctrlsta); + + udelay(2); + + e1000_release_mac_csr_80003es2lan(hw); + + return ret_val; +} + /** * e1000_clear_hw_cntrs_80003es2lan - Clear device specific hardware counters * @hw: pointer to the HW structure @@ -1276,6 +1395,7 @@ static struct e1000_phy_operations es2_phy_ops = { .set_d0_lplu_state = NULL, .set_d3_lplu_state = e1000e_set_d3_lplu_state, .write_phy_reg = e1000_write_phy_reg_gg82563_80003es2lan, + .cfg_on_link_up = e1000_cfg_on_link_up_80003es2lan, }; static struct e1000_nvm_operations es2_nvm_ops = { diff --git a/drivers/net/e1000e/ethtool.c b/drivers/net/e1000e/ethtool.c index 62421ce9631191f3acfdc82d48030ded4655d551..e48956d924b0faff43c4c2156bc795c8e87b5b8a 100644 --- a/drivers/net/e1000e/ethtool.c +++ b/drivers/net/e1000e/ethtool.c @@ -173,11 +173,8 @@ static int e1000_get_settings(struct net_device *netdev, static u32 e1000_get_link(struct net_device *netdev) { struct e1000_adapter *adapter = netdev_priv(netdev); - struct e1000_hw *hw = &adapter->hw; - u32 status; - - status = er32(STATUS); - return (status & E1000_STATUS_LU) ? 1 : 0; + + return e1000_has_link(adapter); } static int e1000_set_spd_dplx(struct e1000_adapter *adapter, u16 spddplx) @@ -249,7 +246,7 @@ static int e1000_set_settings(struct net_device *netdev, ADVERTISED_Autoneg; ecmd->advertising = hw->phy.autoneg_advertised; if (adapter->fc_autoneg) - hw->fc.original_type = e1000_fc_default; + hw->fc.requested_mode = e1000_fc_default; } else { if (e1000_set_spd_dplx(adapter, ecmd->speed + ecmd->duplex)) { clear_bit(__E1000_RESETTING, &adapter->state); @@ -279,11 +276,11 @@ static void e1000_get_pauseparam(struct net_device *netdev, pause->autoneg = (adapter->fc_autoneg ? AUTONEG_ENABLE : AUTONEG_DISABLE); - if (hw->fc.type == e1000_fc_rx_pause) { + if (hw->fc.current_mode == e1000_fc_rx_pause) { pause->rx_pause = 1; - } else if (hw->fc.type == e1000_fc_tx_pause) { + } else if (hw->fc.current_mode == e1000_fc_tx_pause) { pause->tx_pause = 1; - } else if (hw->fc.type == e1000_fc_full) { + } else if (hw->fc.current_mode == e1000_fc_full) { pause->rx_pause = 1; pause->tx_pause = 1; } @@ -301,19 +298,8 @@ static int e1000_set_pauseparam(struct net_device *netdev, while (test_and_set_bit(__E1000_RESETTING, &adapter->state)) msleep(1); - if (pause->rx_pause && pause->tx_pause) - hw->fc.type = e1000_fc_full; - else if (pause->rx_pause && !pause->tx_pause) - hw->fc.type = e1000_fc_rx_pause; - else if (!pause->rx_pause && pause->tx_pause) - hw->fc.type = e1000_fc_tx_pause; - else if (!pause->rx_pause && !pause->tx_pause) - hw->fc.type = e1000_fc_none; - - hw->fc.original_type = hw->fc.type; - if (adapter->fc_autoneg == AUTONEG_ENABLE) { - hw->fc.type = e1000_fc_default; + hw->fc.requested_mode = e1000_fc_default; if (netif_running(adapter->netdev)) { e1000e_down(adapter); e1000e_up(adapter); @@ -321,6 +307,17 @@ static int e1000_set_pauseparam(struct net_device *netdev, e1000e_reset(adapter); } } else { + if (pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = e1000_fc_full; + else if (pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = e1000_fc_rx_pause; + else if (!pause->rx_pause && pause->tx_pause) + hw->fc.requested_mode = e1000_fc_tx_pause; + else if (!pause->rx_pause && !pause->tx_pause) + hw->fc.requested_mode = e1000_fc_none; + + hw->fc.current_mode = hw->fc.requested_mode; + retval = ((hw->phy.media_type == e1000_media_type_fiber) ? hw->mac.ops.setup_link(hw) : e1000e_force_mac_fc(hw)); } @@ -495,18 +492,19 @@ static int e1000_get_eeprom(struct net_device *netdev, for (i = 0; i < last_word - first_word + 1; i++) { ret_val = e1000_read_nvm(hw, first_word + i, 1, &eeprom_buff[i]); - if (ret_val) { - /* a read error occurred, throw away the - * result */ - memset(eeprom_buff, 0xff, sizeof(eeprom_buff)); + if (ret_val) break; - } } } - /* Device's eeprom is always little-endian, word addressable */ - for (i = 0; i < last_word - first_word + 1; i++) - le16_to_cpus(&eeprom_buff[i]); + if (ret_val) { + /* a read error occurred, throw away the result */ + memset(eeprom_buff, 0xff, sizeof(eeprom_buff)); + } else { + /* Device's eeprom is always little-endian, word addressable */ + for (i = 0; i < last_word - first_word + 1; i++) + le16_to_cpus(&eeprom_buff[i]); + } memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 1), eeprom->len); kfree(eeprom_buff); @@ -558,6 +556,9 @@ static int e1000_set_eeprom(struct net_device *netdev, ret_val = e1000_read_nvm(hw, last_word, 1, &eeprom_buff[last_word - first_word]); + if (ret_val) + goto out; + /* Device's eeprom is always little-endian, word addressable */ for (i = 0; i < last_word - first_word + 1; i++) le16_to_cpus(&eeprom_buff[i]); @@ -570,15 +571,18 @@ static int e1000_set_eeprom(struct net_device *netdev, ret_val = e1000_write_nvm(hw, first_word, last_word - first_word + 1, eeprom_buff); + if (ret_val) + goto out; + /* * Update the checksum over the first part of the EEPROM if needed - * and flush shadow RAM for 82573 controllers + * and flush shadow RAM for applicable controllers */ - if ((ret_val == 0) && ((first_word <= NVM_CHECKSUM_REG) || - (hw->mac.type == e1000_82574) || - (hw->mac.type == e1000_82573))) - e1000e_update_nvm_checksum(hw); + if ((first_word <= NVM_CHECKSUM_REG) || + (hw->mac.type == e1000_82574) || (hw->mac.type == e1000_82573)) + ret_val = e1000e_update_nvm_checksum(hw); +out: kfree(eeprom_buff); return ret_val; } @@ -588,7 +592,6 @@ static void e1000_get_drvinfo(struct net_device *netdev, { struct e1000_adapter *adapter = netdev_priv(netdev); char firmware_version[32]; - u16 eeprom_data; strncpy(drvinfo->driver, e1000e_driver_name, 32); strncpy(drvinfo->version, e1000e_driver_version, 32); @@ -597,11 +600,10 @@ static void e1000_get_drvinfo(struct net_device *netdev, * EEPROM image version # is reported as firmware version # for * PCI-E controllers */ - e1000_read_nvm(&adapter->hw, 5, 1, &eeprom_data); sprintf(firmware_version, "%d.%d-%d", - (eeprom_data & 0xF000) >> 12, - (eeprom_data & 0x0FF0) >> 4, - eeprom_data & 0x000F); + (adapter->eeprom_vers & 0xF000) >> 12, + (adapter->eeprom_vers & 0x0FF0) >> 4, + (adapter->eeprom_vers & 0x000F)); strncpy(drvinfo->fw_version, firmware_version, 32); strncpy(drvinfo->bus_info, pci_name(adapter->pdev), 32); @@ -865,7 +867,7 @@ static int e1000_eeprom_test(struct e1000_adapter *adapter, u64 *data) for (i = 0; i < (NVM_CHECKSUM_REG + 1); i++) { if ((e1000_read_nvm(&adapter->hw, i, 1, &temp)) < 0) { *data = 1; - break; + return *data; } checksum += temp; } diff --git a/drivers/net/e1000e/hw.h b/drivers/net/e1000e/hw.h index f66ed37a7f766484e59a91bab9b3565fa34f7555..f25e961c6b3bc37bfbc4ac60b39d41274945bd39 100644 --- a/drivers/net/e1000e/hw.h +++ b/drivers/net/e1000e/hw.h @@ -87,6 +87,7 @@ enum e1e_registers { E1000_EEMNGCTL = 0x01010, /* MNG EEprom Control */ E1000_EEWR = 0x0102C, /* EEPROM Write Register - RW */ E1000_FLOP = 0x0103C, /* FLASH Opcode Register */ + E1000_PBA_ECC = 0x01100, /* PBA ECC Register */ E1000_ERT = 0x02008, /* Early Rx Threshold - RW */ E1000_FCRTL = 0x02160, /* Flow Control Receive Threshold Low - RW */ E1000_FCRTH = 0x02168, /* Flow Control Receive Threshold High - RW */ @@ -436,7 +437,7 @@ enum e1000_rev_polarity{ e1000_rev_polarity_undefined = 0xFF }; -enum e1000_fc_type { +enum e1000_fc_mode { e1000_fc_none = 0, e1000_fc_rx_pause, e1000_fc_tx_pause, @@ -738,6 +739,7 @@ struct e1000_phy_operations { s32 (*set_d0_lplu_state)(struct e1000_hw *, bool); s32 (*set_d3_lplu_state)(struct e1000_hw *, bool); s32 (*write_phy_reg)(struct e1000_hw *, u32, u16); + s32 (*cfg_on_link_up)(struct e1000_hw *); }; /* Function pointers for the NVM. */ @@ -848,8 +850,8 @@ struct e1000_fc_info { u16 pause_time; /* Flow control pause timer */ bool send_xon; /* Flow control send XON */ bool strict_ieee; /* Strict IEEE mode */ - enum e1000_fc_type type; /* Type of flow control */ - enum e1000_fc_type original_type; + enum e1000_fc_mode current_mode; /* FC mode in effect */ + enum e1000_fc_mode requested_mode; /* FC mode requested by caller */ }; struct e1000_dev_spec_82571 { diff --git a/drivers/net/e1000e/ich8lan.c b/drivers/net/e1000e/ich8lan.c index d115a6d30f29c0b3acb81c8038c6215993980e8d..f2a5963b5a9562f153391c4f2b8b364742736d1b 100644 --- a/drivers/net/e1000e/ich8lan.c +++ b/drivers/net/e1000e/ich8lan.c @@ -27,6 +27,7 @@ *******************************************************************************/ /* + * 82562G 10/100 Network Connection * 82562G-2 10/100 Network Connection * 82562GT 10/100 Network Connection * 82562GT-2 10/100 Network Connection @@ -40,6 +41,7 @@ * 82566MM Gigabit Network Connection * 82567LM Gigabit Network Connection * 82567LF Gigabit Network Connection + * 82567V Gigabit Network Connection * 82567LM-2 Gigabit Network Connection * 82567LF-2 Gigabit Network Connection * 82567V-2 Gigabit Network Connection @@ -92,6 +94,8 @@ #define E1000_ICH_NVM_SIG_WORD 0x13 #define E1000_ICH_NVM_SIG_MASK 0xC000 +#define E1000_ICH_NVM_VALID_SIG_MASK 0xC0 +#define E1000_ICH_NVM_SIG_VALUE 0x80 #define E1000_ICH8_LAN_INIT_TIMEOUT 1500 @@ -956,45 +960,62 @@ static s32 e1000_set_d3_lplu_state_ich8lan(struct e1000_hw *hw, bool active) * @bank: pointer to the variable that returns the active bank * * Reads signature byte from the NVM using the flash access registers. + * Word 0x13 bits 15:14 = 10b indicate a valid signature for that bank. **/ static s32 e1000_valid_nvm_bank_detect_ich8lan(struct e1000_hw *hw, u32 *bank) { + u32 eecd; struct e1000_nvm_info *nvm = &hw->nvm; - /* flash bank size is in words */ u32 bank1_offset = nvm->flash_bank_size * sizeof(u16); u32 act_offset = E1000_ICH_NVM_SIG_WORD * 2 + 1; - u8 bank_high_byte = 0; + u8 sig_byte = 0; + s32 ret_val = 0; - if (hw->mac.type != e1000_ich10lan) { - if (er32(EECD) & E1000_EECD_SEC1VAL) - *bank = 1; - else - *bank = 0; - } else { - /* - * Make sure the signature for bank 0 is valid, - * if not check for bank1 - */ - e1000_read_flash_byte_ich8lan(hw, act_offset, &bank_high_byte); - if ((bank_high_byte & 0xC0) == 0x80) { + switch (hw->mac.type) { + case e1000_ich8lan: + case e1000_ich9lan: + eecd = er32(EECD); + if ((eecd & E1000_EECD_SEC1VAL_VALID_MASK) == + E1000_EECD_SEC1VAL_VALID_MASK) { + if (eecd & E1000_EECD_SEC1VAL) + *bank = 1; + else + *bank = 0; + + return 0; + } + hw_dbg(hw, "Unable to determine valid NVM bank via EEC - " + "reading flash signature\n"); + /* fall-thru */ + default: + /* set bank to 0 in case flash read fails */ + *bank = 0; + + /* Check bank 0 */ + ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset, + &sig_byte); + if (ret_val) + return ret_val; + if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == + E1000_ICH_NVM_SIG_VALUE) { *bank = 0; - } else { - /* - * find if segment 1 is valid by verifying - * bit 15:14 = 10b in word 0x13 - */ - e1000_read_flash_byte_ich8lan(hw, - act_offset + bank1_offset, - &bank_high_byte); + return 0; + } - /* bank1 has a valid signature equivalent to SEC1V */ - if ((bank_high_byte & 0xC0) == 0x80) { - *bank = 1; - } else { - hw_dbg(hw, "ERROR: EEPROM not present\n"); - return -E1000_ERR_NVM; - } + /* Check bank 1 */ + ret_val = e1000_read_flash_byte_ich8lan(hw, act_offset + + bank1_offset, + &sig_byte); + if (ret_val) + return ret_val; + if ((sig_byte & E1000_ICH_NVM_VALID_SIG_MASK) == + E1000_ICH_NVM_SIG_VALUE) { + *bank = 1; + return 0; } + + hw_dbg(hw, "ERROR: No valid NVM bank present\n"); + return -E1000_ERR_NVM; } return 0; @@ -1027,11 +1048,11 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, ret_val = e1000_acquire_swflag_ich8lan(hw); if (ret_val) - return ret_val; + goto out; ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); if (ret_val) - return ret_val; + goto release; act_offset = (bank) ? nvm->flash_bank_size : 0; act_offset += offset; @@ -1050,8 +1071,13 @@ static s32 e1000_read_nvm_ich8lan(struct e1000_hw *hw, u16 offset, u16 words, } } +release: e1000_release_swflag_ich8lan(hw); +out: + if (ret_val) + hw_dbg(hw, "NVM read error: %d\n", ret_val); + return ret_val; } @@ -1340,14 +1366,14 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ret_val = e1000e_update_nvm_checksum_generic(hw); if (ret_val) - return ret_val; + goto out; if (nvm->type != e1000_nvm_flash_sw) - return ret_val; + goto out; ret_val = e1000_acquire_swflag_ich8lan(hw); if (ret_val) - return ret_val; + goto out; /* * We're writing to the opposite bank so if we're on bank 1, @@ -1355,17 +1381,27 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) * is going to be written */ ret_val = e1000_valid_nvm_bank_detect_ich8lan(hw, &bank); - if (ret_val) - return ret_val; + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + goto out; + } if (bank == 0) { new_bank_offset = nvm->flash_bank_size; old_bank_offset = 0; - e1000_erase_flash_bank_ich8lan(hw, 1); + ret_val = e1000_erase_flash_bank_ich8lan(hw, 1); + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + goto out; + } } else { old_bank_offset = nvm->flash_bank_size; new_bank_offset = 0; - e1000_erase_flash_bank_ich8lan(hw, 0); + ret_val = e1000_erase_flash_bank_ich8lan(hw, 0); + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + goto out; + } } for (i = 0; i < E1000_ICH8_SHADOW_RAM_WORDS; i++) { @@ -1377,9 +1413,11 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) if (dev_spec->shadow_ram[i].modified) { data = dev_spec->shadow_ram[i].value; } else { - e1000_read_flash_word_ich8lan(hw, - i + old_bank_offset, - &data); + ret_val = e1000_read_flash_word_ich8lan(hw, i + + old_bank_offset, + &data); + if (ret_val) + break; } /* @@ -1420,7 +1458,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) /* Possibly read-only, see e1000e_write_protect_nvm_ich8lan() */ hw_dbg(hw, "Flash commit failed.\n"); e1000_release_swflag_ich8lan(hw); - return ret_val; + goto out; } /* @@ -1430,14 +1468,18 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) * and we need to change bit 14 to 0b */ act_offset = new_bank_offset + E1000_ICH_NVM_SIG_WORD; - e1000_read_flash_word_ich8lan(hw, act_offset, &data); + ret_val = e1000_read_flash_word_ich8lan(hw, act_offset, &data); + if (ret_val) { + e1000_release_swflag_ich8lan(hw); + goto out; + } data &= 0xBFFF; ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset * 2 + 1, (u8)(data >> 8)); if (ret_val) { e1000_release_swflag_ich8lan(hw); - return ret_val; + goto out; } /* @@ -1450,7 +1492,7 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) ret_val = e1000_retry_write_flash_byte_ich8lan(hw, act_offset, 0); if (ret_val) { e1000_release_swflag_ich8lan(hw); - return ret_val; + goto out; } /* Great! Everything worked, we can now clear the cached entries. */ @@ -1468,6 +1510,10 @@ static s32 e1000_update_nvm_checksum_ich8lan(struct e1000_hw *hw) e1000e_reload_nvm(hw); msleep(10); +out: + if (ret_val) + hw_dbg(hw, "NVM update error: %d\n", ret_val); + return ret_val; } @@ -1894,7 +1940,7 @@ static s32 e1000_reset_hw_ich8lan(struct e1000_hw *hw) } ret_val = e1000_acquire_swflag_ich8lan(hw); /* Whether or not the swflag was acquired, we need to reset the part */ - hw_dbg(hw, "Issuing a global reset to ich8lan"); + hw_dbg(hw, "Issuing a global reset to ich8lan\n"); ew32(CTRL, (ctrl | E1000_CTRL_RST)); msleep(20); @@ -2074,12 +2120,17 @@ static s32 e1000_setup_link_ich8lan(struct e1000_hw *hw) * the default flow control setting, so we explicitly * set it to full. */ - if (hw->fc.type == e1000_fc_default) - hw->fc.type = e1000_fc_full; + if (hw->fc.requested_mode == e1000_fc_default) + hw->fc.requested_mode = e1000_fc_full; - hw->fc.original_type = hw->fc.type; + /* + * Save off the requested flow control mode for use later. Depending + * on the link partner's capabilities, we may or may not use this mode. + */ + hw->fc.current_mode = hw->fc.requested_mode; - hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type); + hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", + hw->fc.current_mode); /* Continue to configure the copper link. */ ret_val = e1000_setup_copper_link_ich8lan(hw); diff --git a/drivers/net/e1000e/lib.c b/drivers/net/e1000e/lib.c index 089578f6855a21500188034b6f4fd09809658dfc..66741104ffd1b3e6c02ab4af574e915540591f58 100644 --- a/drivers/net/e1000e/lib.c +++ b/drivers/net/e1000e/lib.c @@ -575,20 +575,42 @@ s32 e1000e_check_for_serdes_link(struct e1000_hw *hw) */ /* SYNCH bit and IV bit are sticky. */ udelay(10); - if (E1000_RXCW_SYNCH & er32(RXCW)) { + rxcw = er32(RXCW); + if (rxcw & E1000_RXCW_SYNCH) { if (!(rxcw & E1000_RXCW_IV)) { - mac->serdes_has_link = 1; - hw_dbg(hw, "SERDES: Link is up.\n"); + mac->serdes_has_link = true; + hw_dbg(hw, "SERDES: Link up - forced.\n"); } } else { - mac->serdes_has_link = 0; - hw_dbg(hw, "SERDES: Link is down.\n"); + mac->serdes_has_link = false; + hw_dbg(hw, "SERDES: Link down - force failed.\n"); } } if (E1000_TXCW_ANE & er32(TXCW)) { status = er32(STATUS); - mac->serdes_has_link = (status & E1000_STATUS_LU); + if (status & E1000_STATUS_LU) { + /* SYNCH bit and IV bit are sticky, so reread rxcw. */ + udelay(10); + rxcw = er32(RXCW); + if (rxcw & E1000_RXCW_SYNCH) { + if (!(rxcw & E1000_RXCW_IV)) { + mac->serdes_has_link = true; + hw_dbg(hw, "SERDES: Link up - autoneg " + "completed sucessfully.\n"); + } else { + mac->serdes_has_link = false; + hw_dbg(hw, "SERDES: Link down - invalid" + "codewords detected in autoneg.\n"); + } + } else { + mac->serdes_has_link = false; + hw_dbg(hw, "SERDES: Link down - no sync.\n"); + } + } else { + mac->serdes_has_link = false; + hw_dbg(hw, "SERDES: Link down - autoneg failed\n"); + } } return 0; @@ -623,12 +645,12 @@ static s32 e1000_set_default_fc_generic(struct e1000_hw *hw) } if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == 0) - hw->fc.type = e1000_fc_none; + hw->fc.requested_mode = e1000_fc_none; else if ((nvm_data & NVM_WORD0F_PAUSE_MASK) == NVM_WORD0F_ASM_DIR) - hw->fc.type = e1000_fc_tx_pause; + hw->fc.requested_mode = e1000_fc_tx_pause; else - hw->fc.type = e1000_fc_full; + hw->fc.requested_mode = e1000_fc_full; return 0; } @@ -656,23 +678,23 @@ s32 e1000e_setup_link(struct e1000_hw *hw) return 0; /* - * If flow control is set to default, set flow control based on - * the EEPROM flow control settings. + * If requested flow control is set to default, set flow control + * based on the EEPROM flow control settings. */ - if (hw->fc.type == e1000_fc_default) { + if (hw->fc.requested_mode == e1000_fc_default) { ret_val = e1000_set_default_fc_generic(hw); if (ret_val) return ret_val; } /* - * We want to save off the original Flow Control configuration just - * in case we get disconnected and then reconnected into a different - * hub or switch with different Flow Control capabilities. + * Save off the requested flow control mode for use later. Depending + * on the link partner's capabilities, we may or may not use this mode. */ - hw->fc.original_type = hw->fc.type; + hw->fc.current_mode = hw->fc.requested_mode; - hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", hw->fc.type); + hw_dbg(hw, "After fix-ups FlowControl is now = %x\n", + hw->fc.current_mode); /* Call the necessary media_type subroutine to configure the link. */ ret_val = mac->ops.setup_physical_interface(hw); @@ -724,7 +746,7 @@ static s32 e1000_commit_fc_settings_generic(struct e1000_hw *hw) * do not support receiving pause frames). * 3: Both Rx and Tx flow control (symmetric) are enabled. */ - switch (hw->fc.type) { + switch (hw->fc.current_mode) { case e1000_fc_none: /* Flow control completely disabled by a software over-ride. */ txcw = (E1000_TXCW_ANE | E1000_TXCW_FD); @@ -906,7 +928,7 @@ s32 e1000e_set_fc_watermarks(struct e1000_hw *hw) * ability to transmit pause frames is not enabled, then these * registers will be set to 0. */ - if (hw->fc.type & e1000_fc_tx_pause) { + if (hw->fc.current_mode & e1000_fc_tx_pause) { /* * We need to set up the Receive Threshold high and low water * marks as well as (optionally) enabling the transmission of @@ -945,7 +967,7 @@ s32 e1000e_force_mac_fc(struct e1000_hw *hw) * receive flow control. * * The "Case" statement below enables/disable flow control - * according to the "hw->fc.type" parameter. + * according to the "hw->fc.current_mode" parameter. * * The possible values of the "fc" parameter are: * 0: Flow control is completely disabled @@ -956,9 +978,9 @@ s32 e1000e_force_mac_fc(struct e1000_hw *hw) * 3: Both Rx and Tx flow control (symmetric) is enabled. * other: No other values should be possible at this point. */ - hw_dbg(hw, "hw->fc.type = %u\n", hw->fc.type); + hw_dbg(hw, "hw->fc.current_mode = %u\n", hw->fc.current_mode); - switch (hw->fc.type) { + switch (hw->fc.current_mode) { case e1000_fc_none: ctrl &= (~(E1000_CTRL_TFCE | E1000_CTRL_RFCE)); break; @@ -1102,11 +1124,11 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) * ONLY. Hence, we must now check to see if we need to * turn OFF the TRANSMISSION of PAUSE frames. */ - if (hw->fc.original_type == e1000_fc_full) { - hw->fc.type = e1000_fc_full; + if (hw->fc.requested_mode == e1000_fc_full) { + hw->fc.current_mode = e1000_fc_full; hw_dbg(hw, "Flow Control = FULL.\r\n"); } else { - hw->fc.type = e1000_fc_rx_pause; + hw->fc.current_mode = e1000_fc_rx_pause; hw_dbg(hw, "Flow Control = " "RX PAUSE frames only.\r\n"); } @@ -1124,7 +1146,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && (mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.type = e1000_fc_tx_pause; + hw->fc.current_mode = e1000_fc_tx_pause; hw_dbg(hw, "Flow Control = Tx PAUSE frames only.\r\n"); } /* @@ -1140,14 +1162,14 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) (mii_nway_adv_reg & NWAY_AR_ASM_DIR) && !(mii_nway_lp_ability_reg & NWAY_LPAR_PAUSE) && (mii_nway_lp_ability_reg & NWAY_LPAR_ASM_DIR)) { - hw->fc.type = e1000_fc_rx_pause; + hw->fc.current_mode = e1000_fc_rx_pause; hw_dbg(hw, "Flow Control = Rx PAUSE frames only.\r\n"); } else { /* * Per the IEEE spec, at this point flow control * should be disabled. */ - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; hw_dbg(hw, "Flow Control = NONE.\r\n"); } @@ -1163,7 +1185,7 @@ s32 e1000e_config_fc_after_link_up(struct e1000_hw *hw) } if (duplex == HALF_DUPLEX) - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; /* * Now we call a subroutine to actually force the MAC diff --git a/drivers/net/e1000e/netdev.c b/drivers/net/e1000e/netdev.c index 122539a0e1feb112f2e4f575f347d78349bb8536..d4639facd1bddcb72a200ada597d02fc284529e7 100644 --- a/drivers/net/e1000e/netdev.c +++ b/drivers/net/e1000e/netdev.c @@ -102,9 +102,7 @@ static void e1000_receive_skb(struct e1000_adapter *adapter, vlan_hwaccel_receive_skb(skb, adapter->vlgrp, le16_to_cpu(vlan)); else - netif_receive_skb(skb); - - netdev->last_rx = jiffies; + napi_gro_receive(&adapter->napi, skb); } /** @@ -1181,12 +1179,12 @@ static irqreturn_t e1000_intr_msi(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + if (netif_rx_schedule_prep(&adapter->napi)) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } return IRQ_HANDLED; @@ -1248,12 +1246,12 @@ static irqreturn_t e1000_intr(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + if (netif_rx_schedule_prep(&adapter->napi)) { adapter->total_tx_bytes = 0; adapter->total_tx_packets = 0; adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } return IRQ_HANDLED; @@ -1322,10 +1320,10 @@ static irqreturn_t e1000_intr_msix_rx(int irq, void *data) adapter->rx_ring->set_itr = 0; } - if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + if (netif_rx_schedule_prep(&adapter->napi)) { adapter->total_rx_bytes = 0; adapter->total_rx_packets = 0; - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } return IRQ_HANDLED; } @@ -1480,7 +1478,7 @@ static int e1000_request_msix(struct e1000_adapter *adapter) int err = 0, vector = 0; if (strlen(netdev->name) < (IFNAMSIZ - 5)) - sprintf(adapter->rx_ring->name, "%s-rx0", netdev->name); + sprintf(adapter->rx_ring->name, "%s-rx-0", netdev->name); else memcpy(adapter->rx_ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, @@ -1493,7 +1491,7 @@ static int e1000_request_msix(struct e1000_adapter *adapter) vector++; if (strlen(netdev->name) < (IFNAMSIZ - 5)) - sprintf(adapter->tx_ring->name, "%s-tx0", netdev->name); + sprintf(adapter->tx_ring->name, "%s-tx-0", netdev->name); else memcpy(adapter->tx_ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, @@ -2003,8 +2001,7 @@ static int e1000_clean(struct napi_struct *napi, int budget) struct net_device *poll_dev = adapter->netdev; int tx_cleaned = 0, work_done = 0; - /* Must NOT use netdev_priv macro here. */ - adapter = poll_dev->priv; + adapter = netdev_priv(poll_dev); if (adapter->msix_entries && !(adapter->rx_ring->ims_val & adapter->tx_ring->ims_val)) @@ -2031,7 +2028,7 @@ clean_rx: if (work_done < budget) { if (adapter->itr_setting & 3) e1000_set_itr(adapter); - netif_rx_complete(poll_dev, napi); + netif_rx_complete(napi); if (adapter->msix_entries) ew32(IMS, adapter->rx_ring->ims_val); else @@ -2787,7 +2784,7 @@ void e1000e_reset(struct e1000_adapter *adapter) else fc->pause_time = E1000_FC_PAUSE_TIME; fc->send_xon = 1; - fc->type = fc->original_type; + fc->current_mode = fc->requested_mode; /* Allow time for pending master requests to run */ mac->ops.reset_hw(hw); @@ -3410,7 +3407,10 @@ static void e1000_print_link_info(struct e1000_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 ctrl = er32(CTRL); - e_info("Link is Up %d Mbps %s, Flow Control: %s\n", + /* Link status message must follow this format for user tools */ + printk(KERN_INFO "e1000e: %s NIC Link is Up %d Mbps %s, " + "Flow Control: %s\n", + adapter->netdev->name, adapter->link_speed, (adapter->link_duplex == FULL_DUPLEX) ? "Full Duplex" : "Half Duplex", @@ -3420,7 +3420,7 @@ static void e1000_print_link_info(struct e1000_adapter *adapter) ((ctrl & E1000_CTRL_TFCE) ? "TX" : "None" ))); } -static bool e1000_has_link(struct e1000_adapter *adapter) +bool e1000_has_link(struct e1000_adapter *adapter) { struct e1000_hw *hw = &adapter->hw; bool link_active = 0; @@ -3495,6 +3495,7 @@ static void e1000_watchdog_task(struct work_struct *work) struct e1000_adapter, watchdog_task); struct net_device *netdev = adapter->netdev; struct e1000_mac_info *mac = &adapter->hw.mac; + struct e1000_phy_info *phy = &adapter->hw.phy; struct e1000_ring *tx_ring = adapter->tx_ring; struct e1000_hw *hw = &adapter->hw; u32 link, tctl; @@ -3601,6 +3602,13 @@ static void e1000_watchdog_task(struct work_struct *work) tctl |= E1000_TCTL_EN; ew32(TCTL, tctl); + /* + * Perform any post-link-up configuration before + * reporting link up. + */ + if (phy->ops.cfg_on_link_up) + phy->ops.cfg_on_link_up(hw); + netif_carrier_on(netdev); netif_tx_wake_all_queues(netdev); @@ -3612,7 +3620,9 @@ static void e1000_watchdog_task(struct work_struct *work) if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; - e_info("Link is Down\n"); + /* Link status message must follow this format */ + printk(KERN_INFO "e1000e: %s NIC Link is Down\n", + adapter->netdev->name); netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); if (!test_bit(__E1000_DOWN, &adapter->state)) @@ -4464,7 +4474,27 @@ static int e1000_suspend(struct pci_dev *pdev, pm_message_t state) pci_disable_device(pdev); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + /* + * The pci-e switch on some quad port adapters will report a + * correctable error when the MAC transitions from D0 to D3. To + * prevent this we need to mask off the correctable errors on the + * downstream port of the pci-e switch. + */ + if (adapter->flags & FLAG_IS_QUAD_PORT) { + struct pci_dev *us_dev = pdev->bus->self; + int pos = pci_find_capability(us_dev, PCI_CAP_ID_EXP); + u16 devctl; + + pci_read_config_word(us_dev, pos + PCI_EXP_DEVCTL, &devctl); + pci_write_config_word(us_dev, pos + PCI_EXP_DEVCTL, + (devctl & ~PCI_EXP_DEVCTL_CERE)); + + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + pci_write_config_word(us_dev, pos + PCI_EXP_DEVCTL, devctl); + } else { + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + } return 0; } @@ -4669,14 +4699,12 @@ static void e1000_print_device_info(struct e1000_adapter *adapter) u32 pba_num; /* print bus type/speed/width info */ - e_info("(PCI Express:2.5GB/s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n", + e_info("(PCI Express:2.5GB/s:%s) %pM\n", /* bus width */ ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : "Width x1"), /* MAC address */ - netdev->dev_addr[0], netdev->dev_addr[1], - netdev->dev_addr[2], netdev->dev_addr[3], - netdev->dev_addr[4], netdev->dev_addr[5]); + netdev->dev_addr); e_info("Intel(R) PRO/%s Network Connection\n", (hw->phy.type == e1000_phy_ife) ? "10/100" : "1000"); e1000e_read_pba_num(hw, &pba_num); @@ -4694,20 +4722,40 @@ static void e1000_eeprom_checks(struct e1000_adapter *adapter) return; ret_val = e1000_read_nvm(hw, NVM_INIT_CONTROL2_REG, 1, &buf); - if (!(le16_to_cpu(buf) & (1 << 0))) { + if (!ret_val && (!(le16_to_cpu(buf) & (1 << 0)))) { /* Deep Smart Power Down (DSPD) */ dev_warn(&adapter->pdev->dev, "Warning: detected DSPD enabled in EEPROM\n"); } ret_val = e1000_read_nvm(hw, NVM_INIT_3GIO_3, 1, &buf); - if (le16_to_cpu(buf) & (3 << 2)) { + if (!ret_val && (le16_to_cpu(buf) & (3 << 2))) { /* ASPM enable */ dev_warn(&adapter->pdev->dev, "Warning: detected ASPM enabled in EEPROM\n"); } } +static const struct net_device_ops e1000e_netdev_ops = { + .ndo_open = e1000_open, + .ndo_stop = e1000_close, + .ndo_start_xmit = e1000_xmit_frame, + .ndo_get_stats = e1000_get_stats, + .ndo_set_multicast_list = e1000_set_multi, + .ndo_set_mac_address = e1000_set_mac, + .ndo_change_mtu = e1000_change_mtu, + .ndo_do_ioctl = e1000_ioctl, + .ndo_tx_timeout = e1000_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + + .ndo_vlan_rx_register = e1000_vlan_rx_register, + .ndo_vlan_rx_add_vid = e1000_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = e1000_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = e1000_netpoll, +#endif +}; + /** * e1000_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -4766,7 +4814,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev, goto err_pci_reg; pci_set_master(pdev); - pci_save_state(pdev); + /* PCI config space info */ + err = pci_save_state(pdev); + if (err) + goto err_alloc_etherdev; err = -ENOMEM; netdev = alloc_etherdev(sizeof(struct e1000_adapter)); @@ -4806,24 +4857,10 @@ static int __devinit e1000_probe(struct pci_dev *pdev, } /* construct the net_device struct */ - netdev->open = &e1000_open; - netdev->stop = &e1000_close; - netdev->hard_start_xmit = &e1000_xmit_frame; - netdev->get_stats = &e1000_get_stats; - netdev->set_multicast_list = &e1000_set_multi; - netdev->set_mac_address = &e1000_set_mac; - netdev->change_mtu = &e1000_change_mtu; - netdev->do_ioctl = &e1000_ioctl; + netdev->netdev_ops = &e1000e_netdev_ops; e1000e_set_ethtool_ops(netdev); - netdev->tx_timeout = &e1000_tx_timeout; netdev->watchdog_timeo = 5 * HZ; netif_napi_add(netdev, &adapter->napi, e1000_clean, 64); - netdev->vlan_rx_register = e1000_vlan_rx_register; - netdev->vlan_rx_add_vid = e1000_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = e1000_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = e1000_netpoll; -#endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); netdev->mem_start = mmio_start; @@ -4924,10 +4961,7 @@ static int __devinit e1000_probe(struct pci_dev *pdev, memcpy(netdev->perm_addr, adapter->hw.mac.addr, netdev->addr_len); if (!is_valid_ether_addr(netdev->perm_addr)) { - e_err("Invalid MAC Address: %02x:%02x:%02x:%02x:%02x:%02x\n", - netdev->perm_addr[0], netdev->perm_addr[1], - netdev->perm_addr[2], netdev->perm_addr[3], - netdev->perm_addr[4], netdev->perm_addr[5]); + e_err("Invalid MAC Address: %pM\n", netdev->perm_addr); err = -EIO; goto err_eeprom; } @@ -4948,8 +4982,8 @@ static int __devinit e1000_probe(struct pci_dev *pdev, /* Initialize link parameters. User can change them with ethtool */ adapter->hw.mac.autoneg = 1; adapter->fc_autoneg = 1; - adapter->hw.fc.original_type = e1000_fc_default; - adapter->hw.fc.type = e1000_fc_default; + adapter->hw.fc.requested_mode = e1000_fc_default; + adapter->hw.fc.current_mode = e1000_fc_default; adapter->hw.phy.autoneg_advertised = 0x2f; /* ring size defaults */ @@ -4990,6 +5024,9 @@ static int __devinit e1000_probe(struct pci_dev *pdev, adapter->wol = adapter->eeprom_wol; device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol); + /* save off EEPROM version number */ + e1000_read_nvm(&adapter->hw, 5, 1, &adapter->eeprom_vers); + /* reset the hardware with the new settings */ e1000e_reset(adapter); diff --git a/drivers/net/e1000e/phy.c b/drivers/net/e1000e/phy.c index 6cd333ae61d038fa6186794121a16561fe036551..dc4a9cba6a73dcc34f16590153cd2e8a557fd9c6 100644 --- a/drivers/net/e1000e/phy.c +++ b/drivers/net/e1000e/phy.c @@ -744,7 +744,7 @@ static s32 e1000_phy_setup_autoneg(struct e1000_hw *hw) * other: No software override. The flow control configuration * in the EEPROM is used. */ - switch (hw->fc.type) { + switch (hw->fc.current_mode) { case e1000_fc_none: /* * Flow control (Rx & Tx) is completely disabled by a @@ -1030,14 +1030,14 @@ s32 e1000e_phy_force_speed_duplex_m88(struct e1000_hw *hw) e1000e_phy_force_speed_duplex_setup(hw, &phy_data); - /* Reset the phy to commit changes. */ - phy_data |= MII_CR_RESET; - ret_val = e1e_wphy(hw, PHY_CONTROL, phy_data); if (ret_val) return ret_val; - udelay(1); + /* Reset the phy to commit changes. */ + ret_val = e1000e_commit_phy(hw); + if (ret_val) + return ret_val; if (phy->autoneg_wait_to_complete) { hw_dbg(hw, "Waiting for forced speed/duplex link on M88 phy.\n"); @@ -1114,7 +1114,7 @@ void e1000e_phy_force_speed_duplex_setup(struct e1000_hw *hw, u16 *phy_ctrl) u32 ctrl; /* Turn off flow control when forcing speed/duplex */ - hw->fc.type = e1000_fc_none; + hw->fc.current_mode = e1000_fc_none; /* Force speed/duplex on the mac */ ctrl = er32(CTRL); diff --git a/drivers/net/e2100.c b/drivers/net/e2100.c index 6390f51ea6fbdc7e455ed70c6650b29edc53fc8a..20eb05cddb83ab92bcb770a57b1c378b7f0c02bb 100644 --- a/drivers/net/e2100.c +++ b/drivers/net/e2100.c @@ -107,7 +107,7 @@ static void e21_block_output(struct net_device *dev, int count, const unsigned char *buf, int start_page); static void e21_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); - +static int e21_open(struct net_device *dev); static int e21_close(struct net_device *dev); @@ -160,6 +160,21 @@ out: } #endif +static const struct net_device_ops e21_netdev_ops = { + .ndo_open = e21_open, + .ndo_stop = e21_close, + + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init e21_probe1(struct net_device *dev, int ioaddr) { int i, status, retval; @@ -265,11 +280,8 @@ static int __init e21_probe1(struct net_device *dev, int ioaddr) ei_status.block_input = &e21_block_input; ei_status.block_output = &e21_block_output; ei_status.get_8390_hdr = &e21_get_8390_hdr; - dev->open = &e21_open; - dev->stop = &e21_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + + dev->netdev_ops = &e21_netdev_ops; NS8390_init(dev, 0); retval = register_netdev(dev); diff --git a/drivers/net/eepro.c b/drivers/net/eepro.c index 1f11350e16cf24b6a1a25d44ab9f8c41d4481a79..e187c88ae1450329a51da2ba64024dd55da2c3e0 100644 --- a/drivers/net/eepro.c +++ b/drivers/net/eepro.c @@ -605,7 +605,7 @@ out: static void __init printEEPROMInfo(struct net_device *dev) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned short Word; int i,j; @@ -690,7 +690,6 @@ static void __init eepro_print_info (struct net_device *dev) struct eepro_local * lp = netdev_priv(dev); int i; const char * ifmap[] = {"AUI", "10Base2", "10BaseT"}; - DECLARE_MAC_BUF(mac); i = inb(dev->base_addr + ID_REG); printk(KERN_DEBUG " id: %#x ",i); @@ -715,7 +714,7 @@ static void __init eepro_print_info (struct net_device *dev) break; } - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); if (net_debug > 3) printk(KERN_DEBUG ", %dK RCV buffer", @@ -1396,7 +1395,7 @@ set_multicast_list(struct net_device *dev) #define eeprom_delay() { udelay(40); } #define EE_READ_CMD (6 << 6) -int +static int read_eeprom(int ioaddr, int location, struct net_device *dev) { int i; @@ -1581,7 +1580,6 @@ eepro_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } @@ -1676,7 +1674,7 @@ eepro_transmit_interrupt(struct net_device *dev) static int eepro_ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct eepro_local *lp = (struct eepro_local *)dev->priv; + struct eepro_local *lp = netdev_priv(dev); cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | diff --git a/drivers/net/eepro100.c b/drivers/net/eepro100.c deleted file mode 100644 index e3e26c595fa340b8de1a4c28d8152964c9b42d69..0000000000000000000000000000000000000000 --- a/drivers/net/eepro100.c +++ /dev/null @@ -1,2401 +0,0 @@ -/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */ -/* - Written 1996-1999 by Donald Becker. - - The driver also contains updates by different kernel developers - (see incomplete list below). - Current maintainer is Andrey V. Savochkin . - Please use this email address and linux-kernel mailing list for bug reports. - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - This driver is for the Intel EtherExpress Pro100 (Speedo3) design. - It should work with all i82557/558/559 boards. - - Version history: - 1998 Apr - 2000 Feb Andrey V. Savochkin - Serious fixes for multicast filter list setting, TX timeout routine; - RX ring refilling logic; other stuff - 2000 Feb Jeff Garzik - Convert to new PCI driver interface - 2000 Mar 24 Dragan Stancevic - Disabled FC and ER, to avoid lockups when when we get FCP interrupts. - 2000 Jul 17 Goutham Rao - PCI DMA API fixes, adding pci_dma_sync_single calls where neccesary - 2000 Aug 31 David Mosberger - rx_align support: enables rx DMA without causing unaligned accesses. -*/ - -static const char * const version = -"eepro100.c:v1.09j-t 9/29/99 Donald Becker\n" -"eepro100.c: $Revision: 1.36 $ 2000/11/17 Modified by Andrey V. Savochkin and others\n"; - -/* A few user-configurable values that apply to all boards. - First set is undocumented and spelled per Intel recommendations. */ - -static int congenb /* = 0 */; /* Enable congestion control in the DP83840. */ -static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */ -static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */ -/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */ -static int txdmacount = 128; -static int rxdmacount /* = 0 */; - -#if defined(__ia64__) || defined(__alpha__) || defined(__sparc__) || defined(__mips__) || \ - defined(__arm__) - /* align rx buffers to 2 bytes so that IP header is aligned */ -# define rx_align(skb) skb_reserve((skb), 2) -# define RxFD_ALIGNMENT __attribute__ ((aligned (2), packed)) -#else -# define rx_align(skb) -# define RxFD_ALIGNMENT -#endif - -/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method. - Lower values use more memory, but are faster. */ -static int rx_copybreak = 200; - -/* Maximum events (Rx packets, etc.) to handle at each interrupt. */ -static int max_interrupt_work = 20; - -/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */ -static int multicast_filter_limit = 64; - -/* 'options' is used to pass a transceiver override or full-duplex flag - e.g. "options=16" for FD, "options=32" for 100mbps-only. */ -static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1}; -static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1}; - -/* A few values that may be tweaked. */ -/* The ring sizes should be a power of two for efficiency. */ -#define TX_RING_SIZE 64 -#define RX_RING_SIZE 64 -/* How much slots multicast filter setup may take. - Do not descrease without changing set_rx_mode() implementaion. */ -#define TX_MULTICAST_SIZE 2 -#define TX_MULTICAST_RESERV (TX_MULTICAST_SIZE*2) -/* Actual number of TX packets queued, must be - <= TX_RING_SIZE-TX_MULTICAST_RESERV. */ -#define TX_QUEUE_LIMIT (TX_RING_SIZE-TX_MULTICAST_RESERV) -/* Hysteresis marking queue as no longer full. */ -#define TX_QUEUE_UNFULL (TX_QUEUE_LIMIT-4) - -/* Operational parameters that usually are not changed. */ - -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (2*HZ) -/* Size of an pre-allocated Rx buffer: + slack.*/ -#define PKT_BUF_SZ 1536 - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -static int use_io; -static int debug = -1; -#define DEBUG_DEFAULT (NETIF_MSG_DRV | \ - NETIF_MSG_HW | \ - NETIF_MSG_RX_ERR | \ - NETIF_MSG_TX_ERR) -#define DEBUG ((debug >= 0) ? (1<"); -MODULE_DESCRIPTION("Intel i82557/i82558/i82559 PCI EtherExpressPro driver"); -MODULE_LICENSE("GPL"); -module_param(use_io, int, 0); -module_param(debug, int, 0); -module_param_array(options, int, NULL, 0); -module_param_array(full_duplex, int, NULL, 0); -module_param(congenb, int, 0); -module_param(txfifo, int, 0); -module_param(rxfifo, int, 0); -module_param(txdmacount, int, 0); -module_param(rxdmacount, int, 0); -module_param(rx_copybreak, int, 0); -module_param(max_interrupt_work, int, 0); -module_param(multicast_filter_limit, int, 0); -MODULE_PARM_DESC(debug, "debug level (0-6)"); -MODULE_PARM_DESC(options, "Bits 0-3: transceiver type, bit 4: full duplex, bit 5: 100Mbps"); -MODULE_PARM_DESC(full_duplex, "full duplex setting(s) (1)"); -MODULE_PARM_DESC(congenb, "Enable congestion control (1)"); -MODULE_PARM_DESC(txfifo, "Tx FIFO threshold in 4 byte units, (0-15)"); -MODULE_PARM_DESC(rxfifo, "Rx FIFO threshold in 4 byte units, (0-15)"); -MODULE_PARM_DESC(txdmacount, "Tx DMA burst length; 128 - disable (0-128)"); -MODULE_PARM_DESC(rxdmacount, "Rx DMA burst length; 128 - disable (0-128)"); -MODULE_PARM_DESC(rx_copybreak, "copy breakpoint for copy-only-tiny-frames"); -MODULE_PARM_DESC(max_interrupt_work, "maximum events handled per interrupt"); -MODULE_PARM_DESC(multicast_filter_limit, "maximum number of filtered multicast addresses"); - -#define RUN_AT(x) (jiffies + (x)) - -#define netdevice_start(dev) -#define netdevice_stop(dev) -#define netif_set_tx_timeout(dev, tf, tm) \ - do { \ - (dev)->tx_timeout = (tf); \ - (dev)->watchdog_timeo = (tm); \ - } while(0) - - - -/* - Theory of Operation - -I. Board Compatibility - -This device driver is designed for the Intel i82557 "Speedo3" chip, Intel's -single-chip fast Ethernet controller for PCI, as used on the Intel -EtherExpress Pro 100 adapter. - -II. Board-specific settings - -PCI bus devices are configured by the system at boot time, so no jumpers -need to be set on the board. The system BIOS should be set to assign the -PCI INTA signal to an otherwise unused system IRQ line. While it's -possible to share PCI interrupt lines, it negatively impacts performance and -only recent kernels support it. - -III. Driver operation - -IIIA. General -The Speedo3 is very similar to other Intel network chips, that is to say -"apparently designed on a different planet". This chips retains the complex -Rx and Tx descriptors and multiple buffers pointers as previous chips, but -also has simplified Tx and Rx buffer modes. This driver uses the "flexible" -Tx mode, but in a simplified lower-overhead manner: it associates only a -single buffer descriptor with each frame descriptor. - -Despite the extra space overhead in each receive skbuff, the driver must use -the simplified Rx buffer mode to assure that only a single data buffer is -associated with each RxFD. The driver implements this by reserving space -for the Rx descriptor at the head of each Rx skbuff. - -The Speedo-3 has receive and command unit base addresses that are added to -almost all descriptor pointers. The driver sets these to zero, so that all -pointer fields are absolute addresses. - -The System Control Block (SCB) of some previous Intel chips exists on the -chip in both PCI I/O and memory space. This driver uses the I/O space -registers, but might switch to memory mapped mode to better support non-x86 -processors. - -IIIB. Transmit structure - -The driver must use the complex Tx command+descriptor mode in order to -have a indirect pointer to the skbuff data section. Each Tx command block -(TxCB) is associated with two immediately appended Tx Buffer Descriptor -(TxBD). A fixed ring of these TxCB+TxBD pairs are kept as part of the -speedo_private data structure for each adapter instance. - -The newer i82558 explicitly supports this structure, and can read the two -TxBDs in the same PCI burst as the TxCB. - -This ring structure is used for all normal transmit packets, but the -transmit packet descriptors aren't long enough for most non-Tx commands such -as CmdConfigure. This is complicated by the possibility that the chip has -already loaded the link address in the previous descriptor. So for these -commands we convert the next free descriptor on the ring to a NoOp, and point -that descriptor's link to the complex command. - -An additional complexity of these non-transmit commands are that they may be -added asynchronous to the normal transmit queue, so we disable interrupts -whenever the Tx descriptor ring is manipulated. - -A notable aspect of these special configure commands is that they do -work with the normal Tx ring entry scavenge method. The Tx ring scavenge -is done at interrupt time using the 'dirty_tx' index, and checking for the -command-complete bit. While the setup frames may have the NoOp command on the -Tx ring marked as complete, but not have completed the setup command, this -is not a problem. The tx_ring entry can be still safely reused, as the -tx_skbuff[] entry is always empty for config_cmd and mc_setup frames. - -Commands may have bits set e.g. CmdSuspend in the command word to either -suspend or stop the transmit/command unit. This driver always flags the last -command with CmdSuspend, erases the CmdSuspend in the previous command, and -then issues a CU_RESUME. -Note: Watch out for the potential race condition here: imagine - erasing the previous suspend - the chip processes the previous command - the chip processes the final command, and suspends - doing the CU_RESUME - the chip processes the next-yet-valid post-final-command. -So blindly sending a CU_RESUME is only safe if we do it immediately after -after erasing the previous CmdSuspend, without the possibility of an -intervening delay. Thus the resume command is always within the -interrupts-disabled region. This is a timing dependence, but handling this -condition in a timing-independent way would considerably complicate the code. - -Note: In previous generation Intel chips, restarting the command unit was a -notoriously slow process. This is presumably no longer true. - -IIIC. Receive structure - -Because of the bus-master support on the Speedo3 this driver uses the new -SKBUFF_RX_COPYBREAK scheme, rather than a fixed intermediate receive buffer. -This scheme allocates full-sized skbuffs as receive buffers. The value -SKBUFF_RX_COPYBREAK is used as the copying breakpoint: it is chosen to -trade-off the memory wasted by passing the full-sized skbuff to the queue -layer for all frames vs. the copying cost of copying a frame to a -correctly-sized skbuff. - -For small frames the copying cost is negligible (esp. considering that we -are pre-loading the cache with immediately useful header information), so we -allocate a new, minimally-sized skbuff. For large frames the copying cost -is non-trivial, and the larger copy might flush the cache of useful data, so -we pass up the skbuff the packet was received into. - -IV. Notes - -Thanks to Steve Williams of Intel for arranging the non-disclosure agreement -that stated that I could disclose the information. But I still resent -having to sign an Intel NDA when I'm helping Intel sell their own product! - -*/ - -static int speedo_found1(struct pci_dev *pdev, void __iomem *ioaddr, int fnd_cnt, int acpi_idle_state); - -/* Offsets to the various registers. - All accesses need not be longword aligned. */ -enum speedo_offsets { - SCBStatus = 0, SCBCmd = 2, /* Rx/Command Unit command and status. */ - SCBIntmask = 3, - SCBPointer = 4, /* General purpose pointer. */ - SCBPort = 8, /* Misc. commands and operands. */ - SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */ - SCBCtrlMDI = 16, /* MDI interface control. */ - SCBEarlyRx = 20, /* Early receive byte count. */ -}; -/* Commands that can be put in a command list entry. */ -enum commands { - CmdNOp = 0, CmdIASetup = 0x10000, CmdConfigure = 0x20000, - CmdMulticastList = 0x30000, CmdTx = 0x40000, CmdTDR = 0x50000, - CmdDump = 0x60000, CmdDiagnose = 0x70000, - CmdSuspend = 0x40000000, /* Suspend after completion. */ - CmdIntr = 0x20000000, /* Interrupt after completion. */ - CmdTxFlex = 0x00080000, /* Use "Flexible mode" for CmdTx command. */ -}; -/* Clear CmdSuspend (1<<30) avoiding interference with the card access to the - status bits. Previous driver versions used separate 16 bit fields for - commands and statuses. --SAW - */ -#if defined(__alpha__) -# define clear_suspend(cmd) clear_bit(30, &(cmd)->cmd_status); -#else -# define clear_suspend(cmd) ((__le16 *)&(cmd)->cmd_status)[1] &= ~cpu_to_le16(1<<14) -#endif - -enum SCBCmdBits { - SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000, - SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400, - SCBTriggerIntr=0x0200, SCBMaskAll=0x0100, - /* The rest are Rx and Tx commands. */ - CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050, - CUCmdBase=0x0060, /* CU Base address (set to zero) . */ - CUDumpStats=0x0070, /* Dump then reset stats counters. */ - RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006, - RxResumeNoResources=0x0007, -}; - -enum SCBPort_cmds { - PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3, -}; - -/* The Speedo3 Rx and Tx frame/buffer descriptors. */ -struct descriptor { /* A generic descriptor. */ - volatile __le32 cmd_status; /* All command and status fields. */ - __le32 link; /* struct descriptor * */ - unsigned char params[0]; -}; - -/* The Speedo3 Rx and Tx buffer descriptors. */ -struct RxFD { /* Receive frame descriptor. */ - volatile __le32 status; - __le32 link; /* struct RxFD * */ - __le32 rx_buf_addr; /* void * */ - __le32 count; -} RxFD_ALIGNMENT; - -/* Selected elements of the Tx/RxFD.status word. */ -enum RxFD_bits { - RxComplete=0x8000, RxOK=0x2000, - RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010, - RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002, - TxUnderrun=0x1000, StatusComplete=0x8000, -}; - -#define CONFIG_DATA_SIZE 22 -struct TxFD { /* Transmit frame descriptor set. */ - __le32 status; - __le32 link; /* void * */ - __le32 tx_desc_addr; /* Always points to the tx_buf_addr element. */ - __le32 count; /* # of TBD (=1), Tx start thresh., etc. */ - /* This constitutes two "TBD" entries -- we only use one. */ -#define TX_DESCR_BUF_OFFSET 16 - __le32 tx_buf_addr0; /* void *, frame to be transmitted. */ - __le32 tx_buf_size0; /* Length of Tx frame. */ - __le32 tx_buf_addr1; /* void *, frame to be transmitted. */ - __le32 tx_buf_size1; /* Length of Tx frame. */ - /* the structure must have space for at least CONFIG_DATA_SIZE starting - * from tx_desc_addr field */ -}; - -/* Multicast filter setting block. --SAW */ -struct speedo_mc_block { - struct speedo_mc_block *next; - unsigned int tx; - dma_addr_t frame_dma; - unsigned int len; - struct descriptor frame __attribute__ ((__aligned__(16))); -}; - -/* Elements of the dump_statistics block. This block must be lword aligned. */ -struct speedo_stats { - __le32 tx_good_frames; - __le32 tx_coll16_errs; - __le32 tx_late_colls; - __le32 tx_underruns; - __le32 tx_lost_carrier; - __le32 tx_deferred; - __le32 tx_one_colls; - __le32 tx_multi_colls; - __le32 tx_total_colls; - __le32 rx_good_frames; - __le32 rx_crc_errs; - __le32 rx_align_errs; - __le32 rx_resource_errs; - __le32 rx_overrun_errs; - __le32 rx_colls_errs; - __le32 rx_runt_errs; - __le32 done_marker; -}; - -enum Rx_ring_state_bits { - RrNoMem=1, RrPostponed=2, RrNoResources=4, RrOOMReported=8, -}; - -/* Do not change the position (alignment) of the first few elements! - The later elements are grouped for cache locality. - - Unfortunately, all the positions have been shifted since there. - A new re-alignment is required. 2000/03/06 SAW */ -struct speedo_private { - void __iomem *regs; - struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */ - struct RxFD *rx_ringp[RX_RING_SIZE]; /* Rx descriptor, used as ring. */ - /* The addresses of a Tx/Rx-in-place packets/buffers. */ - struct sk_buff *tx_skbuff[TX_RING_SIZE]; - struct sk_buff *rx_skbuff[RX_RING_SIZE]; - /* Mapped addresses of the rings. */ - dma_addr_t tx_ring_dma; -#define TX_RING_ELEM_DMA(sp, n) ((sp)->tx_ring_dma + (n)*sizeof(struct TxFD)) - dma_addr_t rx_ring_dma[RX_RING_SIZE]; - struct descriptor *last_cmd; /* Last command sent. */ - unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */ - spinlock_t lock; /* Group with Tx control cache line. */ - u32 tx_threshold; /* The value for txdesc.count. */ - struct RxFD *last_rxf; /* Last filled RX buffer. */ - dma_addr_t last_rxf_dma; - unsigned int cur_rx, dirty_rx; /* The next free ring entry */ - long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */ - struct net_device_stats stats; - struct speedo_stats *lstats; - dma_addr_t lstats_dma; - int chip_id; - struct pci_dev *pdev; - struct timer_list timer; /* Media selection timer. */ - struct speedo_mc_block *mc_setup_head; /* Multicast setup frame list head. */ - struct speedo_mc_block *mc_setup_tail; /* Multicast setup frame list tail. */ - long in_interrupt; /* Word-aligned dev->interrupt */ - unsigned char acpi_pwr; - signed char rx_mode; /* Current PROMISC/ALLMULTI setting. */ - unsigned int tx_full:1; /* The Tx queue is full. */ - unsigned int flow_ctrl:1; /* Use 802.3x flow control. */ - unsigned int rx_bug:1; /* Work around receiver hang errata. */ - unsigned char default_port:8; /* Last dev->if_port value. */ - unsigned char rx_ring_state; /* RX ring status flags. */ - unsigned short phy[2]; /* PHY media interfaces available. */ - unsigned short partner; /* Link partner caps. */ - struct mii_if_info mii_if; /* MII API hooks, info */ - u32 msg_enable; /* debug message level */ -}; - -/* The parameters for a CmdConfigure operation. - There are so many options that it would be difficult to document each bit. - We mostly use the default or recommended settings. */ -static const char i82557_config_cmd[CONFIG_DATA_SIZE] = { - 22, 0x08, 0, 0, 0, 0, 0x32, 0x03, 1, /* 1=Use MII 0=Use AUI */ - 0, 0x2E, 0, 0x60, 0, - 0xf2, 0x48, 0, 0x40, 0xf2, 0x80, /* 0x40=Force full-duplex */ - 0x3f, 0x05, }; -static const char i82558_config_cmd[CONFIG_DATA_SIZE] = { - 22, 0x08, 0, 1, 0, 0, 0x22, 0x03, 1, /* 1=Use MII 0=Use AUI */ - 0, 0x2E, 0, 0x60, 0x08, 0x88, - 0x68, 0, 0x40, 0xf2, 0x84, /* Disable FC */ - 0x31, 0x05, }; - -/* PHY media interface chips. */ -static const char * const phys[] = { - "None", "i82553-A/B", "i82553-C", "i82503", - "DP83840", "80c240", "80c24", "i82555", - "unknown-8", "unknown-9", "DP83840A", "unknown-11", - "unknown-12", "unknown-13", "unknown-14", "unknown-15", }; -enum phy_chips { NonSuchPhy=0, I82553AB, I82553C, I82503, DP83840, S80C240, - S80C24, I82555, DP83840A=10, }; -static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 }; -#define EE_READ_CMD (6) - -static int eepro100_init_one(struct pci_dev *pdev, - const struct pci_device_id *ent); - -static int do_eeprom_cmd(void __iomem *ioaddr, int cmd, int cmd_len); -static int mdio_read(struct net_device *dev, int phy_id, int location); -static void mdio_write(struct net_device *dev, int phy_id, int location, int value); -static int speedo_open(struct net_device *dev); -static void speedo_resume(struct net_device *dev); -static void speedo_timer(unsigned long data); -static void speedo_init_rx_ring(struct net_device *dev); -static void speedo_tx_timeout(struct net_device *dev); -static int speedo_start_xmit(struct sk_buff *skb, struct net_device *dev); -static void speedo_refill_rx_buffers(struct net_device *dev, int force); -static int speedo_rx(struct net_device *dev); -static void speedo_tx_buffer_gc(struct net_device *dev); -static irqreturn_t speedo_interrupt(int irq, void *dev_instance); -static int speedo_close(struct net_device *dev); -static struct net_device_stats *speedo_get_stats(struct net_device *dev); -static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); -static void set_rx_mode(struct net_device *dev); -static void speedo_show_state(struct net_device *dev); -static const struct ethtool_ops ethtool_ops; - - - -#ifdef honor_default_port -/* Optional driver feature to allow forcing the transceiver setting. - Not recommended. */ -static int mii_ctrl[8] = { 0x3300, 0x3100, 0x0000, 0x0100, - 0x2000, 0x2100, 0x0400, 0x3100}; -#endif - -/* How to wait for the command unit to accept a command. - Typically this takes 0 ticks. */ -static inline unsigned char wait_for_cmd_done(struct net_device *dev, - struct speedo_private *sp) -{ - int wait = 1000; - void __iomem *cmd_ioaddr = sp->regs + SCBCmd; - unsigned char r; - - do { - udelay(1); - r = ioread8(cmd_ioaddr); - } while(r && --wait >= 0); - - if (wait < 0) - printk(KERN_ALERT "%s: wait_for_cmd_done timeout!\n", dev->name); - return r; -} - -static int __devinit eepro100_init_one (struct pci_dev *pdev, - const struct pci_device_id *ent) -{ - void __iomem *ioaddr; - int irq, pci_bar; - int acpi_idle_state = 0, pm; - static int cards_found /* = 0 */; - unsigned long pci_base; - -#ifndef MODULE - /* when built-in, we only print version if device is found */ - static int did_version; - if (did_version++ == 0) - printk(version); -#endif - - /* save power state before pci_enable_device overwrites it */ - pm = pci_find_capability(pdev, PCI_CAP_ID_PM); - if (pm) { - u16 pwr_command; - pci_read_config_word(pdev, pm + PCI_PM_CTRL, &pwr_command); - acpi_idle_state = pwr_command & PCI_PM_CTRL_STATE_MASK; - } - - if (pci_enable_device(pdev)) - goto err_out_free_mmio_region; - - pci_set_master(pdev); - - if (!request_region(pci_resource_start(pdev, 1), - pci_resource_len(pdev, 1), "eepro100")) { - dev_err(&pdev->dev, "eepro100: cannot reserve I/O ports\n"); - goto err_out_none; - } - if (!request_mem_region(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0), "eepro100")) { - dev_err(&pdev->dev, "eepro100: cannot reserve MMIO region\n"); - goto err_out_free_pio_region; - } - - irq = pdev->irq; - pci_bar = use_io ? 1 : 0; - pci_base = pci_resource_start(pdev, pci_bar); - if (DEBUG & NETIF_MSG_PROBE) - printk("Found Intel i82557 PCI Speedo at %#lx, IRQ %d.\n", - pci_base, irq); - - ioaddr = pci_iomap(pdev, pci_bar, 0); - if (!ioaddr) { - dev_err(&pdev->dev, "eepro100: cannot remap IO\n"); - goto err_out_free_mmio_region; - } - - if (speedo_found1(pdev, ioaddr, cards_found, acpi_idle_state) == 0) - cards_found++; - else - goto err_out_iounmap; - - return 0; - -err_out_iounmap: ; - pci_iounmap(pdev, ioaddr); -err_out_free_mmio_region: - release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); -err_out_free_pio_region: - release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); -err_out_none: - return -ENODEV; -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -/* - * Polling 'interrupt' - used by things like netconsole to send skbs - * without having to re-enable interrupts. It's not called while - * the interrupt routine is executing. - */ - -static void poll_speedo (struct net_device *dev) -{ - /* disable_irq is not very nice, but with the funny lockless design - we have no other choice. */ - disable_irq(dev->irq); - speedo_interrupt (dev->irq, dev); - enable_irq(dev->irq); -} -#endif - -static int __devinit speedo_found1(struct pci_dev *pdev, - void __iomem *ioaddr, int card_idx, int acpi_idle_state) -{ - struct net_device *dev; - struct speedo_private *sp; - const char *product; - int i, option; - u16 eeprom[0x100]; - int size; - void *tx_ring_space; - dma_addr_t tx_ring_dma; - DECLARE_MAC_BUF(mac); - - size = TX_RING_SIZE * sizeof(struct TxFD) + sizeof(struct speedo_stats); - tx_ring_space = pci_alloc_consistent(pdev, size, &tx_ring_dma); - if (tx_ring_space == NULL) - return -1; - - dev = alloc_etherdev(sizeof(struct speedo_private)); - if (dev == NULL) { - printk(KERN_ERR "eepro100: Could not allocate ethernet device.\n"); - pci_free_consistent(pdev, size, tx_ring_space, tx_ring_dma); - return -1; - } - - SET_NETDEV_DEV(dev, &pdev->dev); - - if (dev->mem_start > 0) - option = dev->mem_start; - else if (card_idx >= 0 && options[card_idx] >= 0) - option = options[card_idx]; - else - option = 0; - - rtnl_lock(); - if (dev_alloc_name(dev, dev->name) < 0) - goto err_free_unlock; - - /* Read the station address EEPROM before doing the reset. - Nominally his should even be done before accepting the device, but - then we wouldn't have a device name with which to report the error. - The size test is for 6 bit vs. 8 bit address serial EEPROMs. - */ - { - void __iomem *iobase; - int read_cmd, ee_size; - u16 sum; - int j; - - /* Use IO only to avoid postponed writes and satisfy EEPROM timing - requirements. */ - iobase = pci_iomap(pdev, 1, pci_resource_len(pdev, 1)); - if (!iobase) - goto err_free_unlock; - if ((do_eeprom_cmd(iobase, EE_READ_CMD << 24, 27) & 0xffe0000) - == 0xffe0000) { - ee_size = 0x100; - read_cmd = EE_READ_CMD << 24; - } else { - ee_size = 0x40; - read_cmd = EE_READ_CMD << 22; - } - - for (j = 0, i = 0, sum = 0; i < ee_size; i++) { - u16 value = do_eeprom_cmd(iobase, read_cmd | (i << 16), 27); - eeprom[i] = value; - sum += value; - if (i < 3) { - dev->dev_addr[j++] = value; - dev->dev_addr[j++] = value >> 8; - } - } - if (sum != 0xBABA) - printk(KERN_WARNING "%s: Invalid EEPROM checksum %#4.4x, " - "check settings before activating this device!\n", - dev->name, sum); - /* Don't unregister_netdev(dev); as the EEPro may actually be - usable, especially if the MAC address is set later. - On the other hand, it may be unusable if MDI data is corrupted. */ - - pci_iounmap(pdev, iobase); - } - - /* Reset the chip: stop Tx and Rx processes and clear counters. - This takes less than 10usec and will easily finish before the next - action. */ - iowrite32(PortReset, ioaddr + SCBPort); - ioread32(ioaddr + SCBPort); - udelay(10); - - if (eeprom[3] & 0x0100) - product = "OEM i82557/i82558 10/100 Ethernet"; - else - product = pci_name(pdev); - - printk(KERN_INFO "%s: %s, %s, IRQ %d.\n", dev->name, product, - print_mac(mac, dev->dev_addr), pdev->irq); - - sp = netdev_priv(dev); - - /* we must initialize this early, for mdio_{read,write} */ - sp->regs = ioaddr; - -#if 1 || defined(kernel_bloat) - /* OK, this is pure kernel bloat. I don't like it when other drivers - waste non-pageable kernel space to emit similar messages, but I need - them for bug reports. */ - { - const char *connectors[] = {" RJ45", " BNC", " AUI", " MII"}; - /* The self-test results must be paragraph aligned. */ - volatile s32 *self_test_results; - int boguscnt = 16000; /* Timeout for set-test. */ - if ((eeprom[3] & 0x03) != 0x03) - printk(KERN_INFO " Receiver lock-up bug exists -- enabling" - " work-around.\n"); - printk(KERN_INFO " Board assembly %4.4x%2.2x-%3.3d, Physical" - " connectors present:", - eeprom[8], eeprom[9]>>8, eeprom[9] & 0xff); - for (i = 0; i < 4; i++) - if (eeprom[5] & (1<>8)&15], eeprom[6] & 0x1f); - if (eeprom[7] & 0x0700) - printk(KERN_INFO " Secondary interface chip %s.\n", - phys[(eeprom[7]>>8)&7]); - if (((eeprom[6]>>8) & 0x3f) == DP83840 - || ((eeprom[6]>>8) & 0x3f) == DP83840A) { - int mdi_reg23 = mdio_read(dev, eeprom[6] & 0x1f, 23) | 0x0422; - if (congenb) - mdi_reg23 |= 0x0100; - printk(KERN_INFO" DP83840 specific setup, setting register 23 to %4.4x.\n", - mdi_reg23); - mdio_write(dev, eeprom[6] & 0x1f, 23, mdi_reg23); - } - if ((option >= 0) && (option & 0x70)) { - printk(KERN_INFO " Forcing %dMbs %s-duplex operation.\n", - (option & 0x20 ? 100 : 10), - (option & 0x10 ? "full" : "half")); - mdio_write(dev, eeprom[6] & 0x1f, MII_BMCR, - ((option & 0x20) ? 0x2000 : 0) | /* 100mbps? */ - ((option & 0x10) ? 0x0100 : 0)); /* Full duplex? */ - } - - /* Perform a system self-test. */ - self_test_results = (s32*) ((((long) tx_ring_space) + 15) & ~0xf); - self_test_results[0] = 0; - self_test_results[1] = -1; - iowrite32(tx_ring_dma | PortSelfTest, ioaddr + SCBPort); - do { - udelay(10); - } while (self_test_results[1] == -1 && --boguscnt >= 0); - - if (boguscnt < 0) { /* Test optimized out. */ - printk(KERN_ERR "Self test failed, status %8.8x:\n" - KERN_ERR " Failure to initialize the i82557.\n" - KERN_ERR " Verify that the card is a bus-master" - " capable slot.\n", - self_test_results[1]); - } else - printk(KERN_INFO " General self-test: %s.\n" - KERN_INFO " Serial sub-system self-test: %s.\n" - KERN_INFO " Internal registers self-test: %s.\n" - KERN_INFO " ROM checksum self-test: %s (%#8.8x).\n", - self_test_results[1] & 0x1000 ? "failed" : "passed", - self_test_results[1] & 0x0020 ? "failed" : "passed", - self_test_results[1] & 0x0008 ? "failed" : "passed", - self_test_results[1] & 0x0004 ? "failed" : "passed", - self_test_results[0]); - } -#endif /* kernel_bloat */ - - iowrite32(PortReset, ioaddr + SCBPort); - ioread32(ioaddr + SCBPort); - udelay(10); - - /* Return the chip to its original power state. */ - pci_set_power_state(pdev, acpi_idle_state); - - pci_set_drvdata (pdev, dev); - SET_NETDEV_DEV(dev, &pdev->dev); - - dev->irq = pdev->irq; - - sp->pdev = pdev; - sp->msg_enable = DEBUG; - sp->acpi_pwr = acpi_idle_state; - sp->tx_ring = tx_ring_space; - sp->tx_ring_dma = tx_ring_dma; - sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE); - sp->lstats_dma = TX_RING_ELEM_DMA(sp, TX_RING_SIZE); - init_timer(&sp->timer); /* used in ioctl() */ - spin_lock_init(&sp->lock); - - sp->mii_if.full_duplex = option >= 0 && (option & 0x10) ? 1 : 0; - if (card_idx >= 0) { - if (full_duplex[card_idx] >= 0) - sp->mii_if.full_duplex = full_duplex[card_idx]; - } - sp->default_port = option >= 0 ? (option & 0x0f) : 0; - - sp->phy[0] = eeprom[6]; - sp->phy[1] = eeprom[7]; - - sp->mii_if.phy_id = eeprom[6] & 0x1f; - sp->mii_if.phy_id_mask = 0x1f; - sp->mii_if.reg_num_mask = 0x1f; - sp->mii_if.dev = dev; - sp->mii_if.mdio_read = mdio_read; - sp->mii_if.mdio_write = mdio_write; - - sp->rx_bug = (eeprom[3] & 0x03) == 3 ? 0 : 1; - if (((pdev->device > 0x1030 && (pdev->device < 0x103F))) - || (pdev->device == 0x2449) || (pdev->device == 0x2459) - || (pdev->device == 0x245D)) { - sp->chip_id = 1; - } - - if (sp->rx_bug) - printk(KERN_INFO " Receiver lock-up workaround activated.\n"); - - /* The Speedo-specific entries in the device structure. */ - dev->open = &speedo_open; - dev->hard_start_xmit = &speedo_start_xmit; - netif_set_tx_timeout(dev, &speedo_tx_timeout, TX_TIMEOUT); - dev->stop = &speedo_close; - dev->get_stats = &speedo_get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &speedo_ioctl; - SET_ETHTOOL_OPS(dev, ðtool_ops); -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = &poll_speedo; -#endif - - if (register_netdevice(dev)) - goto err_free_unlock; - rtnl_unlock(); - - return 0; - - err_free_unlock: - rtnl_unlock(); - free_netdev(dev); - return -1; -} - -static void do_slow_command(struct net_device *dev, struct speedo_private *sp, int cmd) -{ - void __iomem *cmd_ioaddr = sp->regs + SCBCmd; - int wait = 0; - do - if (ioread8(cmd_ioaddr) == 0) break; - while(++wait <= 200); - if (wait > 100) - printk(KERN_ERR "Command %4.4x never accepted (%d polls)!\n", - ioread8(cmd_ioaddr), wait); - - iowrite8(cmd, cmd_ioaddr); - - for (wait = 0; wait <= 100; wait++) - if (ioread8(cmd_ioaddr) == 0) return; - for (; wait <= 20000; wait++) - if (ioread8(cmd_ioaddr) == 0) return; - else udelay(1); - printk(KERN_ERR "Command %4.4x was not accepted after %d polls!" - " Current status %8.8x.\n", - cmd, wait, ioread32(sp->regs + SCBStatus)); -} - -/* Serial EEPROM section. - A "bit" grungy, but we work our way through bit-by-bit :->. */ -/* EEPROM_Ctrl bits. */ -#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */ -#define EE_CS 0x02 /* EEPROM chip select. */ -#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */ -#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ -#define EE_ENB (0x4800 | EE_CS) -#define EE_WRITE_0 0x4802 -#define EE_WRITE_1 0x4806 -#define EE_OFFSET SCBeeprom - -/* The fixes for the code were kindly provided by Dragan Stancevic - to strictly follow Intel specifications of EEPROM - access timing. - The publicly available sheet 64486302 (sec. 3.1) specifies 1us access - interval for serial EEPROM. However, it looks like that there is an - additional requirement dictating larger udelay's in the code below. - 2000/05/24 SAW */ -static int __devinit do_eeprom_cmd(void __iomem *ioaddr, int cmd, int cmd_len) -{ - unsigned retval = 0; - void __iomem *ee_addr = ioaddr + SCBeeprom; - - iowrite16(EE_ENB, ee_addr); udelay(2); - iowrite16(EE_ENB | EE_SHIFT_CLK, ee_addr); udelay(2); - - /* Shift the command bits out. */ - do { - short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0; - iowrite16(dataval, ee_addr); udelay(2); - iowrite16(dataval | EE_SHIFT_CLK, ee_addr); udelay(2); - retval = (retval << 1) | ((ioread16(ee_addr) & EE_DATA_READ) ? 1 : 0); - } while (--cmd_len >= 0); - iowrite16(EE_ENB, ee_addr); udelay(2); - - /* Terminate the EEPROM access. */ - iowrite16(EE_ENB & ~EE_CS, ee_addr); - return retval; -} - -static int mdio_read(struct net_device *dev, int phy_id, int location) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ - iowrite32(0x08000000 | (location<<16) | (phy_id<<21), ioaddr + SCBCtrlMDI); - do { - val = ioread32(ioaddr + SCBCtrlMDI); - if (--boguscnt < 0) { - printk(KERN_ERR " mdio_read() timed out with val = %8.8x.\n", val); - break; - } - } while (! (val & 0x10000000)); - return val & 0xffff; -} - -static void mdio_write(struct net_device *dev, int phy_id, int location, int value) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int val, boguscnt = 64*10; /* <64 usec. to complete, typ 27 ticks */ - iowrite32(0x04000000 | (location<<16) | (phy_id<<21) | value, - ioaddr + SCBCtrlMDI); - do { - val = ioread32(ioaddr + SCBCtrlMDI); - if (--boguscnt < 0) { - printk(KERN_ERR" mdio_write() timed out with val = %8.8x.\n", val); - break; - } - } while (! (val & 0x10000000)); -} - -static int -speedo_open(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int retval; - - if (netif_msg_ifup(sp)) - printk(KERN_DEBUG "%s: speedo_open() irq %d.\n", dev->name, dev->irq); - - pci_set_power_state(sp->pdev, PCI_D0); - - /* Set up the Tx queue early.. */ - sp->cur_tx = 0; - sp->dirty_tx = 0; - sp->last_cmd = NULL; - sp->tx_full = 0; - sp->in_interrupt = 0; - - /* .. we can safely take handler calls during init. */ - retval = request_irq(dev->irq, &speedo_interrupt, IRQF_SHARED, dev->name, dev); - if (retval) { - return retval; - } - - dev->if_port = sp->default_port; - -#ifdef oh_no_you_dont_unless_you_honour_the_options_passed_in_to_us - /* Retrigger negotiation to reset previous errors. */ - if ((sp->phy[0] & 0x8000) == 0) { - int phy_addr = sp->phy[0] & 0x1f ; - /* Use 0x3300 for restarting NWay, other values to force xcvr: - 0x0000 10-HD - 0x0100 10-FD - 0x2000 100-HD - 0x2100 100-FD - */ -#ifdef honor_default_port - mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]); -#else - mdio_write(dev, phy_addr, MII_BMCR, 0x3300); -#endif - } -#endif - - speedo_init_rx_ring(dev); - - /* Fire up the hardware. */ - iowrite16(SCBMaskAll, ioaddr + SCBCmd); - speedo_resume(dev); - - netdevice_start(dev); - netif_start_queue(dev); - - /* Setup the chip and configure the multicast list. */ - sp->mc_setup_head = NULL; - sp->mc_setup_tail = NULL; - sp->flow_ctrl = sp->partner = 0; - sp->rx_mode = -1; /* Invalid -> always reset the mode. */ - set_rx_mode(dev); - if ((sp->phy[0] & 0x8000) == 0) - sp->mii_if.advertising = mdio_read(dev, sp->phy[0] & 0x1f, MII_ADVERTISE); - - mii_check_link(&sp->mii_if); - - if (netif_msg_ifup(sp)) { - printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n", - dev->name, ioread16(ioaddr + SCBStatus)); - } - - /* Set the timer. The timer serves a dual purpose: - 1) to monitor the media interface (e.g. link beat) and perhaps switch - to an alternate media type - 2) to monitor Rx activity, and restart the Rx process if the receiver - hangs. */ - sp->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */ - sp->timer.data = (unsigned long)dev; - sp->timer.function = &speedo_timer; /* timer handler */ - add_timer(&sp->timer); - - /* No need to wait for the command unit to accept here. */ - if ((sp->phy[0] & 0x8000) == 0) - mdio_read(dev, sp->phy[0] & 0x1f, MII_BMCR); - - return 0; -} - -/* Start the chip hardware after a full reset. */ -static void speedo_resume(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - - /* Start with a Tx threshold of 256 (0x..20.... 8 byte units). */ - sp->tx_threshold = 0x01208000; - - /* Set the segment registers to '0'. */ - if (wait_for_cmd_done(dev, sp) != 0) { - iowrite32(PortPartialReset, ioaddr + SCBPort); - udelay(10); - } - - iowrite32(0, ioaddr + SCBPointer); - ioread32(ioaddr + SCBPointer); /* Flush to PCI. */ - udelay(10); /* Bogus, but it avoids the bug. */ - - /* Note: these next two operations can take a while. */ - do_slow_command(dev, sp, RxAddrLoad); - do_slow_command(dev, sp, CUCmdBase); - - /* Load the statistics block and rx ring addresses. */ - iowrite32(sp->lstats_dma, ioaddr + SCBPointer); - ioread32(ioaddr + SCBPointer); /* Flush to PCI */ - - iowrite8(CUStatsAddr, ioaddr + SCBCmd); - sp->lstats->done_marker = 0; - wait_for_cmd_done(dev, sp); - - if (sp->rx_ringp[sp->cur_rx % RX_RING_SIZE] == NULL) { - if (netif_msg_rx_err(sp)) - printk(KERN_DEBUG "%s: NULL cur_rx in speedo_resume().\n", - dev->name); - } else { - iowrite32(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE], - ioaddr + SCBPointer); - ioread32(ioaddr + SCBPointer); /* Flush to PCI */ - } - - /* Note: RxStart should complete instantly. */ - do_slow_command(dev, sp, RxStart); - do_slow_command(dev, sp, CUDumpStats); - - /* Fill the first command with our physical address. */ - { - struct descriptor *ias_cmd; - - ias_cmd = - (struct descriptor *)&sp->tx_ring[sp->cur_tx++ % TX_RING_SIZE]; - /* Avoid a bug(?!) here by marking the command already completed. */ - ias_cmd->cmd_status = cpu_to_le32((CmdSuspend | CmdIASetup) | 0xa000); - ias_cmd->link = - cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE)); - memcpy(ias_cmd->params, dev->dev_addr, 6); - if (sp->last_cmd) - clear_suspend(sp->last_cmd); - sp->last_cmd = ias_cmd; - } - - /* Start the chip's Tx process and unmask interrupts. */ - iowrite32(TX_RING_ELEM_DMA(sp, sp->dirty_tx % TX_RING_SIZE), - ioaddr + SCBPointer); - /* We are not ACK-ing FCP and ER in the interrupt handler yet so they should - remain masked --Dragan */ - iowrite16(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd); -} - -/* - * Sometimes the receiver stops making progress. This routine knows how to - * get it going again, without losing packets or being otherwise nasty like - * a chip reset would be. Previously the driver had a whole sequence - * of if RxSuspended, if it's no buffers do one thing, if it's no resources, - * do another, etc. But those things don't really matter. Separate logic - * in the ISR provides for allocating buffers--the other half of operation - * is just making sure the receiver is active. speedo_rx_soft_reset does that. - * This problem with the old, more involved algorithm is shown up under - * ping floods on the order of 60K packets/second on a 100Mbps fdx network. - */ -static void -speedo_rx_soft_reset(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - struct RxFD *rfd; - void __iomem *ioaddr; - - ioaddr = sp->regs; - if (wait_for_cmd_done(dev, sp) != 0) { - printk("%s: previous command stalled\n", dev->name); - return; - } - /* - * Put the hardware into a known state. - */ - iowrite8(RxAbort, ioaddr + SCBCmd); - - rfd = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE]; - - rfd->rx_buf_addr = cpu_to_le32(0xffffffff); - - if (wait_for_cmd_done(dev, sp) != 0) { - printk("%s: RxAbort command stalled\n", dev->name); - return; - } - iowrite32(sp->rx_ring_dma[sp->cur_rx % RX_RING_SIZE], - ioaddr + SCBPointer); - iowrite8(RxStart, ioaddr + SCBCmd); -} - - -/* Media monitoring and control. */ -static void speedo_timer(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int phy_num = sp->phy[0] & 0x1f; - - /* We have MII and lost link beat. */ - if ((sp->phy[0] & 0x8000) == 0) { - int partner = mdio_read(dev, phy_num, MII_LPA); - if (partner != sp->partner) { - int flow_ctrl = sp->mii_if.advertising & partner & 0x0400 ? 1 : 0; - if (netif_msg_link(sp)) { - printk(KERN_DEBUG "%s: Link status change.\n", dev->name); - printk(KERN_DEBUG "%s: Old partner %x, new %x, adv %x.\n", - dev->name, sp->partner, partner, sp->mii_if.advertising); - } - sp->partner = partner; - if (flow_ctrl != sp->flow_ctrl) { - sp->flow_ctrl = flow_ctrl; - sp->rx_mode = -1; /* Trigger a reload. */ - } - } - } - mii_check_link(&sp->mii_if); - if (netif_msg_timer(sp)) { - printk(KERN_DEBUG "%s: Media control tick, status %4.4x.\n", - dev->name, ioread16(ioaddr + SCBStatus)); - } - if (sp->rx_mode < 0 || - (sp->rx_bug && jiffies - sp->last_rx_time > 2*HZ)) { - /* We haven't received a packet in a Long Time. We might have been - bitten by the receiver hang bug. This can be cleared by sending - a set multicast list command. */ - if (netif_msg_timer(sp)) - printk(KERN_DEBUG "%s: Sending a multicast list set command" - " from a timer routine," - " m=%d, j=%ld, l=%ld.\n", - dev->name, sp->rx_mode, jiffies, sp->last_rx_time); - set_rx_mode(dev); - } - /* We must continue to monitor the media. */ - sp->timer.expires = RUN_AT(2*HZ); /* 2.0 sec. */ - add_timer(&sp->timer); -} - -static void speedo_show_state(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - int i; - - if (netif_msg_pktdata(sp)) { - printk(KERN_DEBUG "%s: Tx ring dump, Tx queue %u / %u:\n", - dev->name, sp->cur_tx, sp->dirty_tx); - for (i = 0; i < TX_RING_SIZE; i++) - printk(KERN_DEBUG "%s: %c%c%2d %8.8x.\n", dev->name, - i == sp->dirty_tx % TX_RING_SIZE ? '*' : ' ', - i == sp->cur_tx % TX_RING_SIZE ? '=' : ' ', - i, sp->tx_ring[i].status); - - printk(KERN_DEBUG "%s: Printing Rx ring" - " (next to receive into %u, dirty index %u).\n", - dev->name, sp->cur_rx, sp->dirty_rx); - for (i = 0; i < RX_RING_SIZE; i++) - printk(KERN_DEBUG "%s: %c%c%c%2d %8.8x.\n", dev->name, - sp->rx_ringp[i] == sp->last_rxf ? 'l' : ' ', - i == sp->dirty_rx % RX_RING_SIZE ? '*' : ' ', - i == sp->cur_rx % RX_RING_SIZE ? '=' : ' ', - i, (sp->rx_ringp[i] != NULL) ? - (unsigned)sp->rx_ringp[i]->status : 0); - } - -#if 0 - { - void __iomem *ioaddr = sp->regs; - int phy_num = sp->phy[0] & 0x1f; - for (i = 0; i < 16; i++) { - /* FIXME: what does it mean? --SAW */ - if (i == 6) i = 21; - printk(KERN_DEBUG "%s: PHY index %d register %d is %4.4x.\n", - dev->name, phy_num, i, mdio_read(dev, phy_num, i)); - } - } -#endif - -} - -/* Initialize the Rx and Tx rings, along with various 'dev' bits. */ -static void -speedo_init_rx_ring(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - struct RxFD *rxf, *last_rxf = NULL; - dma_addr_t last_rxf_dma = 0 /* to shut up the compiler */; - int i; - - sp->cur_rx = 0; - - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb; - skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); - if (skb) - rx_align(skb); /* Align IP on 16 byte boundary */ - sp->rx_skbuff[i] = skb; - if (skb == NULL) - break; /* OK. Just initially short of Rx bufs. */ - skb->dev = dev; /* Mark as being used by this device. */ - rxf = (struct RxFD *)skb->data; - sp->rx_ringp[i] = rxf; - sp->rx_ring_dma[i] = - pci_map_single(sp->pdev, rxf, - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_BIDIRECTIONAL); - skb_reserve(skb, sizeof(struct RxFD)); - if (last_rxf) { - last_rxf->link = cpu_to_le32(sp->rx_ring_dma[i]); - pci_dma_sync_single_for_device(sp->pdev, last_rxf_dma, - sizeof(struct RxFD), PCI_DMA_TODEVICE); - } - last_rxf = rxf; - last_rxf_dma = sp->rx_ring_dma[i]; - rxf->status = cpu_to_le32(0x00000001); /* '1' is flag value only. */ - rxf->link = 0; /* None yet. */ - /* This field unused by i82557. */ - rxf->rx_buf_addr = cpu_to_le32(0xffffffff); - rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); - pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[i], - sizeof(struct RxFD), PCI_DMA_TODEVICE); - } - sp->dirty_rx = (unsigned int)(i - RX_RING_SIZE); - /* Mark the last entry as end-of-list. */ - last_rxf->status = cpu_to_le32(0xC0000002); /* '2' is flag value only. */ - pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[RX_RING_SIZE-1], - sizeof(struct RxFD), PCI_DMA_TODEVICE); - sp->last_rxf = last_rxf; - sp->last_rxf_dma = last_rxf_dma; -} - -static void speedo_purge_tx(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - int entry; - - while ((int)(sp->cur_tx - sp->dirty_tx) > 0) { - entry = sp->dirty_tx % TX_RING_SIZE; - if (sp->tx_skbuff[entry]) { - sp->stats.tx_errors++; - pci_unmap_single(sp->pdev, - le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0), - sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(sp->tx_skbuff[entry]); - sp->tx_skbuff[entry] = NULL; - } - sp->dirty_tx++; - } - while (sp->mc_setup_head != NULL) { - struct speedo_mc_block *t; - if (netif_msg_tx_err(sp)) - printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name); - pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma, - sp->mc_setup_head->len, PCI_DMA_TODEVICE); - t = sp->mc_setup_head->next; - kfree(sp->mc_setup_head); - sp->mc_setup_head = t; - } - sp->mc_setup_tail = NULL; - sp->tx_full = 0; - netif_wake_queue(dev); -} - -static void reset_mii(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - - /* Reset the MII transceiver, suggested by Fred Young @ scalable.com. */ - if ((sp->phy[0] & 0x8000) == 0) { - int phy_addr = sp->phy[0] & 0x1f; - int advertising = mdio_read(dev, phy_addr, MII_ADVERTISE); - int mii_bmcr = mdio_read(dev, phy_addr, MII_BMCR); - mdio_write(dev, phy_addr, MII_BMCR, 0x0400); - mdio_write(dev, phy_addr, MII_BMSR, 0x0000); - mdio_write(dev, phy_addr, MII_ADVERTISE, 0x0000); - mdio_write(dev, phy_addr, MII_BMCR, 0x8000); -#ifdef honor_default_port - mdio_write(dev, phy_addr, MII_BMCR, mii_ctrl[dev->default_port & 7]); -#else - mdio_read(dev, phy_addr, MII_BMCR); - mdio_write(dev, phy_addr, MII_BMCR, mii_bmcr); - mdio_write(dev, phy_addr, MII_ADVERTISE, advertising); -#endif - } -} - -static void speedo_tx_timeout(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int status = ioread16(ioaddr + SCBStatus); - unsigned long flags; - - if (netif_msg_tx_err(sp)) { - printk(KERN_WARNING "%s: Transmit timed out: status %4.4x " - " %4.4x at %d/%d command %8.8x.\n", - dev->name, status, ioread16(ioaddr + SCBCmd), - sp->dirty_tx, sp->cur_tx, - sp->tx_ring[sp->dirty_tx % TX_RING_SIZE].status); - - } - speedo_show_state(dev); -#if 0 - if ((status & 0x00C0) != 0x0080 - && (status & 0x003C) == 0x0010) { - /* Only the command unit has stopped. */ - printk(KERN_WARNING "%s: Trying to restart the transmitter...\n", - dev->name); - iowrite32(TX_RING_ELEM_DMA(sp, dirty_tx % TX_RING_SIZE]), - ioaddr + SCBPointer); - iowrite16(CUStart, ioaddr + SCBCmd); - reset_mii(dev); - } else { -#else - { -#endif - del_timer_sync(&sp->timer); - /* Reset the Tx and Rx units. */ - iowrite32(PortReset, ioaddr + SCBPort); - /* We may get spurious interrupts here. But I don't think that they - may do much harm. 1999/12/09 SAW */ - udelay(10); - /* Disable interrupts. */ - iowrite16(SCBMaskAll, ioaddr + SCBCmd); - synchronize_irq(dev->irq); - speedo_tx_buffer_gc(dev); - /* Free as much as possible. - It helps to recover from a hang because of out-of-memory. - It also simplifies speedo_resume() in case TX ring is full or - close-to-be full. */ - speedo_purge_tx(dev); - speedo_refill_rx_buffers(dev, 1); - spin_lock_irqsave(&sp->lock, flags); - speedo_resume(dev); - sp->rx_mode = -1; - dev->trans_start = jiffies; - spin_unlock_irqrestore(&sp->lock, flags); - set_rx_mode(dev); /* it takes the spinlock itself --SAW */ - /* Reset MII transceiver. Do it before starting the timer to serialize - mdio_xxx operations. Yes, it's a paranoya :-) 2000/05/09 SAW */ - reset_mii(dev); - sp->timer.expires = RUN_AT(2*HZ); - add_timer(&sp->timer); - } - return; -} - -static int -speedo_start_xmit(struct sk_buff *skb, struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int entry; - - /* Prevent interrupts from changing the Tx ring from underneath us. */ - unsigned long flags; - - spin_lock_irqsave(&sp->lock, flags); - - /* Check if there are enough space. */ - if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { - printk(KERN_ERR "%s: incorrect tbusy state, fixed.\n", dev->name); - netif_stop_queue(dev); - sp->tx_full = 1; - spin_unlock_irqrestore(&sp->lock, flags); - return 1; - } - - /* Calculate the Tx descriptor entry. */ - entry = sp->cur_tx++ % TX_RING_SIZE; - - sp->tx_skbuff[entry] = skb; - sp->tx_ring[entry].status = - cpu_to_le32(CmdSuspend | CmdTx | CmdTxFlex); - if (!(entry & ((TX_RING_SIZE>>2)-1))) - sp->tx_ring[entry].status |= cpu_to_le32(CmdIntr); - sp->tx_ring[entry].link = - cpu_to_le32(TX_RING_ELEM_DMA(sp, sp->cur_tx % TX_RING_SIZE)); - sp->tx_ring[entry].tx_desc_addr = - cpu_to_le32(TX_RING_ELEM_DMA(sp, entry) + TX_DESCR_BUF_OFFSET); - /* The data region is always in one buffer descriptor. */ - sp->tx_ring[entry].count = cpu_to_le32(sp->tx_threshold); - sp->tx_ring[entry].tx_buf_addr0 = - cpu_to_le32(pci_map_single(sp->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE)); - sp->tx_ring[entry].tx_buf_size0 = cpu_to_le32(skb->len); - - /* workaround for hardware bug on 10 mbit half duplex */ - - if ((sp->partner == 0) && (sp->chip_id == 1)) { - wait_for_cmd_done(dev, sp); - iowrite8(0 , ioaddr + SCBCmd); - udelay(1); - } - - /* Trigger the command unit resume. */ - wait_for_cmd_done(dev, sp); - clear_suspend(sp->last_cmd); - /* We want the time window between clearing suspend flag on the previous - command and resuming CU to be as small as possible. - Interrupts in between are very undesired. --SAW */ - iowrite8(CUResume, ioaddr + SCBCmd); - sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; - - /* Leave room for set_rx_mode(). If there is no more space than reserved - for multicast filter mark the ring as full. */ - if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { - netif_stop_queue(dev); - sp->tx_full = 1; - } - - spin_unlock_irqrestore(&sp->lock, flags); - - dev->trans_start = jiffies; - - return 0; -} - -static void speedo_tx_buffer_gc(struct net_device *dev) -{ - unsigned int dirty_tx; - struct speedo_private *sp = netdev_priv(dev); - - dirty_tx = sp->dirty_tx; - while ((int)(sp->cur_tx - dirty_tx) > 0) { - int entry = dirty_tx % TX_RING_SIZE; - int status = le32_to_cpu(sp->tx_ring[entry].status); - - if (netif_msg_tx_done(sp)) - printk(KERN_DEBUG " scavenge candidate %d status %4.4x.\n", - entry, status); - if ((status & StatusComplete) == 0) - break; /* It still hasn't been processed. */ - if (status & TxUnderrun) - if (sp->tx_threshold < 0x01e08000) { - if (netif_msg_tx_err(sp)) - printk(KERN_DEBUG "%s: TX underrun, threshold adjusted.\n", - dev->name); - sp->tx_threshold += 0x00040000; - } - /* Free the original skb. */ - if (sp->tx_skbuff[entry]) { - sp->stats.tx_packets++; /* Count only user packets. */ - sp->stats.tx_bytes += sp->tx_skbuff[entry]->len; - pci_unmap_single(sp->pdev, - le32_to_cpu(sp->tx_ring[entry].tx_buf_addr0), - sp->tx_skbuff[entry]->len, PCI_DMA_TODEVICE); - dev_kfree_skb_irq(sp->tx_skbuff[entry]); - sp->tx_skbuff[entry] = NULL; - } - dirty_tx++; - } - - if (netif_msg_tx_err(sp) && (int)(sp->cur_tx - dirty_tx) > TX_RING_SIZE) { - printk(KERN_ERR "out-of-sync dirty pointer, %d vs. %d," - " full=%d.\n", - dirty_tx, sp->cur_tx, sp->tx_full); - dirty_tx += TX_RING_SIZE; - } - - while (sp->mc_setup_head != NULL - && (int)(dirty_tx - sp->mc_setup_head->tx - 1) > 0) { - struct speedo_mc_block *t; - if (netif_msg_tx_err(sp)) - printk(KERN_DEBUG "%s: freeing mc frame.\n", dev->name); - pci_unmap_single(sp->pdev, sp->mc_setup_head->frame_dma, - sp->mc_setup_head->len, PCI_DMA_TODEVICE); - t = sp->mc_setup_head->next; - kfree(sp->mc_setup_head); - sp->mc_setup_head = t; - } - if (sp->mc_setup_head == NULL) - sp->mc_setup_tail = NULL; - - sp->dirty_tx = dirty_tx; -} - -/* The interrupt handler does all of the Rx thread work and cleans up - after the Tx thread. */ -static irqreturn_t speedo_interrupt(int irq, void *dev_instance) -{ - struct net_device *dev = (struct net_device *)dev_instance; - struct speedo_private *sp; - void __iomem *ioaddr; - long boguscnt = max_interrupt_work; - unsigned short status; - unsigned int handled = 0; - - sp = netdev_priv(dev); - ioaddr = sp->regs; - -#ifndef final_version - /* A lock to prevent simultaneous entry on SMP machines. */ - if (test_and_set_bit(0, (void*)&sp->in_interrupt)) { - printk(KERN_ERR"%s: SMP simultaneous entry of an interrupt handler.\n", - dev->name); - sp->in_interrupt = 0; /* Avoid halting machine. */ - return IRQ_NONE; - } -#endif - - do { - status = ioread16(ioaddr + SCBStatus); - /* Acknowledge all of the current interrupt sources ASAP. */ - /* Will change from 0xfc00 to 0xff00 when we start handling - FCP and ER interrupts --Dragan */ - iowrite16(status & 0xfc00, ioaddr + SCBStatus); - - if (netif_msg_intr(sp)) - printk(KERN_DEBUG "%s: interrupt status=%#4.4x.\n", - dev->name, status); - - if ((status & 0xfc00) == 0) - break; - handled = 1; - - - if ((status & 0x5000) || /* Packet received, or Rx error. */ - (sp->rx_ring_state&(RrNoMem|RrPostponed)) == RrPostponed) - /* Need to gather the postponed packet. */ - speedo_rx(dev); - - /* Always check if all rx buffers are allocated. --SAW */ - speedo_refill_rx_buffers(dev, 0); - - spin_lock(&sp->lock); - /* - * The chip may have suspended reception for various reasons. - * Check for that, and re-prime it should this be the case. - */ - switch ((status >> 2) & 0xf) { - case 0: /* Idle */ - break; - case 1: /* Suspended */ - case 2: /* No resources (RxFDs) */ - case 9: /* Suspended with no more RBDs */ - case 10: /* No resources due to no RBDs */ - case 12: /* Ready with no RBDs */ - speedo_rx_soft_reset(dev); - break; - case 3: case 5: case 6: case 7: case 8: - case 11: case 13: case 14: case 15: - /* these are all reserved values */ - break; - } - - - /* User interrupt, Command/Tx unit interrupt or CU not active. */ - if (status & 0xA400) { - speedo_tx_buffer_gc(dev); - if (sp->tx_full - && (int)(sp->cur_tx - sp->dirty_tx) < TX_QUEUE_UNFULL) { - /* The ring is no longer full. */ - sp->tx_full = 0; - netif_wake_queue(dev); /* Attention: under a spinlock. --SAW */ - } - } - - spin_unlock(&sp->lock); - - if (--boguscnt < 0) { - printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n", - dev->name, status); - /* Clear all interrupt sources. */ - /* Will change from 0xfc00 to 0xff00 when we start handling - FCP and ER interrupts --Dragan */ - iowrite16(0xfc00, ioaddr + SCBStatus); - break; - } - } while (1); - - if (netif_msg_intr(sp)) - printk(KERN_DEBUG "%s: exiting interrupt, status=%#4.4x.\n", - dev->name, ioread16(ioaddr + SCBStatus)); - - clear_bit(0, (void*)&sp->in_interrupt); - return IRQ_RETVAL(handled); -} - -static inline struct RxFD *speedo_rx_alloc(struct net_device *dev, int entry) -{ - struct speedo_private *sp = netdev_priv(dev); - struct RxFD *rxf; - struct sk_buff *skb; - /* Get a fresh skbuff to replace the consumed one. */ - skb = dev_alloc_skb(PKT_BUF_SZ + sizeof(struct RxFD)); - if (skb) - rx_align(skb); /* Align IP on 16 byte boundary */ - sp->rx_skbuff[entry] = skb; - if (skb == NULL) { - sp->rx_ringp[entry] = NULL; - return NULL; - } - rxf = sp->rx_ringp[entry] = (struct RxFD *)skb->data; - sp->rx_ring_dma[entry] = - pci_map_single(sp->pdev, rxf, - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); - skb->dev = dev; - skb_reserve(skb, sizeof(struct RxFD)); - rxf->rx_buf_addr = cpu_to_le32(0xffffffff); - pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD), PCI_DMA_TODEVICE); - return rxf; -} - -static inline void speedo_rx_link(struct net_device *dev, int entry, - struct RxFD *rxf, dma_addr_t rxf_dma) -{ - struct speedo_private *sp = netdev_priv(dev); - rxf->status = cpu_to_le32(0xC0000001); /* '1' for driver use only. */ - rxf->link = 0; /* None yet. */ - rxf->count = cpu_to_le32(PKT_BUF_SZ << 16); - sp->last_rxf->link = cpu_to_le32(rxf_dma); - sp->last_rxf->status &= cpu_to_le32(~0xC0000000); - pci_dma_sync_single_for_device(sp->pdev, sp->last_rxf_dma, - sizeof(struct RxFD), PCI_DMA_TODEVICE); - sp->last_rxf = rxf; - sp->last_rxf_dma = rxf_dma; -} - -static int speedo_refill_rx_buf(struct net_device *dev, int force) -{ - struct speedo_private *sp = netdev_priv(dev); - int entry; - struct RxFD *rxf; - - entry = sp->dirty_rx % RX_RING_SIZE; - if (sp->rx_skbuff[entry] == NULL) { - rxf = speedo_rx_alloc(dev, entry); - if (rxf == NULL) { - unsigned int forw; - int forw_entry; - if (netif_msg_rx_err(sp) || !(sp->rx_ring_state & RrOOMReported)) { - printk(KERN_WARNING "%s: can't fill rx buffer (force %d)!\n", - dev->name, force); - sp->rx_ring_state |= RrOOMReported; - } - speedo_show_state(dev); - if (!force) - return -1; /* Better luck next time! */ - /* Borrow an skb from one of next entries. */ - for (forw = sp->dirty_rx + 1; forw != sp->cur_rx; forw++) - if (sp->rx_skbuff[forw % RX_RING_SIZE] != NULL) - break; - if (forw == sp->cur_rx) - return -1; - forw_entry = forw % RX_RING_SIZE; - sp->rx_skbuff[entry] = sp->rx_skbuff[forw_entry]; - sp->rx_skbuff[forw_entry] = NULL; - rxf = sp->rx_ringp[forw_entry]; - sp->rx_ringp[forw_entry] = NULL; - sp->rx_ringp[entry] = rxf; - } - } else { - rxf = sp->rx_ringp[entry]; - } - speedo_rx_link(dev, entry, rxf, sp->rx_ring_dma[entry]); - sp->dirty_rx++; - sp->rx_ring_state &= ~(RrNoMem|RrOOMReported); /* Mark the progress. */ - return 0; -} - -static void speedo_refill_rx_buffers(struct net_device *dev, int force) -{ - struct speedo_private *sp = netdev_priv(dev); - - /* Refill the RX ring. */ - while ((int)(sp->cur_rx - sp->dirty_rx) > 0 && - speedo_refill_rx_buf(dev, force) != -1); -} - -static int -speedo_rx(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - int entry = sp->cur_rx % RX_RING_SIZE; - int rx_work_limit = sp->dirty_rx + RX_RING_SIZE - sp->cur_rx; - int alloc_ok = 1; - int npkts = 0; - - if (netif_msg_intr(sp)) - printk(KERN_DEBUG " In speedo_rx().\n"); - /* If we own the next entry, it's a new packet. Send it up. */ - while (sp->rx_ringp[entry] != NULL) { - int status; - int pkt_len; - - pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD), PCI_DMA_FROMDEVICE); - status = le32_to_cpu(sp->rx_ringp[entry]->status); - pkt_len = le32_to_cpu(sp->rx_ringp[entry]->count) & 0x3fff; - - if (!(status & RxComplete)) - break; - - if (--rx_work_limit < 0) - break; - - /* Check for a rare out-of-memory case: the current buffer is - the last buffer allocated in the RX ring. --SAW */ - if (sp->last_rxf == sp->rx_ringp[entry]) { - /* Postpone the packet. It'll be reaped at an interrupt when this - packet is no longer the last packet in the ring. */ - if (netif_msg_rx_err(sp)) - printk(KERN_DEBUG "%s: RX packet postponed!\n", - dev->name); - sp->rx_ring_state |= RrPostponed; - break; - } - - if (netif_msg_rx_status(sp)) - printk(KERN_DEBUG " speedo_rx() status %8.8x len %d.\n", status, - pkt_len); - if ((status & (RxErrTooBig|RxOK|0x0f90)) != RxOK) { - if (status & RxErrTooBig) - printk(KERN_ERR "%s: Ethernet frame overran the Rx buffer, " - "status %8.8x!\n", dev->name, status); - else if (! (status & RxOK)) { - /* There was a fatal error. This *should* be impossible. */ - sp->stats.rx_errors++; - printk(KERN_ERR "%s: Anomalous event in speedo_rx(), " - "status %8.8x.\n", - dev->name, status); - } - } else { - struct sk_buff *skb; - - /* Check if the packet is long enough to just accept without - copying to a properly sized skbuff. */ - if (pkt_len < rx_copybreak - && (skb = dev_alloc_skb(pkt_len + 2)) != NULL) { - skb_reserve(skb, 2); /* Align IP on 16 byte boundaries */ - /* 'skb_put()' points to the start of sk_buff data area. */ - pci_dma_sync_single_for_cpu(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD) + pkt_len, - PCI_DMA_FROMDEVICE); - -#if 1 || USE_IP_CSUM - /* Packet is in one chunk -- we can copy + cksum. */ - skb_copy_to_linear_data(skb, sp->rx_skbuff[entry]->data, pkt_len); - skb_put(skb, pkt_len); -#else - skb_copy_from_linear_data(sp->rx_skbuff[entry], - skb_put(skb, pkt_len), - pkt_len); -#endif - pci_dma_sync_single_for_device(sp->pdev, sp->rx_ring_dma[entry], - sizeof(struct RxFD) + pkt_len, - PCI_DMA_FROMDEVICE); - npkts++; - } else { - /* Pass up the already-filled skbuff. */ - skb = sp->rx_skbuff[entry]; - if (skb == NULL) { - printk(KERN_ERR "%s: Inconsistent Rx descriptor chain.\n", - dev->name); - break; - } - sp->rx_skbuff[entry] = NULL; - skb_put(skb, pkt_len); - npkts++; - sp->rx_ringp[entry] = NULL; - pci_unmap_single(sp->pdev, sp->rx_ring_dma[entry], - PKT_BUF_SZ + sizeof(struct RxFD), - PCI_DMA_FROMDEVICE); - } - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - dev->last_rx = jiffies; - sp->stats.rx_packets++; - sp->stats.rx_bytes += pkt_len; - } - entry = (++sp->cur_rx) % RX_RING_SIZE; - sp->rx_ring_state &= ~RrPostponed; - /* Refill the recently taken buffers. - Do it one-by-one to handle traffic bursts better. */ - if (alloc_ok && speedo_refill_rx_buf(dev, 0) == -1) - alloc_ok = 0; - } - - /* Try hard to refill the recently taken buffers. */ - speedo_refill_rx_buffers(dev, 1); - - if (npkts) - sp->last_rx_time = jiffies; - - return 0; -} - -static int -speedo_close(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int i; - - netdevice_stop(dev); - netif_stop_queue(dev); - - if (netif_msg_ifdown(sp)) - printk(KERN_DEBUG "%s: Shutting down ethercard, status was %4.4x.\n", - dev->name, ioread16(ioaddr + SCBStatus)); - - /* Shut off the media monitoring timer. */ - del_timer_sync(&sp->timer); - - iowrite16(SCBMaskAll, ioaddr + SCBCmd); - - /* Shutting down the chip nicely fails to disable flow control. So.. */ - iowrite32(PortPartialReset, ioaddr + SCBPort); - ioread32(ioaddr + SCBPort); /* flush posted write */ - /* - * The chip requires a 10 microsecond quiet period. Wait here! - */ - udelay(10); - - free_irq(dev->irq, dev); - speedo_show_state(dev); - - /* Free all the skbuffs in the Rx and Tx queues. */ - for (i = 0; i < RX_RING_SIZE; i++) { - struct sk_buff *skb = sp->rx_skbuff[i]; - sp->rx_skbuff[i] = NULL; - /* Clear the Rx descriptors. */ - if (skb) { - pci_unmap_single(sp->pdev, - sp->rx_ring_dma[i], - PKT_BUF_SZ + sizeof(struct RxFD), PCI_DMA_FROMDEVICE); - dev_kfree_skb(skb); - } - } - - for (i = 0; i < TX_RING_SIZE; i++) { - struct sk_buff *skb = sp->tx_skbuff[i]; - sp->tx_skbuff[i] = NULL; - /* Clear the Tx descriptors. */ - if (skb) { - pci_unmap_single(sp->pdev, - le32_to_cpu(sp->tx_ring[i].tx_buf_addr0), - skb->len, PCI_DMA_TODEVICE); - dev_kfree_skb(skb); - } - } - - /* Free multicast setting blocks. */ - for (i = 0; sp->mc_setup_head != NULL; i++) { - struct speedo_mc_block *t; - t = sp->mc_setup_head->next; - kfree(sp->mc_setup_head); - sp->mc_setup_head = t; - } - sp->mc_setup_tail = NULL; - if (netif_msg_ifdown(sp)) - printk(KERN_DEBUG "%s: %d multicast blocks dropped.\n", dev->name, i); - - pci_set_power_state(sp->pdev, PCI_D2); - - return 0; -} - -/* The Speedo-3 has an especially awkward and unusable method of getting - statistics out of the chip. It takes an unpredictable length of time - for the dump-stats command to complete. To avoid a busy-wait loop we - update the stats with the previous dump results, and then trigger a - new dump. - - Oh, and incoming frames are dropped while executing dump-stats! - */ -static struct net_device_stats * -speedo_get_stats(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - - /* Update only if the previous dump finished. */ - if (sp->lstats->done_marker == cpu_to_le32(0xA007)) { - sp->stats.tx_aborted_errors += le32_to_cpu(sp->lstats->tx_coll16_errs); - sp->stats.tx_window_errors += le32_to_cpu(sp->lstats->tx_late_colls); - sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats->tx_underruns); - sp->stats.tx_fifo_errors += le32_to_cpu(sp->lstats->tx_lost_carrier); - /*sp->stats.tx_deferred += le32_to_cpu(sp->lstats->tx_deferred);*/ - sp->stats.collisions += le32_to_cpu(sp->lstats->tx_total_colls); - sp->stats.rx_crc_errors += le32_to_cpu(sp->lstats->rx_crc_errs); - sp->stats.rx_frame_errors += le32_to_cpu(sp->lstats->rx_align_errs); - sp->stats.rx_over_errors += le32_to_cpu(sp->lstats->rx_resource_errs); - sp->stats.rx_fifo_errors += le32_to_cpu(sp->lstats->rx_overrun_errs); - sp->stats.rx_length_errors += le32_to_cpu(sp->lstats->rx_runt_errs); - sp->lstats->done_marker = 0x0000; - if (netif_running(dev)) { - unsigned long flags; - /* Take a spinlock to make wait_for_cmd_done and sending the - command atomic. --SAW */ - spin_lock_irqsave(&sp->lock, flags); - wait_for_cmd_done(dev, sp); - iowrite8(CUDumpStats, ioaddr + SCBCmd); - spin_unlock_irqrestore(&sp->lock, flags); - } - } - return &sp->stats; -} - -static void speedo_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct speedo_private *sp = netdev_priv(dev); - strncpy(info->driver, "eepro100", sizeof(info->driver)-1); - strncpy(info->version, version, sizeof(info->version)-1); - if (sp->pdev) - strcpy(info->bus_info, pci_name(sp->pdev)); -} - -static int speedo_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - struct speedo_private *sp = netdev_priv(dev); - spin_lock_irq(&sp->lock); - mii_ethtool_gset(&sp->mii_if, ecmd); - spin_unlock_irq(&sp->lock); - return 0; -} - -static int speedo_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) -{ - struct speedo_private *sp = netdev_priv(dev); - int res; - spin_lock_irq(&sp->lock); - res = mii_ethtool_sset(&sp->mii_if, ecmd); - spin_unlock_irq(&sp->lock); - return res; -} - -static int speedo_nway_reset(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - return mii_nway_restart(&sp->mii_if); -} - -static u32 speedo_get_link(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - return mii_link_ok(&sp->mii_if); -} - -static u32 speedo_get_msglevel(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - return sp->msg_enable; -} - -static void speedo_set_msglevel(struct net_device *dev, u32 v) -{ - struct speedo_private *sp = netdev_priv(dev); - sp->msg_enable = v; -} - -static const struct ethtool_ops ethtool_ops = { - .get_drvinfo = speedo_get_drvinfo, - .get_settings = speedo_get_settings, - .set_settings = speedo_set_settings, - .nway_reset = speedo_nway_reset, - .get_link = speedo_get_link, - .get_msglevel = speedo_get_msglevel, - .set_msglevel = speedo_set_msglevel, -}; - -static int speedo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) -{ - struct speedo_private *sp = netdev_priv(dev); - struct mii_ioctl_data *data = if_mii(rq); - int phy = sp->phy[0] & 0x1f; - int saved_acpi; - int t; - - switch(cmd) { - case SIOCGMIIPHY: /* Get address of MII PHY in use. */ - data->phy_id = phy; - - case SIOCGMIIREG: /* Read MII PHY register. */ - /* FIXME: these operations need to be serialized with MDIO - access from the timeout handler. - They are currently serialized only with MDIO access from the - timer routine. 2000/05/09 SAW */ - saved_acpi = pci_set_power_state(sp->pdev, PCI_D0); - t = del_timer_sync(&sp->timer); - data->val_out = mdio_read(dev, data->phy_id & 0x1f, data->reg_num & 0x1f); - if (t) - add_timer(&sp->timer); /* may be set to the past --SAW */ - pci_set_power_state(sp->pdev, saved_acpi); - return 0; - - case SIOCSMIIREG: /* Write MII PHY register. */ - if (!capable(CAP_NET_ADMIN)) - return -EPERM; - saved_acpi = pci_set_power_state(sp->pdev, PCI_D0); - t = del_timer_sync(&sp->timer); - mdio_write(dev, data->phy_id, data->reg_num, data->val_in); - if (t) - add_timer(&sp->timer); /* may be set to the past --SAW */ - pci_set_power_state(sp->pdev, saved_acpi); - return 0; - default: - return -EOPNOTSUPP; - } -} - -/* Set or clear the multicast filter for this adaptor. - This is very ugly with Intel chips -- we usually have to execute an - entire configuration command, plus process a multicast command. - This is complicated. We must put a large configuration command and - an arbitrarily-sized multicast command in the transmit list. - To minimize the disruption -- the previous command might have already - loaded the link -- we convert the current command block, normally a Tx - command, into a no-op and link it to the new command. -*/ -static void set_rx_mode(struct net_device *dev) -{ - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - struct descriptor *last_cmd; - char new_rx_mode; - unsigned long flags; - int entry, i; - - if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */ - new_rx_mode = 3; - } else if ((dev->flags & IFF_ALLMULTI) || - dev->mc_count > multicast_filter_limit) { - new_rx_mode = 1; - } else - new_rx_mode = 0; - - if (netif_msg_rx_status(sp)) - printk(KERN_DEBUG "%s: set_rx_mode %d -> %d\n", dev->name, - sp->rx_mode, new_rx_mode); - - if ((int)(sp->cur_tx - sp->dirty_tx) > TX_RING_SIZE - TX_MULTICAST_SIZE) { - /* The Tx ring is full -- don't add anything! Hope the mode will be - * set again later. */ - sp->rx_mode = -1; - return; - } - - if (new_rx_mode != sp->rx_mode) { - u8 *config_cmd_data; - - spin_lock_irqsave(&sp->lock, flags); - entry = sp->cur_tx++ % TX_RING_SIZE; - last_cmd = sp->last_cmd; - sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; - - sp->tx_skbuff[entry] = NULL; /* Redundant. */ - sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdConfigure); - sp->tx_ring[entry].link = - cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); - config_cmd_data = (void *)&sp->tx_ring[entry].tx_desc_addr; - /* Construct a full CmdConfig frame. */ - memcpy(config_cmd_data, i82558_config_cmd, CONFIG_DATA_SIZE); - config_cmd_data[1] = (txfifo << 4) | rxfifo; - config_cmd_data[4] = rxdmacount; - config_cmd_data[5] = txdmacount + 0x80; - config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0; - /* 0x80 doesn't disable FC 0x84 does. - Disable Flow control since we are not ACK-ing any FC interrupts - for now. --Dragan */ - config_cmd_data[19] = 0x84; - config_cmd_data[19] |= sp->mii_if.full_duplex ? 0x40 : 0; - config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05; - if (sp->phy[0] & 0x8000) { /* Use the AUI port instead. */ - config_cmd_data[15] |= 0x80; - config_cmd_data[8] = 0; - } - /* Trigger the command unit resume. */ - wait_for_cmd_done(dev, sp); - clear_suspend(last_cmd); - iowrite8(CUResume, ioaddr + SCBCmd); - if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { - netif_stop_queue(dev); - sp->tx_full = 1; - } - spin_unlock_irqrestore(&sp->lock, flags); - } - - if (new_rx_mode == 0 && dev->mc_count < 4) { - /* The simple case of 0-3 multicast list entries occurs often, and - fits within one tx_ring[] entry. */ - struct dev_mc_list *mclist; - __le16 *setup_params, *eaddrs; - - spin_lock_irqsave(&sp->lock, flags); - entry = sp->cur_tx++ % TX_RING_SIZE; - last_cmd = sp->last_cmd; - sp->last_cmd = (struct descriptor *)&sp->tx_ring[entry]; - - sp->tx_skbuff[entry] = NULL; - sp->tx_ring[entry].status = cpu_to_le32(CmdSuspend | CmdMulticastList); - sp->tx_ring[entry].link = - cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); - sp->tx_ring[entry].tx_desc_addr = 0; /* Really MC list count. */ - setup_params = (__le16 *)&sp->tx_ring[entry].tx_desc_addr; - *setup_params++ = cpu_to_le16(dev->mc_count*6); - /* Fill in the multicast addresses. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; - i++, mclist = mclist->next) { - eaddrs = (__le16 *)mclist->dmi_addr; - *setup_params++ = *eaddrs++; - *setup_params++ = *eaddrs++; - *setup_params++ = *eaddrs++; - } - - wait_for_cmd_done(dev, sp); - clear_suspend(last_cmd); - /* Immediately trigger the command unit resume. */ - iowrite8(CUResume, ioaddr + SCBCmd); - - if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { - netif_stop_queue(dev); - sp->tx_full = 1; - } - spin_unlock_irqrestore(&sp->lock, flags); - } else if (new_rx_mode == 0) { - struct dev_mc_list *mclist; - __le16 *setup_params, *eaddrs; - struct speedo_mc_block *mc_blk; - struct descriptor *mc_setup_frm; - int i; - - mc_blk = kmalloc(sizeof(*mc_blk) + 2 + multicast_filter_limit*6, - GFP_ATOMIC); - if (mc_blk == NULL) { - printk(KERN_ERR "%s: Failed to allocate a setup frame.\n", - dev->name); - sp->rx_mode = -1; /* We failed, try again. */ - return; - } - mc_blk->next = NULL; - mc_blk->len = 2 + multicast_filter_limit*6; - mc_blk->frame_dma = - pci_map_single(sp->pdev, &mc_blk->frame, mc_blk->len, - PCI_DMA_TODEVICE); - mc_setup_frm = &mc_blk->frame; - - /* Fill the setup frame. */ - if (netif_msg_ifup(sp)) - printk(KERN_DEBUG "%s: Constructing a setup frame at %p.\n", - dev->name, mc_setup_frm); - mc_setup_frm->cmd_status = - cpu_to_le32(CmdSuspend | CmdIntr | CmdMulticastList); - /* Link set below. */ - setup_params = (__le16 *)&mc_setup_frm->params; - *setup_params++ = cpu_to_le16(dev->mc_count*6); - /* Fill in the multicast addresses. */ - for (i = 0, mclist = dev->mc_list; i < dev->mc_count; - i++, mclist = mclist->next) { - eaddrs = (__le16 *)mclist->dmi_addr; - *setup_params++ = *eaddrs++; - *setup_params++ = *eaddrs++; - *setup_params++ = *eaddrs++; - } - - /* Disable interrupts while playing with the Tx Cmd list. */ - spin_lock_irqsave(&sp->lock, flags); - - if (sp->mc_setup_tail) - sp->mc_setup_tail->next = mc_blk; - else - sp->mc_setup_head = mc_blk; - sp->mc_setup_tail = mc_blk; - mc_blk->tx = sp->cur_tx; - - entry = sp->cur_tx++ % TX_RING_SIZE; - last_cmd = sp->last_cmd; - sp->last_cmd = mc_setup_frm; - - /* Change the command to a NoOp, pointing to the CmdMulti command. */ - sp->tx_skbuff[entry] = NULL; - sp->tx_ring[entry].status = cpu_to_le32(CmdNOp); - sp->tx_ring[entry].link = cpu_to_le32(mc_blk->frame_dma); - - /* Set the link in the setup frame. */ - mc_setup_frm->link = - cpu_to_le32(TX_RING_ELEM_DMA(sp, (entry + 1) % TX_RING_SIZE)); - - pci_dma_sync_single_for_device(sp->pdev, mc_blk->frame_dma, - mc_blk->len, PCI_DMA_TODEVICE); - - wait_for_cmd_done(dev, sp); - clear_suspend(last_cmd); - /* Immediately trigger the command unit resume. */ - iowrite8(CUResume, ioaddr + SCBCmd); - - if ((int)(sp->cur_tx - sp->dirty_tx) >= TX_QUEUE_LIMIT) { - netif_stop_queue(dev); - sp->tx_full = 1; - } - spin_unlock_irqrestore(&sp->lock, flags); - - if (netif_msg_rx_status(sp)) - printk(" CmdMCSetup frame length %d in entry %d.\n", - dev->mc_count, entry); - } - - sp->rx_mode = new_rx_mode; -} - -#ifdef CONFIG_PM -static int eepro100_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - - pci_save_state(pdev); - - if (!netif_running(dev)) - return 0; - - del_timer_sync(&sp->timer); - - netif_device_detach(dev); - iowrite32(PortPartialReset, ioaddr + SCBPort); - - /* XXX call pci_set_power_state ()? */ - pci_disable_device(pdev); - pci_set_power_state (pdev, PCI_D3hot); - return 0; -} - -static int eepro100_resume(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = netdev_priv(dev); - void __iomem *ioaddr = sp->regs; - int rc; - - pci_set_power_state(pdev, PCI_D0); - pci_restore_state(pdev); - - rc = pci_enable_device(pdev); - if (rc) - return rc; - - pci_set_master(pdev); - - if (!netif_running(dev)) - return 0; - - /* I'm absolutely uncertain if this part of code may work. - The problems are: - - correct hardware reinitialization; - - correct driver behavior between different steps of the - reinitialization; - - serialization with other driver calls. - 2000/03/08 SAW */ - iowrite16(SCBMaskAll, ioaddr + SCBCmd); - speedo_resume(dev); - netif_device_attach(dev); - sp->rx_mode = -1; - sp->flow_ctrl = sp->partner = 0; - set_rx_mode(dev); - sp->timer.expires = RUN_AT(2*HZ); - add_timer(&sp->timer); - return 0; -} -#endif /* CONFIG_PM */ - -static void __devexit eepro100_remove_one (struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata (pdev); - struct speedo_private *sp = netdev_priv(dev); - - unregister_netdev(dev); - - release_region(pci_resource_start(pdev, 1), pci_resource_len(pdev, 1)); - release_mem_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); - - pci_iounmap(pdev, sp->regs); - pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD) - + sizeof(struct speedo_stats), - sp->tx_ring, sp->tx_ring_dma); - pci_disable_device(pdev); - free_netdev(dev); -} - -static struct pci_device_id eepro100_pci_tbl[] = { - { PCI_VENDOR_ID_INTEL, 0x1229, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1209, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1029, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1030, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1031, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1032, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1033, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1034, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1035, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1036, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1037, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1038, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1039, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103A, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103B, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103C, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103D, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103E, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1050, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1059, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1227, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x2449, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x2459, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x245D, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x5200, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x5201, PCI_ANY_ID, PCI_ANY_ID, }, - { 0,} -}; -MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl); - -static struct pci_driver eepro100_driver = { - .name = "eepro100", - .id_table = eepro100_pci_tbl, - .probe = eepro100_init_one, - .remove = __devexit_p(eepro100_remove_one), -#ifdef CONFIG_PM - .suspend = eepro100_suspend, - .resume = eepro100_resume, -#endif /* CONFIG_PM */ -}; - -static int __init eepro100_init_module(void) -{ -#ifdef MODULE - printk(version); -#endif - return pci_register_driver(&eepro100_driver); -} - -static void __exit eepro100_cleanup_module(void) -{ - pci_unregister_driver(&eepro100_driver); -} - -module_init(eepro100_init_module); -module_exit(eepro100_cleanup_module); - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -c eepro100.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c index b751c1b96cfa77e2d445e3c182a4d2003cb8de73..9ff3f2f5e3829a431b1bb6f010fa172ff005374d 100644 --- a/drivers/net/eexpress.c +++ b/drivers/net/eexpress.c @@ -967,7 +967,6 @@ static void eexp_hw_rx_pio(struct net_device *dev) insw(ioaddr+DATAPORT, skb_put(skb,pkt_len),(pkt_len+1)>>1); skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -1047,7 +1046,7 @@ static void eexp_hw_tx_pio(struct net_device *dev, unsigned short *buf, /* * Sanity check the suspected EtherExpress card * Read hardware address, reset card, size memory and initialize buffer - * memory pointers. These are held in dev->priv, in case someone has more + * memory pointers. These are held in netdev_priv(), in case someone has more * than one card in a machine. */ diff --git a/drivers/net/ehea/ehea.h b/drivers/net/ehea/ehea.h index 002d918fb4c742fc4a66af17a1d427e19959cbe0..9930d5f8b9e11b199459e69936c64a6900ffe4cb 100644 --- a/drivers/net/ehea/ehea.h +++ b/drivers/net/ehea/ehea.h @@ -40,7 +40,7 @@ #include #define DRV_NAME "ehea" -#define DRV_VERSION "EHEA_0095" +#define DRV_VERSION "EHEA_0096" /* eHEA capability flags */ #define DLPAR_PORT_ADD_REM 1 diff --git a/drivers/net/ehea/ehea_main.c b/drivers/net/ehea/ehea_main.c index 422fcb93e2c381b2b80d365244084559184dbc2f..035aa7dfc5cd867e40f72f5bd06ef2b37cb01cf1 100644 --- a/drivers/net/ehea/ehea_main.c +++ b/drivers/net/ehea/ehea_main.c @@ -728,7 +728,6 @@ static int ehea_proc_rwqes(struct net_device *dev, } ehea_proc_skb(pr, cqe, skb); - dev->last_rx = jiffies; } else { pr->p_stats.poll_receive_errors++; port_reset = ehea_treat_poll_error(pr, rq, cqe, @@ -831,7 +830,7 @@ static int ehea_poll(struct napi_struct *napi, int budget) while ((rx != budget) || force_irq) { pr->poll_counter = 0; force_irq = 0; - netif_rx_complete(dev, napi); + netif_rx_complete(napi); ehea_reset_cq_ep(pr->recv_cq); ehea_reset_cq_ep(pr->send_cq); ehea_reset_cq_n1(pr->recv_cq); @@ -860,7 +859,7 @@ static void ehea_netpoll(struct net_device *dev) int i; for (i = 0; i < port->num_def_qps; i++) - netif_rx_schedule(dev, &port->port_res[i].napi); + netif_rx_schedule(&port->port_res[i].napi); } #endif @@ -868,7 +867,7 @@ static irqreturn_t ehea_recv_irq_handler(int irq, void *param) { struct ehea_port_res *pr = param; - netif_rx_schedule(pr->port->netdev, &pr->napi); + netif_rx_schedule(&pr->napi); return IRQ_HANDLED; } diff --git a/drivers/net/ehea/ehea_qmr.c b/drivers/net/ehea/ehea_qmr.c index 9d006878f0459db1dfe30c079639638ae2025fcf..225c692b5d9928997dac0fc3f6bb41175bbca8e4 100644 --- a/drivers/net/ehea/ehea_qmr.c +++ b/drivers/net/ehea/ehea_qmr.c @@ -182,7 +182,7 @@ struct ehea_cq *ehea_create_cq(struct ehea_adapter *adapter, goto out_kill_hwq; } } else { - if ((hret != H_PAGE_REGISTERED) || (!vpage)) { + if (hret != H_PAGE_REGISTERED) { ehea_error("CQ: registration of page failed " "hret=%lx\n", hret); goto out_kill_hwq; @@ -303,7 +303,7 @@ struct ehea_eq *ehea_create_eq(struct ehea_adapter *adapter, goto out_kill_hwq; } else { - if ((hret != H_PAGE_REGISTERED) || (!vpage)) + if (hret != H_PAGE_REGISTERED) goto out_kill_hwq; } @@ -653,7 +653,7 @@ static int ehea_update_busmap(unsigned long pfn, unsigned long nr_pages, int add int top = ehea_calc_index(i, EHEA_TOP_INDEX_SHIFT); int dir = ehea_calc_index(i, EHEA_DIR_INDEX_SHIFT); int idx = i & EHEA_INDEX_MASK; - + if (add) { int ret = ehea_init_bmap(ehea_bmap, top, dir); if (ret) @@ -780,7 +780,7 @@ void ehea_destroy_busmap(void) kfree(ehea_bmap); ehea_bmap = NULL; -out_destroy: +out_destroy: mutex_unlock(&ehea_busmap_mutex); } @@ -858,10 +858,10 @@ static u64 ehea_reg_mr_sections(int top, int dir, u64 *pt, for (idx = 0; idx < EHEA_MAP_ENTRIES; idx++) { if (!ehea_bmap->top[top]->dir[dir]->ent[idx]) continue; - + hret = ehea_reg_mr_section(top, dir, idx, pt, adapter, mr); if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) - return hret; + return hret; } return hret; } @@ -879,7 +879,7 @@ static u64 ehea_reg_mr_dir_sections(int top, u64 *pt, hret = ehea_reg_mr_sections(top, dir, pt, adapter, mr); if ((hret != H_SUCCESS) && (hret != H_PAGE_REGISTERED)) - return hret; + return hret; } return hret; } @@ -893,7 +893,7 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) unsigned long top; - pt = kzalloc(PAGE_SIZE, GFP_KERNEL); + pt = (void *)get_zeroed_page(GFP_KERNEL); if (!pt) { ehea_error("no mem"); ret = -ENOMEM; @@ -937,7 +937,7 @@ int ehea_reg_kernel_mr(struct ehea_adapter *adapter, struct ehea_mr *mr) mr->adapter = adapter; ret = 0; out: - kfree(pt); + free_page((unsigned long)pt); return ret; } diff --git a/drivers/net/enc28j60.c b/drivers/net/enc28j60.c index 36cb6e95b465c2545b822d30c14a675b6bd39e07..b0ef46c51a9d556069c38ed97d0cdf3086555d6f 100644 --- a/drivers/net/enc28j60.c +++ b/drivers/net/enc28j60.c @@ -196,16 +196,32 @@ static void enc28j60_soft_reset(struct enc28j60_net *priv) */ static void enc28j60_set_bank(struct enc28j60_net *priv, u8 addr) { - if ((addr & BANK_MASK) != priv->bank) { - u8 b = (addr & BANK_MASK) >> 5; + u8 b = (addr & BANK_MASK) >> 5; - if (b != (ECON1_BSEL1 | ECON1_BSEL0)) + /* These registers (EIE, EIR, ESTAT, ECON2, ECON1) + * are present in all banks, no need to switch bank + */ + if (addr >= EIE && addr <= ECON1) + return; + + /* Clear or set each bank selection bit as needed */ + if ((b & ECON1_BSEL0) != (priv->bank & ECON1_BSEL0)) { + if (b & ECON1_BSEL0) + spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, + ECON1_BSEL0); + else spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1, - ECON1_BSEL1 | ECON1_BSEL0); - if (b != 0) - spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, b); - priv->bank = (addr & BANK_MASK); + ECON1_BSEL0); } + if ((b & ECON1_BSEL1) != (priv->bank & ECON1_BSEL1)) { + if (b & ECON1_BSEL1) + spi_write_op(priv, ENC28J60_BIT_FIELD_SET, ECON1, + ECON1_BSEL1); + else + spi_write_op(priv, ENC28J60_BIT_FIELD_CLR, ECON1, + ECON1_BSEL1); + } + priv->bank = b; } /* @@ -477,12 +493,10 @@ static int enc28j60_set_hw_macaddr(struct net_device *ndev) mutex_lock(&priv->lock); if (!priv->hw_enable) { - if (netif_msg_drv(priv)) { - DECLARE_MAC_BUF(mac); + if (netif_msg_drv(priv)) printk(KERN_INFO DRV_NAME - ": %s: Setting MAC address to %s\n", - ndev->name, print_mac(mac, ndev->dev_addr)); - } + ": %s: Setting MAC address to %pM\n", + ndev->name, ndev->dev_addr); /* NOTE: MAC address in ENC28J60 is byte-backward */ nolock_regb_write(priv, MAADR5, ndev->dev_addr[0]); nolock_regb_write(priv, MAADR4, ndev->dev_addr[1]); @@ -958,7 +972,6 @@ static void enc28j60_hw_rx(struct net_device *ndev) /* update statistics */ ndev->stats.rx_packets++; ndev->stats.rx_bytes += len; - ndev->last_rx = jiffies; netif_rx_ni(skb); } } @@ -1340,11 +1353,9 @@ static int enc28j60_net_open(struct net_device *dev) printk(KERN_DEBUG DRV_NAME ": %s() enter\n", __func__); if (!is_valid_ether_addr(dev->dev_addr)) { - if (netif_msg_ifup(priv)) { - DECLARE_MAC_BUF(mac); - dev_err(&dev->dev, "invalid MAC address %s\n", - print_mac(mac, dev->dev_addr)); - } + if (netif_msg_ifup(priv)) + dev_err(&dev->dev, "invalid MAC address %pM\n", + dev->dev_addr); return -EADDRNOTAVAIL; } /* Reset the hardware here (and take it out of low power mode) */ @@ -1465,7 +1476,7 @@ enc28j60_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) strlcpy(info->driver, DRV_NAME, sizeof(info->driver)); strlcpy(info->version, DRV_VERSION, sizeof(info->version)); strlcpy(info->bus_info, - dev->dev.parent->bus_id, sizeof(info->bus_info)); + dev_name(dev->dev.parent), sizeof(info->bus_info)); } static int diff --git a/drivers/net/enic/cq_desc.h b/drivers/net/enic/cq_desc.h index c036a8bfd04343559fb23f3b22f99c53e63d0ad0..1eb289f773bf1b32880908d8199da790423ea13d 100644 --- a/drivers/net/enic/cq_desc.h +++ b/drivers/net/enic/cq_desc.h @@ -44,9 +44,10 @@ struct cq_desc { u8 type_color; }; -#define CQ_DESC_TYPE_BITS 7 +#define CQ_DESC_TYPE_BITS 4 #define CQ_DESC_TYPE_MASK ((1 << CQ_DESC_TYPE_BITS) - 1) #define CQ_DESC_COLOR_MASK 1 +#define CQ_DESC_COLOR_SHIFT 7 #define CQ_DESC_Q_NUM_BITS 10 #define CQ_DESC_Q_NUM_MASK ((1 << CQ_DESC_Q_NUM_BITS) - 1) #define CQ_DESC_COMP_NDX_BITS 12 @@ -58,7 +59,7 @@ static inline void cq_desc_dec(const struct cq_desc *desc_arg, const struct cq_desc *desc = desc_arg; const u8 type_color = desc->type_color; - *color = (type_color >> CQ_DESC_TYPE_BITS) & CQ_DESC_COLOR_MASK; + *color = (type_color >> CQ_DESC_COLOR_SHIFT) & CQ_DESC_COLOR_MASK; /* * Make sure color bit is read from desc *before* other fields diff --git a/drivers/net/enic/enic.h b/drivers/net/enic/enic.h index 7f677e89a78875311c5b7a51b09ec14349079770..a832cc5d6a1e3c9061b290f393adeaa897504508 100644 --- a/drivers/net/enic/enic.h +++ b/drivers/net/enic/enic.h @@ -33,7 +33,7 @@ #define DRV_NAME "enic" #define DRV_DESCRIPTION "Cisco 10G Ethernet Driver" -#define DRV_VERSION "0.0.1-18163.472-k1" +#define DRV_VERSION "1.0.0.648" #define DRV_COPYRIGHT "Copyright 2008 Cisco Systems, Inc" #define PFX DRV_NAME ": " diff --git a/drivers/net/enic/enic_main.c b/drivers/net/enic/enic_main.c index 180e968dc54d87401eaa174c30a724223425d4bf..d039e16f276355a1552e4b6be6a7aecdf1bd0b66 100644 --- a/drivers/net/enic/enic_main.c +++ b/drivers/net/enic/enic_main.c @@ -273,6 +273,8 @@ static struct ethtool_ops enic_ethtool_ops = { .set_sg = ethtool_op_set_sg, .get_tso = ethtool_op_get_tso, .set_tso = enic_set_tso, + .get_flags = ethtool_op_get_flags, + .set_flags = ethtool_op_set_flags, }; static void enic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) @@ -409,8 +411,8 @@ static irqreturn_t enic_isr_legacy(int irq, void *data) } if (ENIC_TEST_INTR(pba, ENIC_INTX_WQ_RQ)) { - if (netif_rx_schedule_prep(netdev, &enic->napi)) - __netif_rx_schedule(netdev, &enic->napi); + if (netif_rx_schedule_prep(&enic->napi)) + __netif_rx_schedule(&enic->napi); } else { vnic_intr_unmask(&enic->intr[ENIC_INTX_WQ_RQ]); } @@ -438,7 +440,7 @@ static irqreturn_t enic_isr_msi(int irq, void *data) * writes). */ - netif_rx_schedule(enic->netdev, &enic->napi); + netif_rx_schedule(&enic->napi); return IRQ_HANDLED; } @@ -448,7 +450,7 @@ static irqreturn_t enic_isr_msix_rq(int irq, void *data) struct enic *enic = data; /* schedule NAPI polling for RQ cleanup */ - netif_rx_schedule(enic->netdev, &enic->napi); + netif_rx_schedule(&enic->napi); return IRQ_HANDLED; } @@ -895,6 +897,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, int skipped, void *opaque) { struct enic *enic = vnic_dev_priv(rq->vdev); + struct net_device *netdev = enic->netdev; struct sk_buff *skb; u8 type, color, eop, sop, ingress_port, vlan_stripped; @@ -929,7 +932,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, if (net_ratelimit()) printk(KERN_ERR PFX "%s: packet error: bad FCS\n", - enic->netdev->name); + netdev->name); } dev_kfree_skb_any(skb); @@ -943,19 +946,18 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, */ skb_put(skb, bytes_written); - skb->protocol = eth_type_trans(skb, enic->netdev); + skb->protocol = eth_type_trans(skb, netdev); if (enic->csum_rx_enabled && !csum_not_calc) { skb->csum = htons(checksum); skb->ip_summed = CHECKSUM_COMPLETE; } - skb->dev = enic->netdev; - enic->netdev->last_rx = jiffies; + skb->dev = netdev; if (enic->vlan_group && vlan_stripped) { - if (ENIC_SETTING(enic, LRO) && ipv4) + if ((netdev->features & NETIF_F_LRO) && ipv4) lro_vlan_hwaccel_receive_skb(&enic->lro_mgr, skb, enic->vlan_group, vlan, cq_desc); @@ -965,7 +967,7 @@ static void enic_rq_indicate_buf(struct vnic_rq *rq, } else { - if (ENIC_SETTING(enic, LRO) && ipv4) + if ((netdev->features & NETIF_F_LRO) && ipv4) lro_receive_skb(&enic->lro_mgr, skb, cq_desc); else netif_receive_skb(skb); @@ -1063,10 +1065,10 @@ static int enic_poll(struct napi_struct *napi, int budget) /* If no work done, flush all LROs and exit polling */ - if (ENIC_SETTING(enic, LRO)) + if (netdev->features & NETIF_F_LRO) lro_flush_all(&enic->lro_mgr); - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]); } @@ -1107,10 +1109,10 @@ static int enic_poll_msix(struct napi_struct *napi, int budget) /* If no work done, flush all LROs and exit polling */ - if (ENIC_SETTING(enic, LRO)) + if (netdev->features & NETIF_F_LRO) lro_flush_all(&enic->lro_mgr); - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); vnic_intr_unmask(&enic->intr[ENIC_MSIX_RQ]); } @@ -1591,6 +1593,23 @@ static void enic_iounmap(struct enic *enic) iounmap(enic->bar0.vaddr); } +static const struct net_device_ops enic_netdev_ops = { + .ndo_open = enic_open, + .ndo_stop = enic_stop, + .ndo_start_xmit = enic_hard_start_xmit, + .ndo_get_stats = enic_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = enic_set_multicast_list, + .ndo_change_mtu = enic_change_mtu, + .ndo_vlan_rx_register = enic_vlan_rx_register, + .ndo_vlan_rx_add_vid = enic_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = enic_vlan_rx_kill_vid, + .ndo_tx_timeout = enic_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = enic_poll_controller, +#endif +}; + static int __devinit enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1746,13 +1765,13 @@ static int __devinit enic_probe(struct pci_dev *pdev, } /* Get available resource counts - */ + */ enic_get_res_counts(enic); /* Set interrupt mode based on resource counts and system * capabilities - */ + */ err = enic_set_intr_mode(enic); if (err) { @@ -1814,21 +1833,9 @@ static int __devinit enic_probe(struct pci_dev *pdev, goto err_out_free_vnic_resources; } - netdev->open = enic_open; - netdev->stop = enic_stop; - netdev->hard_start_xmit = enic_hard_start_xmit; - netdev->get_stats = enic_get_stats; - netdev->set_multicast_list = enic_set_multicast_list; - netdev->change_mtu = enic_change_mtu; - netdev->vlan_rx_register = enic_vlan_rx_register; - netdev->vlan_rx_add_vid = enic_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = enic_vlan_rx_kill_vid; - netdev->tx_timeout = enic_tx_timeout; + netdev->netdev_ops = &enic_netdev_ops; netdev->watchdog_timeo = 2 * HZ; netdev->ethtool_ops = &enic_ethtool_ops; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = enic_poll_controller; -#endif switch (vnic_dev_get_intr_mode(enic->vdev)) { default: @@ -1845,22 +1852,23 @@ static int __devinit enic_probe(struct pci_dev *pdev, if (ENIC_SETTING(enic, TSO)) netdev->features |= NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_TSO_ECN; + if (ENIC_SETTING(enic, LRO)) + netdev->features |= NETIF_F_LRO; if (using_dac) netdev->features |= NETIF_F_HIGHDMA; enic->csum_rx_enabled = ENIC_SETTING(enic, RXCSUM); - if (ENIC_SETTING(enic, LRO)) { - enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR; - enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC; - enic->lro_mgr.lro_arr = enic->lro_desc; - enic->lro_mgr.get_skb_header = enic_get_skb_header; - enic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; - enic->lro_mgr.dev = netdev; - enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE; - enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; - } + enic->lro_mgr.max_aggr = ENIC_LRO_MAX_AGGR; + enic->lro_mgr.max_desc = ENIC_LRO_MAX_DESC; + enic->lro_mgr.lro_arr = enic->lro_desc; + enic->lro_mgr.get_skb_header = enic_get_skb_header; + enic->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; + enic->lro_mgr.dev = netdev; + enic->lro_mgr.ip_summed = CHECKSUM_COMPLETE; + enic->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; + err = register_netdev(netdev); if (err) { diff --git a/drivers/net/enic/enic_res.c b/drivers/net/enic/enic_res.c index 95184b9108ef18fec0bbffda0518c4b9754c64c8..e5fc9384f8f51891eefe153fdab71ca7fa7b98c7 100644 --- a/drivers/net/enic/enic_res.c +++ b/drivers/net/enic/enic_res.c @@ -90,11 +90,8 @@ int enic_get_vnic_config(struct enic *enic) c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); - printk(KERN_INFO PFX "vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x " - "wq/rq %d/%d\n", - enic->mac_addr[0], enic->mac_addr[1], enic->mac_addr[2], - enic->mac_addr[3], enic->mac_addr[4], enic->mac_addr[5], - c->wq_desc_count, c->rq_desc_count); + printk(KERN_INFO PFX "vNIC MAC addr %pM wq/rq %d/%d\n", + enic->mac_addr, c->wq_desc_count, c->rq_desc_count); printk(KERN_INFO PFX "vNIC mtu %d csum tx/rx %d/%d tso/lro %d/%d " "intr timer %d\n", c->mtu, ENIC_SETTING(enic, TXCSUM), diff --git a/drivers/net/enic/enic_res.h b/drivers/net/enic/enic_res.h index 68534a29b7ace04487be5e1608d24f8619771ac0..7bf272fa859b32ea530911573ce8450c8e7fc607 100644 --- a/drivers/net/enic/enic_res.h +++ b/drivers/net/enic/enic_res.h @@ -58,8 +58,6 @@ static inline void enic_queue_wq_desc_ex(struct vnic_wq *wq, (u16)vlan_tag, 0 /* loopback */); - wmb(); - vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop); } @@ -127,8 +125,6 @@ static inline void enic_queue_rq_desc(struct vnic_rq *rq, (u64)dma_addr | VNIC_PADDR_TARGET, type, (u16)len); - wmb(); - vnic_rq_post(rq, os_buf, os_buf_index, dma_addr, len); } diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c index 4d104f5c30f97b454880dfaefb147c12656de09a..11708579b6ce7c5bfd8143234bea6c1122cb1748 100644 --- a/drivers/net/enic/vnic_dev.c +++ b/drivers/net/enic/vnic_dev.c @@ -43,6 +43,7 @@ struct vnic_dev { struct vnic_devcmd_notify *notify; struct vnic_devcmd_notify notify_copy; dma_addr_t notify_pa; + u32 notify_sz; u32 *linkstatus; dma_addr_t linkstatus_pa; struct vnic_stats *stats; @@ -235,14 +236,6 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, struct vnic_devcmd __iomem *devcmd = vdev->devcmd; int delay; u32 status; - int dev_cmd_err[] = { - /* convert from fw's version of error.h to host's version */ - 0, /* ERR_SUCCESS */ - EINVAL, /* ERR_EINVAL */ - EFAULT, /* ERR_EFAULT */ - EPERM, /* ERR_EPERM */ - EBUSY, /* ERR_EBUSY */ - }; int err; status = ioread32(&devcmd->status); @@ -270,10 +263,12 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, if (!(status & STAT_BUSY)) { if (status & STAT_ERROR) { - err = dev_cmd_err[(int)readq(&devcmd->args[0])]; - printk(KERN_ERR "Error %d devcmd %d\n", - err, _CMD_N(cmd)); - return -err; + err = (int)readq(&devcmd->args[0]); + if (err != ERR_ECMDUNKNOWN || + cmd != CMD_CAPABILITY) + printk(KERN_ERR "Error %d devcmd %d\n", + err, _CMD_N(cmd)); + return err; } if (_CMD_DIR(cmd) & _CMD_DIR_READ) { @@ -290,6 +285,17 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, return -ETIMEDOUT; } +static int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd) +{ + u64 a0 = (u32)cmd, a1 = 0; + int wait = 1000; + int err; + + err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait); + + return !(err || a0); +} + int vnic_dev_fw_info(struct vnic_dev *vdev, struct vnic_devcmd_fw_info **fw_info) { @@ -489,10 +495,7 @@ void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); if (err) - printk(KERN_ERR - "Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], - err); + printk(KERN_ERR "Can't add addr [%pM], %d\n", addr, err); } void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) @@ -507,16 +510,14 @@ void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); if (err) - printk(KERN_ERR - "Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], - err); + printk(KERN_ERR "Can't del addr [%pM], %d\n", addr, err); } int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) { u64 a0, a1; int wait = 1000; + int r; if (!vdev->notify) { vdev->notify = pci_alloc_consistent(vdev->pdev, @@ -524,13 +525,16 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) &vdev->notify_pa); if (!vdev->notify) return -ENOMEM; + memset(vdev->notify, 0, sizeof(struct vnic_devcmd_notify)); } a0 = vdev->notify_pa; a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL; a1 += sizeof(struct vnic_devcmd_notify); - return vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); + r = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); + vdev->notify_sz = (r == 0) ? (u32)a1 : 0; + return r; } void vnic_dev_notify_unset(struct vnic_dev *vdev) @@ -543,22 +547,22 @@ void vnic_dev_notify_unset(struct vnic_dev *vdev) a1 += sizeof(struct vnic_devcmd_notify); vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); + vdev->notify_sz = 0; } static int vnic_dev_notify_ready(struct vnic_dev *vdev) { u32 *words; - unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4; + unsigned int nwords = vdev->notify_sz / 4; unsigned int i; u32 csum; - if (!vdev->notify) + if (!vdev->notify || !vdev->notify_sz) return 0; do { csum = 0; - memcpy(&vdev->notify_copy, vdev->notify, - sizeof(struct vnic_devcmd_notify)); + memcpy(&vdev->notify_copy, vdev->notify, vdev->notify_sz); words = (u32 *)&vdev->notify_copy; for (i = 1; i < nwords; i++) csum += words[i]; @@ -571,7 +575,20 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg) { u64 a0 = (u32)arg, a1 = 0; int wait = 1000; - return vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); + int r = 0; + + if (vnic_dev_capable(vdev, CMD_INIT)) + r = vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); + else { + vnic_dev_cmd(vdev, CMD_INIT_v1, &a0, &a1, wait); + if (a0 & CMD_INITF_DEFAULT_MAC) { + // Emulate these for old CMD_INIT_v1 which + // didn't pass a0 so no CMD_INITF_*. + vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait); + vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); + } + } + return r; } int vnic_dev_link_status(struct vnic_dev *vdev) @@ -672,3 +689,4 @@ err_out: return NULL; } + diff --git a/drivers/net/enic/vnic_devcmd.h b/drivers/net/enic/vnic_devcmd.h index d8617a3373b14aa1c4b952204607df4344888b79..8062c75154e60d83098aa61293ec338931b7614f 100644 --- a/drivers/net/enic/vnic_devcmd.h +++ b/drivers/net/enic/vnic_devcmd.h @@ -168,7 +168,8 @@ enum vnic_devcmd_cmd { CMD_CLOSE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 25), /* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */ - CMD_INIT = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26), +/***** Replaced by CMD_INIT *****/ + CMD_INIT_v1 = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26), /* variant of CMD_INIT, with provisioning info * (u64)a0=paddr of vnic_devcmd_provinfo @@ -198,6 +199,14 @@ enum vnic_devcmd_cmd { /* undo initialize of virtual link */ CMD_DEINIT = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 34), + + /* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */ + CMD_INIT = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 35), + + /* check fw capability of a cmd: + * in: (u32)a0=cmd + * out: (u32)a0=errno, 0:valid cmd, a1=supported VNIC_STF_* bits */ + CMD_CAPABILITY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 36), }; /* flags for CMD_OPEN */ @@ -249,8 +258,16 @@ struct vnic_devcmd_notify { u32 uif; /* uplink interface */ u32 status; /* status bits (see VNIC_STF_*) */ u32 error; /* error code (see ERR_*) for first ERR */ + u32 link_down_cnt; /* running count of link down transitions */ }; #define VNIC_STF_FATAL_ERR 0x0001 /* fatal fw error */ +#define VNIC_STF_STD_PAUSE 0x0002 /* standard link-level pause on */ +#define VNIC_STF_PFC_PAUSE 0x0004 /* priority flow control pause on */ +/* all supported status flags */ +#define VNIC_STF_ALL (VNIC_STF_FATAL_ERR |\ + VNIC_STF_STD_PAUSE |\ + VNIC_STF_PFC_PAUSE |\ + 0) struct vnic_devcmd_provinfo { u8 oui[3]; diff --git a/drivers/net/enic/vnic_intr.h b/drivers/net/enic/vnic_intr.h index ccc408116af89b07bd1bf500b2a7d124746059e0..ce633a5a7e3c4d7924c43858942fc833257ef50b 100644 --- a/drivers/net/enic/vnic_intr.h +++ b/drivers/net/enic/vnic_intr.h @@ -78,7 +78,7 @@ static inline void vnic_intr_return_credits(struct vnic_intr *intr, static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba) { - /* get and ack interrupt in one read (clear-and-ack-on-read) */ + /* read PBA without clearing */ return ioread32(legacy_pba); } diff --git a/drivers/net/enic/vnic_resource.h b/drivers/net/enic/vnic_resource.h index 144d2812f081082a2b9d294992d97b1053e14849..b61c22aec41a65968c887fa800b7062bf59dd254 100644 --- a/drivers/net/enic/vnic_resource.h +++ b/drivers/net/enic/vnic_resource.h @@ -38,7 +38,7 @@ enum vnic_res_type { RES_TYPE_INTR_CTRL, /* Interrupt ctrl table */ RES_TYPE_INTR_TABLE, /* MSI/MSI-X Interrupt table */ RES_TYPE_INTR_PBA, /* MSI/MSI-X PBA table */ - RES_TYPE_INTR_PBA_LEGACY, /* Legacy intr status, r2c */ + RES_TYPE_INTR_PBA_LEGACY, /* Legacy intr status */ RES_TYPE_RSVD6, RES_TYPE_RSVD7, RES_TYPE_DEVCMD, /* Device command region */ diff --git a/drivers/net/enic/vnic_rq.h b/drivers/net/enic/vnic_rq.h index 82bfca67cc4d18cac256fa61d01fe90b013f5d1b..fd0ef66d2e9f5cfb66d1fe9e0f15858b8da056c6 100644 --- a/drivers/net/enic/vnic_rq.h +++ b/drivers/net/enic/vnic_rq.h @@ -132,8 +132,15 @@ static inline void vnic_rq_post(struct vnic_rq *rq, #define VNIC_RQ_RETURN_RATE 0xf /* keep 2^n - 1 */ #endif - if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) + if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) { + /* Adding write memory barrier prevents compiler and/or CPU + * reordering, thus avoiding descriptor posting before + * descriptor is initialized. Otherwise, hardware can read + * stale descriptor fields. + */ + wmb(); iowrite32(buf->index, &rq->ctrl->posted_index); + } } static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) diff --git a/drivers/net/enic/vnic_rss.h b/drivers/net/enic/vnic_rss.h index e325d65d7c34b4d70684b6f5cccb10ef97c06241..5fbb3c923bcd6a0610bacda69cdc7694d4b507b4 100644 --- a/drivers/net/enic/vnic_rss.h +++ b/drivers/net/enic/vnic_rss.h @@ -1,6 +1,19 @@ /* * Copyright 2008 Cisco Systems, Inc. All rights reserved. * Copyright 2007 Nuova Systems, Inc. All rights reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. */ #ifndef _VNIC_RSS_H_ diff --git a/drivers/net/enic/vnic_wq.h b/drivers/net/enic/vnic_wq.h index 7081828d8a42bd98a8ed7bdacf1cc1254da63b9f..c826137dc6517c2d9d5c5bcef23c45b063659f37 100644 --- a/drivers/net/enic/vnic_wq.h +++ b/drivers/net/enic/vnic_wq.h @@ -108,8 +108,15 @@ static inline void vnic_wq_post(struct vnic_wq *wq, buf->len = len; buf = buf->next; - if (eop) + if (eop) { + /* Adding write memory barrier prevents compiler and/or CPU + * reordering, thus avoiding descriptor posting before + * descriptor is initialized. Otherwise, hardware can read + * stale descriptor fields. + */ + wmb(); iowrite32(buf->index, &wq->ctrl->posted_index); + } wq->to_use = buf; wq->ring.desc_avail--; diff --git a/drivers/net/epic100.c b/drivers/net/epic100.c index 76118ddd104272f82f194746739ceacbb102c017..f9b37c80dda61f7eb84ca32a26dc93789d57c678 100644 --- a/drivers/net/epic100.c +++ b/drivers/net/epic100.c @@ -322,7 +322,6 @@ static int __devinit epic_init_one (struct pci_dev *pdev, int i, ret, option = 0, duplex = 0; void *ring_space; dma_addr_t ring_dma; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -364,7 +363,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, ioaddr = pci_resource_start (pdev, 0); #else ioaddr = pci_resource_start (pdev, 1); - ioaddr = (long) ioremap (ioaddr, pci_resource_len (pdev, 1)); + ioaddr = (long) pci_ioremap_bar(pdev, 1); if (!ioaddr) { dev_err(&pdev->dev, "ioremap failed\n"); goto err_out_free_netdev; @@ -372,7 +371,7 @@ static int __devinit epic_init_one (struct pci_dev *pdev, #endif pci_set_drvdata(pdev, dev); - ep = dev->priv; + ep = netdev_priv(dev); ep->mii.dev = dev; ep->mii.mdio_read = mdio_read; ep->mii.mdio_write = mdio_write; @@ -499,9 +498,9 @@ static int __devinit epic_init_one (struct pci_dev *pdev, if (ret < 0) goto err_out_unmap_rx; - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n", + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %pM\n", dev->name, pci_id_tbl[chip_idx].name, ioaddr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); out: return ret; @@ -655,7 +654,7 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int value) static int epic_open(struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; int i; int retval; @@ -767,7 +766,7 @@ static int epic_open(struct net_device *dev) static void epic_pause(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); netif_stop_queue (dev); @@ -790,7 +789,7 @@ static void epic_pause(struct net_device *dev) static void epic_restart(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); int i; /* Soft reset the chip. */ @@ -842,7 +841,7 @@ static void epic_restart(struct net_device *dev) static void check_media(struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; int mii_lpa = ep->mii_phy_cnt ? mdio_read(dev, ep->phys[0], MII_LPA) : 0; int negotiated = mii_lpa & ep->mii.advertising; @@ -864,7 +863,7 @@ static void check_media(struct net_device *dev) static void epic_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; int next_tick = 5*HZ; @@ -885,7 +884,7 @@ static void epic_timer(unsigned long data) static void epic_tx_timeout(struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; if (debug > 0) { @@ -914,7 +913,7 @@ static void epic_tx_timeout(struct net_device *dev) /* Initialize the Rx and Tx rings, along with various 'dev' bits. */ static void epic_init_ring(struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); int i; ep->tx_full = 0; @@ -960,7 +959,7 @@ static void epic_init_ring(struct net_device *dev) static int epic_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); int entry, free_count; u32 ctrl_word; unsigned long flags; @@ -1088,7 +1087,7 @@ static void epic_tx(struct net_device *dev, struct epic_private *ep) static irqreturn_t epic_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; unsigned int handled = 0; int status; @@ -1110,9 +1109,9 @@ static irqreturn_t epic_interrupt(int irq, void *dev_instance) if ((status & EpicNapiEvent) && !ep->reschedule_in_poll) { spin_lock(&ep->napi_lock); - if (netif_rx_schedule_prep(dev, &ep->napi)) { + if (netif_rx_schedule_prep(&ep->napi)) { epic_napi_irq_off(dev, ep); - __netif_rx_schedule(dev, &ep->napi); + __netif_rx_schedule(&ep->napi); } else ep->reschedule_in_poll++; spin_unlock(&ep->napi_lock); @@ -1156,7 +1155,7 @@ out: static int epic_rx(struct net_device *dev, int budget) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); int entry = ep->cur_rx % RX_RING_SIZE; int rx_work_limit = ep->dirty_rx + RX_RING_SIZE - ep->cur_rx; int work_done = 0; @@ -1223,7 +1222,6 @@ static int epic_rx(struct net_device *dev, int budget) } skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; ep->stats.rx_packets++; ep->stats.rx_bytes += pkt_len; } @@ -1290,7 +1288,7 @@ rx_action: more = ep->reschedule_in_poll; if (!more) { - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); outl(EpicNapiEvent, ioaddr + INTSTAT); epic_napi_irq_on(dev, ep); } else @@ -1308,7 +1306,7 @@ rx_action: static int epic_close(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); struct sk_buff *skb; int i; @@ -1358,7 +1356,7 @@ static int epic_close(struct net_device *dev) static struct net_device_stats *epic_get_stats(struct net_device *dev) { - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); long ioaddr = dev->base_addr; if (netif_running(dev)) { @@ -1379,7 +1377,7 @@ static struct net_device_stats *epic_get_stats(struct net_device *dev) static void set_rx_mode(struct net_device *dev) { long ioaddr = dev->base_addr; - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); unsigned char mc_filter[8]; /* Multicast hash filter */ int i; @@ -1418,7 +1416,7 @@ static void set_rx_mode(struct net_device *dev) static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo *info) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); strcpy (info->driver, DRV_NAME); strcpy (info->version, DRV_VERSION); @@ -1427,7 +1425,7 @@ static void netdev_get_drvinfo (struct net_device *dev, struct ethtool_drvinfo * static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); int rc; spin_lock_irq(&np->lock); @@ -1439,7 +1437,7 @@ static int netdev_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); int rc; spin_lock_irq(&np->lock); @@ -1451,13 +1449,13 @@ static int netdev_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int netdev_nway_reset(struct net_device *dev) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); return mii_nway_restart(&np->mii); } static u32 netdev_get_link(struct net_device *dev) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); return mii_link_ok(&np->mii); } @@ -1506,7 +1504,7 @@ static const struct ethtool_ops netdev_ethtool_ops = { static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { - struct epic_private *np = dev->priv; + struct epic_private *np = netdev_priv(dev); long ioaddr = dev->base_addr; struct mii_ioctl_data *data = if_mii(rq); int rc; @@ -1534,7 +1532,7 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static void __devexit epic_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct epic_private *ep = dev->priv; + struct epic_private *ep = netdev_priv(dev); pci_free_consistent(pdev, TX_TOTAL_SIZE, ep->tx_ring, ep->tx_ring_dma); pci_free_consistent(pdev, RX_TOTAL_SIZE, ep->rx_ring, ep->rx_ring_dma); diff --git a/drivers/net/eql.c b/drivers/net/eql.c index 18f1364d3d5bfeb25c94e30572cb98115fbf7af9..40125694bd9f641209eb03fb90a04e8ad4d99998 100644 --- a/drivers/net/eql.c +++ b/drivers/net/eql.c @@ -162,6 +162,13 @@ static void eql_timer(unsigned long param) static char version[] __initdata = "Equalizer2002: Simon Janes (simon@ncm.com) and David S. Miller (davem@redhat.com)\n"; +static const struct net_device_ops eql_netdev_ops = { + .ndo_open = eql_open, + .ndo_stop = eql_close, + .ndo_do_ioctl = eql_ioctl, + .ndo_start_xmit = eql_slave_xmit, +}; + static void __init eql_setup(struct net_device *dev) { equalizer_t *eql = netdev_priv(dev); @@ -175,10 +182,7 @@ static void __init eql_setup(struct net_device *dev) INIT_LIST_HEAD(&eql->queue.all_slaves); eql->queue.master_dev = dev; - dev->open = eql_open; - dev->stop = eql_close; - dev->do_ioctl = eql_ioctl; - dev->hard_start_xmit = eql_slave_xmit; + dev->netdev_ops = &eql_netdev_ops; /* * Now we undo some of the things that eth_setup does diff --git a/drivers/net/es3210.c b/drivers/net/es3210.c index deefa51b8c31b652cdbbc1509dfcb6d006f0d915..5569f2ffb62cbc2814df1012e11f5ff7e1995727 100644 --- a/drivers/net/es3210.c +++ b/drivers/net/es3210.c @@ -64,9 +64,6 @@ static const char version[] = static int es_probe1(struct net_device *dev, int ioaddr); -static int es_open(struct net_device *dev); -static int es_close(struct net_device *dev); - static void es_reset_8390(struct net_device *dev); static void es_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -179,7 +176,6 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) { int i, retval; unsigned long eisa_id; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr + ES_SA_PROM, ES_IO_EXTENT, "es3210")) return -ENODEV; @@ -205,14 +201,14 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) if (dev->dev_addr[0] != ES_ADDR0 || dev->dev_addr[1] != ES_ADDR1 || dev->dev_addr[2] != ES_ADDR2) { - printk("es3210.c: card not found %s (invalid_prefix).\n", - print_mac(mac, dev->dev_addr)); + printk("es3210.c: card not found %pM (invalid_prefix).\n", + dev->dev_addr); retval = -ENODEV; goto out; } - printk("es3210.c: ES3210 rev. %ld at %#x, node %s", - eisa_id>>24, ioaddr, print_mac(mac, dev->dev_addr)); + printk("es3210.c: ES3210 rev. %ld at %#x, node %pM", + eisa_id>>24, ioaddr, dev->dev_addr); /* Snarf the interrupt now. */ if (dev->irq == 0) { @@ -290,11 +286,7 @@ static int __init es_probe1(struct net_device *dev, int ioaddr) ei_status.block_output = &es_block_output; ei_status.get_8390_hdr = &es_get_8390_hdr; - dev->open = &es_open; - dev->stop = &es_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + dev->netdev_ops = &ei_netdev_ops; NS8390_init(dev, 0); retval = register_netdev(dev); @@ -386,22 +378,6 @@ static void es_block_output(struct net_device *dev, int count, memcpy_toio(shmem, buf, count); } -static int es_open(struct net_device *dev) -{ - ei_open(dev); - return 0; -} - -static int es_close(struct net_device *dev) -{ - - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - - ei_close(dev); - return 0; -} - #ifdef MODULE #define MAX_ES_CARDS 4 /* Max number of ES3210 cards per module */ #define NAMELEN 8 /* # of chars for storing dev->name */ diff --git a/drivers/net/eth16i.c b/drivers/net/eth16i.c index bee8b3fbc56591c9d8f493ae2295dba5ba849793..5c048f2fd74f856bb4e3ef65a07d54376aa18eb6 100644 --- a/drivers/net/eth16i.c +++ b/drivers/net/eth16i.c @@ -1205,7 +1205,6 @@ static void eth16i_rx(struct net_device *dev) printk(KERN_DEBUG ".\n"); } netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; @@ -1466,7 +1465,7 @@ void __exit cleanup_module(void) for(this_dev = 0; this_dev < MAX_ETH16I_CARDS; this_dev++) { struct net_device *dev = dev_eth16i[this_dev]; - if(dev->priv) { + if (netdev_priv(dev)) { unregister_netdev(dev); free_irq(dev->irq, dev); release_region(dev->base_addr, ETH16I_IO_EXTENT); @@ -1475,15 +1474,3 @@ void __exit cleanup_module(void) } } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c eth16i.c" - * alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict -prototypes -O6 -c eth16i.c" - * tab-width: 8 - * c-basic-offset: 8 - * c-indent-level: 8 - * End: - */ - -/* End of file eth16i.c */ diff --git a/drivers/net/ewrk3.c b/drivers/net/ewrk3.c index 593a120e31b2bdc406dd8e3e6cfd8aeca27d1798..b852303c9362a8a3f5c1888624a7d23edd4d2cb5 100644 --- a/drivers/net/ewrk3.c +++ b/drivers/net/ewrk3.c @@ -396,7 +396,6 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase) u_long mem_start, shmem_length; u_char cr, cmr, icr, nicsr, lemac, hard_strapped = 0; u_char eeprom_image[EEPROM_MAX], chksum, eisa_cr = 0; - DECLARE_MAC_BUF(mac); /* ** Stop the EWRK3. Enable the DBR ROM. Disable interrupts and remote boot. @@ -461,7 +460,7 @@ ewrk3_hw_init(struct net_device *dev, u_long iobase) if (lemac != LeMAC2) DevicePresent(iobase); /* need after EWRK3_INIT */ status = get_hw_addr(dev, eeprom_image, lemac); - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); if (status) { printk(" which has an EEPROM CRC error.\n"); @@ -646,10 +645,8 @@ static int ewrk3_open(struct net_device *dev) ewrk3_init(dev); if (ewrk3_debug > 1) { - DECLARE_MAC_BUF(mac); printk("%s: ewrk3 open with irq %d\n", dev->name, dev->irq); - printk(" physical address: %s\n", - print_mac(mac, dev->dev_addr)); + printk(" physical address: %pM\n", dev->dev_addr); if (lp->shmem_length == 0) { printk(" no shared memory, I/O only mode\n"); } else { @@ -1029,7 +1026,6 @@ static int ewrk3_rx(struct net_device *dev) /* ** Update stats */ - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } else { @@ -1971,13 +1967,3 @@ module_exit(ewrk3_exit_module); module_init(ewrk3_init_module); #endif /* MODULE */ MODULE_LICENSE("GPL"); - - - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c ewrk3.c" - * - * compile-command: "gcc -D__KERNEL__ -DMODULE -I/linux/include -Wall -Wstrict-prototypes -fomit-frame-pointer -fno-strength-reduce -malign-loops=2 -malign-jumps=2 -malign-functions=2 -O2 -m486 -c ewrk3.c" - * End: - */ diff --git a/drivers/net/fealnx.c b/drivers/net/fealnx.c index b455ae931f7ac3f76d4efa6d506269f77a3c111c..31ab1ff623fcfca4575939569dfdeb79dc6dd218 100644 --- a/drivers/net/fealnx.c +++ b/drivers/net/fealnx.c @@ -486,7 +486,6 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, #else int bar = 1; #endif - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -665,9 +664,9 @@ static int __devinit fealnx_init_one(struct pci_dev *pdev, if (err) goto err_out_free_tx; - printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", dev->name, skel_netdrv_tbl[chip_id].chip_name, ioaddr, - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); return 0; @@ -1727,7 +1726,6 @@ static int netdev_rx(struct net_device *dev) } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/fec.c b/drivers/net/fec.c index ecd5c71a7a8a5f6470f7362a051434f61529e5b3..7e33c129d51cb4d936fa16ea146b55721fa660ce 100644 --- a/drivers/net/fec.c +++ b/drivers/net/fec.c @@ -1155,7 +1155,7 @@ static phy_info_t const phy_info_ks8721bl = { static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev) { - struct fec_enet_private *fep = dev->priv; + struct fec_enet_private *fep = netdev_priv(dev); volatile uint *s = &(fep->phy_status); *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC); @@ -2562,7 +2562,6 @@ static int __init fec_enet_module_init(void) { struct net_device *dev; int i, err; - DECLARE_MAC_BUF(mac); printk("FEC ENET Version 0.2\n"); @@ -2581,8 +2580,7 @@ static int __init fec_enet_module_init(void) return -EIO; } - printk("%s: ethernet %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: ethernet %pM\n", dev->name, dev->dev_addr); } return 0; } diff --git a/drivers/net/fec_mpc52xx.c b/drivers/net/fec_mpc52xx.c index aec3b97e794d865d9de5373e6a45c072069ad6f6..cd8e98b45ec50d9e253dcc9251ce8e62f8703ab6 100644 --- a/drivers/net/fec_mpc52xx.c +++ b/drivers/net/fec_mpc52xx.c @@ -216,7 +216,7 @@ static int mpc52xx_fec_init_phy(struct net_device *dev) struct phy_device *phydev; char phy_id[BUS_ID_SIZE]; - snprintf(phy_id, BUS_ID_SIZE, "%x:%02x", + snprintf(phy_id, sizeof(phy_id), "%x:%02x", (unsigned int)dev->base_addr, priv->phy_addr); priv->link = PHY_DOWN; @@ -487,7 +487,6 @@ static irqreturn_t mpc52xx_fec_rx_interrupt(int irq, void *dev_id) rskb->protocol = eth_type_trans(rskb, dev); netif_rx(rskb); - dev->last_rx = jiffies; } else { /* Can't get a new one : reuse the same & drop pkt */ dev_notice(&dev->dev, "Memory squeeze, dropping packet.\n"); diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index cc7328b1552136f0fa7c8e8f5587b61e110f216b..5b68dc20168db466a867f63e44823e500568e837 100644 --- a/drivers/net/forcedeth.c +++ b/drivers/net/forcedeth.c @@ -712,12 +712,12 @@ struct nv_skb_map { /* * SMP locking: - * All hardware access under dev->priv->lock, except the performance + * All hardware access under netdev_priv(dev)->lock, except the performance * critical parts: * - rx is (pseudo-) lockless: it relies on the single-threading provided * by the arch code for interrupts. * - tx setup is lockless: it relies on netif_tx_lock. Actual submission - * needs dev->priv->lock :-( + * needs netdev_priv(dev)->lock :-( * - set_multicast_list: preparation lockless, relies on netif_tx_lock. */ @@ -818,7 +818,7 @@ struct fe_priv { * Maximum number of loops until we assume that a bit in the irq mask * is stuck. Overridable with module param. */ -static int max_interrupt_work = 5; +static int max_interrupt_work = 15; /* * Optimization can be either throuput mode or cpu mode @@ -1446,9 +1446,9 @@ static int phy_init(struct net_device *dev) /* some phys clear out pause advertisment on reset, set it back */ mii_rw(dev, np->phyaddr, MII_ADVERTISE, reg); - /* restart auto negotiation */ + /* restart auto negotiation, power down phy */ mii_control = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); - mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE); + mii_control |= (BMCR_ANRESTART | BMCR_ANENABLE | BMCR_PDOWN); if (mii_rw(dev, np->phyaddr, MII_BMCR, mii_control)) { return PHY_ERROR; } @@ -1760,7 +1760,7 @@ static void nv_do_rx_refill(unsigned long data) struct fe_priv *np = netdev_priv(dev); /* Just reschedule NAPI rx processing */ - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); } #else static void nv_do_rx_refill(unsigned long data) @@ -2735,7 +2735,6 @@ static int nv_rx_process(struct net_device *dev, int limit) #else netif_rx(skb); #endif - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; next_pkt: @@ -2848,7 +2847,6 @@ static int nv_rx_process_optimized(struct net_device *dev, int limit) } } - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; } else { @@ -3405,7 +3403,7 @@ static irqreturn_t nv_nic_irq(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); /* Disable furthur receive irq's */ spin_lock(&np->lock); @@ -3522,7 +3520,7 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) #ifdef CONFIG_FORCEDETH_NAPI if (events & NVREG_IRQ_RX_ALL) { - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); /* Disable furthur receive irq's */ spin_lock(&np->lock); @@ -3680,7 +3678,7 @@ static int nv_napi_poll(struct napi_struct *napi, int budget) /* re-enable receive interrupts */ spin_lock_irqsave(&np->lock, flags); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); np->irqmask |= NVREG_IRQ_RX_ALL; if (np->msi_flags & NV_MSI_X_ENABLED) @@ -3706,7 +3704,7 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data) writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus); if (events) { - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); /* disable receive interrupts on the nic */ writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask); pci_push(base); @@ -5210,6 +5208,10 @@ static int nv_open(struct net_device *dev) dprintk(KERN_DEBUG "nv_open: begin\n"); + /* power up phy */ + mii_rw(dev, np->phyaddr, MII_BMCR, + mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ) & ~BMCR_PDOWN); + /* erase previous misconfiguration */ if (np->driver_data & DEV_HAS_POWER_CNTRL) nv_mac_reset(dev); @@ -5403,6 +5405,10 @@ static int nv_close(struct net_device *dev) if (np->wolenabled) { writel(NVREG_PFF_ALWAYS|NVREG_PFF_MYADDR, base + NvRegPacketFilterFlags); nv_start_rx(dev); + } else { + /* power down phy */ + mii_rw(dev, np->phyaddr, MII_BMCR, + mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ)|BMCR_PDOWN); } /* FIXME: power down nic */ @@ -5410,6 +5416,38 @@ static int nv_close(struct net_device *dev) return 0; } +static const struct net_device_ops nv_netdev_ops = { + .ndo_open = nv_open, + .ndo_stop = nv_close, + .ndo_get_stats = nv_get_stats, + .ndo_start_xmit = nv_start_xmit, + .ndo_tx_timeout = nv_tx_timeout, + .ndo_change_mtu = nv_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = nv_set_mac_address, + .ndo_set_multicast_list = nv_set_multicast, + .ndo_vlan_rx_register = nv_vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = nv_poll_controller, +#endif +}; + +static const struct net_device_ops nv_netdev_ops_optimized = { + .ndo_open = nv_open, + .ndo_stop = nv_close, + .ndo_get_stats = nv_get_stats, + .ndo_start_xmit = nv_start_xmit_optimized, + .ndo_tx_timeout = nv_tx_timeout, + .ndo_change_mtu = nv_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = nv_set_mac_address, + .ndo_set_multicast_list = nv_set_multicast, + .ndo_vlan_rx_register = nv_vlan_rx_register, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = nv_poll_controller, +#endif +}; + static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_id *id) { struct net_device *dev; @@ -5420,7 +5458,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i u32 powerstate, txreg; u32 phystate_orig = 0, phystate; int phyinitialized = 0; - DECLARE_MAC_BUF(mac); static int printed_version; if (!printed_version++) @@ -5530,7 +5567,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (id->driver_data & DEV_HAS_VLAN) { np->vlanctl_bits = NVREG_VLANCONTROL_ENABLE; dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; - dev->vlan_rx_register = nv_vlan_rx_register; } np->msi_flags = 0; @@ -5580,25 +5616,15 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i if (!np->rx_skb || !np->tx_skb) goto out_freering; - dev->open = nv_open; - dev->stop = nv_close; - if (!nv_optimized(np)) - dev->hard_start_xmit = nv_start_xmit; + dev->netdev_ops = &nv_netdev_ops; else - dev->hard_start_xmit = nv_start_xmit_optimized; - dev->get_stats = nv_get_stats; - dev->change_mtu = nv_change_mtu; - dev->set_mac_address = nv_set_mac_address; - dev->set_multicast_list = nv_set_multicast; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = nv_poll_controller; -#endif + dev->netdev_ops = &nv_netdev_ops_optimized; + #ifdef CONFIG_FORCEDETH_NAPI netif_napi_add(dev, &np->napi, nv_napi_poll, RX_WORK_PER_LOOP); #endif SET_ETHTOOL_OPS(dev, &ops); - dev->tx_timeout = nv_tx_timeout; dev->watchdog_timeo = NV_WATCHDOG_TIMEO; pci_set_drvdata(pci_dev, dev); @@ -5653,8 +5679,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i * to 01:23:45:67:89:ab */ dev_printk(KERN_ERR, &pci_dev->dev, - "Invalid Mac address detected: %s\n", - print_mac(mac, dev->dev_addr)); + "Invalid Mac address detected: %pM\n", + dev->dev_addr); dev_printk(KERN_ERR, &pci_dev->dev, "Please complain to your hardware vendor. Switching to a random MAC.\n"); dev->dev_addr[0] = 0x00; @@ -5663,8 +5689,8 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i get_random_bytes(&dev->dev_addr[3], 3); } - dprintk(KERN_DEBUG "%s: MAC Address %s\n", - pci_name(pci_dev), print_mac(mac, dev->dev_addr)); + dprintk(KERN_DEBUG "%s: MAC Address %pM\n", + pci_name(pci_dev), dev->dev_addr); /* set mac address */ nv_copy_mac_to_hw(dev); @@ -6141,7 +6167,7 @@ static struct pci_device_id pci_tbl[] = { }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36), - .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, + .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE, }, { /* MCP79 Ethernet Controller */ PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37), diff --git a/drivers/net/fs_enet/fs_enet-main.c b/drivers/net/fs_enet/fs_enet-main.c index a6f49d02578711ed090a7625a34152e4b36655bc..4e6a9195fe5f6503e5bd609098a203186fab936c 100644 --- a/drivers/net/fs_enet/fs_enet-main.c +++ b/drivers/net/fs_enet/fs_enet-main.c @@ -209,7 +209,7 @@ static int fs_enet_rx_napi(struct napi_struct *napi, int budget) if (received < budget) { /* done */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); (*fep->ops->napi_enable_rx)(dev); } return received; @@ -478,7 +478,7 @@ fs_enet_interrupt(int irq, void *dev_id) /* NOTE: it is possible for FCCs in NAPI mode */ /* to submit a spurious interrupt while in poll */ if (napi_ok) - __netif_rx_schedule(dev, &fep->napi); + __netif_rx_schedule(&fep->napi); } } @@ -1117,10 +1117,7 @@ static int __devinit fs_enet_probe(struct of_device *ofdev, if (ret) goto out_free_bd; - printk(KERN_INFO "%s: fs_enet: %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->name, - ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], - ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + printk(KERN_INFO "%s: fs_enet: %pM\n", ndev->name, ndev->dev_addr); return 0; diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index c4af949bf860d81ffd69ce6ff6eceb9cf0c8a69a..c672ecfc95957f24cc3cb0f358bface91b0a2fbd 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c @@ -25,11 +25,8 @@ * * Theory of operation * - * The driver is initialized through platform_device. Structures which - * define the configuration needed by the board are defined in a - * board structure in arch/ppc/platforms (though I do not - * discount the possibility that other architectures could one - * day be supported. + * The driver is initialized through of_device. Configuration information + * is therefore conveyed through an OF-style device tree. * * The Gianfar Ethernet Controller uses a ring of buffer * descriptors. The beginning is indicated by a register @@ -78,7 +75,7 @@ #include #include #include -#include +#include #include #include #include @@ -92,6 +89,8 @@ #include #include #include +#include +#include #include "gianfar.h" #include "gianfar_mii.h" @@ -119,8 +118,9 @@ static irqreturn_t gfar_interrupt(int irq, void *dev_id); static void adjust_link(struct net_device *dev); static void init_registers(struct net_device *dev); static int init_phy(struct net_device *dev); -static int gfar_probe(struct platform_device *pdev); -static int gfar_remove(struct platform_device *pdev); +static int gfar_probe(struct of_device *ofdev, + const struct of_device_id *match); +static int gfar_remove(struct of_device *ofdev); static void free_skb_resources(struct gfar_private *priv); static void gfar_set_multi(struct net_device *dev); static void gfar_set_hash_for_addr(struct net_device *dev, u8 *addr); @@ -131,7 +131,8 @@ static void gfar_netpoll(struct net_device *dev); #endif int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit); static int gfar_clean_tx_ring(struct net_device *dev); -static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, int length); +static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, + int amount_pull); static void gfar_vlan_rx_register(struct net_device *netdev, struct vlan_group *grp); void gfar_halt(struct net_device *dev); @@ -149,29 +150,163 @@ MODULE_LICENSE("GPL"); /* Returns 1 if incoming frames use an FCB */ static inline int gfar_uses_fcb(struct gfar_private *priv) { - return (priv->vlan_enable || priv->rx_csum_enable); + return priv->vlgrp || priv->rx_csum_enable; +} + +static int gfar_of_init(struct net_device *dev) +{ + struct device_node *phy, *mdio; + const unsigned int *id; + const char *model; + const char *ctype; + const void *mac_addr; + const phandle *ph; + u64 addr, size; + int err = 0; + struct gfar_private *priv = netdev_priv(dev); + struct device_node *np = priv->node; + char bus_name[MII_BUS_ID_SIZE]; + + if (!np || !of_device_is_available(np)) + return -ENODEV; + + /* get a pointer to the register memory */ + addr = of_translate_address(np, of_get_address(np, 0, &size, NULL)); + priv->regs = ioremap(addr, size); + + if (priv->regs == NULL) + return -ENOMEM; + + priv->interruptTransmit = irq_of_parse_and_map(np, 0); + + model = of_get_property(np, "model", NULL); + + /* If we aren't the FEC we have multiple interrupts */ + if (model && strcasecmp(model, "FEC")) { + priv->interruptReceive = irq_of_parse_and_map(np, 1); + + priv->interruptError = irq_of_parse_and_map(np, 2); + + if (priv->interruptTransmit < 0 || + priv->interruptReceive < 0 || + priv->interruptError < 0) { + err = -EINVAL; + goto err_out; + } + } + + mac_addr = of_get_mac_address(np); + if (mac_addr) + memcpy(dev->dev_addr, mac_addr, MAC_ADDR_LEN); + + if (model && !strcasecmp(model, "TSEC")) + priv->device_flags = + FSL_GIANFAR_DEV_HAS_GIGABIT | + FSL_GIANFAR_DEV_HAS_COALESCE | + FSL_GIANFAR_DEV_HAS_RMON | + FSL_GIANFAR_DEV_HAS_MULTI_INTR; + if (model && !strcasecmp(model, "eTSEC")) + priv->device_flags = + FSL_GIANFAR_DEV_HAS_GIGABIT | + FSL_GIANFAR_DEV_HAS_COALESCE | + FSL_GIANFAR_DEV_HAS_RMON | + FSL_GIANFAR_DEV_HAS_MULTI_INTR | + FSL_GIANFAR_DEV_HAS_PADDING | + FSL_GIANFAR_DEV_HAS_CSUM | + FSL_GIANFAR_DEV_HAS_VLAN | + FSL_GIANFAR_DEV_HAS_MAGIC_PACKET | + FSL_GIANFAR_DEV_HAS_EXTENDED_HASH; + + ctype = of_get_property(np, "phy-connection-type", NULL); + + /* We only care about rgmii-id. The rest are autodetected */ + if (ctype && !strcmp(ctype, "rgmii-id")) + priv->interface = PHY_INTERFACE_MODE_RGMII_ID; + else + priv->interface = PHY_INTERFACE_MODE_MII; + + if (of_get_property(np, "fsl,magic-packet", NULL)) + priv->device_flags |= FSL_GIANFAR_DEV_HAS_MAGIC_PACKET; + + ph = of_get_property(np, "phy-handle", NULL); + if (ph == NULL) { + u32 *fixed_link; + + fixed_link = (u32 *)of_get_property(np, "fixed-link", NULL); + if (!fixed_link) { + err = -ENODEV; + goto err_out; + } + + snprintf(priv->phy_bus_id, BUS_ID_SIZE, PHY_ID_FMT, "0", + fixed_link[0]); + } else { + phy = of_find_node_by_phandle(*ph); + + if (phy == NULL) { + err = -ENODEV; + goto err_out; + } + + mdio = of_get_parent(phy); + + id = of_get_property(phy, "reg", NULL); + + of_node_put(phy); + of_node_put(mdio); + + gfar_mdio_bus_name(bus_name, mdio); + snprintf(priv->phy_bus_id, BUS_ID_SIZE, "%s:%02x", + bus_name, *id); + } + + /* Find the TBI PHY. If it's not there, we don't support SGMII */ + ph = of_get_property(np, "tbi-handle", NULL); + if (ph) { + struct device_node *tbi = of_find_node_by_phandle(*ph); + struct of_device *ofdev; + struct mii_bus *bus; + + if (!tbi) + return 0; + + mdio = of_get_parent(tbi); + if (!mdio) + return 0; + + ofdev = of_find_device_by_node(mdio); + + of_node_put(mdio); + + id = of_get_property(tbi, "reg", NULL); + if (!id) + return 0; + + of_node_put(tbi); + + bus = dev_get_drvdata(&ofdev->dev); + + priv->tbiphy = bus->phy_map[*id]; + } + + return 0; + +err_out: + iounmap(priv->regs); + return err; } /* Set up the ethernet device structure, private data, * and anything else we need before we start */ -static int gfar_probe(struct platform_device *pdev) +static int gfar_probe(struct of_device *ofdev, + const struct of_device_id *match) { u32 tempval; struct net_device *dev = NULL; struct gfar_private *priv = NULL; - struct gianfar_platform_data *einfo; - struct resource *r; - int err = 0, irq; DECLARE_MAC_BUF(mac); - - einfo = (struct gianfar_platform_data *) pdev->dev.platform_data; - - if (NULL == einfo) { - printk(KERN_ERR "gfar %d: Missing additional data!\n", - pdev->id); - - return -ENODEV; - } + int err = 0; + int len_devname; /* Create an ethernet device instance */ dev = alloc_etherdev(sizeof (*priv)); @@ -181,64 +316,23 @@ static int gfar_probe(struct platform_device *pdev) priv = netdev_priv(dev); priv->dev = dev; + priv->node = ofdev->node; - /* Set the info in the priv to the current info */ - priv->einfo = einfo; - - /* fill out IRQ fields */ - if (einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { - irq = platform_get_irq_byname(pdev, "tx"); - if (irq < 0) - goto regs_fail; - priv->interruptTransmit = irq; - - irq = platform_get_irq_byname(pdev, "rx"); - if (irq < 0) - goto regs_fail; - priv->interruptReceive = irq; - - irq = platform_get_irq_byname(pdev, "error"); - if (irq < 0) - goto regs_fail; - priv->interruptError = irq; - } else { - irq = platform_get_irq(pdev, 0); - if (irq < 0) - goto regs_fail; - priv->interruptTransmit = irq; - } - - /* get a pointer to the register memory */ - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); - priv->regs = ioremap(r->start, sizeof (struct gfar)); + err = gfar_of_init(dev); - if (NULL == priv->regs) { - err = -ENOMEM; + if (err) goto regs_fail; - } spin_lock_init(&priv->txlock); spin_lock_init(&priv->rxlock); spin_lock_init(&priv->bflock); INIT_WORK(&priv->reset_task, gfar_reset_task); - platform_set_drvdata(pdev, dev); + dev_set_drvdata(&ofdev->dev, priv); /* Stop the DMA engine now, in case it was running before */ /* (The firmware could have used it, and left it running). */ - /* To do this, we write Graceful Receive Stop and Graceful */ - /* Transmit Stop, and then wait until the corresponding bits */ - /* in IEVENT indicate the stops have completed. */ - tempval = gfar_read(&priv->regs->dmactrl); - tempval &= ~(DMACTRL_GRS | DMACTRL_GTS); - gfar_write(&priv->regs->dmactrl, tempval); - - tempval = gfar_read(&priv->regs->dmactrl); - tempval |= (DMACTRL_GRS | DMACTRL_GTS); - gfar_write(&priv->regs->dmactrl, tempval); - - while (!(gfar_read(&priv->regs->ievent) & (IEVENT_GRSC | IEVENT_GTSC))) - cpu_relax(); + gfar_halt(dev); /* Reset MAC layer */ gfar_write(&priv->regs->maccfg1, MACCFG1_SOFT_RESET); @@ -252,13 +346,10 @@ static int gfar_probe(struct platform_device *pdev) /* Initialize ECNTRL */ gfar_write(&priv->regs->ecntrl, ECNTRL_INIT_SETTINGS); - /* Copy the station address into the dev structure, */ - memcpy(dev->dev_addr, einfo->mac_addr, MAC_ADDR_LEN); - /* Set the dev->base_addr to the gfar reg region */ dev->base_addr = (unsigned long) (priv->regs); - SET_NETDEV_DEV(dev, &pdev->dev); + SET_NETDEV_DEV(dev, &ofdev->dev); /* Fill in the dev structure */ dev->open = gfar_enet_open; @@ -276,23 +367,21 @@ static int gfar_probe(struct platform_device *pdev) dev->ethtool_ops = &gfar_ethtool_ops; - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) { priv->rx_csum_enable = 1; - dev->features |= NETIF_F_IP_CSUM; + dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG | NETIF_F_HIGHDMA; } else priv->rx_csum_enable = 0; priv->vlgrp = NULL; - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) { dev->vlan_rx_register = gfar_vlan_rx_register; dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - - priv->vlan_enable = 1; } - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) { priv->extended_hash = 1; priv->hash_width = 9; @@ -327,7 +416,7 @@ static int gfar_probe(struct platform_device *pdev) priv->hash_regs[7] = &priv->regs->gaddr7; } - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_PADDING) + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_PADDING) priv->padding = DEFAULT_PADDING; else priv->padding = 0; @@ -338,13 +427,12 @@ static int gfar_probe(struct platform_device *pdev) priv->rx_buffer_size = DEFAULT_RX_BUFFER_SIZE; priv->tx_ring_size = DEFAULT_TX_RING_SIZE; priv->rx_ring_size = DEFAULT_RX_RING_SIZE; + priv->num_txbdfree = DEFAULT_TX_RING_SIZE; priv->txcoalescing = DEFAULT_TX_COALESCE; - priv->txcount = DEFAULT_TXCOUNT; - priv->txtime = DEFAULT_TXTIME; + priv->txic = DEFAULT_TXIC; priv->rxcoalescing = DEFAULT_RX_COALESCE; - priv->rxcount = DEFAULT_RXCOUNT; - priv->rxtime = DEFAULT_RXTIME; + priv->rxic = DEFAULT_RXIC; /* Enable most messages by default */ priv->msg_enable = (NETIF_MSG_IFUP << 1 ) - 1; @@ -360,12 +448,28 @@ static int gfar_probe(struct platform_device *pdev) goto register_fail; } + /* fill out IRQ number and name fields */ + len_devname = strlen(dev->name); + strncpy(&priv->int_name_tx[0], dev->name, len_devname); + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { + strncpy(&priv->int_name_tx[len_devname], + "_tx", sizeof("_tx") + 1); + + strncpy(&priv->int_name_rx[0], dev->name, len_devname); + strncpy(&priv->int_name_rx[len_devname], + "_rx", sizeof("_rx") + 1); + + strncpy(&priv->int_name_er[0], dev->name, len_devname); + strncpy(&priv->int_name_er[len_devname], + "_er", sizeof("_er") + 1); + } else + priv->int_name_tx[len_devname] = '\0'; + /* Create all the sysfs files */ gfar_init_sysfs(dev); /* Print out the device info */ - printk(KERN_INFO DEVICE_NAME "%s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO DEVICE_NAME "%pM\n", dev->name, dev->dev_addr); /* Even more device info helps when determining which kernel */ /* provided which set of benchmarks. */ @@ -382,29 +486,28 @@ regs_fail: return err; } -static int gfar_remove(struct platform_device *pdev) +static int gfar_remove(struct of_device *ofdev) { - struct net_device *dev = platform_get_drvdata(pdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = dev_get_drvdata(&ofdev->dev); - platform_set_drvdata(pdev, NULL); + dev_set_drvdata(&ofdev->dev, NULL); iounmap(priv->regs); - free_netdev(dev); + free_netdev(priv->dev); return 0; } #ifdef CONFIG_PM -static int gfar_suspend(struct platform_device *pdev, pm_message_t state) +static int gfar_suspend(struct of_device *ofdev, pm_message_t state) { - struct net_device *dev = platform_get_drvdata(pdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = dev_get_drvdata(&ofdev->dev); + struct net_device *dev = priv->dev; unsigned long flags; u32 tempval; int magic_packet = priv->wol_en && - (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); + (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); netif_device_detach(dev); @@ -445,14 +548,14 @@ static int gfar_suspend(struct platform_device *pdev, pm_message_t state) return 0; } -static int gfar_resume(struct platform_device *pdev) +static int gfar_resume(struct of_device *ofdev) { - struct net_device *dev = platform_get_drvdata(pdev); - struct gfar_private *priv = netdev_priv(dev); + struct gfar_private *priv = dev_get_drvdata(&ofdev->dev); + struct net_device *dev = priv->dev; unsigned long flags; u32 tempval; int magic_packet = priv->wol_en && - (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); + (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET); if (!netif_running(dev)) { netif_device_attach(dev); @@ -511,7 +614,7 @@ static phy_interface_t gfar_get_interface(struct net_device *dev) if (ecntrl & ECNTRL_REDUCED_MII_MODE) return PHY_INTERFACE_MODE_RMII; else { - phy_interface_t interface = priv->einfo->interface; + phy_interface_t interface = priv->interface; /* * This isn't autodetected right now, so it must @@ -524,7 +627,7 @@ static phy_interface_t gfar_get_interface(struct net_device *dev) } } - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT) + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT) return PHY_INTERFACE_MODE_GMII; return PHY_INTERFACE_MODE_MII; @@ -538,21 +641,18 @@ static int init_phy(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); uint gigabit_support = - priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? + priv->device_flags & FSL_GIANFAR_DEV_HAS_GIGABIT ? SUPPORTED_1000baseT_Full : 0; struct phy_device *phydev; - char phy_id[BUS_ID_SIZE]; phy_interface_t interface; priv->oldlink = 0; priv->oldspeed = 0; priv->oldduplex = -1; - snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->einfo->bus_id, priv->einfo->phy_id); - interface = gfar_get_interface(dev); - phydev = phy_connect(dev, phy_id, &adjust_link, 0, interface); + phydev = phy_connect(dev, priv->phy_bus_id, &adjust_link, 0, interface); if (interface == PHY_INTERFACE_MODE_SGMII) gfar_configure_serdes(dev); @@ -583,35 +683,31 @@ static int init_phy(struct net_device *dev) static void gfar_configure_serdes(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - struct gfar_mii __iomem *regs = - (void __iomem *)&priv->regs->gfar_mii_regs; - int tbipa = gfar_read(&priv->regs->tbipa); - struct mii_bus *bus = gfar_get_miibus(priv); - if (bus) - mutex_lock(&bus->mdio_lock); + if (!priv->tbiphy) { + printk(KERN_WARNING "SGMII mode requires that the device " + "tree specify a tbi-handle\n"); + return; + } - /* If the link is already up, we must already be ok, and don't need to + /* + * If the link is already up, we must already be ok, and don't need to * configure and reset the TBI<->SerDes link. Maybe U-Boot configured * everything for us? Resetting it takes the link down and requires * several seconds for it to come back. */ - if (gfar_local_mdio_read(regs, tbipa, MII_BMSR) & BMSR_LSTATUS) - goto done; + if (phy_read(priv->tbiphy, MII_BMSR) & BMSR_LSTATUS) + return; /* Single clk mode, mii mode off(for serdes communication) */ - gfar_local_mdio_write(regs, tbipa, MII_TBICON, TBICON_CLK_SELECT); + phy_write(priv->tbiphy, MII_TBICON, TBICON_CLK_SELECT); - gfar_local_mdio_write(regs, tbipa, MII_ADVERTISE, + phy_write(priv->tbiphy, MII_ADVERTISE, ADVERTISE_1000XFULL | ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM); - gfar_local_mdio_write(regs, tbipa, MII_BMCR, BMCR_ANENABLE | + phy_write(priv->tbiphy, MII_BMCR, BMCR_ANENABLE | BMCR_ANRESTART | BMCR_FULLDPLX | BMCR_SPEED1000); - - done: - if (bus) - mutex_unlock(&bus->mdio_lock); } static void init_registers(struct net_device *dev) @@ -644,7 +740,7 @@ static void init_registers(struct net_device *dev) gfar_write(&priv->regs->gaddr7, 0); /* Zero out the rmon mib registers if it has them */ - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { memset_io(&(priv->regs->rmon), 0, sizeof (struct rmon_mib)); /* Mask off the CAM interrupts */ @@ -719,7 +815,7 @@ void stop_gfar(struct net_device *dev) spin_unlock_irqrestore(&priv->txlock, flags); /* Free the IRQs */ - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { free_irq(priv->interruptError, dev); free_irq(priv->interruptTransmit, dev); free_irq(priv->interruptReceive, dev); @@ -742,22 +838,26 @@ static void free_skb_resources(struct gfar_private *priv) { struct rxbd8 *rxbdp; struct txbd8 *txbdp; - int i; + int i, j; /* Go through all the buffer descriptors and free their data buffers */ txbdp = priv->tx_bd_base; for (i = 0; i < priv->tx_ring_size; i++) { - - if (priv->tx_skbuff[i]) { - dma_unmap_single(&priv->dev->dev, txbdp->bufPtr, - txbdp->length, - DMA_TO_DEVICE); - dev_kfree_skb_any(priv->tx_skbuff[i]); - priv->tx_skbuff[i] = NULL; + if (!priv->tx_skbuff[i]) + continue; + + dma_unmap_single(&priv->dev->dev, txbdp->bufPtr, + txbdp->length, DMA_TO_DEVICE); + txbdp->lstatus = 0; + for (j = 0; j < skb_shinfo(priv->tx_skbuff[i])->nr_frags; j++) { + txbdp++; + dma_unmap_page(&priv->dev->dev, txbdp->bufPtr, + txbdp->length, DMA_TO_DEVICE); } - txbdp++; + dev_kfree_skb_any(priv->tx_skbuff[i]); + priv->tx_skbuff[i] = NULL; } kfree(priv->tx_skbuff); @@ -777,8 +877,7 @@ static void free_skb_resources(struct gfar_private *priv) priv->rx_skbuff[i] = NULL; } - rxbdp->status = 0; - rxbdp->length = 0; + rxbdp->lstatus = 0; rxbdp->bufPtr = 0; rxbdp++; @@ -815,6 +914,8 @@ void gfar_start(struct net_device *dev) /* Unmask the interrupts we look for */ gfar_write(®s->imask, IMASK_DEFAULT); + + dev->trans_start = jiffies; } /* Bring the controller up and running */ @@ -889,6 +990,7 @@ int startup_gfar(struct net_device *dev) priv->rx_skbuff[i] = NULL; /* Initialize some variables in our dev structure */ + priv->num_txbdfree = priv->tx_ring_size; priv->dirty_tx = priv->cur_tx = priv->tx_bd_base; priv->cur_rx = priv->rx_bd_base; priv->skb_curtx = priv->skb_dirtytx = 0; @@ -897,8 +999,7 @@ int startup_gfar(struct net_device *dev) /* Initialize Transmit Descriptor Ring */ txbdp = priv->tx_bd_base; for (i = 0; i < priv->tx_ring_size; i++) { - txbdp->status = 0; - txbdp->length = 0; + txbdp->lstatus = 0; txbdp->bufPtr = 0; txbdp++; } @@ -933,11 +1034,11 @@ int startup_gfar(struct net_device *dev) /* If the device has multiple interrupts, register for * them. Otherwise, only register for the one */ - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { /* Install our interrupt handlers for Error, * Transmit, and Receive */ if (request_irq(priv->interruptError, gfar_error, - 0, "enet_error", dev) < 0) { + 0, priv->int_name_er, dev) < 0) { if (netif_msg_intr(priv)) printk(KERN_ERR "%s: Can't get IRQ %d\n", dev->name, priv->interruptError); @@ -947,7 +1048,7 @@ int startup_gfar(struct net_device *dev) } if (request_irq(priv->interruptTransmit, gfar_transmit, - 0, "enet_tx", dev) < 0) { + 0, priv->int_name_tx, dev) < 0) { if (netif_msg_intr(priv)) printk(KERN_ERR "%s: Can't get IRQ %d\n", dev->name, priv->interruptTransmit); @@ -958,7 +1059,7 @@ int startup_gfar(struct net_device *dev) } if (request_irq(priv->interruptReceive, gfar_receive, - 0, "enet_rx", dev) < 0) { + 0, priv->int_name_rx, dev) < 0) { if (netif_msg_intr(priv)) printk(KERN_ERR "%s: Can't get IRQ %d (receive0)\n", dev->name, priv->interruptReceive); @@ -968,10 +1069,10 @@ int startup_gfar(struct net_device *dev) } } else { if (request_irq(priv->interruptTransmit, gfar_interrupt, - 0, "gfar_interrupt", dev) < 0) { + 0, priv->int_name_tx, dev) < 0) { if (netif_msg_intr(priv)) printk(KERN_ERR "%s: Can't get IRQ %d\n", - dev->name, priv->interruptError); + dev->name, priv->interruptTransmit); err = -1; goto err_irq_fail; @@ -981,17 +1082,13 @@ int startup_gfar(struct net_device *dev) phy_start(priv->phydev); /* Configure the coalescing support */ + gfar_write(®s->txic, 0); if (priv->txcoalescing) - gfar_write(®s->txic, - mk_ic_value(priv->txcount, priv->txtime)); - else - gfar_write(®s->txic, 0); + gfar_write(®s->txic, priv->txic); + gfar_write(®s->rxic, 0); if (priv->rxcoalescing) - gfar_write(®s->rxic, - mk_ic_value(priv->rxcount, priv->rxtime)); - else - gfar_write(®s->rxic, 0); + gfar_write(®s->rxic, priv->rxic); if (priv->rx_csum_enable) rctrl |= RCTRL_CHECKSUMMING; @@ -1003,9 +1100,6 @@ int startup_gfar(struct net_device *dev) rctrl |= RCTRL_EMEN; } - if (priv->vlan_enable) - rctrl |= RCTRL_VLAN; - if (priv->padding) { rctrl &= ~RCTRL_PAL_MASK; rctrl |= RCTRL_PADDING(priv->padding); @@ -1094,11 +1188,11 @@ static int gfar_enet_open(struct net_device *dev) return err; } -static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb, struct txbd8 *bdp) +static inline struct txfcb *gfar_add_fcb(struct sk_buff *skb) { struct txfcb *fcb = (struct txfcb *)skb_push (skb, GMAC_FCB_LEN); - memset(fcb, 0, GMAC_FCB_LEN); + cacheable_memzero(fcb, GMAC_FCB_LEN); return fcb; } @@ -1137,96 +1231,140 @@ void inline gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb) fcb->vlctl = vlan_tx_tag_get(skb); } +static inline struct txbd8 *skip_txbd(struct txbd8 *bdp, int stride, + struct txbd8 *base, int ring_size) +{ + struct txbd8 *new_bd = bdp + stride; + + return (new_bd >= (base + ring_size)) ? (new_bd - ring_size) : new_bd; +} + +static inline struct txbd8 *next_txbd(struct txbd8 *bdp, struct txbd8 *base, + int ring_size) +{ + return skip_txbd(bdp, 1, base, ring_size); +} + /* This is called by the kernel when a frame is ready for transmission. */ /* It is pointed to by the dev->hard_start_xmit function pointer */ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); struct txfcb *fcb = NULL; - struct txbd8 *txbdp; - u16 status; + struct txbd8 *txbdp, *txbdp_start, *base; + u32 lstatus; + int i; + u32 bufaddr; unsigned long flags; + unsigned int nr_frags, length; + + base = priv->tx_bd_base; + + /* total number of fragments in the SKB */ + nr_frags = skb_shinfo(skb)->nr_frags; + + spin_lock_irqsave(&priv->txlock, flags); + + /* check if there is space to queue this packet */ + if (nr_frags > priv->num_txbdfree) { + /* no space, stop the queue */ + netif_stop_queue(dev); + dev->stats.tx_fifo_errors++; + spin_unlock_irqrestore(&priv->txlock, flags); + return NETDEV_TX_BUSY; + } /* Update transmit stats */ dev->stats.tx_bytes += skb->len; - /* Lock priv now */ - spin_lock_irqsave(&priv->txlock, flags); + txbdp = txbdp_start = priv->cur_tx; - /* Point at the first free tx descriptor */ - txbdp = priv->cur_tx; + if (nr_frags == 0) { + lstatus = txbdp->lstatus | BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); + } else { + /* Place the fragment addresses and lengths into the TxBDs */ + for (i = 0; i < nr_frags; i++) { + /* Point at the next BD, wrapping as needed */ + txbdp = next_txbd(txbdp, base, priv->tx_ring_size); + + length = skb_shinfo(skb)->frags[i].size; - /* Clear all but the WRAP status flags */ - status = txbdp->status & TXBD_WRAP; + lstatus = txbdp->lstatus | length | + BD_LFLAG(TXBD_READY); + + /* Handle the last BD specially */ + if (i == nr_frags - 1) + lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT); + + bufaddr = dma_map_page(&dev->dev, + skb_shinfo(skb)->frags[i].page, + skb_shinfo(skb)->frags[i].page_offset, + length, + DMA_TO_DEVICE); + + /* set the TxBD length and buffer pointer */ + txbdp->bufPtr = bufaddr; + txbdp->lstatus = lstatus; + } + + lstatus = txbdp_start->lstatus; + } /* Set up checksumming */ - if (likely((dev->features & NETIF_F_IP_CSUM) - && (CHECKSUM_PARTIAL == skb->ip_summed))) { - fcb = gfar_add_fcb(skb, txbdp); - status |= TXBD_TOE; + if (CHECKSUM_PARTIAL == skb->ip_summed) { + fcb = gfar_add_fcb(skb); + lstatus |= BD_LFLAG(TXBD_TOE); gfar_tx_checksum(skb, fcb); } - if (priv->vlan_enable && - unlikely(priv->vlgrp && vlan_tx_tag_present(skb))) { + if (priv->vlgrp && vlan_tx_tag_present(skb)) { if (unlikely(NULL == fcb)) { - fcb = gfar_add_fcb(skb, txbdp); - status |= TXBD_TOE; + fcb = gfar_add_fcb(skb); + lstatus |= BD_LFLAG(TXBD_TOE); } gfar_tx_vlan(skb, fcb); } - /* Set buffer length and pointer */ - txbdp->length = skb->len; - txbdp->bufPtr = dma_map_single(&dev->dev, skb->data, - skb->len, DMA_TO_DEVICE); - - /* Save the skb pointer so we can free it later */ + /* setup the TxBD length and buffer pointer for the first BD */ priv->tx_skbuff[priv->skb_curtx] = skb; + txbdp_start->bufPtr = dma_map_single(&dev->dev, skb->data, + skb_headlen(skb), DMA_TO_DEVICE); - /* Update the current skb pointer (wrapping if this was the last) */ - priv->skb_curtx = - (priv->skb_curtx + 1) & TX_RING_MOD_MASK(priv->tx_ring_size); - - /* Flag the BD as interrupt-causing */ - status |= TXBD_INTERRUPT; + lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb); - /* Flag the BD as ready to go, last in frame, and */ - /* in need of CRC */ - status |= (TXBD_READY | TXBD_LAST | TXBD_CRC); - - dev->trans_start = jiffies; - - /* The powerpc-specific eieio() is used, as wmb() has too strong + /* + * The powerpc-specific eieio() is used, as wmb() has too strong * semantics (it requires synchronization between cacheable and * uncacheable mappings, which eieio doesn't provide and which we * don't need), thus requiring a more expensive sync instruction. At * some point, the set of architecture-independent barrier functions * should be expanded to include weaker barriers. */ - eieio(); - txbdp->status = status; - /* If this was the last BD in the ring, the next one */ - /* is at the beginning of the ring */ - if (txbdp->status & TXBD_WRAP) - txbdp = priv->tx_bd_base; - else - txbdp++; + txbdp_start->lstatus = lstatus; + + /* Update the current skb pointer to the next entry we will use + * (wrapping if necessary) */ + priv->skb_curtx = (priv->skb_curtx + 1) & + TX_RING_MOD_MASK(priv->tx_ring_size); + + priv->cur_tx = next_txbd(txbdp, base, priv->tx_ring_size); + + /* reduce TxBD free count */ + priv->num_txbdfree -= (nr_frags + 1); + + dev->trans_start = jiffies; /* If the next BD still needs to be cleaned up, then the bds are full. We need to tell the kernel to stop sending us stuff. */ - if (txbdp == priv->dirty_tx) { + if (!priv->num_txbdfree) { netif_stop_queue(dev); dev->stats.tx_fifo_errors++; } - /* Update the current txbd to the next one */ - priv->cur_tx = txbdp; - /* Tell the DMA to go go go */ gfar_write(&priv->regs->tstat, TSTAT_CLEAR_THALT); @@ -1270,11 +1408,15 @@ static void gfar_vlan_rx_register(struct net_device *dev, { struct gfar_private *priv = netdev_priv(dev); unsigned long flags; + struct vlan_group *old_grp; u32 tempval; spin_lock_irqsave(&priv->rxlock, flags); - priv->vlgrp = grp; + old_grp = priv->vlgrp; + + if (old_grp == grp) + return; if (grp) { /* Enable VLAN tag insertion */ @@ -1286,6 +1428,7 @@ static void gfar_vlan_rx_register(struct net_device *dev, /* Enable VLAN tag extraction */ tempval = gfar_read(&priv->regs->rctrl); tempval |= RCTRL_VLEX; + tempval |= (RCTRL_VLEX | RCTRL_PRSDEP_INIT); gfar_write(&priv->regs->rctrl, tempval); } else { /* Disable VLAN tag insertion */ @@ -1296,9 +1439,16 @@ static void gfar_vlan_rx_register(struct net_device *dev, /* Disable VLAN tag extraction */ tempval = gfar_read(&priv->regs->rctrl); tempval &= ~RCTRL_VLEX; + /* If parse is no longer required, then disable parser */ + if (tempval & RCTRL_REQ_PARSER) + tempval |= RCTRL_PRSDEP_INIT; + else + tempval &= ~RCTRL_PRSDEP_INIT; gfar_write(&priv->regs->rctrl, tempval); } + gfar_change_mtu(dev, dev->mtu); + spin_unlock_irqrestore(&priv->rxlock, flags); } @@ -1309,14 +1459,9 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) int oldsize = priv->rx_buffer_size; int frame_size = new_mtu + ETH_HLEN; - if (priv->vlan_enable) + if (priv->vlgrp) frame_size += VLAN_HLEN; - if (gfar_uses_fcb(priv)) - frame_size += GMAC_FCB_LEN; - - frame_size += priv->padding; - if ((frame_size < 64) || (frame_size > JUMBO_FRAME_SIZE)) { if (netif_msg_drv(priv)) printk(KERN_ERR "%s: Invalid MTU setting\n", @@ -1324,6 +1469,11 @@ static int gfar_change_mtu(struct net_device *dev, int new_mtu) return -EINVAL; } + if (gfar_uses_fcb(priv)) + frame_size += GMAC_FCB_LEN; + + frame_size += priv->padding; + tempsize = (frame_size & ~(INCREMENTAL_BUFFER_SIZE - 1)) + INCREMENTAL_BUFFER_SIZE; @@ -1388,83 +1538,85 @@ static void gfar_timeout(struct net_device *dev) /* Interrupt Handler for Transmit complete */ static int gfar_clean_tx_ring(struct net_device *dev) { - struct txbd8 *bdp; struct gfar_private *priv = netdev_priv(dev); + struct txbd8 *bdp; + struct txbd8 *lbdp = NULL; + struct txbd8 *base = priv->tx_bd_base; + struct sk_buff *skb; + int skb_dirtytx; + int tx_ring_size = priv->tx_ring_size; + int frags = 0; + int i; int howmany = 0; + u32 lstatus; bdp = priv->dirty_tx; - while ((bdp->status & TXBD_READY) == 0) { - /* If dirty_tx and cur_tx are the same, then either the */ - /* ring is empty or full now (it could only be full in the beginning, */ - /* obviously). If it is empty, we are done. */ - if ((bdp == priv->cur_tx) && (netif_queue_stopped(dev) == 0)) - break; + skb_dirtytx = priv->skb_dirtytx; - howmany++; + while ((skb = priv->tx_skbuff[skb_dirtytx])) { + frags = skb_shinfo(skb)->nr_frags; + lbdp = skip_txbd(bdp, frags, base, tx_ring_size); - /* Deferred means some collisions occurred during transmit, */ - /* but we eventually sent the packet. */ - if (bdp->status & TXBD_DEF) - dev->stats.collisions++; + lstatus = lbdp->lstatus; - /* Unmap the DMA memory */ - dma_unmap_single(&priv->dev->dev, bdp->bufPtr, - bdp->length, DMA_TO_DEVICE); + /* Only clean completed frames */ + if ((lstatus & BD_LFLAG(TXBD_READY)) && + (lstatus & BD_LENGTH_MASK)) + break; + + dma_unmap_single(&dev->dev, + bdp->bufPtr, + bdp->length, + DMA_TO_DEVICE); - /* Free the sk buffer associated with this TxBD */ - dev_kfree_skb_irq(priv->tx_skbuff[priv->skb_dirtytx]); + bdp->lstatus &= BD_LFLAG(TXBD_WRAP); + bdp = next_txbd(bdp, base, tx_ring_size); - priv->tx_skbuff[priv->skb_dirtytx] = NULL; - priv->skb_dirtytx = - (priv->skb_dirtytx + - 1) & TX_RING_MOD_MASK(priv->tx_ring_size); + for (i = 0; i < frags; i++) { + dma_unmap_page(&dev->dev, + bdp->bufPtr, + bdp->length, + DMA_TO_DEVICE); + bdp->lstatus &= BD_LFLAG(TXBD_WRAP); + bdp = next_txbd(bdp, base, tx_ring_size); + } - /* Clean BD length for empty detection */ - bdp->length = 0; + dev_kfree_skb_any(skb); + priv->tx_skbuff[skb_dirtytx] = NULL; - /* update bdp to point at next bd in the ring (wrapping if necessary) */ - if (bdp->status & TXBD_WRAP) - bdp = priv->tx_bd_base; - else - bdp++; + skb_dirtytx = (skb_dirtytx + 1) & + TX_RING_MOD_MASK(tx_ring_size); - /* Move dirty_tx to be the next bd */ - priv->dirty_tx = bdp; + howmany++; + priv->num_txbdfree += frags + 1; + } + + /* If we freed a buffer, we can restart transmission, if necessary */ + if (netif_queue_stopped(dev) && priv->num_txbdfree) + netif_wake_queue(dev); - /* We freed a buffer, so now we can restart transmission */ - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); - } /* while ((bdp->status & TXBD_READY) == 0) */ + /* Update dirty indicators */ + priv->skb_dirtytx = skb_dirtytx; + priv->dirty_tx = bdp; dev->stats.tx_packets += howmany; return howmany; } -/* Interrupt Handler for Transmit complete */ -static irqreturn_t gfar_transmit(int irq, void *dev_id) +static void gfar_schedule_cleanup(struct net_device *dev) { - struct net_device *dev = (struct net_device *) dev_id; struct gfar_private *priv = netdev_priv(dev); - - /* Clear IEVENT */ - gfar_write(&priv->regs->ievent, IEVENT_TX_MASK); - - /* Lock priv */ - spin_lock(&priv->txlock); - - gfar_clean_tx_ring(dev); - - /* If we are coalescing the interrupts, reset the timer */ - /* Otherwise, clear it */ - if (likely(priv->txcoalescing)) { - gfar_write(&priv->regs->txic, 0); - gfar_write(&priv->regs->txic, - mk_ic_value(priv->txcount, priv->txtime)); + if (netif_rx_schedule_prep(&priv->napi)) { + gfar_write(&priv->regs->imask, IMASK_RTX_DISABLED); + __netif_rx_schedule(&priv->napi); } +} - spin_unlock(&priv->txlock); - +/* Interrupt Handler for Transmit complete */ +static irqreturn_t gfar_transmit(int irq, void *dev_id) +{ + gfar_schedule_cleanup((struct net_device *)dev_id); return IRQ_HANDLED; } @@ -1472,20 +1624,19 @@ static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp, struct sk_buff *skb) { struct gfar_private *priv = netdev_priv(dev); - u32 * status_len = (u32 *)bdp; - u16 flags; + u32 lstatus; bdp->bufPtr = dma_map_single(&dev->dev, skb->data, priv->rx_buffer_size, DMA_FROM_DEVICE); - flags = RXBD_EMPTY | RXBD_INTERRUPT; + lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT); if (bdp == priv->rx_bd_base + priv->rx_ring_size - 1) - flags |= RXBD_WRAP; + lstatus |= BD_LFLAG(RXBD_WRAP); eieio(); - *status_len = (u32)flags << 16; + bdp->lstatus = lstatus; } @@ -1552,28 +1703,7 @@ static inline void count_errors(unsigned short status, struct net_device *dev) irqreturn_t gfar_receive(int irq, void *dev_id) { - struct net_device *dev = (struct net_device *) dev_id; - struct gfar_private *priv = netdev_priv(dev); - u32 tempval; - - /* support NAPI */ - /* Clear IEVENT, so interrupts aren't called again - * because of the packets that have already arrived */ - gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK); - - if (netif_rx_schedule_prep(dev, &priv->napi)) { - tempval = gfar_read(&priv->regs->imask); - tempval &= IMASK_RTX_DISABLED; - gfar_write(&priv->regs->imask, tempval); - - __netif_rx_schedule(dev, &priv->napi); - } else { - if (netif_msg_rx_err(priv)) - printk(KERN_DEBUG "%s: receive called twice (%x)[%x]\n", - dev->name, gfar_read(&priv->regs->ievent), - gfar_read(&priv->regs->imask)); - } - + gfar_schedule_cleanup((struct net_device *)dev_id); return IRQ_HANDLED; } @@ -1589,59 +1719,38 @@ static inline void gfar_rx_checksum(struct sk_buff *skb, struct rxfcb *fcb) } -static inline struct rxfcb *gfar_get_fcb(struct sk_buff *skb) -{ - struct rxfcb *fcb = (struct rxfcb *)skb->data; - - /* Remove the FCB from the skb */ - skb_pull(skb, GMAC_FCB_LEN); - - return fcb; -} - /* gfar_process_frame() -- handle one incoming packet if skb * isn't NULL. */ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, - int length) + int amount_pull) { struct gfar_private *priv = netdev_priv(dev); struct rxfcb *fcb = NULL; - if (NULL == skb) { - if (netif_msg_rx_err(priv)) - printk(KERN_WARNING "%s: Missing skb!!.\n", dev->name); - dev->stats.rx_dropped++; - priv->extra_stats.rx_skbmissing++; - } else { - int ret; - - /* Prep the skb for the packet */ - skb_put(skb, length); + int ret; - /* Grab the FCB if there is one */ - if (gfar_uses_fcb(priv)) - fcb = gfar_get_fcb(skb); + /* fcb is at the beginning if exists */ + fcb = (struct rxfcb *)skb->data; - /* Remove the padded bytes, if there are any */ - if (priv->padding) - skb_pull(skb, priv->padding); + /* Remove the FCB from the skb */ + /* Remove the padded bytes, if there are any */ + if (amount_pull) + skb_pull(skb, amount_pull); - if (priv->rx_csum_enable) - gfar_rx_checksum(skb, fcb); + if (priv->rx_csum_enable) + gfar_rx_checksum(skb, fcb); - /* Tell the skb what kind of packet this is */ - skb->protocol = eth_type_trans(skb, dev); + /* Tell the skb what kind of packet this is */ + skb->protocol = eth_type_trans(skb, dev); - /* Send the packet up the stack */ - if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN))) { - ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp, - fcb->vlctl); - } else - ret = netif_receive_skb(skb); + /* Send the packet up the stack */ + if (unlikely(priv->vlgrp && (fcb->flags & RXFCB_VLN))) + ret = vlan_hwaccel_receive_skb(skb, priv->vlgrp, fcb->vlctl); + else + ret = netif_receive_skb(skb); - if (NET_RX_DROP == ret) - priv->extra_stats.kernel_dropped++; - } + if (NET_RX_DROP == ret) + priv->extra_stats.kernel_dropped++; return 0; } @@ -1652,14 +1761,19 @@ static int gfar_process_frame(struct net_device *dev, struct sk_buff *skb, */ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) { - struct rxbd8 *bdp; + struct rxbd8 *bdp, *base; struct sk_buff *skb; - u16 pkt_len; + int pkt_len; + int amount_pull; int howmany = 0; struct gfar_private *priv = netdev_priv(dev); /* Get the first full descriptor */ bdp = priv->cur_rx; + base = priv->rx_bd_base; + + amount_pull = (gfar_uses_fcb(priv) ? GMAC_FCB_LEN : 0) + + priv->padding; while (!((bdp->status & RXBD_EMPTY) || (--rx_work_limit < 0))) { struct sk_buff *newskb; @@ -1680,23 +1794,30 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) if (unlikely(!newskb)) newskb = skb; - - if (skb) + else if (skb) dev_kfree_skb_any(skb); } else { /* Increment the number of packets */ dev->stats.rx_packets++; howmany++; - /* Remove the FCS from the packet length */ - pkt_len = bdp->length - 4; + if (likely(skb)) { + pkt_len = bdp->length - ETH_FCS_LEN; + /* Remove the FCS from the packet length */ + skb_put(skb, pkt_len); + dev->stats.rx_bytes += pkt_len; - gfar_process_frame(dev, skb, pkt_len); + gfar_process_frame(dev, skb, amount_pull); - dev->stats.rx_bytes += pkt_len; - } + } else { + if (netif_msg_rx_err(priv)) + printk(KERN_WARNING + "%s: Missing skb!\n", dev->name); + dev->stats.rx_dropped++; + priv->extra_stats.rx_skbmissing++; + } - dev->last_rx = jiffies; + } priv->rx_skbuff[priv->skb_currx] = newskb; @@ -1704,10 +1825,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) gfar_new_rxbdp(dev, bdp, newskb); /* Update to the next pointer */ - if (bdp->status & RXBD_WRAP) - bdp = priv->rx_bd_base; - else - bdp++; + bdp = next_bd(bdp, base, priv->rx_ring_size); /* update to point at the next skb */ priv->skb_currx = @@ -1725,19 +1843,27 @@ static int gfar_poll(struct napi_struct *napi, int budget) { struct gfar_private *priv = container_of(napi, struct gfar_private, napi); struct net_device *dev = priv->dev; - int howmany; + int tx_cleaned = 0; + int rx_cleaned = 0; unsigned long flags; + /* Clear IEVENT, so interrupts aren't called again + * because of the packets that have already arrived */ + gfar_write(&priv->regs->ievent, IEVENT_RTX_MASK); + /* If we fail to get the lock, don't bother with the TX BDs */ if (spin_trylock_irqsave(&priv->txlock, flags)) { - gfar_clean_tx_ring(dev); + tx_cleaned = gfar_clean_tx_ring(dev); spin_unlock_irqrestore(&priv->txlock, flags); } - howmany = gfar_clean_rx_ring(dev, budget); + rx_cleaned = gfar_clean_rx_ring(dev, budget); + + if (tx_cleaned) + return budget; - if (howmany < budget) { - netif_rx_complete(dev, napi); + if (rx_cleaned < budget) { + netif_rx_complete(napi); /* Clear the halt bit in RSTAT */ gfar_write(&priv->regs->rstat, RSTAT_CLEAR_RHALT); @@ -1748,12 +1874,15 @@ static int gfar_poll(struct napi_struct *napi, int budget) /* Otherwise, clear it */ if (likely(priv->rxcoalescing)) { gfar_write(&priv->regs->rxic, 0); - gfar_write(&priv->regs->rxic, - mk_ic_value(priv->rxcount, priv->rxtime)); + gfar_write(&priv->regs->rxic, priv->rxic); + } + if (likely(priv->txcoalescing)) { + gfar_write(&priv->regs->txic, 0); + gfar_write(&priv->regs->txic, priv->txic); } } - return howmany; + return rx_cleaned; } #ifdef CONFIG_NET_POLL_CONTROLLER @@ -1767,7 +1896,7 @@ static void gfar_netpoll(struct net_device *dev) struct gfar_private *priv = netdev_priv(dev); /* If the device has multiple interrupts, run tx/rx */ - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MULTI_INTR) { disable_irq(priv->interruptTransmit); disable_irq(priv->interruptReceive); disable_irq(priv->interruptError); @@ -2061,7 +2190,7 @@ static irqreturn_t gfar_error(int irq, void *dev_id) gfar_write(&priv->regs->ievent, events & IEVENT_ERR_MASK); /* Magic Packet is not an error. */ - if ((priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) && + if ((priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) && (events & IEVENT_MAG)) events &= ~IEVENT_MAG; @@ -2127,16 +2256,24 @@ static irqreturn_t gfar_error(int irq, void *dev_id) /* work with hotplug and coldplug */ MODULE_ALIAS("platform:fsl-gianfar"); +static struct of_device_id gfar_match[] = +{ + { + .type = "network", + .compatible = "gianfar", + }, + {}, +}; + /* Structure for a device driver */ -static struct platform_driver gfar_driver = { +static struct of_platform_driver gfar_driver = { + .name = "fsl-gianfar", + .match_table = gfar_match, + .probe = gfar_probe, .remove = gfar_remove, .suspend = gfar_suspend, .resume = gfar_resume, - .driver = { - .name = "fsl-gianfar", - .owner = THIS_MODULE, - }, }; static int __init gfar_init(void) @@ -2146,7 +2283,7 @@ static int __init gfar_init(void) if (err) return err; - err = platform_driver_register(&gfar_driver); + err = of_register_platform_driver(&gfar_driver); if (err) gfar_mdio_exit(); @@ -2156,7 +2293,7 @@ static int __init gfar_init(void) static void __exit gfar_exit(void) { - platform_driver_unregister(&gfar_driver); + of_unregister_platform_driver(&gfar_driver); gfar_mdio_exit(); } diff --git a/drivers/net/gianfar.h b/drivers/net/gianfar.h index f46e9b63af134873bca42ec6622ad4701910cc01..b1a83344acc75de952a5b4ed3345448595875d33 100644 --- a/drivers/net/gianfar.h +++ b/drivers/net/gianfar.h @@ -189,6 +189,18 @@ extern const char gfar_driver_version[]; #define mk_ic_value(count, time) (IC_ICEN | \ mk_ic_icft(count) | \ mk_ic_ictt(time)) +#define get_icft_value(ic) (((unsigned long)ic & IC_ICFT_MASK) >> \ + IC_ICFT_SHIFT) +#define get_ictt_value(ic) ((unsigned long)ic & IC_ICTT_MASK) + +#define DEFAULT_TXIC mk_ic_value(DEFAULT_TXCOUNT, DEFAULT_TXTIME) +#define DEFAULT_RXIC mk_ic_value(DEFAULT_RXCOUNT, DEFAULT_RXTIME) + +#define skip_bd(bdp, stride, base, ring_size) ({ \ + typeof(bdp) new_bd = (bdp) + (stride); \ + (new_bd >= (base) + (ring_size)) ? (new_bd - (ring_size)) : new_bd; }) + +#define next_bd(bdp, base, ring_size) skip_bd(bdp, 1, base, ring_size) #define RCTRL_PAL_MASK 0x001f0000 #define RCTRL_VLEX 0x00002000 @@ -200,8 +212,10 @@ extern const char gfar_driver_version[]; #define RCTRL_PRSDEP_INIT 0x000000c0 #define RCTRL_PROM 0x00000008 #define RCTRL_EMEN 0x00000002 -#define RCTRL_CHECKSUMMING (RCTRL_IPCSEN \ - | RCTRL_TUCSEN | RCTRL_PRSDEP_INIT) +#define RCTRL_REQ_PARSER (RCTRL_VLEX | RCTRL_IPCSEN | \ + RCTRL_TUCSEN) +#define RCTRL_CHECKSUMMING (RCTRL_IPCSEN | RCTRL_TUCSEN | \ + RCTRL_PRSDEP_INIT) #define RCTRL_EXTHASH (RCTRL_GHTX) #define RCTRL_VLAN (RCTRL_PRSDEP_INIT) #define RCTRL_PADDING(x) ((x << 16) & RCTRL_PAL_MASK) @@ -237,7 +251,7 @@ extern const char gfar_driver_version[]; #define IEVENT_FIQ 0x00000004 #define IEVENT_DPE 0x00000002 #define IEVENT_PERR 0x00000001 -#define IEVENT_RX_MASK (IEVENT_RXB0 | IEVENT_RXF0) +#define IEVENT_RX_MASK (IEVENT_RXB0 | IEVENT_RXF0 | IEVENT_BSY) #define IEVENT_TX_MASK (IEVENT_TXB | IEVENT_TXF) #define IEVENT_RTX_MASK (IEVENT_RX_MASK | IEVENT_TX_MASK) #define IEVENT_ERR_MASK \ @@ -297,6 +311,8 @@ extern const char gfar_driver_version[]; #define ATTRELI_EI_MASK 0x00003fff #define ATTRELI_EI(x) (x) +#define BD_LFLAG(flags) ((flags) << 16) +#define BD_LENGTH_MASK 0x00ff /* TxBD status field bits */ #define TXBD_READY 0x8000 @@ -358,10 +374,17 @@ extern const char gfar_driver_version[]; #define RXFCB_PERR_MASK 0x000c #define RXFCB_PERR_BADL3 0x0008 +#define GFAR_INT_NAME_MAX IFNAMSIZ + 4 + struct txbd8 { - u16 status; /* Status Fields */ - u16 length; /* Buffer length */ + union { + struct { + u16 status; /* Status Fields */ + u16 length; /* Buffer length */ + }; + u32 lstatus; + }; u32 bufPtr; /* Buffer Pointer */ }; @@ -376,8 +399,13 @@ struct txfcb { struct rxbd8 { - u16 status; /* Status Fields */ - u16 length; /* Buffer Length */ + union { + struct { + u16 status; /* Status Fields */ + u16 length; /* Buffer Length */ + }; + u32 lstatus; + }; u32 bufPtr; /* Buffer Pointer */ }; @@ -657,6 +685,19 @@ struct gfar { }; +/* Flags related to gianfar device features */ +#define FSL_GIANFAR_DEV_HAS_GIGABIT 0x00000001 +#define FSL_GIANFAR_DEV_HAS_COALESCE 0x00000002 +#define FSL_GIANFAR_DEV_HAS_RMON 0x00000004 +#define FSL_GIANFAR_DEV_HAS_MULTI_INTR 0x00000008 +#define FSL_GIANFAR_DEV_HAS_CSUM 0x00000010 +#define FSL_GIANFAR_DEV_HAS_VLAN 0x00000020 +#define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH 0x00000040 +#define FSL_GIANFAR_DEV_HAS_PADDING 0x00000080 +#define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET 0x00000100 +#define FSL_GIANFAR_DEV_HAS_BD_STASHING 0x00000200 +#define FSL_GIANFAR_DEV_HAS_BUF_STASHING 0x00000400 + /* Struct stolen almost completely (and shamelessly) from the FCC enet source * (Ok, that's not so true anymore, but there is a family resemblence) * The GFAR buffer descriptors track the ring buffers. The rx_bd_base @@ -681,8 +722,7 @@ struct gfar_private { /* Configuration info for the coalescing features */ unsigned char txcoalescing; - unsigned short txcount; - unsigned short txtime; + unsigned long txic; /* Buffer descriptor pointers */ struct txbd8 *tx_bd_base; /* First tx buffer descriptor */ @@ -690,10 +730,12 @@ struct gfar_private { struct txbd8 *dirty_tx; /* First buffer in line to be transmitted */ unsigned int tx_ring_size; + unsigned int num_txbdfree; /* number of TxBDs free */ /* RX Locked fields */ spinlock_t rxlock; + struct device_node *node; struct net_device *dev; struct napi_struct napi; @@ -703,8 +745,7 @@ struct gfar_private { /* RX Coalescing values */ unsigned char rxcoalescing; - unsigned short rxcount; - unsigned short rxtime; + unsigned long rxic; struct rxbd8 *rx_bd_base; /* First Rx buffers */ struct rxbd8 *cur_rx; /* Next free rx ring entry */ @@ -733,8 +774,10 @@ struct gfar_private { /* Bitfield update lock */ spinlock_t bflock; - unsigned char vlan_enable:1, - rx_csum_enable:1, + phy_interface_t interface; + char phy_bus_id[BUS_ID_SIZE]; + u32 device_flags; + unsigned char rx_csum_enable:1, extended_hash:1, bd_stash_en:1, wol_en:1; /* Wake-on-LAN enabled */ @@ -744,11 +787,9 @@ struct gfar_private { unsigned int interruptReceive; unsigned int interruptError; - /* info structure initialized by platform code */ - struct gianfar_platform_data *einfo; - /* PHY stuff */ struct phy_device *phydev; + struct phy_device *tbiphy; struct mii_bus *mii_bus; int oldspeed; int oldduplex; @@ -757,6 +798,11 @@ struct gfar_private { uint32_t msg_enable; struct work_struct reset_task; + + char int_name_tx[GFAR_INT_NAME_MAX]; + char int_name_rx[GFAR_INT_NAME_MAX]; + char int_name_er[GFAR_INT_NAME_MAX]; + /* Network Statistics */ struct gfar_extra_stats extra_stats; }; diff --git a/drivers/net/gianfar_ethtool.c b/drivers/net/gianfar_ethtool.c index fb7d3ccc0fdce8eec47cef3218e39c67746d662f..59b3b5d98efe5bcc746e687b766301e5c6b52720 100644 --- a/drivers/net/gianfar_ethtool.c +++ b/drivers/net/gianfar_ethtool.c @@ -121,7 +121,7 @@ static void gfar_gstrings(struct net_device *dev, u32 stringset, u8 * buf) { struct gfar_private *priv = netdev_priv(dev); - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) memcpy(buf, stat_gstrings, GFAR_STATS_LEN * ETH_GSTRING_LEN); else memcpy(buf, stat_gstrings, @@ -138,7 +138,7 @@ static void gfar_fill_stats(struct net_device *dev, struct ethtool_stats *dummy, struct gfar_private *priv = netdev_priv(dev); u64 *extra = (u64 *) & priv->extra_stats; - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) { u32 __iomem *rmon = (u32 __iomem *) & priv->regs->rmon; struct gfar_stats *stats = (struct gfar_stats *) buf; @@ -158,7 +158,7 @@ static int gfar_sset_count(struct net_device *dev, int sset) switch (sset) { case ETH_SS_STATS: - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_RMON) + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_RMON) return GFAR_STATS_LEN; else return GFAR_EXTRA_STATS_LEN; @@ -201,8 +201,8 @@ static int gfar_gsettings(struct net_device *dev, struct ethtool_cmd *cmd) if (NULL == phydev) return -ENODEV; - cmd->maxtxpkt = priv->txcount; - cmd->maxrxpkt = priv->rxcount; + cmd->maxtxpkt = get_icft_value(priv->txic); + cmd->maxrxpkt = get_icft_value(priv->rxic); return phy_ethtool_gset(phydev, cmd); } @@ -279,18 +279,26 @@ static unsigned int gfar_ticks2usecs(struct gfar_private *priv, unsigned int tic static int gfar_gcoalesce(struct net_device *dev, struct ethtool_coalesce *cvals) { struct gfar_private *priv = netdev_priv(dev); + unsigned long rxtime; + unsigned long rxcount; + unsigned long txtime; + unsigned long txcount; - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; if (NULL == priv->phydev) return -ENODEV; - cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, priv->rxtime); - cvals->rx_max_coalesced_frames = priv->rxcount; + rxtime = get_ictt_value(priv->rxic); + rxcount = get_icft_value(priv->rxic); + txtime = get_ictt_value(priv->txic); + txcount = get_icft_value(priv->txic);; + cvals->rx_coalesce_usecs = gfar_ticks2usecs(priv, rxtime); + cvals->rx_max_coalesced_frames = rxcount; - cvals->tx_coalesce_usecs = gfar_ticks2usecs(priv, priv->txtime); - cvals->tx_max_coalesced_frames = priv->txcount; + cvals->tx_coalesce_usecs = gfar_ticks2usecs(priv, txtime); + cvals->tx_max_coalesced_frames = txcount; cvals->use_adaptive_rx_coalesce = 0; cvals->use_adaptive_tx_coalesce = 0; @@ -332,7 +340,7 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals { struct gfar_private *priv = netdev_priv(dev); - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_COALESCE)) return -EOPNOTSUPP; /* Set up rx coalescing */ @@ -358,8 +366,9 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals return -EINVAL; } - priv->rxtime = gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs); - priv->rxcount = cvals->rx_max_coalesced_frames; + priv->rxic = mk_ic_value( + gfar_usecs2ticks(priv, cvals->rx_coalesce_usecs), + cvals->rx_max_coalesced_frames); /* Set up tx coalescing */ if ((cvals->tx_coalesce_usecs == 0) || @@ -381,20 +390,17 @@ static int gfar_scoalesce(struct net_device *dev, struct ethtool_coalesce *cvals return -EINVAL; } - priv->txtime = gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs); - priv->txcount = cvals->tx_max_coalesced_frames; + priv->txic = mk_ic_value( + gfar_usecs2ticks(priv, cvals->tx_coalesce_usecs), + cvals->tx_max_coalesced_frames); + gfar_write(&priv->regs->rxic, 0); if (priv->rxcoalescing) - gfar_write(&priv->regs->rxic, - mk_ic_value(priv->rxcount, priv->rxtime)); - else - gfar_write(&priv->regs->rxic, 0); + gfar_write(&priv->regs->rxic, priv->rxic); + gfar_write(&priv->regs->txic, 0); if (priv->txcoalescing) - gfar_write(&priv->regs->txic, - mk_ic_value(priv->txcount, priv->txtime)); - else - gfar_write(&priv->regs->txic, 0); + gfar_write(&priv->regs->txic, priv->txic); return 0; } @@ -456,11 +462,12 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva spin_lock(&priv->rxlock); gfar_halt(dev); - gfar_clean_rx_ring(dev, priv->rx_ring_size); spin_unlock(&priv->rxlock); spin_unlock_irqrestore(&priv->txlock, flags); + gfar_clean_rx_ring(dev, priv->rx_ring_size); + /* Now we take down the rings to rebuild them */ stop_gfar(dev); } @@ -468,11 +475,13 @@ static int gfar_sringparam(struct net_device *dev, struct ethtool_ringparam *rva /* Change the size */ priv->rx_ring_size = rvals->rx_pending; priv->tx_ring_size = rvals->tx_pending; + priv->num_txbdfree = priv->tx_ring_size; /* Rebuild the rings with the new size */ - if (dev->flags & IFF_UP) + if (dev->flags & IFF_UP) { err = startup_gfar(dev); - + netif_wake_queue(dev); + } return err; } @@ -482,7 +491,7 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) unsigned long flags; int err = 0; - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) return -EOPNOTSUPP; if (dev->flags & IFF_UP) { @@ -492,11 +501,12 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) spin_lock(&priv->rxlock); gfar_halt(dev); - gfar_clean_rx_ring(dev, priv->rx_ring_size); spin_unlock(&priv->rxlock); spin_unlock_irqrestore(&priv->txlock, flags); + gfar_clean_rx_ring(dev, priv->rx_ring_size); + /* Now we take down the rings to rebuild them */ stop_gfar(dev); } @@ -505,9 +515,10 @@ static int gfar_set_rx_csum(struct net_device *dev, uint32_t data) priv->rx_csum_enable = data; spin_unlock_irqrestore(&priv->bflock, flags); - if (dev->flags & IFF_UP) + if (dev->flags & IFF_UP) { err = startup_gfar(dev); - + netif_wake_queue(dev); + } return err; } @@ -515,7 +526,7 @@ static uint32_t gfar_get_rx_csum(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) return 0; return priv->rx_csum_enable; @@ -523,22 +534,19 @@ static uint32_t gfar_get_rx_csum(struct net_device *dev) static int gfar_set_tx_csum(struct net_device *dev, uint32_t data) { - unsigned long flags; struct gfar_private *priv = netdev_priv(dev); - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) return -EOPNOTSUPP; - spin_lock_irqsave(&priv->txlock, flags); - gfar_halt(dev); + netif_tx_lock_bh(dev); if (data) dev->features |= NETIF_F_IP_CSUM; else dev->features &= ~NETIF_F_IP_CSUM; - gfar_start(dev); - spin_unlock_irqrestore(&priv->txlock, flags); + netif_tx_unlock_bh(dev); return 0; } @@ -547,7 +555,7 @@ static uint32_t gfar_get_tx_csum(struct net_device *dev) { struct gfar_private *priv = netdev_priv(dev); - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM)) return 0; return (dev->features & NETIF_F_IP_CSUM) != 0; @@ -570,7 +578,7 @@ static void gfar_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { struct gfar_private *priv = netdev_priv(dev); - if (priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) { + if (priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) { wol->supported = WAKE_MAGIC; wol->wolopts = priv->wol_en ? WAKE_MAGIC : 0; } else { @@ -583,7 +591,7 @@ static int gfar_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct gfar_private *priv = netdev_priv(dev); unsigned long flags; - if (!(priv->einfo->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) && + if (!(priv->device_flags & FSL_GIANFAR_DEV_HAS_MAGIC_PACKET) && wol->wolopts != 0) return -EINVAL; @@ -616,6 +624,7 @@ const struct ethtool_ops gfar_ethtool_ops = { .get_tx_csum = gfar_get_tx_csum, .set_rx_csum = gfar_set_rx_csum, .set_tx_csum = gfar_set_tx_csum, + .set_sg = ethtool_op_set_sg, .get_msglevel = gfar_get_msglevel, .set_msglevel = gfar_set_msglevel, #ifdef CONFIG_PM diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c index 0e2595d24933cd8f6549153782d87010672ee2d7..f3706e415b45323e8de205581b6ed4a57e8ea51b 100644 --- a/drivers/net/gianfar_mii.c +++ b/drivers/net/gianfar_mii.c @@ -34,6 +34,8 @@ #include #include #include +#include +#include #include #include @@ -150,19 +152,83 @@ static int gfar_mdio_reset(struct mii_bus *bus) return 0; } +/* Allocate an array which provides irq #s for each PHY on the given bus */ +static int *create_irq_map(struct device_node *np) +{ + int *irqs; + int i; + struct device_node *child = NULL; + + irqs = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL); + + if (!irqs) + return NULL; + + for (i = 0; i < PHY_MAX_ADDR; i++) + irqs[i] = PHY_POLL; + + while ((child = of_get_next_child(np, child)) != NULL) { + int irq = irq_of_parse_and_map(child, 0); + const u32 *id; + + if (irq == NO_IRQ) + continue; + + id = of_get_property(child, "reg", NULL); + + if (!id) + continue; + + if (*id < PHY_MAX_ADDR && *id >= 0) + irqs[*id] = irq; + else + printk(KERN_WARNING "%s: " + "%d is not a valid PHY address\n", + np->full_name, *id); + } + + return irqs; +} + + +void gfar_mdio_bus_name(char *name, struct device_node *np) +{ + const u32 *reg; + + reg = of_get_property(np, "reg", NULL); -static int gfar_mdio_probe(struct device *dev) + snprintf(name, MII_BUS_ID_SIZE, "%s@%x", np->name, reg ? *reg : 0); +} + +/* Scan the bus in reverse, looking for an empty spot */ +static int gfar_mdio_find_free(struct mii_bus *new_bus) +{ + int i; + + for (i = PHY_MAX_ADDR; i > 0; i--) { + u32 phy_id; + + if (get_phy_id(new_bus, i, &phy_id)) + return -1; + + if (phy_id == 0xffffffff) + break; + } + + return i; +} + +static int gfar_mdio_probe(struct of_device *ofdev, + const struct of_device_id *match) { - struct platform_device *pdev = to_platform_device(dev); - struct gianfar_mdio_data *pdata; struct gfar_mii __iomem *regs; struct gfar __iomem *enet_regs; struct mii_bus *new_bus; - struct resource *r; - int i, err = 0; - - if (NULL == dev) - return -EINVAL; + int err = 0; + u64 addr, size; + struct device_node *np = ofdev->node; + struct device_node *tbi; + int tbiaddr = -1; new_bus = mdiobus_alloc(); if (NULL == new_bus) @@ -172,31 +238,28 @@ static int gfar_mdio_probe(struct device *dev) new_bus->read = &gfar_mdio_read, new_bus->write = &gfar_mdio_write, new_bus->reset = &gfar_mdio_reset, - snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); - - pdata = (struct gianfar_mdio_data *)pdev->dev.platform_data; - - if (NULL == pdata) { - printk(KERN_ERR "gfar mdio %d: Missing platform data!\n", pdev->id); - return -ENODEV; - } - - r = platform_get_resource(pdev, IORESOURCE_MEM, 0); + gfar_mdio_bus_name(new_bus->id, np); /* Set the PHY base address */ - regs = ioremap(r->start, sizeof (struct gfar_mii)); + addr = of_translate_address(np, of_get_address(np, 0, &size, NULL)); + regs = ioremap(addr, size); if (NULL == regs) { err = -ENOMEM; - goto reg_map_fail; + goto err_free_bus; } new_bus->priv = (void __force *)regs; - new_bus->irq = pdata->irq; + new_bus->irq = create_irq_map(np); + + if (new_bus->irq == NULL) { + err = -ENOMEM; + goto err_unmap_regs; + } - new_bus->parent = dev; - dev_set_drvdata(dev, new_bus); + new_bus->parent = &ofdev->dev; + dev_set_drvdata(&ofdev->dev, new_bus); /* * This is mildly evil, but so is our hardware for doing this. @@ -206,96 +269,109 @@ static int gfar_mdio_probe(struct device *dev) enet_regs = (struct gfar __iomem *) ((char *)regs - offsetof(struct gfar, gfar_mii_regs)); - /* Scan the bus, looking for an empty spot for TBIPA */ - gfar_write(&enet_regs->tbipa, 0); - for (i = PHY_MAX_ADDR; i > 0; i--) { - u32 phy_id; + for_each_child_of_node(np, tbi) { + if (!strncmp(tbi->type, "tbi-phy", 8)) + break; + } - err = get_phy_id(new_bus, i, &phy_id); - if (err) - goto bus_register_fail; + if (tbi) { + const u32 *prop = of_get_property(tbi, "reg", NULL); - if (phy_id == 0xffffffff) - break; + if (prop) + tbiaddr = *prop; } - /* The bus is full. We don't support using 31 PHYs, sorry */ - if (i == 0) { + if (tbiaddr == -1) { + gfar_write(&enet_regs->tbipa, 0); + + tbiaddr = gfar_mdio_find_free(new_bus); + } + + /* + * We define TBIPA at 0 to be illegal, opting to fail for boards that + * have PHYs at 1-31, rather than change tbipa and rescan. + */ + if (tbiaddr == 0) { err = -EBUSY; - goto bus_register_fail; + goto err_free_irqs; } - gfar_write(&enet_regs->tbipa, i); + gfar_write(&enet_regs->tbipa, tbiaddr); + + /* + * The TBIPHY-only buses will find PHYs at every address, + * so we mask them all but the TBI + */ + if (!of_device_is_compatible(np, "fsl,gianfar-mdio")) + new_bus->phy_mask = ~(1 << tbiaddr); err = mdiobus_register(new_bus); - if (0 != err) { + if (err != 0) { printk (KERN_ERR "%s: Cannot register as MDIO bus\n", new_bus->name); - goto bus_register_fail; + goto err_free_irqs; } return 0; -bus_register_fail: +err_free_irqs: + kfree(new_bus->irq); +err_unmap_regs: iounmap(regs); -reg_map_fail: +err_free_bus: mdiobus_free(new_bus); return err; } -static int gfar_mdio_remove(struct device *dev) +static int gfar_mdio_remove(struct of_device *ofdev) { - struct mii_bus *bus = dev_get_drvdata(dev); + struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); mdiobus_unregister(bus); - dev_set_drvdata(dev, NULL); + dev_set_drvdata(&ofdev->dev, NULL); iounmap((void __iomem *)bus->priv); bus->priv = NULL; + kfree(bus->irq); mdiobus_free(bus); return 0; } -static struct device_driver gianfar_mdio_driver = { +static struct of_device_id gfar_mdio_match[] = +{ + { + .compatible = "fsl,gianfar-mdio", + }, + { + .compatible = "fsl,gianfar-tbi", + }, + { + .type = "mdio", + .compatible = "gianfar", + }, + {}, +}; + +static struct of_platform_driver gianfar_mdio_driver = { .name = "fsl-gianfar_mdio", - .bus = &platform_bus_type, + .match_table = gfar_mdio_match, + .probe = gfar_mdio_probe, .remove = gfar_mdio_remove, }; -static int match_mdio_bus(struct device *dev, void *data) -{ - const struct gfar_private *priv = data; - const struct platform_device *pdev = to_platform_device(dev); - - return !strcmp(pdev->name, gianfar_mdio_driver.name) && - pdev->id == priv->einfo->mdio_bus; -} - -/* Given a gfar_priv structure, find the mii_bus controlled by this device (not - * necessarily the same as the bus the gfar's PHY is on), if one exists. - * Normally only the first gianfar controls a mii_bus. */ -struct mii_bus *gfar_get_miibus(const struct gfar_private *priv) -{ - /*const*/ struct device *d; - - d = bus_find_device(gianfar_mdio_driver.bus, NULL, (void *)priv, - match_mdio_bus); - return d ? dev_get_drvdata(d) : NULL; -} - int __init gfar_mdio_init(void) { - return driver_register(&gianfar_mdio_driver); + return of_register_platform_driver(&gianfar_mdio_driver); } void gfar_mdio_exit(void) { - driver_unregister(&gianfar_mdio_driver); + of_unregister_platform_driver(&gianfar_mdio_driver); } diff --git a/drivers/net/gianfar_mii.h b/drivers/net/gianfar_mii.h index 02dc970ca1ffb25e79c63c6205a46c0fceafdcfa..65c242cd468aca22bed0dba1484a3f38d1d98a07 100644 --- a/drivers/net/gianfar_mii.h +++ b/drivers/net/gianfar_mii.h @@ -49,4 +49,6 @@ int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum); struct mii_bus *gfar_get_miibus(const struct gfar_private *priv); int __init gfar_mdio_init(void); void gfar_mdio_exit(void); + +void gfar_mdio_bus_name(char *name, struct device_node *np); #endif /* GIANFAR_PHY_H */ diff --git a/drivers/net/hamachi.c b/drivers/net/hamachi.c index 3199526bcecbab3f879f9cd56507c570305a8c2f..32200227c9236ea22fb791992531353ab0a729c4 100644 --- a/drivers/net/hamachi.c +++ b/drivers/net/hamachi.c @@ -568,6 +568,19 @@ static void set_rx_mode(struct net_device *dev); static const struct ethtool_ops ethtool_ops; static const struct ethtool_ops ethtool_ops_no_mii; +static const struct net_device_ops hamachi_netdev_ops = { + .ndo_open = hamachi_open, + .ndo_stop = hamachi_close, + .ndo_start_xmit = hamachi_start_xmit, + .ndo_get_stats = hamachi_get_stats, + .ndo_set_multicast_list = set_rx_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = hamachi_tx_timeout, + .ndo_do_ioctl = netdev_ioctl, +}; + + static int __devinit hamachi_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -582,7 +595,6 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, void *ring_space; dma_addr_t ring_dma; int ret = -ENOMEM; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -723,17 +735,11 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, /* The Hamachi-specific entries in the device structure. */ - dev->open = &hamachi_open; - dev->hard_start_xmit = &hamachi_start_xmit; - dev->stop = &hamachi_close; - dev->get_stats = &hamachi_get_stats; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &netdev_ioctl; + dev->netdev_ops = &hamachi_netdev_ops; if (chip_tbl[hmp->chip_id].flags & CanHaveMII) SET_ETHTOOL_OPS(dev, ðtool_ops); else SET_ETHTOOL_OPS(dev, ðtool_ops_no_mii); - dev->tx_timeout = &hamachi_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; if (mtu) dev->mtu = mtu; @@ -744,9 +750,9 @@ static int __devinit hamachi_init_one (struct pci_dev *pdev, goto err_out_unmap_rx; } - printk(KERN_INFO "%s: %s type %x at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s type %x at %p, %pM, IRQ %d.\n", dev->name, chip_tbl[chip_id].name, readl(ioaddr + ChipRev), - ioaddr, print_mac(mac, dev->dev_addr), irq); + ioaddr, dev->dev_addr, irq); i = readb(ioaddr + PCIClkMeas); printk(KERN_INFO "%s: %d-bit %d Mhz PCI bus (%d), Virtual Jumpers " "%2.2x, LPA %4.4x.\n", @@ -1646,7 +1652,6 @@ static int hamachi_rx(struct net_device *dev) #endif /* RX_CHECKSUM */ netif_rx(skb); - dev->last_rx = jiffies; hmp->stats.rx_packets++; } entry = (++hmp->cur_rx) % RX_RING_SIZE; diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c index 0f501d2ca93560553bed346b225cc53793b5e17a..50f1e172ee8f9556a09e7fbdb1ab05f69c09f74e 100644 --- a/drivers/net/hamradio/6pack.c +++ b/drivers/net/hamradio/6pack.c @@ -373,7 +373,6 @@ static void sp_bump(struct sixpack *sp, char cmd) memcpy(ptr, sp->cooked_buf + 1, count); skb->protocol = ax25_type_trans(skb, sp->dev); netif_rx(skb); - sp->dev->last_rx = jiffies; sp->dev->stats.rx_packets++; return; diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c index 00bc7fbb6b374687ebd45f79a84cee5ad472bcaa..81a65e3a1c053fe070e9a3c8985ef6f909439801 100644 --- a/drivers/net/hamradio/baycom_epp.c +++ b/drivers/net/hamradio/baycom_epp.c @@ -555,7 +555,6 @@ static void do_rxpacket(struct net_device *dev) memcpy(cp, bc->hdlcrx.buf, pktlen - 1); skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; bc->stats.rx_packets++; } diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c index 58f4b1d7bf1fc303d5b962b9820aa423c943168b..46f8f3390e7d1806c038f791f0f103c744c09830 100644 --- a/drivers/net/hamradio/bpqether.c +++ b/drivers/net/hamradio/bpqether.c @@ -230,7 +230,6 @@ static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_ty skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; unlock: rcu_read_unlock(); @@ -441,16 +440,15 @@ static int bpq_seq_show(struct seq_file *seq, void *v) "dev ether destination accept from\n"); else { const struct bpqdev *bpqdev = v; - DECLARE_MAC_BUF(mac); - seq_printf(seq, "%-5s %-10s %s ", + seq_printf(seq, "%-5s %-10s %pM ", bpqdev->axdev->name, bpqdev->ethdev->name, - print_mac(mac, bpqdev->dest_addr)); + bpqdev->dest_addr); if (is_multicast_ether_addr(bpqdev->acpt_addr)) seq_printf(seq, "*\n"); else - seq_printf(seq, "%s\n", print_mac(mac, bpqdev->acpt_addr)); + seq_printf(seq, "%pM\n", bpqdev->acpt_addr); } return 0; diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c index e8cfadefa4b6751dbb74bd663a0f101e76a98d54..e67103396ed7649b32a331e7f4d9fc341f6dc206 100644 --- a/drivers/net/hamradio/dmascc.c +++ b/drivers/net/hamradio/dmascc.c @@ -572,7 +572,7 @@ static int __init setup_adapter(int card_base, int type, int n) priv->param.persist = 256; priv->param.dma = -1; INIT_WORK(&priv->rx_work, rx_bh); - dev->priv = priv; + dev->ml_priv = priv; sprintf(dev->name, "dmascc%i", 2 * n + i); dev->base_addr = card_base; dev->irq = irq; @@ -720,7 +720,7 @@ static int read_scc_data(struct scc_priv *priv) static int scc_open(struct net_device *dev) { - struct scc_priv *priv = dev->priv; + struct scc_priv *priv = dev->ml_priv; struct scc_info *info = priv->info; int card_base = priv->card_base; @@ -862,7 +862,7 @@ static int scc_open(struct net_device *dev) static int scc_close(struct net_device *dev) { - struct scc_priv *priv = dev->priv; + struct scc_priv *priv = dev->ml_priv; struct scc_info *info = priv->info; int card_base = priv->card_base; @@ -891,7 +891,7 @@ static int scc_close(struct net_device *dev) static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct scc_priv *priv = dev->priv; + struct scc_priv *priv = dev->ml_priv; switch (cmd) { case SIOCGSCCPARAM: @@ -918,7 +918,7 @@ static int scc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) { - struct scc_priv *priv = dev->priv; + struct scc_priv *priv = dev->ml_priv; unsigned long flags; int i; @@ -963,7 +963,7 @@ static int scc_send_packet(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *scc_get_stats(struct net_device *dev) { - struct scc_priv *priv = dev->priv; + struct scc_priv *priv = dev->ml_priv; return &priv->stats; } @@ -1283,7 +1283,6 @@ static void rx_bh(struct work_struct *ugli_api) memcpy(&data[1], priv->rx_buf[i], cb); skb->protocol = ax25_type_trans(skb, priv->dev); netif_rx(skb); - priv->dev->last_rx = jiffies; priv->stats.rx_packets++; priv->stats.rx_bytes += cb; } diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c index c258a0586e611d641c134f53114c76df0025ec66..8eba61a1d4abc3ff7365b08d33f4d70c2d368819 100644 --- a/drivers/net/hamradio/hdlcdrv.c +++ b/drivers/net/hamradio/hdlcdrv.c @@ -162,7 +162,6 @@ static void hdlc_rx_flag(struct net_device *dev, struct hdlcdrv_state *s) memcpy(cp, s->hdlcrx.buffer, pkt_len - 1); skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; s->stats.rx_packets++; } diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c index b8e25c4624d2c2db3d6e84bb90e7b7cd55261a6e..bbdb311b8420c6cd500a60d8293132d7e67b3059 100644 --- a/drivers/net/hamradio/mkiss.c +++ b/drivers/net/hamradio/mkiss.c @@ -303,7 +303,6 @@ static void ax_bump(struct mkiss *ax) memcpy(skb_put(skb,count), ax->rbuff, count); skb->protocol = ax25_type_trans(skb, ax->dev); netif_rx(skb); - ax->dev->last_rx = jiffies; ax->stats.rx_packets++; ax->stats.rx_bytes += count; spin_unlock_bh(&ax->buflock); @@ -847,12 +846,13 @@ static int mkiss_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { struct mkiss *ax = mkiss_get(tty); - struct net_device *dev = ax->dev; + struct net_device *dev; unsigned int tmp, err; /* First make sure we're connected. */ if (ax == NULL) return -ENXIO; + dev = ax->dev; switch (cmd) { case SIOCGIFNAME: diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c index c17e39bc546007cda47673ead55580e4e6b22357..c011af7088ea41cfb06325c02b6847addafed2bd 100644 --- a/drivers/net/hamradio/scc.c +++ b/drivers/net/hamradio/scc.c @@ -1518,7 +1518,7 @@ static int scc_net_alloc(const char *name, struct scc_channel *scc) if (!dev) return -ENOMEM; - dev->priv = scc; + dev->ml_priv = scc; scc->dev = dev; spin_lock_init(&scc->lock); init_timer(&scc->tx_t); @@ -1575,7 +1575,7 @@ static void scc_net_setup(struct net_device *dev) static int scc_net_open(struct net_device *dev) { - struct scc_channel *scc = (struct scc_channel *) dev->priv; + struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; if (!scc->init) return -EINVAL; @@ -1593,7 +1593,7 @@ static int scc_net_open(struct net_device *dev) static int scc_net_close(struct net_device *dev) { - struct scc_channel *scc = (struct scc_channel *) dev->priv; + struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; unsigned long flags; netif_stop_queue(dev); @@ -1627,7 +1627,6 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb) skb->protocol = ax25_type_trans(skb, scc->dev); netif_rx(skb); - scc->dev->last_rx = jiffies; return; } @@ -1635,7 +1634,7 @@ static void scc_net_rx(struct scc_channel *scc, struct sk_buff *skb) static int scc_net_tx(struct sk_buff *skb, struct net_device *dev) { - struct scc_channel *scc = (struct scc_channel *) dev->priv; + struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; unsigned long flags; char kisscmd; @@ -1705,7 +1704,7 @@ static int scc_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct scc_mem_config memcfg; struct scc_hw_config hwcfg; struct scc_calibrate cal; - struct scc_channel *scc = (struct scc_channel *) dev->priv; + struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; int chan; unsigned char device_name[IFNAMSIZ]; void __user *arg = ifr->ifr_data; @@ -1952,7 +1951,7 @@ static int scc_net_set_mac_address(struct net_device *dev, void *addr) static struct net_device_stats *scc_net_get_stats(struct net_device *dev) { - struct scc_channel *scc = (struct scc_channel *) dev->priv; + struct scc_channel *scc = (struct scc_channel *) dev->ml_priv; scc->dev_stat.rx_errors = scc->stat.rxerrs + scc->stat.rx_over; scc->dev_stat.tx_errors = scc->stat.txerrs + scc->stat.tx_under; diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c index 1c942862a3f4944710de74c546cba66943b8b81a..5407f7486c9c00cdc310962e237284897eac9113 100644 --- a/drivers/net/hamradio/yam.c +++ b/drivers/net/hamradio/yam.c @@ -515,7 +515,6 @@ static inline void yam_rx_flag(struct net_device *dev, struct yam_port *yp) memcpy(cp, yp->rx_buf, pkt_len - 1); skb->protocol = ax25_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; ++yp->stats.rx_packets; } } diff --git a/drivers/net/hp-plus.c b/drivers/net/hp-plus.c index c01e290d09d28b7e9c1fb240a26a9ba6f92e0900..b507dbc16e62adc5dfb8eaf3b8bfc66ed86b9a95 100644 --- a/drivers/net/hp-plus.c +++ b/drivers/net/hp-plus.c @@ -158,6 +158,21 @@ out: } #endif +static const struct net_device_ops hpp_netdev_ops = { + .ndo_open = hpp_open, + .ndo_stop = hpp_close, + .ndo_start_xmit = eip_start_xmit, + .ndo_tx_timeout = eip_tx_timeout, + .ndo_get_stats = eip_get_stats, + .ndo_set_multicast_list = eip_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = eip_poll, +#endif +}; + + /* Do the interesting part of the probe at a single address. */ static int __init hpp_probe1(struct net_device *dev, int ioaddr) { @@ -166,7 +181,6 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) const char name[] = "HP-PC-LAN+"; int mem_start; static unsigned version_printed; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -193,7 +207,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) } checksum += inb(ioaddr + 14); - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); if (checksum != 0xff) { printk(" bad checksum %2.2x.\n", checksum); @@ -227,11 +241,7 @@ static int __init hpp_probe1(struct net_device *dev, int ioaddr) /* Set the base address to point to the NIC, not the "real" base! */ dev->base_addr = ioaddr + NIC_OFFSET; - dev->open = &hpp_open; - dev->stop = &hpp_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = eip_poll; -#endif + dev->netdev_ops = &hpp_netdev_ops; ei_status.name = name; ei_status.word16 = 0; /* Agggghhhhh! Debug time: 2 days! */ @@ -302,8 +312,7 @@ hpp_open(struct net_device *dev) /* Select the operational page. */ outw(Perf_Page, ioaddr + HP_PAGING); - eip_open(dev); - return 0; + return eip_open(dev); } static int diff --git a/drivers/net/hp.c b/drivers/net/hp.c index 0a8c64930ad305fc756d0dfb7addffff50d406a2..5c4d78c1ff42ae87db44d8dd5f72c32b9a6867e4 100644 --- a/drivers/net/hp.c +++ b/drivers/net/hp.c @@ -59,8 +59,6 @@ static unsigned int hppclan_portlist[] __initdata = static int hp_probe1(struct net_device *dev, int ioaddr); -static int hp_open(struct net_device *dev); -static int hp_close(struct net_device *dev); static void hp_reset_8390(struct net_device *dev); static void hp_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -127,7 +125,6 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) int i, retval, board_id, wordmode; const char *name; static unsigned version_printed; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, HP_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -161,7 +158,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); /* Snarf the interrupt now. Someday this could be moved to open(). */ if (dev->irq < 2) { @@ -199,11 +196,7 @@ static int __init hp_probe1(struct net_device *dev, int ioaddr) /* Set the base address to point to the NIC, not the "real" base! */ dev->base_addr = ioaddr + NIC_OFFSET; - dev->open = &hp_open; - dev->stop = &hp_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = eip_poll; -#endif + dev->netdev_ops = &eip_netdev_ops; ei_status.name = name; ei_status.word16 = wordmode; @@ -228,20 +221,6 @@ out: return retval; } -static int -hp_open(struct net_device *dev) -{ - eip_open(dev); - return 0; -} - -static int -hp_close(struct net_device *dev) -{ - eip_close(dev); - return 0; -} - static void hp_reset_8390(struct net_device *dev) { diff --git a/drivers/net/hp100.c b/drivers/net/hp100.c index 571dd80fb85009910f6a49d3cda27baa085b54f1..ebe7651fcb863b6f560cd533fc0b09b97050fcf7 100644 --- a/drivers/net/hp100.c +++ b/drivers/net/hp100.c @@ -1212,7 +1212,7 @@ static int hp100_init_rxpdl(struct net_device *dev, *(pdlptr + 2) = (u_int) virt_to_whatever(dev, pdlptr); /* Address Frag 1 */ *(pdlptr + 3) = 4; /* Length Frag 1 */ - return ((((MAX_RX_FRAG * 2 + 2) + 3) / 4) * 4); + return roundup(MAX_RX_FRAG * 2 + 2, 4); } @@ -1227,7 +1227,7 @@ static int hp100_init_txpdl(struct net_device *dev, ringptr->pdl_paddr = virt_to_whatever(dev, pdlptr); /* +1 */ ringptr->skb = (void *) NULL; - return ((((MAX_TX_FRAG * 2 + 2) + 3) / 4) * 4); + return roundup(MAX_TX_FRAG * 2 + 2, 4); } /* @@ -1256,7 +1256,7 @@ static int hp100_build_rx_pdl(hp100_ring_t * ringptr, /* Note: This depends on the alloc_skb functions allocating more * space than requested, i.e. aligning to 16bytes */ - ringptr->skb = dev_alloc_skb(((MAX_ETHER_SIZE + 2 + 3) / 4) * 4); + ringptr->skb = dev_alloc_skb(roundup(MAX_ETHER_SIZE + 2, 4)); if (NULL != ringptr->skb) { /* @@ -1279,7 +1279,7 @@ static int hp100_build_rx_pdl(hp100_ring_t * ringptr, #ifdef HP100_DEBUG_BM printk("hp100: %s: build_rx_pdl: PDH@0x%x, skb->data (len %d) at 0x%x\n", dev->name, (u_int) ringptr->pdl, - ((MAX_ETHER_SIZE + 2 + 3) / 4) * 4, + roundup(MAX_ETHER_SIZE + 2, 4), (unsigned int) ringptr->skb->data); #endif @@ -1834,7 +1834,6 @@ static void hp100_rx(struct net_device *dev) ptr[9], ptr[10], ptr[11]); #endif netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } @@ -1925,7 +1924,6 @@ static void hp100_rx_bm(struct net_device *dev) netif_rx(ptr->skb); /* Up and away... */ - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } @@ -2093,9 +2091,8 @@ static void hp100_set_multicast_list(struct net_device *dev) addrs = dmi->dmi_addr; if ((*addrs & 0x01) == 0x01) { /* multicast address? */ #ifdef HP100_DEBUG - DECLARE_MAC_BUF(mac); - printk("hp100: %s: multicast = %s, ", - dev->name, print_mac(mac, addrs)); + printk("hp100: %s: multicast = %pM, ", + dev->name, addrs); #endif for (j = idx = 0; j < 6; j++) { idx ^= *addrs++ & 0x3f; @@ -3057,12 +3054,3 @@ static void __exit hp100_module_exit(void) module_init(hp100_module_init) module_exit(hp100_module_exit) - - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp100.c" - * c-indent-level: 2 - * tab-width: 8 - * End: - */ diff --git a/drivers/net/hydra.c b/drivers/net/hydra.c index b96cf2dcb10932bf7a6758fcd399dba1385b50f1..9cb38a8d4387b8f20f213ebf3d6d9f15361c3a2d 100644 --- a/drivers/net/hydra.c +++ b/drivers/net/hydra.c @@ -94,6 +94,21 @@ static int __devinit hydra_init_one(struct zorro_dev *z, return 0; } +static const struct net_device_ops hydra_netdev_ops = { + .ndo_open = hydra_open, + .ndo_stop = hydra_close, + + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __devinit hydra_init(struct zorro_dev *z) { struct net_device *dev; @@ -103,14 +118,13 @@ static int __devinit hydra_init(struct zorro_dev *z) int start_page, stop_page; int j; int err; - DECLARE_MAC_BUF(mac); static u32 hydra_offsets[16] = { 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - dev = ____alloc_ei_netdev(0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; @@ -145,12 +159,8 @@ static int __devinit hydra_init(struct zorro_dev *z) ei_status.block_output = &hydra_block_output; ei_status.get_8390_hdr = &hydra_get_8390_hdr; ei_status.reg_offset = hydra_offsets; - dev->open = &hydra_open; - dev->stop = &hydra_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = __ei_poll; -#endif + dev->netdev_ops = &hydra_netdev_ops; __NS8390_init(dev, 0); err = register_netdev(dev); @@ -163,8 +173,8 @@ static int __devinit hydra_init(struct zorro_dev *z) zorro_set_drvdata(z, dev); printk(KERN_INFO "%s: Hydra at 0x%08lx, address " - "%s (hydra.c " HYDRA_VERSION ")\n", - dev->name, z->resource.start, print_mac(mac, dev->dev_addr)); + "%pM (hydra.c " HYDRA_VERSION ")\n", + dev->name, z->resource.start, dev->dev_addr); return 0; } diff --git a/drivers/net/ibm_newemac/core.c b/drivers/net/ibm_newemac/core.c index 901212aa37cbf7a55be095d372b47865d9ebb1df..87a706694fb35f6519e4933944b06df429849d48 100644 --- a/drivers/net/ibm_newemac/core.c +++ b/drivers/net/ibm_newemac/core.c @@ -396,9 +396,7 @@ static void emac_hash_mc(struct emac_instance *dev) for (dmi = dev->ndev->mc_list; dmi; dmi = dmi->next) { int slot, reg, mask; - DBG2(dev, "mc %02x:%02x:%02x:%02x:%02x:%02x" NL, - dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2], - dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5]); + DBG2(dev, "mc %pM" NL, dmi->dmi_addr); slot = EMAC_XAHT_CRC_TO_SLOT(dev, ether_crc(ETH_ALEN, dmi->dmi_addr)); reg = EMAC_XAHT_SLOT_TO_REG(dev, slot); @@ -2865,11 +2863,8 @@ static int __devinit emac_probe(struct of_device *ofdev, wake_up_all(&emac_probe_wait); - printk(KERN_INFO - "%s: EMAC-%d %s, MAC %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->name, dev->cell_index, np->full_name, - ndev->dev_addr[0], ndev->dev_addr[1], ndev->dev_addr[2], - ndev->dev_addr[3], ndev->dev_addr[4], ndev->dev_addr[5]); + printk(KERN_INFO "%s: EMAC-%d %s, MAC %pM\n", + ndev->name, dev->cell_index, np->full_name, ndev->dev_addr); if (dev->phy_mode == PHY_MODE_SGMII) printk(KERN_NOTICE "%s: in SGMII mode\n", ndev->name); diff --git a/drivers/net/ibmlana.c b/drivers/net/ibmlana.c index f02764725a221fdde54b43ea9be1e7d65c8e8b75..5b5bf9f9861ac2f63ef8f9db6bca6cfd945fba34 100644 --- a/drivers/net/ibmlana.c +++ b/drivers/net/ibmlana.c @@ -605,7 +605,6 @@ static void irqrx_handler(struct net_device *dev) skb->ip_summed = CHECKSUM_NONE; /* bookkeeping */ - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += rda.length; @@ -914,7 +913,6 @@ static int __devinit ibmlana_init_one(struct device *kdev) int base = 0, irq = 0, iobase = 0, memlen = 0; ibmlana_priv *priv; ibmlana_medium medium; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(ibmlana_priv)); if (!dev) @@ -990,10 +988,10 @@ static int __devinit ibmlana_init_one(struct device *kdev) /* print config */ printk(KERN_INFO "%s: IRQ %d, I/O %#lx, memory %#lx-%#lx, " - "MAC address %s.\n", + "MAC address %pM.\n", dev->name, priv->realirq, dev->base_addr, dev->mem_start, dev->mem_end - 1, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); printk(KERN_INFO "%s: %s medium\n", dev->name, MediaNames[priv->medium]); /* reset board */ diff --git a/drivers/net/ibmveth.c b/drivers/net/ibmveth.c index c2d57f836088c4ba38955de02a5ecd9408f478f8..1f055a9550896824656b5aeb8f7d42b036c3bb0b 100644 --- a/drivers/net/ibmveth.c +++ b/drivers/net/ibmveth.c @@ -527,7 +527,7 @@ retry: static int ibmveth_open(struct net_device *netdev) { - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); u64 mac_address = 0; int rxq_entries = 1; unsigned long lpar_rc; @@ -666,7 +666,7 @@ static int ibmveth_open(struct net_device *netdev) static int ibmveth_close(struct net_device *netdev) { - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); long lpar_rc; ibmveth_debug_printk("close starting\n"); @@ -722,7 +722,7 @@ static u32 netdev_get_link(struct net_device *dev) { static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); if (data) adapter->rx_csum = 1; @@ -741,7 +741,7 @@ static void ibmveth_set_rx_csum_flags(struct net_device *dev, u32 data) static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); if (data) { dev->features |= NETIF_F_IP_CSUM; @@ -753,7 +753,7 @@ static void ibmveth_set_tx_csum_flags(struct net_device *dev, u32 data) static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, void (*done) (struct net_device *, u32)) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); u64 set_attr, clr_attr, ret_attr; long ret; int rc1 = 0, rc2 = 0; @@ -805,7 +805,7 @@ static int ibmveth_set_csum_offload(struct net_device *dev, u32 data, static int ibmveth_set_rx_csum(struct net_device *dev, u32 data) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); if ((data && adapter->rx_csum) || (!data && !adapter->rx_csum)) return 0; @@ -815,7 +815,7 @@ static int ibmveth_set_rx_csum(struct net_device *dev, u32 data) static int ibmveth_set_tx_csum(struct net_device *dev, u32 data) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); int rc = 0; if (data && (dev->features & NETIF_F_IP_CSUM)) @@ -833,7 +833,7 @@ static int ibmveth_set_tx_csum(struct net_device *dev, u32 data) static u32 ibmveth_get_rx_csum(struct net_device *dev) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); return adapter->rx_csum; } @@ -862,7 +862,7 @@ static void ibmveth_get_ethtool_stats(struct net_device *dev, struct ethtool_stats *stats, u64 *data) { int i; - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); for (i = 0; i < ARRAY_SIZE(ibmveth_stats); i++) data[i] = IBMVETH_GET_STAT(adapter, ibmveth_stats[i].offset); @@ -889,7 +889,7 @@ static int ibmveth_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int ibmveth_start_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); union ibmveth_buf_desc desc; unsigned long lpar_rc; unsigned long correlator; @@ -1014,7 +1014,6 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) netdev->stats.rx_packets++; netdev->stats.rx_bytes += length; frames_processed++; - netdev->last_rx = jiffies; } } while (frames_processed < budget); @@ -1029,7 +1028,7 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) ibmveth_assert(lpar_rc == H_SUCCESS); - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); if (ibmveth_rxq_pending_buffer(adapter) && netif_rx_reschedule(netdev, napi)) { @@ -1045,21 +1044,21 @@ static int ibmveth_poll(struct napi_struct *napi, int budget) static irqreturn_t ibmveth_interrupt(int irq, void *dev_instance) { struct net_device *netdev = dev_instance; - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); unsigned long lpar_rc; - if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + if (netif_rx_schedule_prep(&adapter->napi)) { lpar_rc = h_vio_signal(adapter->vdev->unit_address, VIO_IRQ_DISABLE); ibmveth_assert(lpar_rc == H_SUCCESS); - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } return IRQ_HANDLED; } static void ibmveth_set_multicast_list(struct net_device *netdev) { - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); unsigned long lpar_rc; if((netdev->flags & IFF_PROMISC) || (netdev->mc_count > adapter->mcastFilterSize)) { @@ -1107,7 +1106,7 @@ static void ibmveth_set_multicast_list(struct net_device *netdev) static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) { - struct ibmveth_adapter *adapter = dev->priv; + struct ibmveth_adapter *adapter = netdev_priv(dev); struct vio_dev *viodev = adapter->vdev; int new_mtu_oh = new_mtu + IBMVETH_BUFF_OH; int i; @@ -1159,7 +1158,7 @@ static int ibmveth_change_mtu(struct net_device *dev, int new_mtu) #ifdef CONFIG_NET_POLL_CONTROLLER static void ibmveth_poll_controller(struct net_device *dev) { - ibmveth_replenish_task(dev->priv); + ibmveth_replenish_task(netdev_priv(dev)); ibmveth_interrupt(dev->irq, dev); } #endif @@ -1241,7 +1240,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ if(!netdev) return -ENOMEM; - adapter = netdev->priv; + adapter = netdev_priv(netdev); dev->dev.driver_data = netdev; adapter->vdev = dev; @@ -1337,7 +1336,7 @@ static int __devinit ibmveth_probe(struct vio_dev *dev, const struct vio_device_ static int __devexit ibmveth_remove(struct vio_dev *dev) { struct net_device *netdev = dev->dev.driver_data; - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); int i; for(i = 0; iprivate; char *current_mac = ((char*) &adapter->netdev->dev_addr); char *firmware_mac = ((char*) &adapter->mac_addr) ; - DECLARE_MAC_BUF(mac); seq_printf(seq, "%s %s\n\n", ibmveth_driver_string, ibmveth_driver_version); seq_printf(seq, "Unit Address: 0x%x\n", adapter->vdev->unit_address); - seq_printf(seq, "Current MAC: %s\n", print_mac(mac, current_mac)); - seq_printf(seq, "Firmware MAC: %s\n", print_mac(mac, firmware_mac)); + seq_printf(seq, "Current MAC: %pM\n", current_mac); + seq_printf(seq, "Firmware MAC: %pM\n", firmware_mac); seq_printf(seq, "\nAdapter Statistics:\n"); seq_printf(seq, " TX: vio_map_single failres: %ld\n", adapter->tx_map_failed); @@ -1472,7 +1470,7 @@ const char * buf, size_t count) kobj); struct net_device *netdev = container_of(kobj->parent, struct device, kobj)->driver_data; - struct ibmveth_adapter *adapter = netdev->priv; + struct ibmveth_adapter *adapter = netdev_priv(netdev); long value = simple_strtol(buf, NULL, 10); long rc; diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index e4fbefc8c82f80797c5808efcadba2219aafb3c7..60a263001933a53e48e32d28f7adc7dc8914d437 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -137,18 +137,23 @@ resched: } +static const struct net_device_ops ifb_netdev_ops = { + .ndo_open = ifb_open, + .ndo_stop = ifb_close, + .ndo_start_xmit = ifb_xmit, + .ndo_validate_addr = eth_validate_addr, +}; + static void ifb_setup(struct net_device *dev) { /* Initialize the device structure. */ - dev->hard_start_xmit = ifb_xmit; - dev->open = &ifb_open; - dev->stop = &ifb_close; dev->destructor = free_netdev; + dev->netdev_ops = &ifb_netdev_ops; /* Fill in device structure with ethernet-generic values. */ ether_setup(dev); dev->tx_queue_len = TX_Q_LIMIT; - dev->change_mtu = NULL; + dev->flags |= IFF_NOARP; dev->flags &= ~IFF_MULTICAST; random_ether_addr(dev->dev_addr); diff --git a/drivers/net/igb/e1000_defines.h b/drivers/net/igb/e1000_defines.h index ce700689fb57a0ecd09711de176dab632754856a..40d03426c1223f85639e6f03c2d61c6499144636 100644 --- a/drivers/net/igb/e1000_defines.h +++ b/drivers/net/igb/e1000_defines.h @@ -168,18 +168,12 @@ #define E1000_RCTL_RDMTS_HALF 0x00000000 /* rx desc min threshold size */ #define E1000_RCTL_MO_SHIFT 12 /* multicast offset shift */ #define E1000_RCTL_BAM 0x00008000 /* broadcast enable */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 0 */ #define E1000_RCTL_SZ_2048 0x00000000 /* rx buffer size 2048 */ #define E1000_RCTL_SZ_1024 0x00010000 /* rx buffer size 1024 */ #define E1000_RCTL_SZ_512 0x00020000 /* rx buffer size 512 */ #define E1000_RCTL_SZ_256 0x00030000 /* rx buffer size 256 */ -/* these buffer sizes are valid if E1000_RCTL_BSEX is 1 */ -#define E1000_RCTL_SZ_16384 0x00010000 /* rx buffer size 16384 */ -#define E1000_RCTL_SZ_8192 0x00020000 /* rx buffer size 8192 */ -#define E1000_RCTL_SZ_4096 0x00030000 /* rx buffer size 4096 */ #define E1000_RCTL_VFE 0x00040000 /* vlan filter enable */ #define E1000_RCTL_CFIEN 0x00080000 /* canonical form enable */ -#define E1000_RCTL_BSEX 0x02000000 /* Buffer size extension */ #define E1000_RCTL_SECRC 0x04000000 /* Strip Ethernet CRC */ /* @@ -329,6 +323,7 @@ #define E1000_TXD_CMD_IFCS 0x02000000 /* Insert FCS (Ethernet CRC) */ #define E1000_TXD_CMD_RS 0x08000000 /* Report Status */ #define E1000_TXD_CMD_DEXT 0x20000000 /* Descriptor extension (0 = legacy) */ +#define E1000_TXD_STAT_DD 0x00000001 /* Descriptor Done */ /* Extended desc bits for Linksec and timesync */ /* Transmit Control */ diff --git a/drivers/net/igb/e1000_mac.c b/drivers/net/igb/e1000_mac.c index e18747c70becb6521b58f046d7e740e45f410408..97f0049a5d6b60cca24d390e300c4f5938169a1b 100644 --- a/drivers/net/igb/e1000_mac.c +++ b/drivers/net/igb/e1000_mac.c @@ -50,13 +50,6 @@ void igb_remove_device(struct e1000_hw *hw) kfree(hw->dev_spec); } -static void igb_read_pci_cfg(struct e1000_hw *hw, u32 reg, u16 *value) -{ - struct igb_adapter *adapter = hw->back; - - pci_read_config_word(adapter->pdev, reg, value); -} - static s32 igb_read_pcie_cap_reg(struct e1000_hw *hw, u32 reg, u16 *value) { struct igb_adapter *adapter = hw->back; @@ -83,8 +76,8 @@ s32 igb_get_bus_info_pcie(struct e1000_hw *hw) { struct e1000_bus_info *bus = &hw->bus; s32 ret_val; - u32 status; - u16 pcie_link_status, pci_header_type; + u32 reg; + u16 pcie_link_status; bus->type = e1000_bus_type_pci_express; bus->speed = e1000_bus_speed_2500; @@ -99,14 +92,8 @@ s32 igb_get_bus_info_pcie(struct e1000_hw *hw) PCIE_LINK_WIDTH_MASK) >> PCIE_LINK_WIDTH_SHIFT); - igb_read_pci_cfg(hw, PCI_HEADER_TYPE_REGISTER, &pci_header_type); - if (pci_header_type & PCI_HEADER_TYPE_MULTIFUNC) { - status = rd32(E1000_STATUS); - bus->func = (status & E1000_STATUS_FUNC_MASK) - >> E1000_STATUS_FUNC_SHIFT; - } else { - bus->func = 0; - } + reg = rd32(E1000_STATUS); + bus->func = (reg & E1000_STATUS_FUNC_MASK) >> E1000_STATUS_FUNC_SHIFT; return 0; } @@ -229,8 +216,8 @@ void igb_rar_set(struct e1000_hw *hw, u8 *addr, u32 index) if (!hw->mac.disable_av) rar_high |= E1000_RAH_AV; - array_wr32(E1000_RA, (index << 1), rar_low); - array_wr32(E1000_RA, ((index << 1) + 1), rar_high); + wr32(E1000_RAL(index), rar_low); + wr32(E1000_RAH(index), rar_high); } /** diff --git a/drivers/net/igb/e1000_regs.h b/drivers/net/igb/e1000_regs.h index 95523af260562e2a915862b5f3d5049acafa6e78..bdf5d839c4bf96452b76f7eed848bfe0841484c2 100644 --- a/drivers/net/igb/e1000_regs.h +++ b/drivers/net/igb/e1000_regs.h @@ -221,6 +221,10 @@ #define E1000_MTA 0x05200 /* Multicast Table Array - RW Array */ #define E1000_RA 0x05400 /* Receive Address - RW Array */ #define E1000_RA2 0x054E0 /* 2nd half of receive address array - RW Array */ +#define E1000_RAL(_i) (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \ + (0x054E0 + ((_i - 16) * 8))) +#define E1000_RAH(_i) (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \ + (0x054E4 + ((_i - 16) * 8))) #define E1000_VFTA 0x05600 /* VLAN Filter Table Array - RW Array */ #define E1000_VMD_CTL 0x0581C /* VMDq Control - RW */ #define E1000_WUC 0x05800 /* Wakeup Control - RW */ diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index 4ff6f0567f3f1184382712b3ee0c4bf9ac0fd2e0..5a27825cc48a3de22be22fdfd32bd455778549b7 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h @@ -43,8 +43,6 @@ struct igb_adapter; #endif /* Interrupt defines */ -#define IGB_MAX_TX_CLEAN 72 - #define IGB_MIN_DYN_ITR 3000 #define IGB_MAX_DYN_ITR 96000 @@ -127,7 +125,8 @@ struct igb_buffer { /* TX */ struct { unsigned long time_stamp; - u32 length; + u16 length; + u16 next_to_watch; }; /* RX */ struct { @@ -160,7 +159,8 @@ struct igb_ring { u16 itr_register; u16 cpu; - int queue_index; + u16 queue_index; + u16 reg_idx; unsigned int total_bytes; unsigned int total_packets; @@ -294,6 +294,8 @@ struct igb_adapter { unsigned int lro_flushed; unsigned int lro_no_desc; #endif + unsigned int tx_ring_count; + unsigned int rx_ring_count; }; #define IGB_FLAG_HAS_MSI (1 << 0) @@ -325,7 +327,41 @@ extern void igb_reset(struct igb_adapter *); extern int igb_set_spd_dplx(struct igb_adapter *, u16); extern int igb_setup_tx_resources(struct igb_adapter *, struct igb_ring *); extern int igb_setup_rx_resources(struct igb_adapter *, struct igb_ring *); +extern void igb_free_tx_resources(struct igb_ring *); +extern void igb_free_rx_resources(struct igb_ring *); extern void igb_update_stats(struct igb_adapter *); extern void igb_set_ethtool_ops(struct net_device *); +static inline s32 igb_reset_phy(struct e1000_hw *hw) +{ + if (hw->phy.ops.reset_phy) + return hw->phy.ops.reset_phy(hw); + + return 0; +} + +static inline s32 igb_read_phy_reg(struct e1000_hw *hw, u32 offset, u16 *data) +{ + if (hw->phy.ops.read_phy_reg) + return hw->phy.ops.read_phy_reg(hw, offset, data); + + return 0; +} + +static inline s32 igb_write_phy_reg(struct e1000_hw *hw, u32 offset, u16 data) +{ + if (hw->phy.ops.write_phy_reg) + return hw->phy.ops.write_phy_reg(hw, offset, data); + + return 0; +} + +static inline s32 igb_get_phy_info(struct e1000_hw *hw) +{ + if (hw->phy.ops.get_phy_info) + return hw->phy.ops.get_phy_info(hw); + + return 0; +} + #endif /* _IGB_H_ */ diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index 89964fa739a031bb2a778298a96a11e1a30e8ad3..3c831f1472adcbb6608f258e33900c8d6e91088a 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c @@ -101,8 +101,8 @@ static const struct igb_stats igb_gstrings_stats[] = { }; #define IGB_QUEUE_STATS_LEN \ - ((((struct igb_adapter *)netdev->priv)->num_rx_queues + \ - ((struct igb_adapter *)netdev->priv)->num_tx_queues) * \ + ((((struct igb_adapter *)netdev_priv(netdev))->num_rx_queues + \ + ((struct igb_adapter *)netdev_priv(netdev))->num_tx_queues) * \ (sizeof(struct igb_queue_stats) / sizeof(u64))) #define IGB_GLOBAL_STATS_LEN \ sizeof(igb_gstrings_stats) / sizeof(struct igb_stats) @@ -494,8 +494,6 @@ static void igb_get_regs(struct net_device *netdev, /* These should probably be added to e1000_regs.h instead */ #define E1000_PSRTYPE_REG(_i) (0x05480 + ((_i) * 4)) - #define E1000_RAL(_i) (0x05400 + ((_i) * 8)) - #define E1000_RAH(_i) (0x05404 + ((_i) * 8)) #define E1000_IP4AT_REG(_i) (0x05840 + ((_i) * 8)) #define E1000_IP6AT_REG(_i) (0x05880 + ((_i) * 4)) #define E1000_WUPM_REG(_i) (0x05A00 + ((_i) * 4)) @@ -714,15 +712,13 @@ static void igb_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct igb_adapter *adapter = netdev_priv(netdev); - struct igb_ring *tx_ring = adapter->tx_ring; - struct igb_ring *rx_ring = adapter->rx_ring; ring->rx_max_pending = IGB_MAX_RXD; ring->tx_max_pending = IGB_MAX_TXD; ring->rx_mini_max_pending = 0; ring->rx_jumbo_max_pending = 0; - ring->rx_pending = rx_ring->count; - ring->tx_pending = tx_ring->count; + ring->rx_pending = adapter->rx_ring_count; + ring->tx_pending = adapter->tx_ring_count; ring->rx_mini_pending = 0; ring->rx_jumbo_pending = 0; } @@ -731,12 +727,9 @@ static int igb_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { struct igb_adapter *adapter = netdev_priv(netdev); - struct igb_buffer *old_buf; - struct igb_buffer *old_rx_buf; - void *old_desc; + struct igb_ring *temp_ring; int i, err; - u32 new_rx_count, new_tx_count, old_size; - dma_addr_t old_dma; + u32 new_rx_count, new_tx_count; if ((ring->rx_mini_pending) || (ring->rx_jumbo_pending)) return -EINVAL; @@ -749,12 +742,19 @@ static int igb_set_ringparam(struct net_device *netdev, new_tx_count = min(new_tx_count, (u32)IGB_MAX_TXD); new_tx_count = ALIGN(new_tx_count, REQ_TX_DESCRIPTOR_MULTIPLE); - if ((new_tx_count == adapter->tx_ring->count) && - (new_rx_count == adapter->rx_ring->count)) { + if ((new_tx_count == adapter->tx_ring_count) && + (new_rx_count == adapter->rx_ring_count)) { /* nothing to do */ return 0; } + if (adapter->num_tx_queues > adapter->num_rx_queues) + temp_ring = vmalloc(adapter->num_tx_queues * sizeof(struct igb_ring)); + else + temp_ring = vmalloc(adapter->num_rx_queues * sizeof(struct igb_ring)); + if (!temp_ring) + return -ENOMEM; + while (test_and_set_bit(__IGB_RESETTING, &adapter->state)) msleep(1); @@ -766,62 +766,55 @@ static int igb_set_ringparam(struct net_device *netdev, * because the ISRs in MSI-X mode get passed pointers * to the tx and rx ring structs. */ - if (new_tx_count != adapter->tx_ring->count) { + if (new_tx_count != adapter->tx_ring_count) { + memcpy(temp_ring, adapter->tx_ring, + adapter->num_tx_queues * sizeof(struct igb_ring)); + for (i = 0; i < adapter->num_tx_queues; i++) { - /* Save existing descriptor ring */ - old_buf = adapter->tx_ring[i].buffer_info; - old_desc = adapter->tx_ring[i].desc; - old_size = adapter->tx_ring[i].size; - old_dma = adapter->tx_ring[i].dma; - /* Try to allocate a new one */ - adapter->tx_ring[i].buffer_info = NULL; - adapter->tx_ring[i].desc = NULL; - adapter->tx_ring[i].count = new_tx_count; - err = igb_setup_tx_resources(adapter, - &adapter->tx_ring[i]); + temp_ring[i].count = new_tx_count; + err = igb_setup_tx_resources(adapter, &temp_ring[i]); if (err) { - /* Restore the old one so at least - the adapter still works, even if - we failed the request */ - adapter->tx_ring[i].buffer_info = old_buf; - adapter->tx_ring[i].desc = old_desc; - adapter->tx_ring[i].size = old_size; - adapter->tx_ring[i].dma = old_dma; + while (i) { + i--; + igb_free_tx_resources(&temp_ring[i]); + } goto err_setup; } - /* Free the old buffer manually */ - vfree(old_buf); - pci_free_consistent(adapter->pdev, old_size, - old_desc, old_dma); } + + for (i = 0; i < adapter->num_tx_queues; i++) + igb_free_tx_resources(&adapter->tx_ring[i]); + + memcpy(adapter->tx_ring, temp_ring, + adapter->num_tx_queues * sizeof(struct igb_ring)); + + adapter->tx_ring_count = new_tx_count; } if (new_rx_count != adapter->rx_ring->count) { - for (i = 0; i < adapter->num_rx_queues; i++) { + memcpy(temp_ring, adapter->rx_ring, + adapter->num_rx_queues * sizeof(struct igb_ring)); - old_rx_buf = adapter->rx_ring[i].buffer_info; - old_desc = adapter->rx_ring[i].desc; - old_size = adapter->rx_ring[i].size; - old_dma = adapter->rx_ring[i].dma; - - adapter->rx_ring[i].buffer_info = NULL; - adapter->rx_ring[i].desc = NULL; - adapter->rx_ring[i].dma = 0; - adapter->rx_ring[i].count = new_rx_count; - err = igb_setup_rx_resources(adapter, - &adapter->rx_ring[i]); + for (i = 0; i < adapter->num_rx_queues; i++) { + temp_ring[i].count = new_rx_count; + err = igb_setup_rx_resources(adapter, &temp_ring[i]); if (err) { - adapter->rx_ring[i].buffer_info = old_rx_buf; - adapter->rx_ring[i].desc = old_desc; - adapter->rx_ring[i].size = old_size; - adapter->rx_ring[i].dma = old_dma; + while (i) { + i--; + igb_free_rx_resources(&temp_ring[i]); + } goto err_setup; } - vfree(old_rx_buf); - pci_free_consistent(adapter->pdev, old_size, old_desc, - old_dma); } + + for (i = 0; i < adapter->num_rx_queues; i++) + igb_free_rx_resources(&adapter->rx_ring[i]); + + memcpy(adapter->rx_ring, temp_ring, + adapter->num_rx_queues * sizeof(struct igb_ring)); + + adapter->rx_ring_count = new_rx_count; } err = 0; @@ -830,6 +823,7 @@ err_setup: igb_up(adapter); clear_bit(__IGB_RESETTING, &adapter->state); + vfree(temp_ring); return err; } @@ -1343,8 +1337,9 @@ static int igb_setup_desc_rings(struct igb_adapter *adapter) wr32(E1000_RDLEN(0), rx_ring->size); wr32(E1000_RDH(0), 0); wr32(E1000_RDT(0), 0); + rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); rctl = E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_SZ_2048 | - E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + E1000_RCTL_RDMTS_HALF | (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); wr32(E1000_RCTL, rctl); wr32(E1000_SRRCTL(0), 0); @@ -1380,10 +1375,10 @@ static void igb_phy_disable_receiver(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; /* Write out to PHY registers 29 and 30 to disable the Receiver. */ - hw->phy.ops.write_phy_reg(hw, 29, 0x001F); - hw->phy.ops.write_phy_reg(hw, 30, 0x8FFC); - hw->phy.ops.write_phy_reg(hw, 29, 0x001A); - hw->phy.ops.write_phy_reg(hw, 30, 0x8FF0); + igb_write_phy_reg(hw, 29, 0x001F); + igb_write_phy_reg(hw, 30, 0x8FFC); + igb_write_phy_reg(hw, 29, 0x001A); + igb_write_phy_reg(hw, 30, 0x8FF0); } static int igb_integrated_phy_loopback(struct igb_adapter *adapter) @@ -1396,17 +1391,17 @@ static int igb_integrated_phy_loopback(struct igb_adapter *adapter) if (hw->phy.type == e1000_phy_m88) { /* Auto-MDI/MDIX Off */ - hw->phy.ops.write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); + igb_write_phy_reg(hw, M88E1000_PHY_SPEC_CTRL, 0x0808); /* reset to update Auto-MDI/MDIX */ - hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x9140); + igb_write_phy_reg(hw, PHY_CONTROL, 0x9140); /* autoneg off */ - hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x8140); + igb_write_phy_reg(hw, PHY_CONTROL, 0x8140); } ctrl_reg = rd32(E1000_CTRL); /* force 1000, set loopback */ - hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, 0x4140); + igb_write_phy_reg(hw, PHY_CONTROL, 0x4140); /* Now set up the MAC to the same speed/duplex as the PHY. */ ctrl_reg = rd32(E1000_CTRL); @@ -1500,10 +1495,10 @@ static void igb_loopback_cleanup(struct igb_adapter *adapter) wr32(E1000_RCTL, rctl); hw->mac.autoneg = true; - hw->phy.ops.read_phy_reg(hw, PHY_CONTROL, &phy_reg); + igb_read_phy_reg(hw, PHY_CONTROL, &phy_reg); if (phy_reg & MII_CR_LOOPBACK) { phy_reg &= ~MII_CR_LOOPBACK; - hw->phy.ops.write_phy_reg(hw, PHY_CONTROL, phy_reg); + igb_write_phy_reg(hw, PHY_CONTROL, phy_reg); igb_phy_sw_reset(hw); } } diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 20d27e622ec10c1fabefdc24e85a67cb443d27a4..022794e579c7367f326aaa886128579d042b18d4 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c @@ -42,6 +42,7 @@ #include #include #include +#include #ifdef CONFIG_IGB_DCA #include #endif @@ -76,8 +77,6 @@ static int igb_setup_all_tx_resources(struct igb_adapter *); static int igb_setup_all_rx_resources(struct igb_adapter *); static void igb_free_all_tx_resources(struct igb_adapter *); static void igb_free_all_rx_resources(struct igb_adapter *); -static void igb_free_tx_resources(struct igb_ring *); -static void igb_free_rx_resources(struct igb_ring *); void igb_update_stats(struct igb_adapter *); static int igb_probe(struct pci_dev *, const struct pci_device_id *); static void __devexit igb_remove(struct pci_dev *pdev); @@ -232,6 +231,40 @@ static void __exit igb_exit_module(void) module_exit(igb_exit_module); +#define Q_IDX_82576(i) (((i & 0x1) << 3) + (i >> 1)) +/** + * igb_cache_ring_register - Descriptor ring to register mapping + * @adapter: board private structure to initialize + * + * Once we know the feature-set enabled for the device, we'll cache + * the register offset the descriptor ring is assigned to. + **/ +static void igb_cache_ring_register(struct igb_adapter *adapter) +{ + int i; + + switch (adapter->hw.mac.type) { + case e1000_82576: + /* The queues are allocated for virtualization such that VF 0 + * is allocated queues 0 and 8, VF 1 queues 1 and 9, etc. + * In order to avoid collision we start at the first free queue + * and continue consuming queues in the same sequence + */ + for (i = 0; i < adapter->num_rx_queues; i++) + adapter->rx_ring[i].reg_idx = Q_IDX_82576(i); + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].reg_idx = Q_IDX_82576(i); + break; + case e1000_82575: + default: + for (i = 0; i < adapter->num_rx_queues; i++) + adapter->rx_ring[i].reg_idx = i; + for (i = 0; i < adapter->num_tx_queues; i++) + adapter->tx_ring[i].reg_idx = i; + break; + } +} + /** * igb_alloc_queues - Allocate memory for all rings * @adapter: board private structure to initialize @@ -259,11 +292,13 @@ static int igb_alloc_queues(struct igb_adapter *adapter) for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *ring = &(adapter->tx_ring[i]); + ring->count = adapter->tx_ring_count; ring->adapter = adapter; ring->queue_index = i; } for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *ring = &(adapter->rx_ring[i]); + ring->count = adapter->rx_ring_count; ring->adapter = adapter; ring->queue_index = i; ring->itr_register = E1000_ITR; @@ -271,6 +306,8 @@ static int igb_alloc_queues(struct igb_adapter *adapter) /* set a default napi handler for each rx_ring */ netif_napi_add(adapter->netdev, &ring->napi, igb_poll, 64); } + + igb_cache_ring_register(adapter); return 0; } @@ -311,36 +348,36 @@ static void igb_assign_vector(struct igb_adapter *adapter, int rx_queue, array_wr32(E1000_MSIXBM(0), msix_vector, msixbm); break; case e1000_82576: - /* The 82576 uses a table-based method for assigning vectors. + /* 82576 uses a table-based method for assigning vectors. Each queue has a single entry in the table to which we write a vector number along with a "valid" bit. Sadly, the layout of the table is somewhat counterintuitive. */ if (rx_queue > IGB_N0_QUEUE) { - index = (rx_queue & 0x7); + index = (rx_queue >> 1); ivar = array_rd32(E1000_IVAR0, index); - if (rx_queue < 8) { - /* vector goes into low byte of register */ - ivar = ivar & 0xFFFFFF00; - ivar |= msix_vector | E1000_IVAR_VALID; - } else { + if (rx_queue & 0x1) { /* vector goes into third byte of register */ ivar = ivar & 0xFF00FFFF; ivar |= (msix_vector | E1000_IVAR_VALID) << 16; + } else { + /* vector goes into low byte of register */ + ivar = ivar & 0xFFFFFF00; + ivar |= msix_vector | E1000_IVAR_VALID; } adapter->rx_ring[rx_queue].eims_value= 1 << msix_vector; array_wr32(E1000_IVAR0, index, ivar); } if (tx_queue > IGB_N0_QUEUE) { - index = (tx_queue & 0x7); + index = (tx_queue >> 1); ivar = array_rd32(E1000_IVAR0, index); - if (tx_queue < 8) { - /* vector goes into second byte of register */ - ivar = ivar & 0xFFFF00FF; - ivar |= (msix_vector | E1000_IVAR_VALID) << 8; - } else { + if (tx_queue & 0x1) { /* vector goes into high byte of register */ ivar = ivar & 0x00FFFFFF; ivar |= (msix_vector | E1000_IVAR_VALID) << 24; + } else { + /* vector goes into second byte of register */ + ivar = ivar & 0xFFFF00FF; + ivar |= (msix_vector | E1000_IVAR_VALID) << 8; } adapter->tx_ring[tx_queue].eims_value= 1 << msix_vector; array_wr32(E1000_IVAR0, index, ivar); @@ -445,7 +482,7 @@ static int igb_request_msix(struct igb_adapter *adapter) for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *ring = &(adapter->tx_ring[i]); - sprintf(ring->name, "%s-tx%d", netdev->name, i); + sprintf(ring->name, "%s-tx-%d", netdev->name, i); err = request_irq(adapter->msix_entries[vector].vector, &igb_msix_tx, 0, ring->name, &(adapter->tx_ring[i])); @@ -458,7 +495,7 @@ static int igb_request_msix(struct igb_adapter *adapter) for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *ring = &(adapter->rx_ring[i]); if (strlen(netdev->name) < (IFNAMSIZ - 5)) - sprintf(ring->name, "%s-rx%d", netdev->name, i); + sprintf(ring->name, "%s-rx-%d", netdev->name, i); else memcpy(ring->name, netdev->name, IFNAMSIZ); err = request_irq(adapter->msix_entries[vector].vector, @@ -931,8 +968,7 @@ void igb_reset(struct igb_adapter *adapter) wr32(E1000_VET, ETHERNET_IEEE_VLAN_TYPE); igb_reset_adaptive(&adapter->hw); - if (adapter->hw.phy.ops.get_phy_info) - adapter->hw.phy.ops.get_phy_info(&adapter->hw); + igb_get_phy_info(&adapter->hw); } /** @@ -950,6 +986,25 @@ static int igb_is_need_ioport(struct pci_dev *pdev) } } +static const struct net_device_ops igb_netdev_ops = { + .ndo_open = igb_open, + .ndo_stop = igb_close, + .ndo_start_xmit = igb_xmit_frame_adv, + .ndo_get_stats = igb_get_stats, + .ndo_set_multicast_list = igb_set_multi, + .ndo_set_mac_address = igb_set_mac, + .ndo_change_mtu = igb_change_mtu, + .ndo_do_ioctl = igb_ioctl, + .ndo_tx_timeout = igb_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_vlan_rx_register = igb_vlan_rx_register, + .ndo_vlan_rx_add_vid = igb_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = igb_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = igb_netpoll, +#endif +}; + /** * igb_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -1031,6 +1086,13 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (err) goto err_pci_reg; + err = pci_enable_pcie_error_reporting(pdev); + if (err) { + dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed " + "0x%x\n", err); + /* non-fatal, continue */ + } + pci_set_master(pdev); pci_save_state(pdev); @@ -1059,23 +1121,9 @@ static int __devinit igb_probe(struct pci_dev *pdev, if (!adapter->hw.hw_addr) goto err_ioremap; - netdev->open = &igb_open; - netdev->stop = &igb_close; - netdev->get_stats = &igb_get_stats; - netdev->set_multicast_list = &igb_set_multi; - netdev->set_mac_address = &igb_set_mac; - netdev->change_mtu = &igb_change_mtu; - netdev->do_ioctl = &igb_ioctl; + netdev->netdev_ops = &igb_netdev_ops; igb_set_ethtool_ops(netdev); - netdev->tx_timeout = &igb_tx_timeout; netdev->watchdog_timeo = 5 * HZ; - netdev->vlan_rx_register = igb_vlan_rx_register; - netdev->vlan_rx_add_vid = igb_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = igb_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = igb_netpoll; -#endif - netdev->hard_start_xmit = &igb_xmit_frame_adv; strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); @@ -1275,16 +1323,14 @@ static int __devinit igb_probe(struct pci_dev *pdev, dev_info(&pdev->dev, "Intel(R) Gigabit Ethernet Network Connection\n"); /* print bus type/speed/width info */ - dev_info(&pdev->dev, - "%s: (PCIe:%s:%s) %02x:%02x:%02x:%02x:%02x:%02x\n", + dev_info(&pdev->dev, "%s: (PCIe:%s:%s) %pM\n", netdev->name, ((hw->bus.speed == e1000_bus_speed_2500) ? "2.5Gb/s" : "unknown"), ((hw->bus.width == e1000_bus_width_pcie_x4) ? "Width x4" : (hw->bus.width == e1000_bus_width_pcie_x1) ? "Width x1" : "unknown"), - netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], - netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + netdev->dev_addr); igb_read_part_num(hw, &part_num); dev_info(&pdev->dev, "%s: PBA No: %06x-%03x\n", netdev->name, @@ -1302,7 +1348,7 @@ err_register: igb_release_hw_control(adapter); err_eeprom: if (!igb_check_reset_block(hw)) - hw->phy.ops.reset_phy(hw); + igb_reset_phy(hw); if (hw->flash_address) iounmap(hw->flash_address); @@ -1338,6 +1384,7 @@ static void __devexit igb_remove(struct pci_dev *pdev) #ifdef CONFIG_IGB_DCA struct e1000_hw *hw = &adapter->hw; #endif + int err; /* flush_scheduled work may reschedule our watchdog task, so * explicitly disable watchdog tasks from being rescheduled */ @@ -1362,9 +1409,8 @@ static void __devexit igb_remove(struct pci_dev *pdev) unregister_netdev(netdev); - if (adapter->hw.phy.ops.reset_phy && - !igb_check_reset_block(&adapter->hw)) - adapter->hw.phy.ops.reset_phy(&adapter->hw); + if (!igb_check_reset_block(&adapter->hw)) + igb_reset_phy(&adapter->hw); igb_remove_device(&adapter->hw); igb_reset_interrupt_capability(adapter); @@ -1378,6 +1424,11 @@ static void __devexit igb_remove(struct pci_dev *pdev) free_netdev(netdev); + err = pci_disable_pcie_error_reporting(pdev); + if (err) + dev_err(&pdev->dev, + "pci_disable_pcie_error_reporting failed 0x%x\n", err); + pci_disable_device(pdev); } @@ -1397,6 +1448,8 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter) pci_read_config_word(pdev, PCI_COMMAND, &hw->bus.pci_cmd_word); + adapter->tx_ring_count = IGB_DEFAULT_TXD; + adapter->rx_ring_count = IGB_DEFAULT_RXD; adapter->rx_buffer_len = MAXIMUM_ETHERNET_VLAN_SIZE; adapter->rx_ps_hdr_size = 0; /* disable packet split */ adapter->max_frame_size = netdev->mtu + ETH_HLEN + ETH_FCS_LEN; @@ -1558,8 +1611,7 @@ int igb_setup_tx_resources(struct igb_adapter *adapter, memset(tx_ring->buffer_info, 0, size); /* round up to nearest 4K */ - tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc) - + sizeof(u32); + tx_ring->size = tx_ring->count * sizeof(struct e1000_tx_desc); tx_ring->size = ALIGN(tx_ring->size, 4096); tx_ring->desc = pci_alloc_consistent(pdev, tx_ring->size, @@ -1618,43 +1670,37 @@ static int igb_setup_all_tx_resources(struct igb_adapter *adapter) **/ static void igb_configure_tx(struct igb_adapter *adapter) { - u64 tdba, tdwba; + u64 tdba; struct e1000_hw *hw = &adapter->hw; u32 tctl; u32 txdctl, txctrl; - int i; + int i, j; for (i = 0; i < adapter->num_tx_queues; i++) { struct igb_ring *ring = &(adapter->tx_ring[i]); - - wr32(E1000_TDLEN(i), + j = ring->reg_idx; + wr32(E1000_TDLEN(j), ring->count * sizeof(struct e1000_tx_desc)); tdba = ring->dma; - wr32(E1000_TDBAL(i), + wr32(E1000_TDBAL(j), tdba & 0x00000000ffffffffULL); - wr32(E1000_TDBAH(i), tdba >> 32); - - tdwba = ring->dma + ring->count * sizeof(struct e1000_tx_desc); - tdwba |= 1; /* enable head wb */ - wr32(E1000_TDWBAL(i), - tdwba & 0x00000000ffffffffULL); - wr32(E1000_TDWBAH(i), tdwba >> 32); + wr32(E1000_TDBAH(j), tdba >> 32); - ring->head = E1000_TDH(i); - ring->tail = E1000_TDT(i); + ring->head = E1000_TDH(j); + ring->tail = E1000_TDT(j); writel(0, hw->hw_addr + ring->tail); writel(0, hw->hw_addr + ring->head); - txdctl = rd32(E1000_TXDCTL(i)); + txdctl = rd32(E1000_TXDCTL(j)); txdctl |= E1000_TXDCTL_QUEUE_ENABLE; - wr32(E1000_TXDCTL(i), txdctl); + wr32(E1000_TXDCTL(j), txdctl); /* Turn off Relaxed Ordering on head write-backs. The * writebacks MUST be delivered in order or it will * completely screw up our bookeeping. */ - txctrl = rd32(E1000_DCA_TXCTRL(i)); + txctrl = rd32(E1000_DCA_TXCTRL(j)); txctrl &= ~E1000_DCA_TXCTRL_TX_WB_RO_EN; - wr32(E1000_DCA_TXCTRL(i), txctrl); + wr32(E1000_DCA_TXCTRL(j), txctrl); } @@ -1771,14 +1817,14 @@ static void igb_setup_rctl(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 rctl; u32 srrctl = 0; - int i; + int i, j; rctl = rd32(E1000_RCTL); rctl &= ~(3 << E1000_RCTL_MO_SHIFT); + rctl &= ~(E1000_RCTL_LBM_TCVR | E1000_RCTL_LBM_MAC); - rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | - E1000_RCTL_LBM_NO | E1000_RCTL_RDMTS_HALF | + rctl |= E1000_RCTL_EN | E1000_RCTL_BAM | E1000_RCTL_RDMTS_HALF | (adapter->hw.mac.mc_filter_type << E1000_RCTL_MO_SHIFT); /* @@ -1788,38 +1834,26 @@ static void igb_setup_rctl(struct igb_adapter *adapter) */ rctl |= E1000_RCTL_SECRC; - rctl &= ~E1000_RCTL_SBP; + /* + * disable store bad packets, long packet enable, and clear size bits. + */ + rctl &= ~(E1000_RCTL_SBP | E1000_RCTL_LPE | E1000_RCTL_SZ_256); - if (adapter->netdev->mtu <= ETH_DATA_LEN) - rctl &= ~E1000_RCTL_LPE; - else + if (adapter->netdev->mtu > ETH_DATA_LEN) rctl |= E1000_RCTL_LPE; - if (adapter->rx_buffer_len <= IGB_RXBUFFER_2048) { - /* Setup buffer sizes */ - rctl &= ~E1000_RCTL_SZ_4096; - rctl |= E1000_RCTL_BSEX; - switch (adapter->rx_buffer_len) { - case IGB_RXBUFFER_256: - rctl |= E1000_RCTL_SZ_256; - rctl &= ~E1000_RCTL_BSEX; - break; - case IGB_RXBUFFER_512: - rctl |= E1000_RCTL_SZ_512; - rctl &= ~E1000_RCTL_BSEX; - break; - case IGB_RXBUFFER_1024: - rctl |= E1000_RCTL_SZ_1024; - rctl &= ~E1000_RCTL_BSEX; - break; - case IGB_RXBUFFER_2048: - default: - rctl |= E1000_RCTL_SZ_2048; - rctl &= ~E1000_RCTL_BSEX; - break; - } - } else { - rctl &= ~E1000_RCTL_BSEX; - srrctl = adapter->rx_buffer_len >> E1000_SRRCTL_BSIZEPKT_SHIFT; + + /* Setup buffer sizes */ + switch (adapter->rx_buffer_len) { + case IGB_RXBUFFER_256: + rctl |= E1000_RCTL_SZ_256; + break; + case IGB_RXBUFFER_512: + rctl |= E1000_RCTL_SZ_512; + break; + default: + srrctl = ALIGN(adapter->rx_buffer_len, 1024) + >> E1000_SRRCTL_BSIZEPKT_SHIFT; + break; } /* 82575 and greater support packet-split where the protocol @@ -1841,8 +1875,10 @@ static void igb_setup_rctl(struct igb_adapter *adapter) srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF; } - for (i = 0; i < adapter->num_rx_queues; i++) - wr32(E1000_SRRCTL(i), srrctl); + for (i = 0; i < adapter->num_rx_queues; i++) { + j = adapter->rx_ring[i].reg_idx; + wr32(E1000_SRRCTL(j), srrctl); + } wr32(E1000_RCTL, rctl); } @@ -1859,7 +1895,7 @@ static void igb_configure_rx(struct igb_adapter *adapter) struct e1000_hw *hw = &adapter->hw; u32 rctl, rxcsum; u32 rxdctl; - int i; + int i, j; /* disable receives while setting up the descriptors */ rctl = rd32(E1000_RCTL); @@ -1874,25 +1910,26 @@ static void igb_configure_rx(struct igb_adapter *adapter) * the Base and Length of the Rx Descriptor Ring */ for (i = 0; i < adapter->num_rx_queues; i++) { struct igb_ring *ring = &(adapter->rx_ring[i]); + j = ring->reg_idx; rdba = ring->dma; - wr32(E1000_RDBAL(i), + wr32(E1000_RDBAL(j), rdba & 0x00000000ffffffffULL); - wr32(E1000_RDBAH(i), rdba >> 32); - wr32(E1000_RDLEN(i), + wr32(E1000_RDBAH(j), rdba >> 32); + wr32(E1000_RDLEN(j), ring->count * sizeof(union e1000_adv_rx_desc)); - ring->head = E1000_RDH(i); - ring->tail = E1000_RDT(i); + ring->head = E1000_RDH(j); + ring->tail = E1000_RDT(j); writel(0, hw->hw_addr + ring->tail); writel(0, hw->hw_addr + ring->head); - rxdctl = rd32(E1000_RXDCTL(i)); + rxdctl = rd32(E1000_RXDCTL(j)); rxdctl |= E1000_RXDCTL_QUEUE_ENABLE; rxdctl &= 0xFFF00000; rxdctl |= IGB_RX_PTHRESH; rxdctl |= IGB_RX_HTHRESH << 8; rxdctl |= IGB_RX_WTHRESH << 16; - wr32(E1000_RXDCTL(i), rxdctl); + wr32(E1000_RXDCTL(j), rxdctl); #ifdef CONFIG_IGB_LRO /* Intitial LRO Settings */ ring->lro_mgr.max_aggr = MAX_LRO_AGGR; @@ -1922,7 +1959,7 @@ static void igb_configure_rx(struct igb_adapter *adapter) shift = 6; for (j = 0; j < (32 * 4); j++) { reta.bytes[j & 3] = - (j % adapter->num_rx_queues) << shift; + adapter->rx_ring[(j % adapter->num_rx_queues)].reg_idx << shift; if ((j & 3) == 3) writel(reta.dword, hw->hw_addr + E1000_RETA(0) + (j & ~3)); @@ -1984,7 +2021,7 @@ static void igb_configure_rx(struct igb_adapter *adapter) * * Free all transmit software resources **/ -static void igb_free_tx_resources(struct igb_ring *tx_ring) +void igb_free_tx_resources(struct igb_ring *tx_ring) { struct pci_dev *pdev = tx_ring->adapter->pdev; @@ -2082,7 +2119,7 @@ static void igb_clean_all_tx_rings(struct igb_adapter *adapter) * * Free all receive software resources **/ -static void igb_free_rx_resources(struct igb_ring *rx_ring) +void igb_free_rx_resources(struct igb_ring *rx_ring) { struct pci_dev *pdev = rx_ring->adapter->pdev; @@ -2274,8 +2311,7 @@ static void igb_set_multi(struct net_device *netdev) static void igb_update_phy_info(unsigned long data) { struct igb_adapter *adapter = (struct igb_adapter *) data; - if (adapter->hw.phy.ops.get_phy_info) - adapter->hw.phy.ops.get_phy_info(&adapter->hw); + igb_get_phy_info(&adapter->hw); } /** @@ -2330,9 +2366,10 @@ static void igb_watchdog_task(struct work_struct *work) &adapter->link_duplex); ctrl = rd32(E1000_CTRL); - dev_info(&adapter->pdev->dev, - "NIC Link is Up %d Mbps %s, " + /* Links status message must follow this format */ + printk(KERN_INFO "igb: %s NIC Link is Up %d Mbps %s, " "Flow Control: %s\n", + netdev->name, adapter->link_speed, adapter->link_duplex == FULL_DUPLEX ? "Full Duplex" : "Half Duplex", @@ -2367,7 +2404,9 @@ static void igb_watchdog_task(struct work_struct *work) if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; - dev_info(&adapter->pdev->dev, "NIC Link is Down\n"); + /* Links status message must follow this format */ + printk(KERN_INFO "igb: %s NIC Link is Down\n", + netdev->name); netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); if (!test_bit(__IGB_DOWN, &adapter->state)) @@ -2703,6 +2742,7 @@ static inline int igb_tso_adv(struct igb_adapter *adapter, context_desc->seqnum_seed = 0; buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; buffer_info->dma = 0; i++; if (i == tx_ring->count) @@ -2766,6 +2806,7 @@ static inline bool igb_tx_csum_adv(struct igb_adapter *adapter, cpu_to_le32(tx_ring->queue_index << 4); buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; buffer_info->dma = 0; i++; @@ -2784,8 +2825,8 @@ static inline bool igb_tx_csum_adv(struct igb_adapter *adapter, #define IGB_MAX_DATA_PER_TXD (1<length = len; /* set time_stamp *before* dma to help avoid a possible race */ buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; buffer_info->dma = pci_map_single(adapter->pdev, skb->data, len, PCI_DMA_TODEVICE); count++; @@ -2816,6 +2858,7 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter, BUG_ON(len >= IGB_MAX_DATA_PER_TXD); buffer_info->length = len; buffer_info->time_stamp = jiffies; + buffer_info->next_to_watch = i; buffer_info->dma = pci_map_page(adapter->pdev, frag->page, frag->page_offset, @@ -2828,8 +2871,9 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter, i = 0; } - i = (i == 0) ? tx_ring->count - 1 : i - 1; + i = ((i == 0) ? tx_ring->count - 1 : i - 1); tx_ring->buffer_info[i].skb = skb; + tx_ring->buffer_info[first].next_to_watch = i; return count; } @@ -2936,6 +2980,7 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, struct igb_ring *tx_ring) { struct igb_adapter *adapter = netdev_priv(netdev); + unsigned int first; unsigned int tx_flags = 0; unsigned int len; u8 hdr_len = 0; @@ -2972,6 +3017,8 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, if (skb->protocol == htons(ETH_P_IP)) tx_flags |= IGB_TX_FLAGS_IPV4; + first = tx_ring->next_to_use; + tso = skb_is_gso(skb) ? igb_tso_adv(adapter, tx_ring, skb, tx_flags, &hdr_len) : 0; @@ -2987,7 +3034,7 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb, tx_flags |= IGB_TX_FLAGS_CSUM; igb_tx_queue_adv(adapter, tx_ring, tx_flags, - igb_tx_map_adv(adapter, tx_ring, skb), + igb_tx_map_adv(adapter, tx_ring, skb, first), skb->len, hdr_len); netdev->trans_start = jiffies; @@ -3249,7 +3296,7 @@ void igb_update_stats(struct igb_adapter *adapter) /* Phy Stats */ if (hw->phy.media_type == e1000_media_type_copper) { if ((adapter->link_speed == SPEED_1000) && - (!hw->phy.ops.read_phy_reg(hw, PHY_1000T_STATUS, + (!igb_read_phy_reg(hw, PHY_1000T_STATUS, &phy_tmp))) { phy_tmp &= PHY_IDLE_ERROR_COUNT_MASK; adapter->phy_stats.idle_errors += phy_tmp; @@ -3332,7 +3379,6 @@ static void igb_write_itr(struct igb_ring *ring) static irqreturn_t igb_msix_rx(int irq, void *data) { struct igb_ring *rx_ring = data; - struct igb_adapter *adapter = rx_ring->adapter; /* Write the ITR value calculated at the end of the * previous interrupt. @@ -3340,11 +3386,11 @@ static irqreturn_t igb_msix_rx(int irq, void *data) igb_write_itr(rx_ring); - if (netif_rx_schedule_prep(adapter->netdev, &rx_ring->napi)) - __netif_rx_schedule(adapter->netdev, &rx_ring->napi); + if (netif_rx_schedule_prep(&rx_ring->napi)) + __netif_rx_schedule(&rx_ring->napi); #ifdef CONFIG_IGB_DCA - if (adapter->flags & IGB_FLAG_DCA_ENABLED) + if (rx_ring->adapter->flags & IGB_FLAG_DCA_ENABLED) igb_update_rx_dca(rx_ring); #endif return IRQ_HANDLED; @@ -3357,7 +3403,7 @@ static void igb_update_rx_dca(struct igb_ring *rx_ring) struct igb_adapter *adapter = rx_ring->adapter; struct e1000_hw *hw = &adapter->hw; int cpu = get_cpu(); - int q = rx_ring - adapter->rx_ring; + int q = rx_ring->reg_idx; if (rx_ring->cpu != cpu) { dca_rxctrl = rd32(E1000_DCA_RXCTRL(q)); @@ -3384,7 +3430,7 @@ static void igb_update_tx_dca(struct igb_ring *tx_ring) struct igb_adapter *adapter = tx_ring->adapter; struct e1000_hw *hw = &adapter->hw; int cpu = get_cpu(); - int q = tx_ring - adapter->tx_ring; + int q = tx_ring->reg_idx; if (tx_ring->cpu != cpu) { dca_txctrl = rd32(E1000_DCA_TXCTRL(q)); @@ -3493,7 +3539,7 @@ static irqreturn_t igb_intr_msi(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - netif_rx_schedule(netdev, &adapter->rx_ring[0].napi); + netif_rx_schedule(&adapter->rx_ring[0].napi); return IRQ_HANDLED; } @@ -3531,7 +3577,7 @@ static irqreturn_t igb_intr(int irq, void *data) mod_timer(&adapter->watchdog_timer, jiffies + 1); } - netif_rx_schedule(netdev, &adapter->rx_ring[0].napi); + netif_rx_schedule(&adapter->rx_ring[0].napi); return IRQ_HANDLED; } @@ -3566,7 +3612,7 @@ static int igb_poll(struct napi_struct *napi, int budget) !netif_running(netdev)) { if (adapter->itr_setting & 3) igb_set_itr(adapter); - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); if (!test_bit(__IGB_DOWN, &adapter->state)) igb_irq_enable(adapter); return 0; @@ -3592,7 +3638,7 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) /* If not enough Rx work done, exit the polling mode */ if ((work_done == 0) || !netif_running(netdev)) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); if (adapter->itr_setting & 3) { if (adapter->num_rx_queues == 1) @@ -3610,12 +3656,6 @@ static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget) return 1; } -static inline u32 get_head(struct igb_ring *tx_ring) -{ - void *end = (struct e1000_tx_desc *)tx_ring->desc + tx_ring->count; - return le32_to_cpu(*(volatile __le32 *)end); -} - /** * igb_clean_tx_irq - Reclaim resources after transmit completes * @adapter: board private structure @@ -3624,24 +3664,25 @@ static inline u32 get_head(struct igb_ring *tx_ring) static bool igb_clean_tx_irq(struct igb_ring *tx_ring) { struct igb_adapter *adapter = tx_ring->adapter; - struct e1000_hw *hw = &adapter->hw; struct net_device *netdev = adapter->netdev; - struct e1000_tx_desc *tx_desc; + struct e1000_hw *hw = &adapter->hw; struct igb_buffer *buffer_info; struct sk_buff *skb; - unsigned int i; - u32 head, oldhead; - unsigned int count = 0; + union e1000_adv_tx_desc *tx_desc, *eop_desc; unsigned int total_bytes = 0, total_packets = 0; - bool retval = true; + unsigned int i, eop, count = 0; + bool cleaned = false; - rmb(); - head = get_head(tx_ring); i = tx_ring->next_to_clean; - while (1) { - while (i != head) { - tx_desc = E1000_TX_DESC(*tx_ring, i); + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop); + + while ((eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)) && + (count < tx_ring->count)) { + for (cleaned = false; !cleaned; count++) { + tx_desc = E1000_TX_DESC_ADV(*tx_ring, i); buffer_info = &tx_ring->buffer_info[i]; + cleaned = (i == eop); skb = buffer_info->skb; if (skb) { @@ -3656,25 +3697,17 @@ static bool igb_clean_tx_irq(struct igb_ring *tx_ring) } igb_unmap_and_free_tx_resource(adapter, buffer_info); + tx_desc->wb.status = 0; i++; if (i == tx_ring->count) i = 0; - - count++; - if (count == IGB_MAX_TX_CLEAN) { - retval = false; - goto done_cleaning; - } } - oldhead = head; - rmb(); - head = get_head(tx_ring); - if (head == oldhead) - goto done_cleaning; - } /* while (1) */ - -done_cleaning: + + eop = tx_ring->buffer_info[i].next_to_watch; + eop_desc = E1000_TX_DESC_ADV(*tx_ring, eop); + } + tx_ring->next_to_clean = i; if (unlikely(count && @@ -3701,7 +3734,6 @@ done_cleaning: && !(rd32(E1000_STATUS) & E1000_STATUS_TXOFF)) { - tx_desc = E1000_TX_DESC(*tx_ring, i); /* detected Tx unit hang */ dev_err(&adapter->pdev->dev, "Detected Tx Unit Hang\n" @@ -3710,9 +3742,9 @@ done_cleaning: " TDT <%x>\n" " next_to_use <%x>\n" " next_to_clean <%x>\n" - " head (WB) <%x>\n" "buffer_info[next_to_clean]\n" " time_stamp <%lx>\n" + " next_to_watch <%x>\n" " jiffies <%lx>\n" " desc.status <%x>\n", tx_ring->queue_index, @@ -3720,10 +3752,10 @@ done_cleaning: readl(adapter->hw.hw_addr + tx_ring->tail), tx_ring->next_to_use, tx_ring->next_to_clean, - head, tx_ring->buffer_info[i].time_stamp, + eop, jiffies, - tx_desc->upper.fields.status); + eop_desc->wb.status); netif_stop_subqueue(netdev, tx_ring->queue_index); } } @@ -3733,7 +3765,7 @@ done_cleaning: tx_ring->tx_stats.packets += total_packets; adapter->net_stats.tx_bytes += total_bytes; adapter->net_stats.tx_packets += total_packets; - return retval; + return (count < tx_ring->count); } #ifdef CONFIG_IGB_LRO @@ -3919,8 +3951,10 @@ send_up: next_buffer = &rx_ring->buffer_info[i]; if (!(staterr & E1000_RXD_STAT_EOP)) { - buffer_info->skb = xchg(&next_buffer->skb, skb); - buffer_info->dma = xchg(&next_buffer->dma, 0); + buffer_info->skb = next_buffer->skb; + buffer_info->dma = next_buffer->dma; + next_buffer->skb = skb; + next_buffer->dma = 0; goto next_desc; } @@ -3938,8 +3972,6 @@ send_up: igb_receive_skb(rx_ring, staterr, rx_desc, skb); - netdev->last_rx = jiffies; - next_desc: rx_desc->wb.upper.status_error = 0; @@ -4102,9 +4134,8 @@ static int igb_mii_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd) case SIOCGMIIREG: if (!capable(CAP_NET_ADMIN)) return -EPERM; - if (adapter->hw.phy.ops.read_phy_reg(&adapter->hw, - data->reg_num - & 0x1F, &data->val_out)) + if (igb_read_phy_reg(&adapter->hw, data->reg_num & 0x1F, + &data->val_out)) return -EIO; break; case SIOCSMIIREG: @@ -4474,27 +4505,38 @@ static pci_ers_result_t igb_io_slot_reset(struct pci_dev *pdev) struct net_device *netdev = pci_get_drvdata(pdev); struct igb_adapter *adapter = netdev_priv(netdev); struct e1000_hw *hw = &adapter->hw; + pci_ers_result_t result; int err; if (adapter->need_ioport) err = pci_enable_device(pdev); else err = pci_enable_device_mem(pdev); + if (err) { dev_err(&pdev->dev, "Cannot re-enable PCI device after reset.\n"); - return PCI_ERS_RESULT_DISCONNECT; - } - pci_set_master(pdev); - pci_restore_state(pdev); + result = PCI_ERS_RESULT_DISCONNECT; + } else { + pci_set_master(pdev); + pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); - igb_reset(adapter); - wr32(E1000_WUS, ~0); + igb_reset(adapter); + wr32(E1000_WUS, ~0); + result = PCI_ERS_RESULT_RECOVERED; + } + + err = pci_cleanup_aer_uncorrect_error_status(pdev); + if (err) { + dev_err(&pdev->dev, "pci_cleanup_aer_uncorrect_error_status " + "failed 0x%0x\n", err); + /* non-fatal, continue */ + } - return PCI_ERS_RESULT_RECOVERED; + return result; } /** @@ -4522,7 +4564,6 @@ static void igb_io_resume(struct pci_dev *pdev) /* let the f/w know that the h/w is now under the control of the * driver. */ igb_get_hw_control(adapter); - } /* igb_main.c */ diff --git a/drivers/net/ioc3-eth.c b/drivers/net/ioc3-eth.c index 1f25263dc7ebb8f90066d7388bbd297bd8d82b26..170b12d1d70e49e2ab02918b41e1236bd9544a84 100644 --- a/drivers/net/ioc3-eth.c +++ b/drivers/net/ioc3-eth.c @@ -390,11 +390,8 @@ static int nic_init(struct ioc3 *ioc3) } printk("Found %s NIC", type); - if (type != unknown) { - printk (" registration number %02x:%02x:%02x:%02x:%02x:%02x," - " CRC %02x", serial[0], serial[1], serial[2], - serial[3], serial[4], serial[5], crc); - } + if (type != unknown) + printk (" registration number %pM, CRC %02x", serial, crc); printk(".\n"); return 0; @@ -443,12 +440,9 @@ static void ioc3_get_eaddr_nic(struct ioc3_private *ip) */ static void ioc3_get_eaddr(struct ioc3_private *ip) { - DECLARE_MAC_BUF(mac); - ioc3_get_eaddr_nic(ip); - printk("Ethernet address is %s.\n", - print_mac(mac, priv_netdev(ip)->dev_addr)); + printk("Ethernet address is %pM.\n", priv_netdev(ip)->dev_addr); } static void __ioc3_set_mac_address(struct net_device *dev) @@ -627,7 +621,6 @@ static inline void ioc3_rx(struct ioc3_private *ip) rxb = (struct ioc3_erxbuf *) new_skb->data; skb_reserve(new_skb, RX_OFFSET); - priv_netdev(ip)->last_rx = jiffies; ip->stats.rx_packets++; /* Statistics */ ip->stats.rx_bytes += len; } else { diff --git a/drivers/net/ipg.c b/drivers/net/ipg.c index 059369885be1c71c96ea1cbf5807659c7fdba793..7b6d435a84680e487cdebe5953ee487ba4333f47 100644 --- a/drivers/net/ipg.c +++ b/drivers/net/ipg.c @@ -1222,7 +1222,6 @@ static void ipg_nic_rx_with_start_and_end(struct net_device *dev, skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); - dev->last_rx = jiffies; sp->rx_buff[entry] = NULL; } @@ -1256,7 +1255,6 @@ static void ipg_nic_rx_with_start(struct net_device *dev, jumbo->skb = skb; sp->rx_buff[entry] = NULL; - dev->last_rx = jiffies; } static void ipg_nic_rx_with_end(struct net_device *dev, @@ -1292,7 +1290,6 @@ static void ipg_nic_rx_with_end(struct net_device *dev, } } - dev->last_rx = jiffies; jumbo->found_start = 0; jumbo->current_size = 0; jumbo->skb = NULL; @@ -1325,7 +1322,6 @@ static void ipg_nic_rx_no_start_no_end(struct net_device *dev, skb->data, sp->rxfrag_size); } } - dev->last_rx = jiffies; ipg_nic_rx_free_skb(dev); } } else { @@ -1494,11 +1490,6 @@ static int ipg_nic_rx(struct net_device *dev) * when processing completes. */ netif_rx(skb); - - /* Record frame receive time (jiffies = Linux - * kernel current time stamp). - */ - dev->last_rx = jiffies; } /* Assure RX buffer is not reused by IPG. */ diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c index 2ff181861d2d05b51ccc9a1c8f8f55a5aa897027..3c58e67ef1e491c16af64cea5994cc4d88272bee 100644 --- a/drivers/net/irda/ali-ircc.c +++ b/drivers/net/irda/ali-ircc.c @@ -292,7 +292,7 @@ static int ali_ircc_open(int i, chipio_t *info) return -ENOMEM; } - self = dev->priv; + self = netdev_priv(dev); self->netdev = dev; spin_lock_init(&self->lock); @@ -665,7 +665,7 @@ static irqreturn_t ali_ircc_interrupt(int irq, void *dev_id) IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__); - self = dev->priv; + self = netdev_priv(dev); spin_lock(&self->lock); @@ -1333,7 +1333,7 @@ static int ali_ircc_net_open(struct net_device *dev) IRDA_ASSERT(dev != NULL, return -1;); - self = (struct ali_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); @@ -1396,7 +1396,7 @@ static int ali_ircc_net_close(struct net_device *dev) IRDA_ASSERT(dev != NULL, return -1;); - self = (struct ali_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); /* Stop device */ @@ -1436,7 +1436,7 @@ static int ali_ircc_fir_hard_xmit(struct sk_buff *skb, struct net_device *dev) IRDA_DEBUG(1, "%s(), ---------------- Start -----------------\n", __func__ ); - self = (struct ali_ircc_cb *) dev->priv; + self = netdev_priv(dev); iobase = self->io.fir_base; netif_stop_queue(dev); @@ -1931,7 +1931,6 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self) skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); - self->netdev->last_rx = jiffies; } } @@ -1960,7 +1959,7 @@ static int ali_ircc_sir_hard_xmit(struct sk_buff *skb, struct net_device *dev) IRDA_ASSERT(dev != NULL, return 0;); - self = (struct ali_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); iobase = self->io.sir_base; @@ -2028,7 +2027,7 @@ static int ali_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT(dev != NULL, return -1;); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return -1;); @@ -2114,7 +2113,7 @@ static int ali_ircc_is_receiving(struct ali_ircc_cb *self) static struct net_device_stats *ali_ircc_net_get_stats(struct net_device *dev) { - struct ali_ircc_cb *self = (struct ali_ircc_cb *) dev->priv; + struct ali_ircc_cb *self = netdev_priv(dev); IRDA_DEBUG(2, "%s(), ---------------- Start ----------------\n", __func__ ); diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c index a1e4508717c8743bfa8f8d15c77a1383318e8884..6c4b53ffbcaccf453067a4e58b99d96df887fe8a 100644 --- a/drivers/net/irda/au1k_ir.c +++ b/drivers/net/irda/au1k_ir.c @@ -620,7 +620,6 @@ static int au1k_irda_rx(struct net_device *dev) /* next descriptor */ prxd = aup->rx_ring[aup->rx_head]; flags = prxd->flags; - dev->last_rx = jiffies; } return 0; diff --git a/drivers/net/irda/donauboe.c b/drivers/net/irda/donauboe.c index 69d16b30323b8fca6ecb974c2e66967e115f15bc..687c2d53d4d2135a244c5be1c9438601dd8687c6 100644 --- a/drivers/net/irda/donauboe.c +++ b/drivers/net/irda/donauboe.c @@ -979,7 +979,7 @@ toshoboe_hard_xmit (struct sk_buff *skb, struct net_device *dev) unsigned long flags; struct irda_skb_cb *cb = (struct irda_skb_cb *) skb->cb; - self = (struct toshoboe_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT (self != NULL, return 0; ); @@ -1384,7 +1384,7 @@ toshoboe_net_close (struct net_device *dev) IRDA_DEBUG (4, "%s()\n", __func__); IRDA_ASSERT (dev != NULL, return -1; ); - self = (struct toshoboe_cb *) dev->priv; + self = netdev_priv(dev); /* Stop device */ netif_stop_queue(dev); @@ -1422,7 +1422,7 @@ toshoboe_net_ioctl (struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT (dev != NULL, return -1; ); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT (self != NULL, return -1; ); @@ -1546,7 +1546,7 @@ toshoboe_open (struct pci_dev *pci_dev, const struct pci_device_id *pdid) return -ENOMEM; } - self = dev->priv; + self = netdev_priv(dev); self->netdev = dev; self->pdev = pci_dev; self->base = pci_resource_start(pci_dev,0); diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c index b5d6b9ac162ae813ca4f74955c32187f31fa6053..205e4e825a97639320d1898995e2de52368aefb2 100644 --- a/drivers/net/irda/irda-usb.c +++ b/drivers/net/irda/irda-usb.c @@ -384,7 +384,7 @@ static void speed_bulk_callback(struct urb *urb) */ static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev) { - struct irda_usb_cb *self = netdev->priv; + struct irda_usb_cb *self = netdev_priv(netdev); struct urb *urb = self->tx_urb; unsigned long flags; s32 speed; @@ -628,7 +628,7 @@ static void write_bulk_callback(struct urb *urb) static void irda_usb_net_timeout(struct net_device *netdev) { unsigned long flags; - struct irda_usb_cb *self = netdev->priv; + struct irda_usb_cb *self = netdev_priv(netdev); struct urb *urb; int done = 0; /* If we have made any progress */ @@ -929,7 +929,6 @@ static void irda_usb_receive(struct urb *urb) /* Keep stats up to date */ self->stats.rx_bytes += len; self->stats.rx_packets++; - self->netdev->last_rx = jiffies; done: /* Note : at this point, the URB we've just received (urb) @@ -1175,7 +1174,7 @@ static int irda_usb_net_open(struct net_device *netdev) IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(netdev != NULL, return -1;); - self = (struct irda_usb_cb *) netdev->priv; + self = netdev_priv(netdev); IRDA_ASSERT(self != NULL, return -1;); spin_lock_irqsave(&self->lock, flags); @@ -1257,7 +1256,7 @@ static int irda_usb_net_close(struct net_device *netdev) IRDA_DEBUG(1, "%s()\n", __func__); IRDA_ASSERT(netdev != NULL, return -1;); - self = (struct irda_usb_cb *) netdev->priv; + self = netdev_priv(netdev); IRDA_ASSERT(self != NULL, return -1;); /* Clear this flag *before* unlinking the urbs and *before* @@ -1306,7 +1305,7 @@ static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) int ret = 0; IRDA_ASSERT(dev != NULL, return -1;); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return -1;); IRDA_DEBUG(2, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); @@ -1348,7 +1347,7 @@ static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) */ static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev) { - struct irda_usb_cb *self = dev->priv; + struct irda_usb_cb *self = netdev_priv(dev); return &self->stats; } @@ -1641,7 +1640,7 @@ static int irda_usb_probe(struct usb_interface *intf, goto err_out; SET_NETDEV_DEV(net, &intf->dev); - self = net->priv; + self = netdev_priv(net); self->netdev = net; spin_lock_init(&self->lock); init_timer(&self->rx_defer_timer); diff --git a/drivers/net/irda/irtty-sir.c b/drivers/net/irda/irtty-sir.c index 6bcee01c684cd4bb3aea00abb6e2dd00ff0e8d3b..d53aa9582137d241f0cdf22e092de488ec81efb9 100644 --- a/drivers/net/irda/irtty-sir.c +++ b/drivers/net/irda/irtty-sir.c @@ -191,7 +191,7 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t tty = priv->tty; if (!tty->ops->write) return 0; - tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); writelen = tty_write_room(tty); if (writelen > len) writelen = len; @@ -263,8 +263,7 @@ static void irtty_write_wakeup(struct tty_struct *tty) IRDA_ASSERT(priv != NULL, return;); IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;); - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (priv->dev) sirdev_write_complete(priv->dev); } @@ -522,7 +521,7 @@ static void irtty_close(struct tty_struct *tty) /* Stop tty */ irtty_stop_receiver(tty, TRUE); - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); if (tty->ops->stop) tty->ops->stop(tty); diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c index e1429fc6d05036abc63f34d22009f850d455d7da..c747c874d44d8388acaf199ab6373761e27a0f4d 100644 --- a/drivers/net/irda/kingsun-sir.c +++ b/drivers/net/irda/kingsun-sir.c @@ -235,7 +235,6 @@ static void kingsun_rcv_irq(struct urb *urb) &kingsun->stats, &kingsun->rx_buff, bytes[i]); } - kingsun->netdev->last_rx = jiffies; do_gettimeofday(&kingsun->rx_time); kingsun->receiving = (kingsun->rx_buff.state != OUTSIDE_FRAME) diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c index 2e67ae015d916eae51ca1a2ceb666b7b6905e5a7..600d96f9cdb7408d619bb78c7481c645c24caa4e 100644 --- a/drivers/net/irda/ks959-sir.c +++ b/drivers/net/irda/ks959-sir.c @@ -474,7 +474,6 @@ static void ks959_rcv_irq(struct urb *urb) bytes[i]); } } - kingsun->netdev->last_rx = jiffies; do_gettimeofday(&kingsun->rx_time); kingsun->receiving = (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; diff --git a/drivers/net/irda/ksdazzle-sir.c b/drivers/net/irda/ksdazzle-sir.c index 3843b5faba8b5da67a7463c02cba196b6a8b6105..0e7f89337b25791ec137eb0d910cb548fa75152e 100644 --- a/drivers/net/irda/ksdazzle-sir.c +++ b/drivers/net/irda/ksdazzle-sir.c @@ -371,7 +371,6 @@ static void ksdazzle_rcv_irq(struct urb *urb) async_unwrap_char(kingsun->netdev, &kingsun->stats, &kingsun->rx_unwrap_buff, bytes[i]); } - kingsun->netdev->last_rx = jiffies; kingsun->receiving = (kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0; } diff --git a/drivers/net/irda/ma600-sir.c b/drivers/net/irda/ma600-sir.c index 1ceed9cfb7c4fc5ba7af1ad41a847e71f24a44f3..e91216452379f318d53b2c953555593d7c796eae 100644 --- a/drivers/net/irda/ma600-sir.c +++ b/drivers/net/irda/ma600-sir.c @@ -236,7 +236,7 @@ static int ma600_change_speed(struct sir_dev *dev, unsigned speed) * avoid the state machine complexity before we get things working */ -int ma600_reset(struct sir_dev *dev) +static int ma600_reset(struct sir_dev *dev) { IRDA_DEBUG(2, "%s()\n", __func__); diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c index ad92d3ff1c4093ff6ea8281c430374ab26ff3ac2..904c9610c0dd61a5d1de949aaadc2d3a87f8bb3e 100644 --- a/drivers/net/irda/mcs7780.c +++ b/drivers/net/irda/mcs7780.c @@ -806,7 +806,6 @@ static void mcs_receive_irq(struct urb *urb) mcs_unwrap_fir(mcs, urb->transfer_buffer, urb->actual_length); } - mcs->netdev->last_rx = jiffies; do_gettimeofday(&mcs->rx_time); } diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c index 8583d951a6ad15529fb4c8ec2169865582e5aa6f..2c6bf2d11bb13451d422f465110e69edd6e695a4 100644 --- a/drivers/net/irda/nsc-ircc.c +++ b/drivers/net/irda/nsc-ircc.c @@ -373,7 +373,7 @@ static int __init nsc_ircc_open(chipio_t *info) return -ENOMEM; } - self = dev->priv; + self = netdev_priv(dev); self->netdev = dev; spin_lock_init(&self->lock); @@ -1354,7 +1354,7 @@ static int nsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) __s32 speed; __u8 bank; - self = (struct nsc_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); @@ -1427,7 +1427,7 @@ static int nsc_ircc_hard_xmit_fir(struct sk_buff *skb, struct net_device *dev) __u8 bank; int mtt, diff; - self = (struct nsc_ircc_cb *) dev->priv; + self = netdev_priv(dev); iobase = self->io.fir_base; netif_stop_queue(dev); @@ -1896,7 +1896,6 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase) skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); - self->netdev->last_rx = jiffies; } } /* Restore bank register */ @@ -2085,7 +2084,7 @@ static irqreturn_t nsc_ircc_interrupt(int irq, void *dev_id) __u8 bsr, eir; int iobase; - self = dev->priv; + self = netdev_priv(dev); spin_lock(&self->lock); @@ -2166,7 +2165,7 @@ static int nsc_ircc_net_open(struct net_device *dev) IRDA_DEBUG(4, "%s()\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); - self = (struct nsc_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); @@ -2229,7 +2228,7 @@ static int nsc_ircc_net_close(struct net_device *dev) IRDA_ASSERT(dev != NULL, return -1;); - self = (struct nsc_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); /* Stop device */ @@ -2275,7 +2274,7 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT(dev != NULL, return -1;); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return -1;); @@ -2310,7 +2309,7 @@ static int nsc_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static struct net_device_stats *nsc_ircc_net_get_stats(struct net_device *dev) { - struct nsc_ircc_cb *self = (struct nsc_ircc_cb *) dev->priv; + struct nsc_ircc_cb *self = netdev_priv(dev); return &self->stats; } diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index c5b02b66f7560a570210f075e6d72eda219e97df..a0ee053181556bd4b600f5f001ae2eba236f901e 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c @@ -225,7 +225,6 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) } lsr = STLSR; } - dev->last_rx = jiffies; si->last_oscr = OSCR; break; @@ -237,7 +236,6 @@ static irqreturn_t pxa_irda_sir_irq(int irq, void *dev_id) si->stats.rx_bytes++; async_unwrap_char(dev, &si->stats, &si->rx_buff, STRBR); } while (STLSR & LSR_DR); - dev->last_rx = jiffies; si->last_oscr = OSCR; break; @@ -397,8 +395,6 @@ static void pxa_irda_fir_irq_eif(struct pxa_irda *si, struct net_device *dev, in si->stats.rx_packets++; si->stats.rx_bytes += len; - - dev->last_rx = jiffies; } } diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c index a95188948de7b80a385ddeab5fe7b437e898aa33..ccde5829ba21139b6947e4218c9c00492487e0a1 100644 --- a/drivers/net/irda/sa1100_ir.c +++ b/drivers/net/irda/sa1100_ir.c @@ -298,7 +298,7 @@ static int sa1100_irda_suspend(struct platform_device *pdev, pm_message_t state) if (!dev) return 0; - si = dev->priv; + si = netdev_priv(dev); if (si->open) { /* * Stop the transmit queue @@ -323,7 +323,7 @@ static int sa1100_irda_resume(struct platform_device *pdev) if (!dev) return 0; - si = dev->priv; + si = netdev_priv(dev); if (si->open) { /* * If we missed a speed change, initialise at the new speed @@ -359,7 +359,7 @@ static int sa1100_irda_resume(struct platform_device *pdev) */ static void sa1100_irda_hpsir_irq(struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); int status; status = Ser2UTSR0; @@ -410,7 +410,6 @@ static void sa1100_irda_hpsir_irq(struct net_device *dev) Ser2UTDR); } while (Ser2UTSR1 & UTSR1_RNE); - dev->last_rx = jiffies; } if (status & UTSR0_TFS && si->tx_buff.len) { @@ -515,7 +514,6 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev sa1100_irda_rx_alloc(si); netif_rx(skb); - dev->last_rx = jiffies; } else { /* * Remap the buffer. @@ -534,7 +532,7 @@ static void sa1100_irda_fir_error(struct sa1100_irda *si, struct net_device *dev */ static void sa1100_irda_fir_irq(struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); /* * Stop RX DMA @@ -582,7 +580,7 @@ static void sa1100_irda_fir_irq(struct net_device *dev) static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) { struct net_device *dev = dev_id; - if (IS_FIR(((struct sa1100_irda *)dev->priv))) + if (IS_FIR(((struct sa1100_irda *)netdev_priv(dev)))) sa1100_irda_fir_irq(dev); else sa1100_irda_hpsir_irq(dev); @@ -595,7 +593,7 @@ static irqreturn_t sa1100_irda_irq(int irq, void *dev_id) static void sa1100_irda_txdma_irq(void *id) { struct net_device *dev = id; - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); struct sk_buff *skb = si->txskb; si->txskb = NULL; @@ -649,7 +647,7 @@ static void sa1100_irda_txdma_irq(void *id) static int sa1100_irda_hard_xmit(struct sk_buff *skb, struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); int speed = irda_get_next_speed(skb); /* @@ -724,7 +722,7 @@ static int sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) { struct if_irda_req *rq = (struct if_irda_req *)ifreq; - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); int ret = -EOPNOTSUPP; switch (cmd) { @@ -766,13 +764,13 @@ sa1100_irda_ioctl(struct net_device *dev, struct ifreq *ifreq, int cmd) static struct net_device_stats *sa1100_irda_stats(struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); return &si->stats; } static int sa1100_irda_start(struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); int err; si->speed = 9600; @@ -835,7 +833,7 @@ err_irq: static int sa1100_irda_stop(struct net_device *dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); disable_irq(dev->irq); sa1100_irda_shutdown(si); @@ -908,7 +906,7 @@ static int sa1100_irda_probe(struct platform_device *pdev) if (!dev) goto err_mem_4; - si = dev->priv; + si = netdev_priv(dev); si->dev = &pdev->dev; si->pdata = pdev->dev.platform_data; @@ -987,7 +985,7 @@ static int sa1100_irda_remove(struct platform_device *pdev) struct net_device *dev = platform_get_drvdata(pdev); if (dev) { - struct sa1100_irda *si = dev->priv; + struct sa1100_irda *si = netdev_priv(dev); unregister_netdev(dev); kfree(si->tx_buff.head); kfree(si->rx_buff.head); diff --git a/drivers/net/irda/sir_dev.c b/drivers/net/irda/sir_dev.c index 3f32909c24c81ff61307bd7cb37f03937221aa33..ceef040aa76d2a63c9ad579a5eb463c9a98e8bd0 100644 --- a/drivers/net/irda/sir_dev.c +++ b/drivers/net/irda/sir_dev.c @@ -584,14 +584,14 @@ EXPORT_SYMBOL(sirdev_receive); static struct net_device_stats *sirdev_get_stats(struct net_device *ndev) { - struct sir_dev *dev = ndev->priv; + struct sir_dev *dev = netdev_priv(ndev); return (dev) ? &dev->stats : NULL; } static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) { - struct sir_dev *dev = ndev->priv; + struct sir_dev *dev = netdev_priv(ndev); unsigned long flags; int actual = 0; int err; @@ -683,7 +683,7 @@ static int sirdev_hard_xmit(struct sk_buff *skb, struct net_device *ndev) static int sirdev_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { struct if_irda_req *irq = (struct if_irda_req *) rq; - struct sir_dev *dev = ndev->priv; + struct sir_dev *dev = netdev_priv(ndev); int ret = 0; IRDA_ASSERT(dev != NULL, return -1;); @@ -795,7 +795,7 @@ static void sirdev_free_buffers(struct sir_dev *dev) static int sirdev_open(struct net_device *ndev) { - struct sir_dev *dev = ndev->priv; + struct sir_dev *dev = netdev_priv(ndev); const struct sir_driver *drv = dev->drv; if (!drv) @@ -840,7 +840,7 @@ errout_dec: static int sirdev_close(struct net_device *ndev) { - struct sir_dev *dev = ndev->priv; + struct sir_dev *dev = netdev_priv(ndev); const struct sir_driver *drv; // IRDA_DEBUG(0, "%s\n", __func__); @@ -896,7 +896,7 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n IRDA_ERROR("%s - Can't allocate memory for IrDA control block!\n", __func__); goto out; } - dev = ndev->priv; + dev = netdev_priv(ndev); irda_init_max_qos_capabilies(&dev->qos); dev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|IR_115200; diff --git a/drivers/net/irda/smsc-ircc2.c b/drivers/net/irda/smsc-ircc2.c index b5360fe99d3a5669b89180f96462dc8340d065f5..5d09e157e15bc1fa890b5f9c94cec44465d66352 100644 --- a/drivers/net/irda/smsc-ircc2.c +++ b/drivers/net/irda/smsc-ircc2.c @@ -872,7 +872,7 @@ static void smsc_ircc_timeout(struct net_device *dev) * waits until the next transmit interrupt, and continues until the * frame is transmitted. */ -int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) +static int smsc_ircc_hard_xmit_sir(struct sk_buff *skb, struct net_device *dev) { struct smsc_ircc_cb *self; unsigned long flags; @@ -1128,7 +1128,7 @@ static void smsc_ircc_change_speed(struct smsc_ircc_cb *self, u32 speed) * Set speed of IrDA port to specified baudrate * */ -void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed) +static void smsc_ircc_set_sir_speed(struct smsc_ircc_cb *self, __u32 speed) { int iobase; int fcr; /* FIFO control reg */ @@ -1894,7 +1894,7 @@ static void __exit smsc_ircc_cleanup(void) * This function *must* be called with spinlock held, because it may * be called from the irq handler (via smsc_ircc_change_speed()). - Jean II */ -void smsc_ircc_sir_start(struct smsc_ircc_cb *self) +static void smsc_ircc_sir_start(struct smsc_ircc_cb *self) { struct net_device *dev; int fir_base, sir_base; diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c index 3575804fd7c644b4fe5202a289b80eb20b59a799..ca4cd9266e55ef45c97d77e0afada0eb67a8677e 100644 --- a/drivers/net/irda/stir4200.c +++ b/drivers/net/irda/stir4200.c @@ -824,7 +824,6 @@ static void stir_rcv_irq(struct urb *urb) unwrap_chars(stir, urb->transfer_buffer, urb->actual_length); - stir->netdev->last_rx = jiffies; do_gettimeofday(&stir->rx_time); } diff --git a/drivers/net/irda/via-ircc.c b/drivers/net/irda/via-ircc.c index 84e609ea5fbbc1a5e1a25d72a60b9aa369ea9a73..74c78cf7a333c95b49ea7c2ecd0f2703266c3044 100644 --- a/drivers/net/irda/via-ircc.c +++ b/drivers/net/irda/via-ircc.c @@ -334,7 +334,7 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id) if (dev == NULL) return -ENOMEM; - self = dev->priv; + self = netdev_priv(dev); self->netdev = dev; spin_lock_init(&self->lock); @@ -824,7 +824,7 @@ static int via_ircc_hard_xmit_sir(struct sk_buff *skb, u16 iobase; __u32 speed; - self = (struct via_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); iobase = self->io.fir_base; @@ -896,7 +896,7 @@ static int via_ircc_hard_xmit_fir(struct sk_buff *skb, __u32 speed; unsigned long flags; - self = (struct via_ircc_cb *) dev->priv; + self = netdev_priv(dev); iobase = self->io.fir_base; if (self->st_fifo.len) @@ -1349,7 +1349,7 @@ static int RxTimerHandler(struct via_ircc_cb *self, int iobase) static irqreturn_t via_ircc_interrupt(int dummy, void *dev_id) { struct net_device *dev = dev_id; - struct via_ircc_cb *self = dev->priv; + struct via_ircc_cb *self = netdev_priv(dev); int iobase; u8 iHostIntType, iRxIntType, iTxIntType; @@ -1522,7 +1522,7 @@ static int via_ircc_net_open(struct net_device *dev) IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); - self = (struct via_ircc_cb *) dev->priv; + self = netdev_priv(dev); self->stats.rx_packets = 0; IRDA_ASSERT(self != NULL, return 0;); iobase = self->io.fir_base; @@ -1589,7 +1589,7 @@ static int via_ircc_net_close(struct net_device *dev) IRDA_DEBUG(3, "%s()\n", __func__); IRDA_ASSERT(dev != NULL, return -1;); - self = (struct via_ircc_cb *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); /* Stop device */ @@ -1628,7 +1628,7 @@ static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, int ret = 0; IRDA_ASSERT(dev != NULL, return -1;); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return -1;); IRDA_DEBUG(1, "%s(), %s, (cmd=0x%X)\n", __func__, dev->name, cmd); @@ -1663,7 +1663,7 @@ static int via_ircc_net_ioctl(struct net_device *dev, struct ifreq *rq, static struct net_device_stats *via_ircc_net_get_stats(struct net_device *dev) { - struct via_ircc_cb *self = (struct via_ircc_cb *) dev->priv; + struct via_ircc_cb *self = netdev_priv(dev); return &self->stats; } diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c index 9c926d205de971d69ee7873522ec4a657dfc8cfb..0d30f8d659a1995b083eb4e507833dd7fa92f0d7 100644 --- a/drivers/net/irda/vlsi_ir.c +++ b/drivers/net/irda/vlsi_ir.c @@ -178,7 +178,7 @@ static void vlsi_proc_pdev(struct seq_file *seq, struct pci_dev *pdev) static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); u8 byte; u16 word; unsigned delta1, delta2; @@ -346,7 +346,7 @@ static void vlsi_proc_ring(struct seq_file *seq, struct vlsi_ring *r) static int vlsi_seq_show(struct seq_file *seq, void *v) { struct net_device *ndev = seq->private; - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); unsigned long flags; seq_printf(seq, "\n%s %s\n\n", DRIVER_NAME, DRIVER_VERSION); @@ -543,7 +543,7 @@ static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd) struct sk_buff *skb; int ret = 0; struct net_device *ndev = (struct net_device *)pci_get_drvdata(r->pdev); - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); pci_dma_sync_single_for_cpu(r->pdev, rd_get_addr(rd), r->len, r->dir); /* dma buffer now owned by the CPU */ @@ -600,7 +600,6 @@ static int vlsi_process_rx(struct vlsi_ring *r, struct ring_descr *rd) netif_rx(skb); else netif_rx_ni(skb); - ndev->last_rx = jiffies; done: rd_set_status(rd, 0); @@ -638,7 +637,7 @@ static void vlsi_fill_rx(struct vlsi_ring *r) static void vlsi_rx_interrupt(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); struct vlsi_ring *r = idev->rx_ring; struct ring_descr *rd; int ret; @@ -856,7 +855,7 @@ static int vlsi_set_baud(vlsi_irda_dev_t *idev, unsigned iobase) static int vlsi_hard_start_xmit(struct sk_buff *skb, struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); struct vlsi_ring *r = idev->tx_ring; struct ring_descr *rd; unsigned long flags; @@ -1063,7 +1062,7 @@ drop: static void vlsi_tx_interrupt(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); struct vlsi_ring *r = idev->tx_ring; struct ring_descr *rd; unsigned iobase; @@ -1262,7 +1261,7 @@ static inline void vlsi_clear_regs(unsigned iobase) static int vlsi_init_chip(struct pci_dev *pdev) { struct net_device *ndev = pci_get_drvdata(pdev); - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); unsigned iobase; u16 ptr; @@ -1376,14 +1375,14 @@ static int vlsi_stop_hw(vlsi_irda_dev_t *idev) static struct net_device_stats * vlsi_get_stats(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); return &idev->stats; } static void vlsi_tx_timeout(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); vlsi_reg_debug(ndev->base_addr, __func__); @@ -1408,7 +1407,7 @@ static void vlsi_tx_timeout(struct net_device *ndev) static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); struct if_irda_req *irq = (struct if_irda_req *) rq; unsigned long flags; u16 fifocnt; @@ -1458,7 +1457,7 @@ static int vlsi_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd) static irqreturn_t vlsi_interrupt(int irq, void *dev_instance) { struct net_device *ndev = dev_instance; - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); unsigned iobase; u8 irintr; int boguscount = 5; @@ -1499,7 +1498,7 @@ static irqreturn_t vlsi_interrupt(int irq, void *dev_instance) static int vlsi_open(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); int err = -EAGAIN; char hwname[32]; @@ -1558,7 +1557,7 @@ errout: static int vlsi_close(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); netif_stop_queue(ndev); @@ -1581,7 +1580,7 @@ static int vlsi_close(struct net_device *ndev) static int vlsi_irda_init(struct net_device *ndev) { - vlsi_irda_dev_t *idev = ndev->priv; + vlsi_irda_dev_t *idev = netdev_priv(ndev); struct pci_dev *pdev = idev->pdev; ndev->irq = pdev->irq; @@ -1656,7 +1655,7 @@ vlsi_irda_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto out_disable; } - idev = ndev->priv; + idev = netdev_priv(ndev); spin_lock_init(&idev->lock); mutex_init(&idev->mtx); @@ -1713,7 +1712,7 @@ static void __devexit vlsi_irda_remove(struct pci_dev *pdev) unregister_netdev(ndev); - idev = ndev->priv; + idev = netdev_priv(ndev); mutex_lock(&idev->mtx); if (idev->proc_entry) { remove_proc_entry(ndev->name, vlsi_proc_root); @@ -1748,7 +1747,7 @@ static int vlsi_irda_suspend(struct pci_dev *pdev, pm_message_t state) __func__, pci_name(pdev)); return 0; } - idev = ndev->priv; + idev = netdev_priv(ndev); mutex_lock(&idev->mtx); if (pdev->current_state != 0) { /* already suspended */ if (state.event > pdev->current_state) { /* simply go deeper */ @@ -1787,7 +1786,7 @@ static int vlsi_irda_resume(struct pci_dev *pdev) __func__, pci_name(pdev)); return 0; } - idev = ndev->priv; + idev = netdev_priv(ndev); mutex_lock(&idev->mtx); if (pdev->current_state == 0) { mutex_unlock(&idev->mtx); diff --git a/drivers/net/irda/w83977af_ir.c b/drivers/net/irda/w83977af_ir.c index 002a6d769f21f244912b6584c33e9e6a4cc92615..30ec9131c5ce2cf41849dcb2040cc9eb500a33cd 100644 --- a/drivers/net/irda/w83977af_ir.c +++ b/drivers/net/irda/w83977af_ir.c @@ -147,8 +147,8 @@ static void __exit w83977af_cleanup(void) * Open driver instance * */ -int w83977af_open(int i, unsigned int iobase, unsigned int irq, - unsigned int dma) +static int w83977af_open(int i, unsigned int iobase, unsigned int irq, + unsigned int dma) { struct net_device *dev; struct w83977af_ir *self; @@ -178,7 +178,7 @@ int w83977af_open(int i, unsigned int iobase, unsigned int irq, goto err_out; } - self = dev->priv; + self = netdev_priv(dev); spin_lock_init(&self->lock); @@ -310,7 +310,7 @@ static int w83977af_close(struct w83977af_ir *self) return 0; } -int w83977af_probe( int iobase, int irq, int dma) +static int w83977af_probe(int iobase, int irq, int dma) { int version; int i; @@ -409,7 +409,7 @@ int w83977af_probe( int iobase, int irq, int dma) return -1; } -void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) +static void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) { int ir_mode = HCR_SIR; int iobase; @@ -489,7 +489,7 @@ void w83977af_change_speed(struct w83977af_ir *self, __u32 speed) * Sets up a DMA transfer to send the current frame. * */ -int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) +static int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) { struct w83977af_ir *self; __s32 speed; @@ -497,7 +497,7 @@ int w83977af_hard_xmit(struct sk_buff *skb, struct net_device *dev) __u8 set; int mtt; - self = (struct w83977af_ir *) dev->priv; + self = netdev_priv(dev); iobase = self->io.fir_base; @@ -731,7 +731,7 @@ static void w83977af_dma_xmit_complete(struct w83977af_ir *self) * if it starts to receive a frame. * */ -int w83977af_dma_receive(struct w83977af_ir *self) +static int w83977af_dma_receive(struct w83977af_ir *self) { int iobase; __u8 set; @@ -803,7 +803,7 @@ int w83977af_dma_receive(struct w83977af_ir *self) * Finished with receiving a frame * */ -int w83977af_dma_receive_complete(struct w83977af_ir *self) +static int w83977af_dma_receive_complete(struct w83977af_ir *self) { struct sk_buff *skb; struct st_fifo *st_fifo; @@ -923,7 +923,6 @@ int w83977af_dma_receive_complete(struct w83977af_ir *self) skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IRDA); netif_rx(skb); - self->netdev->last_rx = jiffies; } } /* Restore set register */ @@ -1119,7 +1118,7 @@ static irqreturn_t w83977af_interrupt(int irq, void *dev_id) __u8 set, icr, isr; int iobase; - self = dev->priv; + self = netdev_priv(dev); iobase = self->io.fir_base; @@ -1192,7 +1191,7 @@ static int w83977af_net_open(struct net_device *dev) IRDA_DEBUG(0, "%s()\n", __func__ ); IRDA_ASSERT(dev != NULL, return -1;); - self = (struct w83977af_ir *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); @@ -1256,7 +1255,7 @@ static int w83977af_net_close(struct net_device *dev) IRDA_ASSERT(dev != NULL, return -1;); - self = (struct w83977af_ir *) dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return 0;); @@ -1303,7 +1302,7 @@ static int w83977af_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) IRDA_ASSERT(dev != NULL, return -1;); - self = dev->priv; + self = netdev_priv(dev); IRDA_ASSERT(self != NULL, return -1;); @@ -1339,7 +1338,7 @@ out: static struct net_device_stats *w83977af_net_get_stats(struct net_device *dev) { - struct w83977af_ir *self = (struct w83977af_ir *) dev->priv; + struct w83977af_ir *self = netdev_priv(dev); return &self->stats; } diff --git a/drivers/net/isa-skeleton.c b/drivers/net/isa-skeleton.c index d6ff26af37b3e5c1dc5a60d5c979819855389e1b..3126678bdd3c593f6035fb62ce864ef6d4d02d39 100644 --- a/drivers/net/isa-skeleton.c +++ b/drivers/net/isa-skeleton.c @@ -192,7 +192,6 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) static unsigned version_printed; int i; int err = -ENODEV; - DECLARE_MAC_BUF(mac); /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, NETCARD_IO_EXTENT, cardname)) @@ -220,7 +219,7 @@ static int __init netcard_probe1(struct net_device *dev, int ioaddr) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); err = -EAGAIN; #ifdef jumpered_interrupts @@ -584,7 +583,6 @@ net_rx(struct net_device *dev) insw(ioaddr, skb->data, (pkt_len + 1) >> 1); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } @@ -711,15 +709,3 @@ cleanup_module(void) } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: - * gcc -D__KERNEL__ -Wall -Wstrict-prototypes -Wwrite-strings - * -Wredundant-decls -O2 -m486 -c skeleton.c - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * c-indent-level: 4 - * End: - */ diff --git a/drivers/net/iseries_veth.c b/drivers/net/iseries_veth.c index c46864d626b28e44b7e25669ea319d1f74a2dd53..c7457f97259d9ad9d60226b76f22d45108206d60 100644 --- a/drivers/net/iseries_veth.c +++ b/drivers/net/iseries_veth.c @@ -952,7 +952,7 @@ static int veth_change_mtu(struct net_device *dev, int new_mtu) static void veth_set_multicast_list(struct net_device *dev) { - struct veth_port *port = (struct veth_port *) dev->priv; + struct veth_port *port = netdev_priv(dev); unsigned long flags; write_lock_irqsave(&port->mcast_gate, flags); @@ -1044,7 +1044,7 @@ static struct net_device *veth_probe_one(int vlan, return NULL; } - port = (struct veth_port *) dev->priv; + port = netdev_priv(dev); spin_lock_init(&port->queue_lock); rwlock_init(&port->mcast_gate); @@ -1102,7 +1102,7 @@ static int veth_transmit_to_one(struct sk_buff *skb, HvLpIndex rlp, struct net_device *dev) { struct veth_lpar_connection *cnx = veth_cnx[rlp]; - struct veth_port *port = (struct veth_port *) dev->priv; + struct veth_port *port = netdev_priv(dev); HvLpEvent_Rc rc; struct veth_msg *msg = NULL; unsigned long flags; @@ -1191,7 +1191,7 @@ static void veth_transmit_to_many(struct sk_buff *skb, static int veth_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned char *frame = skb->data; - struct veth_port *port = (struct veth_port *) dev->priv; + struct veth_port *port = netdev_priv(dev); HvLpIndexMap lpmask; if (! (frame[0] & 0x01)) { @@ -1255,7 +1255,7 @@ static void veth_wake_queues(struct veth_lpar_connection *cnx) if (! dev) continue; - port = (struct veth_port *)dev->priv; + port = netdev_priv(dev); if (! (port->lpar_map & (1<remote_lp))) continue; @@ -1284,7 +1284,7 @@ static void veth_stop_queues(struct veth_lpar_connection *cnx) if (! dev) continue; - port = (struct veth_port *)dev->priv; + port = netdev_priv(dev); /* If this cnx is not on the vlan for this port, continue */ if (! (port->lpar_map & (1 << cnx->remote_lp))) @@ -1506,7 +1506,7 @@ static void veth_receive(struct veth_lpar_connection *cnx, continue; } - port = (struct veth_port *)dev->priv; + port = netdev_priv(dev); dest = *((u64 *) skb->data) & 0xFFFFFFFFFFFF0000; if ((vlan > HVMAXARCHITECTEDVIRTUALLANS) || !port) { diff --git a/drivers/net/ixgb/ixgb_main.c b/drivers/net/ixgb/ixgb_main.c index be3c7dc96f633d2842d6394abd72a469b27e6dab..eee28d3956827cb8dcb3951df9738ab6c9cd54e6 100644 --- a/drivers/net/ixgb/ixgb_main.c +++ b/drivers/net/ixgb/ixgb_main.c @@ -321,6 +321,24 @@ ixgb_reset(struct ixgb_adapter *adapter) } } +static const struct net_device_ops ixgb_netdev_ops = { + .ndo_open = ixgb_open, + .ndo_stop = ixgb_close, + .ndo_start_xmit = ixgb_xmit_frame, + .ndo_get_stats = ixgb_get_stats, + .ndo_set_multicast_list = ixgb_set_multi, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = ixgb_set_mac, + .ndo_change_mtu = ixgb_change_mtu, + .ndo_tx_timeout = ixgb_tx_timeout, + .ndo_vlan_rx_register = ixgb_vlan_rx_register, + .ndo_vlan_rx_add_vid = ixgb_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = ixgb_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ixgb_netpoll, +#endif +}; + /** * ixgb_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -381,8 +399,7 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) adapter->hw.back = adapter; adapter->msg_enable = netif_msg_init(debug, DEFAULT_DEBUG_LEVEL_SHIFT); - adapter->hw.hw_addr = ioremap(pci_resource_start(pdev, BAR_0), - pci_resource_len(pdev, BAR_0)); + adapter->hw.hw_addr = pci_ioremap_bar(pdev, BAR_0); if (!adapter->hw.hw_addr) { err = -EIO; goto err_ioremap; @@ -397,23 +414,10 @@ ixgb_probe(struct pci_dev *pdev, const struct pci_device_id *ent) } } - netdev->open = &ixgb_open; - netdev->stop = &ixgb_close; - netdev->hard_start_xmit = &ixgb_xmit_frame; - netdev->get_stats = &ixgb_get_stats; - netdev->set_multicast_list = &ixgb_set_multi; - netdev->set_mac_address = &ixgb_set_mac; - netdev->change_mtu = &ixgb_change_mtu; + netdev->netdev_ops = &ixgb_netdev_ops; ixgb_set_ethtool_ops(netdev); - netdev->tx_timeout = &ixgb_tx_timeout; netdev->watchdog_timeo = 5 * HZ; netif_napi_add(netdev, &adapter->napi, ixgb_clean, 64); - netdev->vlan_rx_register = ixgb_vlan_rx_register; - netdev->vlan_rx_add_vid = ixgb_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = ixgb_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = ixgb_netpoll; -#endif strncpy(netdev->name, pci_name(pdev), sizeof(netdev->name) - 1); @@ -1106,8 +1110,15 @@ ixgb_watchdog(unsigned long data) if (adapter->hw.link_up) { if (!netif_carrier_ok(netdev)) { - DPRINTK(LINK, INFO, - "NIC Link is Up 10000 Mbps Full Duplex\n"); + printk(KERN_INFO "ixgb: %s NIC Link is Up 10 Gbps " + "Full Duplex, Flow Control: %s\n", + netdev->name, + (adapter->hw.fc.type == ixgb_fc_full) ? + "RX/TX" : + ((adapter->hw.fc.type == ixgb_fc_rx_pause) ? + "RX" : + ((adapter->hw.fc.type == ixgb_fc_tx_pause) ? + "TX" : "None"))); adapter->link_speed = 10000; adapter->link_duplex = FULL_DUPLEX; netif_carrier_on(netdev); @@ -1117,7 +1128,8 @@ ixgb_watchdog(unsigned long data) if (netif_carrier_ok(netdev)) { adapter->link_speed = 0; adapter->link_duplex = 0; - DPRINTK(LINK, INFO, "NIC Link is Down\n"); + printk(KERN_INFO "ixgb: %s NIC Link is Down\n", + netdev->name); netif_carrier_off(netdev); netif_stop_queue(netdev); @@ -1709,14 +1721,14 @@ ixgb_intr(int irq, void *data) if (!test_bit(__IXGB_DOWN, &adapter->flags)) mod_timer(&adapter->watchdog_timer, jiffies); - if (netif_rx_schedule_prep(netdev, &adapter->napi)) { + if (netif_rx_schedule_prep(&adapter->napi)) { /* Disable interrupts and register for poll. The flush of the posted write is intentionally left out. */ IXGB_WRITE_REG(&adapter->hw, IMC, ~0); - __netif_rx_schedule(netdev, &adapter->napi); + __netif_rx_schedule(&adapter->napi); } return IRQ_HANDLED; } @@ -1730,7 +1742,6 @@ static int ixgb_clean(struct napi_struct *napi, int budget) { struct ixgb_adapter *adapter = container_of(napi, struct ixgb_adapter, napi); - struct net_device *netdev = adapter->netdev; int work_done = 0; ixgb_clean_tx_irq(adapter); @@ -1738,7 +1749,7 @@ ixgb_clean(struct napi_struct *napi, int budget) /* If budget not fully consumed, exit the polling mode */ if (work_done < budget) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); if (!test_bit(__IXGB_DOWN, &adapter->flags)) ixgb_irq_enable(adapter); } @@ -1981,7 +1992,6 @@ ixgb_clean_rx_irq(struct ixgb_adapter *adapter, int *work_done, int work_to_do) } else { netif_receive_skb(skb); } - netdev->last_rx = jiffies; rxdesc_done: /* clean up descriptor, might be written over by hw */ diff --git a/drivers/net/ixgbe/Makefile b/drivers/net/ixgbe/Makefile index ccd83d9f579ef48cff32d3586535faea655e17fa..6e7ef765bcd882ec2257dcd5c244f0352846f36c 100644 --- a/drivers/net/ixgbe/Makefile +++ b/drivers/net/ixgbe/Makefile @@ -34,3 +34,5 @@ obj-$(CONFIG_IXGBE) += ixgbe.o ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \ ixgbe_82598.o ixgbe_phy.o + +ixgbe-$(CONFIG_IXGBE_DCB) += ixgbe_dcb.o ixgbe_dcb_82598.o ixgbe_dcb_nl.o diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index e116d340dcc6e158b35160f43ccd76d92feaa796..e112008f39c1dc889a73e4b9c0af5a4ceb7b95f1 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h @@ -32,10 +32,11 @@ #include #include #include +#include #include "ixgbe_type.h" #include "ixgbe_common.h" - +#include "ixgbe_dcb.h" #ifdef CONFIG_IXGBE_DCA #include #endif @@ -84,6 +85,7 @@ #define IXGBE_TX_FLAGS_TSO (u32)(1 << 2) #define IXGBE_TX_FLAGS_IPV4 (u32)(1 << 3) #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 +#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000 #define IXGBE_TX_FLAGS_VLAN_SHIFT 16 #define IXGBE_MAX_LRO_DESCRIPTORS 8 @@ -134,7 +136,7 @@ struct ixgbe_ring { u16 reg_idx; /* holds the special value that gets the hardware register * offset associated with this ring, which is different - * for DCE and RSS modes */ + * for DCB and RSS modes */ #ifdef CONFIG_IXGBE_DCA /* cpu for tx queue */ @@ -152,8 +154,10 @@ struct ixgbe_ring { u16 rx_buf_len; }; +#define RING_F_DCB 0 #define RING_F_VMDQ 1 #define RING_F_RSS 2 +#define IXGBE_MAX_DCB_INDICES 8 #define IXGBE_MAX_RSS_INDICES 16 #define IXGBE_MAX_VMDQ_INDICES 16 struct ixgbe_ring_feature { @@ -164,6 +168,10 @@ struct ixgbe_ring_feature { #define MAX_RX_QUEUES 64 #define MAX_TX_QUEUES 32 +#define MAX_RX_PACKET_BUFFERS ((adapter->flags & IXGBE_FLAG_DCB_ENABLED) \ + ? 8 : 1) +#define MAX_TX_PACKET_BUFFERS MAX_RX_PACKET_BUFFERS + /* MAX_MSIX_Q_VECTORS of these are allocated, * but we only use one per queue-specific vector. */ @@ -215,6 +223,9 @@ struct ixgbe_adapter { struct work_struct reset_task; struct ixgbe_q_vector q_vector[MAX_MSIX_Q_VECTORS]; char name[MAX_MSIX_COUNT][IFNAMSIZ + 5]; + struct ixgbe_dcb_config dcb_cfg; + struct ixgbe_dcb_config temp_dcb_cfg; + u8 dcb_set_bitmap; /* Interrupt Throttle Rate */ u32 itr_setting; @@ -267,8 +278,10 @@ struct ixgbe_adapter { #define IXGBE_FLAG_RSS_CAPABLE (u32)(1 << 17) #define IXGBE_FLAG_VMDQ_CAPABLE (u32)(1 << 18) #define IXGBE_FLAG_VMDQ_ENABLED (u32)(1 << 19) +#define IXGBE_FLAG_FAN_FAIL_CAPABLE (u32)(1 << 20) #define IXGBE_FLAG_NEED_LINK_UPDATE (u32)(1 << 22) #define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1 << 23) +#define IXGBE_FLAG_DCB_ENABLED (u32)(1 << 24) /* default to trying for four seconds */ #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ) @@ -299,12 +312,15 @@ struct ixgbe_adapter { unsigned long link_check_timeout; struct work_struct watchdog_task; + struct work_struct sfp_task; + struct timer_list sfp_timer; }; enum ixbge_state_t { __IXGBE_TESTING, __IXGBE_RESETTING, - __IXGBE_DOWN + __IXGBE_DOWN, + __IXGBE_SFP_MODULE_NOT_FOUND }; enum ixgbe_boards { @@ -312,6 +328,12 @@ enum ixgbe_boards { }; extern struct ixgbe_info ixgbe_82598_info; +#ifdef CONFIG_IXGBE_DCB +extern struct dcbnl_rtnl_ops dcbnl_ops; +extern int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, + struct ixgbe_dcb_config *dst_dcb_cfg, + int tc_max); +#endif extern char ixgbe_driver_name[]; extern const char ixgbe_driver_version[]; @@ -326,5 +348,9 @@ extern int ixgbe_setup_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *) extern void ixgbe_free_rx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); extern void ixgbe_free_tx_resources(struct ixgbe_adapter *, struct ixgbe_ring *); extern void ixgbe_update_stats(struct ixgbe_adapter *adapter); +extern void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter); +extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter); +void ixgbe_napi_add_all(struct ixgbe_adapter *adapter); +void ixgbe_napi_del_all(struct ixgbe_adapter *adapter); #endif /* _IXGBE_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_82598.c b/drivers/net/ixgbe/ixgbe_82598.c index 7cddcfba809e73bbd86a6ae108951de1f21376d3..ad5699d9ab0dacaaecf5fd6069b1268ff07d5e9c 100644 --- a/drivers/net/ixgbe/ixgbe_82598.c +++ b/drivers/net/ixgbe/ixgbe_82598.c @@ -46,6 +46,8 @@ static s32 ixgbe_setup_copper_link_speed_82598(struct ixgbe_hw *hw, ixgbe_link_speed speed, bool autoneg, bool autoneg_wait_to_complete); +static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, + u8 *eeprom_data); /** */ @@ -53,12 +55,40 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) { struct ixgbe_mac_info *mac = &hw->mac; struct ixgbe_phy_info *phy = &hw->phy; + s32 ret_val = 0; + u16 list_offset, data_offset; /* Call PHY identify routine to get the phy type */ ixgbe_identify_phy_generic(hw); /* PHY Init */ switch (phy->type) { + case ixgbe_phy_tn: + phy->ops.check_link = &ixgbe_check_phy_link_tnx; + phy->ops.get_firmware_version = + &ixgbe_get_phy_firmware_version_tnx; + break; + case ixgbe_phy_nl: + phy->ops.reset = &ixgbe_reset_phy_nl; + + /* Call SFP+ identify routine to get the SFP+ module type */ + ret_val = phy->ops.identify_sfp(hw); + if (ret_val != 0) + goto out; + else if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) { + ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; + goto out; + } + + /* Check to see if SFP+ module is supported */ + ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, + &list_offset, + &data_offset); + if (ret_val != 0) { + ret_val = IXGBE_ERR_SFP_NOT_SUPPORTED; + goto out; + } + break; default: break; } @@ -77,7 +107,8 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw) mac->max_rx_queues = IXGBE_82598_MAX_RX_QUEUES; mac->max_tx_queues = IXGBE_82598_MAX_TX_QUEUES; - return 0; +out: + return ret_val; } /** @@ -146,9 +177,9 @@ static s32 ixgbe_get_link_capabilities_82598(struct ixgbe_hw *hw, * * Determines the link capabilities by reading the AUTOC register. **/ -s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, - ixgbe_link_speed *speed, - bool *autoneg) +static s32 ixgbe_get_copper_link_capabilities_82598(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *autoneg) { s32 status = IXGBE_ERR_LINK_SETUP; u16 speed_ability; @@ -186,9 +217,15 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82598AF_SINGLE_PORT: case IXGBE_DEV_ID_82598EB_CX4: case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: + case IXGBE_DEV_ID_82598_DA_DUAL_PORT: + case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: case IXGBE_DEV_ID_82598EB_XF_LR: + case IXGBE_DEV_ID_82598EB_SFP_LOM: media_type = ixgbe_media_type_fiber; break; + case IXGBE_DEV_ID_82598AT: + media_type = ixgbe_media_type_copper; + break; default: media_type = ixgbe_media_type_unknown; break; @@ -205,7 +242,7 @@ static enum ixgbe_media_type ixgbe_get_media_type_82598(struct ixgbe_hw *hw) * Configures the flow control settings based on SW configuration. This * function is used for 802.3x flow control configuration only. **/ -s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) +static s32 ixgbe_setup_fc_82598(struct ixgbe_hw *hw, s32 packetbuf_num) { u32 frctl_reg; u32 rmcs_reg; @@ -391,6 +428,46 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, { u32 links_reg; u32 i; + u16 link_reg, adapt_comp_reg; + + /* + * SERDES PHY requires us to read link status from register 0xC79F. + * Bit 0 set indicates link is up/ready; clear indicates link down. + * 0xC00C is read to check that the XAUI lanes are active. Bit 0 + * clear indicates active; set indicates inactive. + */ + if (hw->phy.type == ixgbe_phy_nl) { + hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); + hw->phy.ops.read_reg(hw, 0xC79F, IXGBE_TWINAX_DEV, &link_reg); + hw->phy.ops.read_reg(hw, 0xC00C, IXGBE_TWINAX_DEV, + &adapt_comp_reg); + if (link_up_wait_to_complete) { + for (i = 0; i < IXGBE_LINK_UP_TIME; i++) { + if ((link_reg & 1) && + ((adapt_comp_reg & 1) == 0)) { + *link_up = true; + break; + } else { + *link_up = false; + } + msleep(100); + hw->phy.ops.read_reg(hw, 0xC79F, + IXGBE_TWINAX_DEV, + &link_reg); + hw->phy.ops.read_reg(hw, 0xC00C, + IXGBE_TWINAX_DEV, + &adapt_comp_reg); + } + } else { + if ((link_reg & 1) && ((adapt_comp_reg & 1) == 0)) + *link_up = true; + else + *link_up = false; + } + + if (*link_up == false) + goto out; + } links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS); if (link_up_wait_to_complete) { @@ -416,6 +493,7 @@ static s32 ixgbe_check_mac_link_82598(struct ixgbe_hw *hw, else *speed = IXGBE_LINK_SPEED_1GB_FULL; +out: return 0; } @@ -648,7 +726,7 @@ static s32 ixgbe_reset_hw_82598(struct ixgbe_hw *hw) * @rar: receive address register index to associate with a VMDq index * @vmdq: VMDq set index **/ -s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) +static s32 ixgbe_set_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) { u32 rar_high; @@ -692,8 +770,8 @@ static s32 ixgbe_clear_vmdq_82598(struct ixgbe_hw *hw, u32 rar, u32 vmdq) * * Turn on/off specified VLAN in the VLAN filter table. **/ -s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, - bool vlan_on) +static s32 ixgbe_set_vfta_82598(struct ixgbe_hw *hw, u32 vlan, u32 vind, + bool vlan_on) { u32 regindex; u32 bitindex; @@ -816,7 +894,7 @@ static s32 ixgbe_blink_led_stop_82598(struct ixgbe_hw *hw, u32 index) * * Performs read operation to Atlas analog register specified. **/ -s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val) +static s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val) { u32 atlas_ctl; @@ -838,7 +916,7 @@ s32 ixgbe_read_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 *val) * * Performs write operation to Atlas analog register specified. **/ -s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) +static s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) { u32 atlas_ctl; @@ -850,13 +928,76 @@ s32 ixgbe_write_analog_reg8_82598(struct ixgbe_hw *hw, u32 reg, u8 val) return 0; } +/** + * ixgbe_read_i2c_eeprom_82598 - Read 8 bit EEPROM word of an SFP+ module + * over I2C interface through an intermediate phy. + * @hw: pointer to hardware structure + * @byte_offset: EEPROM byte offset to read + * @eeprom_data: value read + * + * Performs byte read operation to SFP module's EEPROM over I2C interface. + **/ +static s32 ixgbe_read_i2c_eeprom_82598(struct ixgbe_hw *hw, u8 byte_offset, + u8 *eeprom_data) +{ + s32 status = 0; + u16 sfp_addr = 0; + u16 sfp_data = 0; + u16 sfp_stat = 0; + u32 i; + + if (hw->phy.type == ixgbe_phy_nl) { + /* + * phy SDA/SCL registers are at addresses 0xC30A to + * 0xC30D. These registers are used to talk to the SFP+ + * module's EEPROM through the SDA/SCL (I2C) interface. + */ + sfp_addr = (IXGBE_I2C_EEPROM_DEV_ADDR << 8) + byte_offset; + sfp_addr = (sfp_addr | IXGBE_I2C_EEPROM_READ_MASK); + hw->phy.ops.write_reg(hw, + IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + sfp_addr); + + /* Poll status */ + for (i = 0; i < 100; i++) { + hw->phy.ops.read_reg(hw, + IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, + &sfp_stat); + sfp_stat = sfp_stat & IXGBE_I2C_EEPROM_STATUS_MASK; + if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS) + break; + msleep(10); + } + + if (sfp_stat != IXGBE_I2C_EEPROM_STATUS_PASS) { + hw_dbg(hw, "EEPROM read did not pass.\n"); + status = IXGBE_ERR_SFP_NOT_PRESENT; + goto out; + } + + /* Read data */ + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA, + IXGBE_MDIO_PMA_PMD_DEV_TYPE, &sfp_data); + + *eeprom_data = (u8)(sfp_data >> 8); + } else { + status = IXGBE_ERR_PHY; + goto out; + } + +out: + return status; +} + /** * ixgbe_get_supported_physical_layer_82598 - Returns physical layer type * @hw: pointer to hardware structure * * Determines physical layer capabilities of the current configuration. **/ -s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) +static s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) { s32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; @@ -865,13 +1006,39 @@ s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw) case IXGBE_DEV_ID_82598_CX4_DUAL_PORT: physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_CX4; break; + case IXGBE_DEV_ID_82598_DA_DUAL_PORT: + physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; + break; case IXGBE_DEV_ID_82598AF_DUAL_PORT: case IXGBE_DEV_ID_82598AF_SINGLE_PORT: + case IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM: physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; break; case IXGBE_DEV_ID_82598EB_XF_LR: physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; break; + case IXGBE_DEV_ID_82598AT: + physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_T | + IXGBE_PHYSICAL_LAYER_1000BASE_T); + break; + case IXGBE_DEV_ID_82598EB_SFP_LOM: + hw->phy.ops.identify_sfp(hw); + + switch (hw->phy.sfp_type) { + case ixgbe_sfp_type_da_cu: + physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU; + break; + case ixgbe_sfp_type_sr: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR; + break; + case ixgbe_sfp_type_lr: + physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR; + break; + default: + physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; + break; + } + break; default: physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN; @@ -923,12 +1090,13 @@ static struct ixgbe_eeprom_operations eeprom_ops_82598 = { static struct ixgbe_phy_operations phy_ops_82598 = { .identify = &ixgbe_identify_phy_generic, - /* .identify_sfp = &ixgbe_identify_sfp_module_generic, */ + .identify_sfp = &ixgbe_identify_sfp_module_generic, .reset = &ixgbe_reset_phy_generic, .read_reg = &ixgbe_read_phy_reg_generic, .write_reg = &ixgbe_write_phy_reg_generic, .setup_link = &ixgbe_setup_phy_link_generic, .setup_link_speed = &ixgbe_setup_phy_link_speed_generic, + .read_i2c_eeprom = &ixgbe_read_i2c_eeprom_82598, }; struct ixgbe_info ixgbe_82598_info = { diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c new file mode 100644 index 0000000000000000000000000000000000000000..e2e28ac63deca37eb752b1da2a8d7f1239d11e12 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_dcb.c @@ -0,0 +1,332 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + + +#include "ixgbe.h" +#include "ixgbe_type.h" +#include "ixgbe_dcb.h" +#include "ixgbe_dcb_82598.h" + +/** + * ixgbe_dcb_config - Struct containing DCB settings. + * @dcb_config: Pointer to DCB config structure + * + * This function checks DCB rules for DCB settings. + * The following rules are checked: + * 1. The sum of bandwidth percentages of all Bandwidth Groups must total 100%. + * 2. The sum of bandwidth percentages of all Traffic Classes within a Bandwidth + * Group must total 100. + * 3. A Traffic Class should not be set to both Link Strict Priority + * and Group Strict Priority. + * 4. Link strict Bandwidth Groups can only have link strict traffic classes + * with zero bandwidth. + */ +s32 ixgbe_dcb_check_config(struct ixgbe_dcb_config *dcb_config) +{ + struct tc_bw_alloc *p; + s32 ret_val = 0; + u8 i, j, bw = 0, bw_id; + u8 bw_sum[2][MAX_BW_GROUP]; + bool link_strict[2][MAX_BW_GROUP]; + + memset(bw_sum, 0, sizeof(bw_sum)); + memset(link_strict, 0, sizeof(link_strict)); + + /* First Tx, then Rx */ + for (i = 0; i < 2; i++) { + /* Check each traffic class for rule violation */ + for (j = 0; j < MAX_TRAFFIC_CLASS; j++) { + p = &dcb_config->tc_config[j].path[i]; + + bw = p->bwg_percent; + bw_id = p->bwg_id; + + if (bw_id >= MAX_BW_GROUP) { + ret_val = DCB_ERR_CONFIG; + goto err_config; + } + if (p->prio_type == prio_link) { + link_strict[i][bw_id] = true; + /* Link strict should have zero bandwidth */ + if (bw) { + ret_val = DCB_ERR_LS_BW_NONZERO; + goto err_config; + } + } else if (!bw) { + /* + * Traffic classes without link strict + * should have non-zero bandwidth. + */ + ret_val = DCB_ERR_TC_BW_ZERO; + goto err_config; + } + bw_sum[i][bw_id] += bw; + } + + bw = 0; + + /* Check each bandwidth group for rule violation */ + for (j = 0; j < MAX_BW_GROUP; j++) { + bw += dcb_config->bw_percentage[i][j]; + /* + * Sum of bandwidth percentages of all traffic classes + * within a Bandwidth Group must total 100 except for + * link strict group (zero bandwidth). + */ + if (link_strict[i][j]) { + if (bw_sum[i][j]) { + /* + * Link strict group should have zero + * bandwidth. + */ + ret_val = DCB_ERR_LS_BWG_NONZERO; + goto err_config; + } + } else if (bw_sum[i][j] != BW_PERCENT && + bw_sum[i][j] != 0) { + ret_val = DCB_ERR_TC_BW; + goto err_config; + } + } + + if (bw != BW_PERCENT) { + ret_val = DCB_ERR_BW_GROUP; + goto err_config; + } + } + +err_config: + return ret_val; +} + +/** + * ixgbe_dcb_calculate_tc_credits - Calculates traffic class credits + * @ixgbe_dcb_config: Struct containing DCB settings. + * @direction: Configuring either Tx or Rx. + * + * This function calculates the credits allocated to each traffic class. + * It should be called only after the rules are checked by + * ixgbe_dcb_check_config(). + */ +s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *dcb_config, + u8 direction) +{ + struct tc_bw_alloc *p; + s32 ret_val = 0; + /* Initialization values default for Tx settings */ + u32 credit_refill = 0; + u32 credit_max = 0; + u16 link_percentage = 0; + u8 bw_percent = 0; + u8 i; + + if (dcb_config == NULL) { + ret_val = DCB_ERR_CONFIG; + goto out; + } + + /* Find out the link percentage for each TC first */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[direction]; + bw_percent = dcb_config->bw_percentage[direction][p->bwg_id]; + + link_percentage = p->bwg_percent; + /* Must be careful of integer division for very small nums */ + link_percentage = (link_percentage * bw_percent) / 100; + if (p->bwg_percent > 0 && link_percentage == 0) + link_percentage = 1; + + /* Save link_percentage for reference */ + p->link_percent = (u8)link_percentage; + + /* Calculate credit refill and save it */ + credit_refill = link_percentage * MINIMUM_CREDIT_REFILL; + p->data_credits_refill = (u16)credit_refill; + + /* Calculate maximum credit for the TC */ + credit_max = (link_percentage * MAX_CREDIT) / 100; + + /* + * Adjustment based on rule checking, if the percentage + * of a TC is too small, the maximum credit may not be + * enough to send out a jumbo frame in data plane arbitration. + */ + if (credit_max && (credit_max < MINIMUM_CREDIT_FOR_JUMBO)) + credit_max = MINIMUM_CREDIT_FOR_JUMBO; + + if (direction == DCB_TX_CONFIG) { + /* + * Adjustment based on rule checking, if the + * percentage of a TC is too small, the maximum + * credit may not be enough to send out a TSO + * packet in descriptor plane arbitration. + */ + if (credit_max && + (credit_max < MINIMUM_CREDIT_FOR_TSO)) + credit_max = MINIMUM_CREDIT_FOR_TSO; + + dcb_config->tc_config[i].desc_credits_max = + (u16)credit_max; + } + + p->data_credits_max = (u16)credit_max; + } + +out: + return ret_val; +} + +/** + * ixgbe_dcb_get_tc_stats - Returns status of each traffic class + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the status data for each of the Traffic Classes in use. + */ +s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_get_tc_stats_82598(hw, stats, tc_count); + return ret; +} + +/** + * ixgbe_dcb_get_pfc_stats - Returns CBFC status of each traffic class + * hw - pointer to hardware structure + * stats - pointer to statistics structure + * tc_count - Number of elements in bwg_array. + * + * This function returns the CBFC status data for each of the Traffic Classes. + */ +s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_get_pfc_stats_82598(hw, stats, tc_count); + return ret; +} + +/** + * ixgbe_dcb_config_rx_arbiter - Config Rx arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Rx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_rx_arbiter(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config); + return ret; +} + +/** + * ixgbe_dcb_config_tx_desc_arbiter - Config Tx Desc arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Descriptor Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_desc_arbiter(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config); + return ret; +} + +/** + * ixgbe_dcb_config_tx_data_arbiter - Config Tx data arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_data_arbiter(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config); + return ret; +} + +/** + * ixgbe_dcb_config_pfc - Config priority flow control + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Priority Flow Control for each traffic class. + */ +s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_config_pfc_82598(hw, dcb_config); + return ret; +} + +/** + * ixgbe_dcb_config_tc_stats - Config traffic class statistics + * @hw: pointer to hardware structure + * + * Configure queue statistics registers, all queues belonging to same traffic + * class uses a single set of queue statistics counters. + */ +s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *hw) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_config_tc_stats_82598(hw); + return ret; +} + +/** + * ixgbe_dcb_hw_config - Config and enable DCB + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure dcb settings and enable dcb mode. + */ +s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret = 0; + if (hw->mac.type == ixgbe_mac_82598EB) + ret = ixgbe_dcb_hw_config_82598(hw, dcb_config); + return ret; +} + diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h new file mode 100644 index 0000000000000000000000000000000000000000..75f6efe1e36920a9fba4c1f4859ec701f0a2549a --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_dcb.h @@ -0,0 +1,184 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _DCB_CONFIG_H_ +#define _DCB_CONFIG_H_ + +#include "ixgbe_type.h" + +/* DCB data structures */ + +#define IXGBE_MAX_PACKET_BUFFERS 8 +#define MAX_USER_PRIORITY 8 +#define MAX_TRAFFIC_CLASS 8 +#define MAX_BW_GROUP 8 +#define BW_PERCENT 100 + +#define DCB_TX_CONFIG 0 +#define DCB_RX_CONFIG 1 + +/* DCB error Codes */ +#define DCB_SUCCESS 0 +#define DCB_ERR_CONFIG -1 +#define DCB_ERR_PARAM -2 + +/* Transmit and receive Errors */ +/* Error in bandwidth group allocation */ +#define DCB_ERR_BW_GROUP -3 +/* Error in traffic class bandwidth allocation */ +#define DCB_ERR_TC_BW -4 +/* Traffic class has both link strict and group strict enabled */ +#define DCB_ERR_LS_GS -5 +/* Link strict traffic class has non zero bandwidth */ +#define DCB_ERR_LS_BW_NONZERO -6 +/* Link strict bandwidth group has non zero bandwidth */ +#define DCB_ERR_LS_BWG_NONZERO -7 +/* Traffic class has zero bandwidth */ +#define DCB_ERR_TC_BW_ZERO -8 + +#define DCB_NOT_IMPLEMENTED 0x7FFFFFFF + +struct dcb_pfc_tc_debug { + u8 tc; + u8 pause_status; + u64 pause_quanta; +}; + +enum strict_prio_type { + prio_none = 0, + prio_group, + prio_link +}; + +/* Traffic class bandwidth allocation per direction */ +struct tc_bw_alloc { + u8 bwg_id; /* Bandwidth Group (BWG) ID */ + u8 bwg_percent; /* % of BWG's bandwidth */ + u8 link_percent; /* % of link bandwidth */ + u8 up_to_tc_bitmap; /* User Priority to Traffic Class mapping */ + u16 data_credits_refill; /* Credit refill amount in 64B granularity */ + u16 data_credits_max; /* Max credits for a configured packet buffer + * in 64B granularity.*/ + enum strict_prio_type prio_type; /* Link or Group Strict Priority */ +}; + +enum dcb_pfc_type { + pfc_disabled = 0, + pfc_enabled_full, + pfc_enabled_tx, + pfc_enabled_rx +}; + +/* Traffic class configuration */ +struct tc_configuration { + struct tc_bw_alloc path[2]; /* One each for Tx/Rx */ + enum dcb_pfc_type dcb_pfc; /* Class based flow control setting */ + + u16 desc_credits_max; /* For Tx Descriptor arbitration */ + u8 tc; /* Traffic class (TC) */ +}; + +enum dcb_rx_pba_cfg { + pba_equal, /* PBA[0-7] each use 64KB FIFO */ + pba_80_48 /* PBA[0-3] each use 80KB, PBA[4-7] each use 48KB */ +}; + +/* + * This structure contains many values encoded as fixed-point + * numbers, meaning that some of bits are dedicated to the + * magnitude and others to the fraction part. In the comments + * this is shown as f=n, where n is the number of fraction bits. + * These fraction bits are always the low-order bits. The size + * of the magnitude is not specified. + */ +struct bcn_config { + u32 rp_admin_mode[MAX_TRAFFIC_CLASS]; /* BCN enabled, per TC */ + u32 bcna_option[2]; /* BCNA Port + MAC Addr */ + u32 rp_w; /* Derivative Weight, f=3 */ + u32 rp_gi; /* Increase Gain, f=12 */ + u32 rp_gd; /* Decrease Gain, f=12 */ + u32 rp_ru; /* Rate Unit */ + u32 rp_alpha; /* Max Decrease Factor, f=12 */ + u32 rp_beta; /* Max Increase Factor, f=12 */ + u32 rp_ri; /* Initial Rate */ + u32 rp_td; /* Drift Interval Timer */ + u32 rp_rd; /* Drift Increase */ + u32 rp_tmax; /* Severe Congestion Backoff Timer Range */ + u32 rp_rmin; /* Severe Congestion Restart Rate */ + u32 rp_wrtt; /* RTT Moving Average Weight */ +}; + +struct ixgbe_dcb_config { + struct bcn_config bcn; + + struct tc_configuration tc_config[MAX_TRAFFIC_CLASS]; + u8 bw_percentage[2][MAX_BW_GROUP]; /* One each for Tx/Rx */ + + bool round_robin_enable; + + enum dcb_rx_pba_cfg rx_pba_cfg; + + u32 dcb_cfg_version; /* Not used...OS-specific? */ + u32 link_speed; /* For bandwidth allocation validation purpose */ +}; + +/* DCB driver APIs */ + +/* DCB rule checking function.*/ +s32 ixgbe_dcb_check_config(struct ixgbe_dcb_config *config); + +/* DCB credits calculation */ +s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_dcb_config *, u8); + +/* DCB PFC functions */ +s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *, struct ixgbe_dcb_config *g); +s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *, struct ixgbe_hw_stats *, u8); + +/* DCB traffic class stats */ +s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *); +s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *, struct ixgbe_hw_stats *, u8); + +/* DCB config arbiters */ +s32 ixgbe_dcb_config_tx_desc_arbiter(struct ixgbe_hw *, + struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_tx_data_arbiter(struct ixgbe_hw *, + struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_rx_arbiter(struct ixgbe_hw *, struct ixgbe_dcb_config *); + +/* DCB hw initialization */ +s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *); + +/* DCB definitions for credit calculation */ +#define MAX_CREDIT_REFILL 511 /* 0x1FF * 64B = 32704B */ +#define MINIMUM_CREDIT_REFILL 5 /* 5*64B = 320B */ +#define MINIMUM_CREDIT_FOR_JUMBO 145 /* 145= UpperBound((9*1024+54)/64B) for 9KB jumbo frame */ +#define DCB_MAX_TSO_SIZE (32*1024) /* MAX TSO packet size supported in DCB mode */ +#define MINIMUM_CREDIT_FOR_TSO (DCB_MAX_TSO_SIZE/64 + 1) /* 513 for 32KB TSO packet */ +#define MAX_CREDIT 4095 /* Maximum credit supported: 256KB * 1204 / 64B */ + +#endif /* _DCB_CONFIG_H */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c new file mode 100644 index 0000000000000000000000000000000000000000..2c046b0b5d2806507178e5a2ff948cf9217f4d61 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c @@ -0,0 +1,398 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include "ixgbe.h" +#include "ixgbe_type.h" +#include "ixgbe_dcb.h" +#include "ixgbe_dcb_82598.h" + +/** + * ixgbe_dcb_get_tc_stats_82598 - Return status data for each traffic class + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the status data for each of the Traffic Classes in use. + */ +s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *hw, + struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + int tc; + + if (tc_count > MAX_TRAFFIC_CLASS) + return DCB_ERR_PARAM; + + /* Statistics pertaining to each traffic class */ + for (tc = 0; tc < tc_count; tc++) { + /* Transmitted Packets */ + stats->qptc[tc] += IXGBE_READ_REG(hw, IXGBE_QPTC(tc)); + /* Transmitted Bytes */ + stats->qbtc[tc] += IXGBE_READ_REG(hw, IXGBE_QBTC(tc)); + /* Received Packets */ + stats->qprc[tc] += IXGBE_READ_REG(hw, IXGBE_QPRC(tc)); + /* Received Bytes */ + stats->qbrc[tc] += IXGBE_READ_REG(hw, IXGBE_QBRC(tc)); + } + + return 0; +} + +/** + * ixgbe_dcb_get_pfc_stats_82598 - Returns CBFC status data + * @hw: pointer to hardware structure + * @stats: pointer to statistics structure + * @tc_count: Number of elements in bwg_array. + * + * This function returns the CBFC status data for each of the Traffic Classes. + */ +s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *hw, + struct ixgbe_hw_stats *stats, + u8 tc_count) +{ + int tc; + + if (tc_count > MAX_TRAFFIC_CLASS) + return DCB_ERR_PARAM; + + for (tc = 0; tc < tc_count; tc++) { + /* Priority XOFF Transmitted */ + stats->pxofftxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(tc)); + /* Priority XOFF Received */ + stats->pxoffrxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFRXC(tc)); + } + + return 0; +} + +/** + * ixgbe_dcb_config_packet_buffers_82598 - Configure packet buffers + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure packet buffers for DCB mode. + */ +static s32 ixgbe_dcb_config_packet_buffers_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + s32 ret_val = 0; + u32 value = IXGBE_RXPBSIZE_64KB; + u8 i = 0; + + /* Setup Rx packet buffer sizes */ + switch (dcb_config->rx_pba_cfg) { + case pba_80_48: + /* Setup the first four at 80KB */ + value = IXGBE_RXPBSIZE_80KB; + for (; i < 4; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); + /* Setup the last four at 48KB...don't re-init i */ + value = IXGBE_RXPBSIZE_48KB; + /* Fall Through */ + case pba_equal: + default: + for (; i < IXGBE_MAX_PACKET_BUFFERS; i++) + IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value); + + /* Setup Tx packet buffer sizes */ + for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) { + IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i), + IXGBE_TXPBSIZE_40KB); + } + break; + } + + return ret_val; +} + +/** + * ixgbe_dcb_config_rx_arbiter_82598 - Config Rx data arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Rx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + struct tc_bw_alloc *p; + u32 reg = 0; + u32 credit_refill = 0; + u32 credit_max = 0; + u8 i = 0; + + reg = IXGBE_READ_REG(hw, IXGBE_RUPPBMR) | IXGBE_RUPPBMR_MQA; + IXGBE_WRITE_REG(hw, IXGBE_RUPPBMR, reg); + + reg = IXGBE_READ_REG(hw, IXGBE_RMCS); + /* Enable Arbiter */ + reg &= ~IXGBE_RMCS_ARBDIS; + /* Enable Receive Recycle within the BWG */ + reg |= IXGBE_RMCS_RRM; + /* Enable Deficit Fixed Priority arbitration*/ + reg |= IXGBE_RMCS_DFP; + + IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg); + + /* Configure traffic class credits and priority */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[DCB_RX_CONFIG]; + credit_refill = p->data_credits_refill; + credit_max = p->data_credits_max; + + reg = credit_refill | (credit_max << IXGBE_RT2CR_MCL_SHIFT); + + if (p->prio_type == prio_link) + reg |= IXGBE_RT2CR_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_RT2CR(i), reg); + } + + reg = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); + reg |= IXGBE_RDRXCTL_RDMTS_1_2; + reg |= IXGBE_RDRXCTL_MPBEN; + reg |= IXGBE_RDRXCTL_MCEN; + IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, reg); + + reg = IXGBE_READ_REG(hw, IXGBE_RXCTRL); + /* Make sure there is enough descriptors before arbitration */ + reg &= ~IXGBE_RXCTRL_DMBYPS; + IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, reg); + + return 0; +} + +/** + * ixgbe_dcb_config_tx_desc_arbiter_82598 - Config Tx Desc. arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Descriptor Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + struct tc_bw_alloc *p; + u32 reg, max_credits; + u8 i; + + reg = IXGBE_READ_REG(hw, IXGBE_DPMCS); + + /* Enable arbiter */ + reg &= ~IXGBE_DPMCS_ARBDIS; + if (!(dcb_config->round_robin_enable)) { + /* Enable DFP and Recycle mode */ + reg |= (IXGBE_DPMCS_TDPAC | IXGBE_DPMCS_TRM); + } + reg |= IXGBE_DPMCS_TSOEF; + /* Configure Max TSO packet size 34KB including payload and headers */ + reg |= (0x4 << IXGBE_DPMCS_MTSOS_SHIFT); + + IXGBE_WRITE_REG(hw, IXGBE_DPMCS, reg); + + /* Configure traffic class credits and priority */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG]; + max_credits = dcb_config->tc_config[i].desc_credits_max; + reg = max_credits << IXGBE_TDTQ2TCCR_MCL_SHIFT; + reg |= p->data_credits_refill; + reg |= (u32)(p->bwg_id) << IXGBE_TDTQ2TCCR_BWG_SHIFT; + + if (p->prio_type == prio_group) + reg |= IXGBE_TDTQ2TCCR_GSP; + + if (p->prio_type == prio_link) + reg |= IXGBE_TDTQ2TCCR_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_TDTQ2TCCR(i), reg); + } + + return 0; +} + +/** + * ixgbe_dcb_config_tx_data_arbiter_82598 - Config Tx data arbiter + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Tx Data Arbiter and credits for each traffic class. + */ +s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + struct tc_bw_alloc *p; + u32 reg; + u8 i; + + reg = IXGBE_READ_REG(hw, IXGBE_PDPMCS); + /* Enable Data Plane Arbiter */ + reg &= ~IXGBE_PDPMCS_ARBDIS; + /* Enable DFP and Transmit Recycle Mode */ + reg |= (IXGBE_PDPMCS_TPPAC | IXGBE_PDPMCS_TRM); + + IXGBE_WRITE_REG(hw, IXGBE_PDPMCS, reg); + + /* Configure traffic class credits and priority */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG]; + reg = p->data_credits_refill; + reg |= (u32)(p->data_credits_max) << IXGBE_TDPT2TCCR_MCL_SHIFT; + reg |= (u32)(p->bwg_id) << IXGBE_TDPT2TCCR_BWG_SHIFT; + + if (p->prio_type == prio_group) + reg |= IXGBE_TDPT2TCCR_GSP; + + if (p->prio_type == prio_link) + reg |= IXGBE_TDPT2TCCR_LSP; + + IXGBE_WRITE_REG(hw, IXGBE_TDPT2TCCR(i), reg); + } + + /* Enable Tx packet buffer division */ + reg = IXGBE_READ_REG(hw, IXGBE_DTXCTL); + reg |= IXGBE_DTXCTL_ENDBUBD; + IXGBE_WRITE_REG(hw, IXGBE_DTXCTL, reg); + + return 0; +} + +/** + * ixgbe_dcb_config_pfc_82598 - Config priority flow control + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure Priority Flow Control for each traffic class. + */ +s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + u32 reg, rx_pba_size; + u8 i; + + /* Enable Transmit Priority Flow Control */ + reg = IXGBE_READ_REG(hw, IXGBE_RMCS); + reg &= ~IXGBE_RMCS_TFCE_802_3X; + /* correct the reporting of our flow control status */ + hw->fc.type = ixgbe_fc_none; + reg |= IXGBE_RMCS_TFCE_PRIORITY; + IXGBE_WRITE_REG(hw, IXGBE_RMCS, reg); + + /* Enable Receive Priority Flow Control */ + reg = IXGBE_READ_REG(hw, IXGBE_FCTRL); + reg &= ~IXGBE_FCTRL_RFCE; + reg |= IXGBE_FCTRL_RPFCE; + IXGBE_WRITE_REG(hw, IXGBE_FCTRL, reg); + + /* + * Configure flow control thresholds and enable priority flow control + * for each traffic class. + */ + for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { + if (dcb_config->rx_pba_cfg == pba_equal) { + rx_pba_size = IXGBE_RXPBSIZE_64KB; + } else { + rx_pba_size = (i < 4) ? IXGBE_RXPBSIZE_80KB + : IXGBE_RXPBSIZE_48KB; + } + + reg = ((rx_pba_size >> 5) & 0xFFF0); + if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx || + dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full) + reg |= IXGBE_FCRTL_XONE; + + IXGBE_WRITE_REG(hw, IXGBE_FCRTL(i), reg); + + reg = ((rx_pba_size >> 2) & 0xFFF0); + if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx || + dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full) + reg |= IXGBE_FCRTH_FCEN; + + IXGBE_WRITE_REG(hw, IXGBE_FCRTH(i), reg); + } + + /* Configure pause time */ + for (i = 0; i < (MAX_TRAFFIC_CLASS >> 1); i++) + IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), 0x68006800); + + /* Configure flow control refresh threshold value */ + IXGBE_WRITE_REG(hw, IXGBE_FCRTV, 0x3400); + + return 0; +} + +/** + * ixgbe_dcb_config_tc_stats_82598 - Configure traffic class statistics + * @hw: pointer to hardware structure + * + * Configure queue statistics registers, all queues belonging to same traffic + * class uses a single set of queue statistics counters. + */ +s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) +{ + u32 reg = 0; + u8 i = 0; + u8 j = 0; + + /* Receive Queues stats setting - 8 queues per statistics reg */ + for (i = 0, j = 0; i < 15 && j < 8; i = i + 2, j++) { + reg = IXGBE_READ_REG(hw, IXGBE_RQSMR(i)); + reg |= ((0x1010101) * j); + IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i), reg); + reg = IXGBE_READ_REG(hw, IXGBE_RQSMR(i + 1)); + reg |= ((0x1010101) * j); + IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i + 1), reg); + } + /* Transmit Queues stats setting - 4 queues per statistics reg */ + for (i = 0; i < 8; i++) { + reg = IXGBE_READ_REG(hw, IXGBE_TQSMR(i)); + reg |= ((0x1010101) * i); + IXGBE_WRITE_REG(hw, IXGBE_TQSMR(i), reg); + } + + return 0; +} + +/** + * ixgbe_dcb_hw_config_82598 - Config and enable DCB + * @hw: pointer to hardware structure + * @dcb_config: pointer to ixgbe_dcb_config structure + * + * Configure dcb settings and enable dcb mode. + */ +s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *hw, + struct ixgbe_dcb_config *dcb_config) +{ + ixgbe_dcb_config_packet_buffers_82598(hw, dcb_config); + ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config); + ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config); + ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config); + ixgbe_dcb_config_pfc_82598(hw, dcb_config); + ixgbe_dcb_config_tc_stats_82598(hw); + + return 0; +} diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.h b/drivers/net/ixgbe/ixgbe_dcb_82598.h new file mode 100644 index 0000000000000000000000000000000000000000..1e6a313719d7e2a0237896aa997c8871b8ee25bf --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_dcb_82598.h @@ -0,0 +1,94 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2007 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#ifndef _DCB_82598_CONFIG_H_ +#define _DCB_82598_CONFIG_H_ + +/* DCB register definitions */ + +#define IXGBE_DPMCS_MTSOS_SHIFT 16 +#define IXGBE_DPMCS_TDPAC 0x00000001 /* 0 Round Robin, 1 DFP - Deficit Fixed Priority */ +#define IXGBE_DPMCS_TRM 0x00000010 /* Transmit Recycle Mode */ +#define IXGBE_DPMCS_ARBDIS 0x00000040 /* DCB arbiter disable */ +#define IXGBE_DPMCS_TSOEF 0x00080000 /* TSO Expand Factor: 0=x4, 1=x2 */ + +#define IXGBE_RUPPBMR_MQA 0x80000000 /* Enable UP to queue mapping */ + +#define IXGBE_RT2CR_MCL_SHIFT 12 /* Offset to Max Credit Limit setting */ +#define IXGBE_RT2CR_LSP 0x80000000 /* LSP enable bit */ + +#define IXGBE_RDRXCTL_MPBEN 0x00000010 /* DMA config for multiple packet buffers enable */ +#define IXGBE_RDRXCTL_MCEN 0x00000040 /* DMA config for multiple cores (RSS) enable */ + +#define IXGBE_TDTQ2TCCR_MCL_SHIFT 12 +#define IXGBE_TDTQ2TCCR_BWG_SHIFT 9 +#define IXGBE_TDTQ2TCCR_GSP 0x40000000 +#define IXGBE_TDTQ2TCCR_LSP 0x80000000 + +#define IXGBE_TDPT2TCCR_MCL_SHIFT 12 +#define IXGBE_TDPT2TCCR_BWG_SHIFT 9 +#define IXGBE_TDPT2TCCR_GSP 0x40000000 +#define IXGBE_TDPT2TCCR_LSP 0x80000000 + +#define IXGBE_PDPMCS_TPPAC 0x00000020 /* 0 Round Robin, 1 for DFP - Deficit Fixed Priority */ +#define IXGBE_PDPMCS_ARBDIS 0x00000040 /* Arbiter disable */ +#define IXGBE_PDPMCS_TRM 0x00000100 /* Transmit Recycle Mode enable */ + +#define IXGBE_DTXCTL_ENDBUBD 0x00000004 /* Enable DBU buffer division */ + +#define IXGBE_TXPBSIZE_40KB 0x0000A000 /* 40KB Packet Buffer */ +#define IXGBE_RXPBSIZE_48KB 0x0000C000 /* 48KB Packet Buffer */ +#define IXGBE_RXPBSIZE_64KB 0x00010000 /* 64KB Packet Buffer */ +#define IXGBE_RXPBSIZE_80KB 0x00014000 /* 80KB Packet Buffer */ + +#define IXGBE_RDRXCTL_RDMTS_1_2 0x00000000 + +/* DCB hardware-specific driver APIs */ + +/* DCB PFC functions */ +s32 ixgbe_dcb_config_pfc_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *); +s32 ixgbe_dcb_get_pfc_stats_82598(struct ixgbe_hw *, struct ixgbe_hw_stats *, + u8); + +/* DCB traffic class stats */ +s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *); +s32 ixgbe_dcb_get_tc_stats_82598(struct ixgbe_hw *, struct ixgbe_hw_stats *, + u8); + +/* DCB config arbiters */ +s32 ixgbe_dcb_config_tx_desc_arbiter_82598(struct ixgbe_hw *, + struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_tx_data_arbiter_82598(struct ixgbe_hw *, + struct ixgbe_dcb_config *); +s32 ixgbe_dcb_config_rx_arbiter_82598(struct ixgbe_hw *, + struct ixgbe_dcb_config *); + +/* DCB hw initialization */ +s32 ixgbe_dcb_hw_config_82598(struct ixgbe_hw *, struct ixgbe_dcb_config *); + +#endif /* _DCB_82598_CONFIG_H */ diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c new file mode 100644 index 0000000000000000000000000000000000000000..4129976953f5609f58c4f442b22f58095c8a54f7 --- /dev/null +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c @@ -0,0 +1,641 @@ +/******************************************************************************* + + Intel 10 Gigabit PCI Express Linux driver + Copyright(c) 1999 - 2008 Intel Corporation. + + This program is free software; you can redistribute it and/or modify it + under the terms and conditions of the GNU General Public License, + version 2, as published by the Free Software Foundation. + + This program is distributed in the hope 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". + + Contact Information: + Linux NICS + e1000-devel Mailing List + Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + +*******************************************************************************/ + +#include "ixgbe.h" +#include + +/* Callbacks for DCB netlink in the kernel */ +#define BIT_DCB_MODE 0x01 +#define BIT_PFC 0x02 +#define BIT_PG_RX 0x04 +#define BIT_PG_TX 0x08 +#define BIT_BCN 0x10 + +int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg, + struct ixgbe_dcb_config *dst_dcb_cfg, int tc_max) +{ + struct tc_configuration *src_tc_cfg = NULL; + struct tc_configuration *dst_tc_cfg = NULL; + int i; + + if (!src_dcb_cfg || !dst_dcb_cfg) + return -EINVAL; + + for (i = DCB_PG_ATTR_TC_0; i < tc_max + DCB_PG_ATTR_TC_0; i++) { + src_tc_cfg = &src_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0]; + dst_tc_cfg = &dst_dcb_cfg->tc_config[i - DCB_PG_ATTR_TC_0]; + + dst_tc_cfg->path[DCB_TX_CONFIG].prio_type = + src_tc_cfg->path[DCB_TX_CONFIG].prio_type; + + dst_tc_cfg->path[DCB_TX_CONFIG].bwg_id = + src_tc_cfg->path[DCB_TX_CONFIG].bwg_id; + + dst_tc_cfg->path[DCB_TX_CONFIG].bwg_percent = + src_tc_cfg->path[DCB_TX_CONFIG].bwg_percent; + + dst_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap = + src_tc_cfg->path[DCB_TX_CONFIG].up_to_tc_bitmap; + + dst_tc_cfg->path[DCB_RX_CONFIG].prio_type = + src_tc_cfg->path[DCB_RX_CONFIG].prio_type; + + dst_tc_cfg->path[DCB_RX_CONFIG].bwg_id = + src_tc_cfg->path[DCB_RX_CONFIG].bwg_id; + + dst_tc_cfg->path[DCB_RX_CONFIG].bwg_percent = + src_tc_cfg->path[DCB_RX_CONFIG].bwg_percent; + + dst_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap = + src_tc_cfg->path[DCB_RX_CONFIG].up_to_tc_bitmap; + } + + for (i = DCB_PG_ATTR_BW_ID_0; i < DCB_PG_ATTR_BW_ID_MAX; i++) { + dst_dcb_cfg->bw_percentage[DCB_TX_CONFIG] + [i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage + [DCB_TX_CONFIG][i-DCB_PG_ATTR_BW_ID_0]; + dst_dcb_cfg->bw_percentage[DCB_RX_CONFIG] + [i-DCB_PG_ATTR_BW_ID_0] = src_dcb_cfg->bw_percentage + [DCB_RX_CONFIG][i-DCB_PG_ATTR_BW_ID_0]; + } + + for (i = DCB_PFC_UP_ATTR_0; i < DCB_PFC_UP_ATTR_MAX; i++) { + dst_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc = + src_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc; + } + + for (i = DCB_BCN_ATTR_RP_0; i < DCB_BCN_ATTR_RP_ALL; i++) { + dst_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0] = + src_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0]; + } + dst_dcb_cfg->bcn.bcna_option[0] = src_dcb_cfg->bcn.bcna_option[0]; + dst_dcb_cfg->bcn.bcna_option[1] = src_dcb_cfg->bcn.bcna_option[1]; + dst_dcb_cfg->bcn.rp_alpha = src_dcb_cfg->bcn.rp_alpha; + dst_dcb_cfg->bcn.rp_beta = src_dcb_cfg->bcn.rp_beta; + dst_dcb_cfg->bcn.rp_gd = src_dcb_cfg->bcn.rp_gd; + dst_dcb_cfg->bcn.rp_gi = src_dcb_cfg->bcn.rp_gi; + dst_dcb_cfg->bcn.rp_tmax = src_dcb_cfg->bcn.rp_tmax; + dst_dcb_cfg->bcn.rp_td = src_dcb_cfg->bcn.rp_td; + dst_dcb_cfg->bcn.rp_rmin = src_dcb_cfg->bcn.rp_rmin; + dst_dcb_cfg->bcn.rp_w = src_dcb_cfg->bcn.rp_w; + dst_dcb_cfg->bcn.rp_rd = src_dcb_cfg->bcn.rp_rd; + dst_dcb_cfg->bcn.rp_ru = src_dcb_cfg->bcn.rp_ru; + dst_dcb_cfg->bcn.rp_wrtt = src_dcb_cfg->bcn.rp_wrtt; + dst_dcb_cfg->bcn.rp_ri = src_dcb_cfg->bcn.rp_ri; + + return 0; +} + +static u8 ixgbe_dcbnl_get_state(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + DPRINTK(DRV, INFO, "Get DCB Admin Mode.\n"); + + return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED); +} + +static u16 ixgbe_dcb_select_queue(struct net_device *dev, struct sk_buff *skb) +{ + /* All traffic should default to class 0 */ + return 0; +} + +static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state) +{ + u8 err = 0; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + DPRINTK(DRV, INFO, "Set DCB Admin Mode.\n"); + + if (state > 0) { + /* Turn on DCB */ + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) + goto out; + + if (!(adapter->flags & IXGBE_FLAG_MSIX_ENABLED)) { + DPRINTK(DRV, ERR, "Enable failed, needs MSI-X\n"); + err = 1; + goto out; + } + + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + ixgbe_reset_interrupt_capability(adapter); + ixgbe_napi_del_all(adapter); + INIT_LIST_HEAD(&netdev->napi_list); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + adapter->tx_ring = NULL; + adapter->rx_ring = NULL; + netdev->select_queue = &ixgbe_dcb_select_queue; + + adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + adapter->flags |= IXGBE_FLAG_DCB_ENABLED; + ixgbe_init_interrupt_scheme(adapter); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + } else { + /* Turn off DCB */ + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + ixgbe_reset_interrupt_capability(adapter); + ixgbe_napi_del_all(adapter); + INIT_LIST_HEAD(&netdev->napi_list); + kfree(adapter->tx_ring); + kfree(adapter->rx_ring); + adapter->tx_ring = NULL; + adapter->rx_ring = NULL; + netdev->select_queue = NULL; + + adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; + adapter->flags |= IXGBE_FLAG_RSS_ENABLED; + ixgbe_init_interrupt_scheme(adapter); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + } + } +out: + return err; +} + +static void ixgbe_dcbnl_get_perm_hw_addr(struct net_device *netdev, + u8 *perm_addr) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + int i; + + for (i = 0; i < netdev->addr_len; i++) + perm_addr[i] = adapter->hw.mac.perm_addr[i]; +} + +static void ixgbe_dcbnl_set_pg_tc_cfg_tx(struct net_device *netdev, int tc, + u8 prio, u8 bwg_id, u8 bw_pct, + u8 up_map) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (prio != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type = prio; + if (bwg_id != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id = bwg_id; + if (bw_pct != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent = + bw_pct; + if (up_map != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap = + up_map; + + if ((adapter->temp_dcb_cfg.tc_config[tc].path[0].prio_type != + adapter->dcb_cfg.tc_config[tc].path[0].prio_type) || + (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_id != + adapter->dcb_cfg.tc_config[tc].path[0].bwg_id) || + (adapter->temp_dcb_cfg.tc_config[tc].path[0].bwg_percent != + adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent) || + (adapter->temp_dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap != + adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap)) + adapter->dcb_set_bitmap |= BIT_PG_TX; +} + +static void ixgbe_dcbnl_set_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, + u8 bw_pct) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] = bw_pct; + + if (adapter->temp_dcb_cfg.bw_percentage[0][bwg_id] != + adapter->dcb_cfg.bw_percentage[0][bwg_id]) + adapter->dcb_set_bitmap |= BIT_PG_RX; +} + +static void ixgbe_dcbnl_set_pg_tc_cfg_rx(struct net_device *netdev, int tc, + u8 prio, u8 bwg_id, u8 bw_pct, + u8 up_map) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + if (prio != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type = prio; + if (bwg_id != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id = bwg_id; + if (bw_pct != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent = + bw_pct; + if (up_map != DCB_ATTR_VALUE_UNDEFINED) + adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap = + up_map; + + if ((adapter->temp_dcb_cfg.tc_config[tc].path[1].prio_type != + adapter->dcb_cfg.tc_config[tc].path[1].prio_type) || + (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_id != + adapter->dcb_cfg.tc_config[tc].path[1].bwg_id) || + (adapter->temp_dcb_cfg.tc_config[tc].path[1].bwg_percent != + adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent) || + (adapter->temp_dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap != + adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap)) + adapter->dcb_set_bitmap |= BIT_PG_RX; +} + +static void ixgbe_dcbnl_set_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, + u8 bw_pct) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] = bw_pct; + + if (adapter->temp_dcb_cfg.bw_percentage[1][bwg_id] != + adapter->dcb_cfg.bw_percentage[1][bwg_id]) + adapter->dcb_set_bitmap |= BIT_PG_RX; +} + +static void ixgbe_dcbnl_get_pg_tc_cfg_tx(struct net_device *netdev, int tc, + u8 *prio, u8 *bwg_id, u8 *bw_pct, + u8 *up_map) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *prio = adapter->dcb_cfg.tc_config[tc].path[0].prio_type; + *bwg_id = adapter->dcb_cfg.tc_config[tc].path[0].bwg_id; + *bw_pct = adapter->dcb_cfg.tc_config[tc].path[0].bwg_percent; + *up_map = adapter->dcb_cfg.tc_config[tc].path[0].up_to_tc_bitmap; +} + +static void ixgbe_dcbnl_get_pg_bwg_cfg_tx(struct net_device *netdev, int bwg_id, + u8 *bw_pct) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *bw_pct = adapter->dcb_cfg.bw_percentage[0][bwg_id]; +} + +static void ixgbe_dcbnl_get_pg_tc_cfg_rx(struct net_device *netdev, int tc, + u8 *prio, u8 *bwg_id, u8 *bw_pct, + u8 *up_map) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *prio = adapter->dcb_cfg.tc_config[tc].path[1].prio_type; + *bwg_id = adapter->dcb_cfg.tc_config[tc].path[1].bwg_id; + *bw_pct = adapter->dcb_cfg.tc_config[tc].path[1].bwg_percent; + *up_map = adapter->dcb_cfg.tc_config[tc].path[1].up_to_tc_bitmap; +} + +static void ixgbe_dcbnl_get_pg_bwg_cfg_rx(struct net_device *netdev, int bwg_id, + u8 *bw_pct) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *bw_pct = adapter->dcb_cfg.bw_percentage[1][bwg_id]; +} + +static void ixgbe_dcbnl_set_pfc_cfg(struct net_device *netdev, int priority, + u8 setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc = setting; + if (adapter->temp_dcb_cfg.tc_config[priority].dcb_pfc != + adapter->dcb_cfg.tc_config[priority].dcb_pfc) + adapter->dcb_set_bitmap |= BIT_PFC; +} + +static void ixgbe_dcbnl_get_pfc_cfg(struct net_device *netdev, int priority, + u8 *setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *setting = adapter->dcb_cfg.tc_config[priority].dcb_pfc; +} + +static u8 ixgbe_dcbnl_set_all(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + int ret; + + adapter->dcb_set_bitmap &= ~BIT_BCN; /* no set for BCN */ + if (!adapter->dcb_set_bitmap) + return 1; + + while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) + msleep(1); + + if (netif_running(netdev)) + ixgbe_down(adapter); + + ret = ixgbe_copy_dcb_cfg(&adapter->temp_dcb_cfg, &adapter->dcb_cfg, + adapter->ring_feature[RING_F_DCB].indices); + if (ret) { + clear_bit(__IXGBE_RESETTING, &adapter->state); + return ret; + } + + if (netif_running(netdev)) + ixgbe_up(adapter); + + adapter->dcb_set_bitmap = 0x00; + clear_bit(__IXGBE_RESETTING, &adapter->state); + return ret; +} + +static u8 ixgbe_dcbnl_getcap(struct net_device *netdev, int capid, u8 *cap) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u8 rval = 0; + + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + switch (capid) { + case DCB_CAP_ATTR_PG: + *cap = true; + break; + case DCB_CAP_ATTR_PFC: + *cap = true; + break; + case DCB_CAP_ATTR_UP2TC: + *cap = false; + break; + case DCB_CAP_ATTR_PG_TCS: + *cap = 0x80; + break; + case DCB_CAP_ATTR_PFC_TCS: + *cap = 0x80; + break; + case DCB_CAP_ATTR_GSP: + *cap = true; + break; + case DCB_CAP_ATTR_BCN: + *cap = false; + break; + default: + rval = -EINVAL; + break; + } + } else { + rval = -EINVAL; + } + + return rval; +} + +static u8 ixgbe_dcbnl_getnumtcs(struct net_device *netdev, int tcid, u8 *num) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + u8 rval = 0; + + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + switch (tcid) { + case DCB_NUMTCS_ATTR_PG: + *num = MAX_TRAFFIC_CLASS; + break; + case DCB_NUMTCS_ATTR_PFC: + *num = MAX_TRAFFIC_CLASS; + break; + default: + rval = -EINVAL; + break; + } + } else { + rval = -EINVAL; + } + + return rval; +} + +static u8 ixgbe_dcbnl_setnumtcs(struct net_device *netdev, int tcid, u8 num) +{ + return -EINVAL; +} + +static u8 ixgbe_dcbnl_getpfcstate(struct net_device *netdev) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED); +} + +static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state) +{ + return; +} + +static void ixgbe_dcbnl_getbcnrp(struct net_device *netdev, int priority, + u8 *setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + *setting = adapter->dcb_cfg.bcn.rp_admin_mode[priority]; +} + + +static void ixgbe_dcbnl_getbcncfg(struct net_device *netdev, int enum_index, + u32 *setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + switch (enum_index) { + case DCB_BCN_ATTR_BCNA_0: + *setting = adapter->dcb_cfg.bcn.bcna_option[0]; + break; + case DCB_BCN_ATTR_BCNA_1: + *setting = adapter->dcb_cfg.bcn.bcna_option[1]; + break; + case DCB_BCN_ATTR_ALPHA: + *setting = adapter->dcb_cfg.bcn.rp_alpha; + break; + case DCB_BCN_ATTR_BETA: + *setting = adapter->dcb_cfg.bcn.rp_beta; + break; + case DCB_BCN_ATTR_GD: + *setting = adapter->dcb_cfg.bcn.rp_gd; + break; + case DCB_BCN_ATTR_GI: + *setting = adapter->dcb_cfg.bcn.rp_gi; + break; + case DCB_BCN_ATTR_TMAX: + *setting = adapter->dcb_cfg.bcn.rp_tmax; + break; + case DCB_BCN_ATTR_TD: + *setting = adapter->dcb_cfg.bcn.rp_td; + break; + case DCB_BCN_ATTR_RMIN: + *setting = adapter->dcb_cfg.bcn.rp_rmin; + break; + case DCB_BCN_ATTR_W: + *setting = adapter->dcb_cfg.bcn.rp_w; + break; + case DCB_BCN_ATTR_RD: + *setting = adapter->dcb_cfg.bcn.rp_rd; + break; + case DCB_BCN_ATTR_RU: + *setting = adapter->dcb_cfg.bcn.rp_ru; + break; + case DCB_BCN_ATTR_WRTT: + *setting = adapter->dcb_cfg.bcn.rp_wrtt; + break; + case DCB_BCN_ATTR_RI: + *setting = adapter->dcb_cfg.bcn.rp_ri; + break; + default: + *setting = -1; + } +} + +static void ixgbe_dcbnl_setbcnrp(struct net_device *netdev, int priority, + u8 setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + adapter->temp_dcb_cfg.bcn.rp_admin_mode[priority] = setting; + + if (adapter->temp_dcb_cfg.bcn.rp_admin_mode[priority] != + adapter->dcb_cfg.bcn.rp_admin_mode[priority]) + adapter->dcb_set_bitmap |= BIT_BCN; +} + +static void ixgbe_dcbnl_setbcncfg(struct net_device *netdev, int enum_index, + u32 setting) +{ + struct ixgbe_adapter *adapter = netdev_priv(netdev); + + switch (enum_index) { + case DCB_BCN_ATTR_BCNA_0: + adapter->temp_dcb_cfg.bcn.bcna_option[0] = setting; + if (adapter->temp_dcb_cfg.bcn.bcna_option[0] != + adapter->dcb_cfg.bcn.bcna_option[0]) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_BCNA_1: + adapter->temp_dcb_cfg.bcn.bcna_option[1] = setting; + if (adapter->temp_dcb_cfg.bcn.bcna_option[1] != + adapter->dcb_cfg.bcn.bcna_option[1]) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_ALPHA: + adapter->temp_dcb_cfg.bcn.rp_alpha = setting; + if (adapter->temp_dcb_cfg.bcn.rp_alpha != + adapter->dcb_cfg.bcn.rp_alpha) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_BETA: + adapter->temp_dcb_cfg.bcn.rp_beta = setting; + if (adapter->temp_dcb_cfg.bcn.rp_beta != + adapter->dcb_cfg.bcn.rp_beta) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_GD: + adapter->temp_dcb_cfg.bcn.rp_gd = setting; + if (adapter->temp_dcb_cfg.bcn.rp_gd != + adapter->dcb_cfg.bcn.rp_gd) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_GI: + adapter->temp_dcb_cfg.bcn.rp_gi = setting; + if (adapter->temp_dcb_cfg.bcn.rp_gi != + adapter->dcb_cfg.bcn.rp_gi) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_TMAX: + adapter->temp_dcb_cfg.bcn.rp_tmax = setting; + if (adapter->temp_dcb_cfg.bcn.rp_tmax != + adapter->dcb_cfg.bcn.rp_tmax) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_TD: + adapter->temp_dcb_cfg.bcn.rp_td = setting; + if (adapter->temp_dcb_cfg.bcn.rp_td != + adapter->dcb_cfg.bcn.rp_td) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_RMIN: + adapter->temp_dcb_cfg.bcn.rp_rmin = setting; + if (adapter->temp_dcb_cfg.bcn.rp_rmin != + adapter->dcb_cfg.bcn.rp_rmin) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_W: + adapter->temp_dcb_cfg.bcn.rp_w = setting; + if (adapter->temp_dcb_cfg.bcn.rp_w != + adapter->dcb_cfg.bcn.rp_w) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_RD: + adapter->temp_dcb_cfg.bcn.rp_rd = setting; + if (adapter->temp_dcb_cfg.bcn.rp_rd != + adapter->dcb_cfg.bcn.rp_rd) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_RU: + adapter->temp_dcb_cfg.bcn.rp_ru = setting; + if (adapter->temp_dcb_cfg.bcn.rp_ru != + adapter->dcb_cfg.bcn.rp_ru) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_WRTT: + adapter->temp_dcb_cfg.bcn.rp_wrtt = setting; + if (adapter->temp_dcb_cfg.bcn.rp_wrtt != + adapter->dcb_cfg.bcn.rp_wrtt) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + case DCB_BCN_ATTR_RI: + adapter->temp_dcb_cfg.bcn.rp_ri = setting; + if (adapter->temp_dcb_cfg.bcn.rp_ri != + adapter->dcb_cfg.bcn.rp_ri) + adapter->dcb_set_bitmap |= BIT_BCN; + break; + default: + break; + } +} + +struct dcbnl_rtnl_ops dcbnl_ops = { + .getstate = ixgbe_dcbnl_get_state, + .setstate = ixgbe_dcbnl_set_state, + .getpermhwaddr = ixgbe_dcbnl_get_perm_hw_addr, + .setpgtccfgtx = ixgbe_dcbnl_set_pg_tc_cfg_tx, + .setpgbwgcfgtx = ixgbe_dcbnl_set_pg_bwg_cfg_tx, + .setpgtccfgrx = ixgbe_dcbnl_set_pg_tc_cfg_rx, + .setpgbwgcfgrx = ixgbe_dcbnl_set_pg_bwg_cfg_rx, + .getpgtccfgtx = ixgbe_dcbnl_get_pg_tc_cfg_tx, + .getpgbwgcfgtx = ixgbe_dcbnl_get_pg_bwg_cfg_tx, + .getpgtccfgrx = ixgbe_dcbnl_get_pg_tc_cfg_rx, + .getpgbwgcfgrx = ixgbe_dcbnl_get_pg_bwg_cfg_rx, + .setpfccfg = ixgbe_dcbnl_set_pfc_cfg, + .getpfccfg = ixgbe_dcbnl_get_pfc_cfg, + .setall = ixgbe_dcbnl_set_all, + .getcap = ixgbe_dcbnl_getcap, + .getnumtcs = ixgbe_dcbnl_getnumtcs, + .setnumtcs = ixgbe_dcbnl_setnumtcs, + .getpfcstate = ixgbe_dcbnl_getpfcstate, + .setpfcstate = ixgbe_dcbnl_setpfcstate, + .getbcncfg = ixgbe_dcbnl_getbcncfg, + .getbcnrp = ixgbe_dcbnl_getbcnrp, + .setbcncfg = ixgbe_dcbnl_setbcncfg, + .setbcnrp = ixgbe_dcbnl_setbcnrp +}; + diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 81a9c4b8672683a8033ef5e73e3a4096e5e7a724..67f87a79154dbff3f88ab64bddaa7ab2577b7099 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c @@ -94,12 +94,21 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { }; #define IXGBE_QUEUE_STATS_LEN \ - ((((struct ixgbe_adapter *)netdev->priv)->num_tx_queues + \ - ((struct ixgbe_adapter *)netdev->priv)->num_rx_queues) * \ - (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) -#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) + ((((struct ixgbe_adapter *)netdev_priv(netdev))->num_tx_queues + \ + ((struct ixgbe_adapter *)netdev_priv(netdev))->num_rx_queues) * \ + (sizeof(struct ixgbe_queue_stats) / sizeof(u64))) #define IXGBE_GLOBAL_STATS_LEN ARRAY_SIZE(ixgbe_gstrings_stats) -#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + IXGBE_QUEUE_STATS_LEN) +#define IXGBE_PB_STATS_LEN ( \ + (((struct ixgbe_adapter *)netdev_priv(netdev))->flags & \ + IXGBE_FLAG_DCB_ENABLED) ? \ + (sizeof(((struct ixgbe_adapter *)0)->stats.pxonrxc) + \ + sizeof(((struct ixgbe_adapter *)0)->stats.pxontxc) + \ + sizeof(((struct ixgbe_adapter *)0)->stats.pxoffrxc) + \ + sizeof(((struct ixgbe_adapter *)0)->stats.pxofftxc)) \ + / sizeof(u64) : 0) +#define IXGBE_STATS_LEN (IXGBE_GLOBAL_STATS_LEN + \ + IXGBE_PB_STATS_LEN + \ + IXGBE_QUEUE_STATS_LEN) static int ixgbe_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) @@ -149,6 +158,8 @@ static int ixgbe_set_settings(struct net_device *netdev, { struct ixgbe_adapter *adapter = netdev_priv(netdev); struct ixgbe_hw *hw = &adapter->hw; + u32 advertised, old; + s32 err; switch (hw->phy.media_type) { case ixgbe_media_type_fiber: @@ -157,6 +168,31 @@ static int ixgbe_set_settings(struct net_device *netdev, return -EINVAL; /* in this case we currently only support 10Gb/FULL */ break; + case ixgbe_media_type_copper: + /* 10000/copper and 1000/copper must autoneg + * this function does not support any duplex forcing, but can + * limit the advertising of the adapter to only 10000 or 1000 */ + if (ecmd->autoneg == AUTONEG_DISABLE) + return -EINVAL; + + old = hw->phy.autoneg_advertised; + advertised = 0; + if (ecmd->advertising & ADVERTISED_10000baseT_Full) + advertised |= IXGBE_LINK_SPEED_10GB_FULL; + + if (ecmd->advertising & ADVERTISED_1000baseT_Full) + advertised |= IXGBE_LINK_SPEED_1GB_FULL; + + if (old == advertised) + break; + /* this sets the link speed and restarts auto-neg */ + err = hw->mac.ops.setup_link_speed(hw, advertised, true, true); + if (err) { + DPRINTK(PROBE, INFO, + "setup link failed with code %d\n", err); + hw->mac.ops.setup_link_speed(hw, old, true, true); + } + break; default: break; } @@ -676,30 +712,15 @@ static int ixgbe_set_ringparam(struct net_device *netdev, return 0; } - if (adapter->num_tx_queues > adapter->num_rx_queues) - temp_ring = vmalloc(adapter->num_tx_queues * - sizeof(struct ixgbe_ring)); - else - temp_ring = vmalloc(adapter->num_rx_queues * - sizeof(struct ixgbe_ring)); + temp_ring = kcalloc(adapter->num_tx_queues, + sizeof(struct ixgbe_ring), GFP_KERNEL); if (!temp_ring) return -ENOMEM; while (test_and_set_bit(__IXGBE_RESETTING, &adapter->state)) msleep(1); - if (netif_running(netdev)) - ixgbe_down(adapter); - - /* - * We can't just free everything and then setup again, - * because the ISRs in MSI-X mode get passed pointers - * to the tx and rx ring structs. - */ if (new_tx_count != adapter->tx_ring->count) { - memcpy(temp_ring, adapter->tx_ring, - adapter->num_tx_queues * sizeof(struct ixgbe_ring)); - for (i = 0; i < adapter->num_tx_queues; i++) { temp_ring[i].count = new_tx_count; err = ixgbe_setup_tx_resources(adapter, &temp_ring[i]); @@ -711,21 +732,28 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } goto err_setup; } + temp_ring[i].v_idx = adapter->tx_ring[i].v_idx; } - - for (i = 0; i < adapter->num_tx_queues; i++) - ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]); - - memcpy(adapter->tx_ring, temp_ring, - adapter->num_tx_queues * sizeof(struct ixgbe_ring)); - + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + ixgbe_reset_interrupt_capability(adapter); + ixgbe_napi_del_all(adapter); + INIT_LIST_HEAD(&netdev->napi_list); + kfree(adapter->tx_ring); + adapter->tx_ring = temp_ring; + temp_ring = NULL; adapter->tx_ring_count = new_tx_count; } - if (new_rx_count != adapter->rx_ring->count) { - memcpy(temp_ring, adapter->rx_ring, - adapter->num_rx_queues * sizeof(struct ixgbe_ring)); + temp_ring = kcalloc(adapter->num_rx_queues, + sizeof(struct ixgbe_ring), GFP_KERNEL); + if (!temp_ring) { + if (netif_running(netdev)) + netdev->netdev_ops->ndo_open(netdev); + return -ENOMEM; + } + if (new_rx_count != adapter->rx_ring->count) { for (i = 0; i < adapter->num_rx_queues; i++) { temp_ring[i].count = new_rx_count; err = ixgbe_setup_rx_resources(adapter, &temp_ring[i]); @@ -737,13 +765,16 @@ static int ixgbe_set_ringparam(struct net_device *netdev, } goto err_setup; } + temp_ring[i].v_idx = adapter->rx_ring[i].v_idx; } - - for (i = 0; i < adapter->num_rx_queues; i++) - ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]); - - memcpy(adapter->rx_ring, temp_ring, - adapter->num_rx_queues * sizeof(struct ixgbe_ring)); + if (netif_running(netdev)) + netdev->netdev_ops->ndo_stop(netdev); + ixgbe_reset_interrupt_capability(adapter); + ixgbe_napi_del_all(adapter); + INIT_LIST_HEAD(&netdev->napi_list); + kfree(adapter->rx_ring); + adapter->rx_ring = temp_ring; + temp_ring = NULL; adapter->rx_ring_count = new_rx_count; } @@ -751,8 +782,9 @@ static int ixgbe_set_ringparam(struct net_device *netdev, /* success! */ err = 0; err_setup: + ixgbe_init_interrupt_scheme(adapter); if (netif_running(netdev)) - ixgbe_up(adapter); + netdev->netdev_ops->ndo_open(netdev); clear_bit(__IXGBE_RESETTING, &adapter->state); return err; @@ -804,6 +836,16 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, data[i + k] = queue_stat[k]; i += k; } + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + for (j = 0; j < MAX_TX_PACKET_BUFFERS; j++) { + data[i++] = adapter->stats.pxontxc[j]; + data[i++] = adapter->stats.pxofftxc[j]; + } + for (j = 0; j < MAX_RX_PACKET_BUFFERS; j++) { + data[i++] = adapter->stats.pxonrxc[j]; + data[i++] = adapter->stats.pxoffrxc[j]; + } + } } static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, @@ -832,6 +874,20 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, sprintf(p, "rx_queue_%u_bytes", i); p += ETH_GSTRING_LEN; } + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + for (i = 0; i < MAX_TX_PACKET_BUFFERS; i++) { + sprintf(p, "tx_pb_%u_pxon", i); + p += ETH_GSTRING_LEN; + sprintf(p, "tx_pb_%u_pxoff", i); + p += ETH_GSTRING_LEN; + } + for (i = 0; i < MAX_RX_PACKET_BUFFERS; i++) { + sprintf(p, "rx_pb_%u_pxon", i); + p += ETH_GSTRING_LEN; + sprintf(p, "rx_pb_%u_pxoff", i); + p += ETH_GSTRING_LEN; + } + } /* BUG_ON(p - data != IXGBE_STATS_LEN * ETH_GSTRING_LEN); */ break; } diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 5236f633ee36e3361af138cf3e2c2ae3033e1b53..acef3c65cd2c4c2d3ba463c10f5f5cf0b3a725ff 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c @@ -68,12 +68,20 @@ static struct pci_device_id ixgbe_pci_tbl[] = { board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AF_SINGLE_PORT), board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598AT), + board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_CX4), board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_CX4_DUAL_PORT), board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_DA_DUAL_PORT), + board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM), + board_82598 }, {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_XF_LR), board_82598 }, + {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598EB_SFP_LOM), + board_82598 }, /* required last entry */ {0, } @@ -402,7 +410,7 @@ static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, if (adapter->netdev->features & NETIF_F_LRO && skb->ip_summed == CHECKSUM_UNNECESSARY) { - if (adapter->vlgrp && is_vlan) + if (adapter->vlgrp && is_vlan && (tag != 0)) lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb, adapter->vlgrp, tag, rx_desc); @@ -411,12 +419,12 @@ static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, ring->lro_used = true; } else { if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { - if (adapter->vlgrp && is_vlan) + if (adapter->vlgrp && is_vlan && (tag != 0)) vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); else netif_receive_skb(skb); } else { - if (adapter->vlgrp && is_vlan) + if (adapter->vlgrp && is_vlan && (tag != 0)) vlan_hwaccel_rx(skb, adapter->vlgrp, tag); else netif_rx(skb); @@ -471,7 +479,6 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, union ixgbe_adv_rx_desc *rx_desc; struct ixgbe_rx_buffer *bi; unsigned int i; - unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN; i = rx_ring->next_to_use; bi = &rx_ring->rx_buffer_info[i]; @@ -500,8 +507,10 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, } if (!bi->skb) { - struct sk_buff *skb = netdev_alloc_skb(adapter->netdev, - bufsz); + struct sk_buff *skb; + skb = netdev_alloc_skb(adapter->netdev, + (rx_ring->rx_buf_len + + NET_IP_ALIGN)); if (!skb) { adapter->alloc_rx_buff_failed++; @@ -516,7 +525,8 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter, skb_reserve(skb, NET_IP_ALIGN); bi->skb = skb; - bi->dma = pci_map_single(pdev, skb->data, bufsz, + bi->dma = pci_map_single(pdev, skb->data, + rx_ring->rx_buf_len, PCI_DMA_FROMDEVICE); } /* Refresh the desc even if buffer_addrs didn't change because @@ -607,7 +617,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, if (len && !skb_shinfo(skb)->nr_frags) { pci_unmap_single(pdev, rx_buffer_info->dma, - rx_ring->rx_buf_len + NET_IP_ALIGN, + rx_ring->rx_buf_len, PCI_DMA_FROMDEVICE); skb_put(skb, len); } @@ -666,7 +676,6 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, skb->protocol = eth_type_trans(skb, adapter->netdev); ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc); - adapter->netdev->last_rx = jiffies; next_desc: rx_desc->wb.upper.status_error = 0; @@ -904,6 +913,17 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector) return; } +static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr) +{ + struct ixgbe_hw *hw = &adapter->hw; + + if ((adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) && + (eicr & IXGBE_EICR_GPI_SDP1)) { + DPRINTK(PROBE, CRIT, "Fan has stopped, replace the adapter\n"); + /* write to clear the interrupt */ + IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1); + } +} static void ixgbe_check_lsc(struct ixgbe_adapter *adapter) { @@ -928,6 +948,8 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data) if (eicr & IXGBE_EICR_LSC) ixgbe_check_lsc(adapter); + ixgbe_check_fan_failure(adapter, eicr); + if (!test_bit(__IXGBE_DOWN, &adapter->state)) IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER); @@ -990,7 +1012,7 @@ static irqreturn_t ixgbe_msix_clean_rx(int irq, void *data) rx_ring = &(adapter->rx_ring[r_idx]); /* disable interrupts on this vector only */ IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, rx_ring->v_idx); - netif_rx_schedule(adapter->netdev, &q_vector->napi); + netif_rx_schedule(&q_vector->napi); return IRQ_HANDLED; } @@ -1031,7 +1053,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget) /* If all Rx work done, exit the polling mode */ if (work_done < budget) { - netif_rx_complete(adapter->netdev, napi); + netif_rx_complete(napi); if (adapter->itr_setting & 3) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) @@ -1080,7 +1102,7 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget) rx_ring = &(adapter->rx_ring[r_idx]); /* If all Rx work done, exit the polling mode */ if (work_done < budget) { - netif_rx_complete(adapter->netdev, napi); + netif_rx_complete(napi); if (adapter->itr_setting & 3) ixgbe_set_itr_msix(q_vector); if (!test_bit(__IXGBE_DOWN, &adapter->state)) @@ -1187,6 +1209,7 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) struct net_device *netdev = adapter->netdev; irqreturn_t (*handler)(int, void *); int i, vector, q_vectors, err; + int ri=0, ti=0; /* Decrement for Other and TCP Timer vectors */ q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; @@ -1201,10 +1224,19 @@ static int ixgbe_request_msix_irqs(struct ixgbe_adapter *adapter) &ixgbe_msix_clean_many) for (vector = 0; vector < q_vectors; vector++) { handler = SET_HANDLER(&adapter->q_vector[vector]); - sprintf(adapter->name[vector], "%s:v%d-%s", - netdev->name, vector, - (handler == &ixgbe_msix_clean_rx) ? "Rx" : - ((handler == &ixgbe_msix_clean_tx) ? "Tx" : "TxRx")); + + if(handler == &ixgbe_msix_clean_rx) { + sprintf(adapter->name[vector], "%s-%s-%d", + netdev->name, "rx", ri++); + } + else if(handler == &ixgbe_msix_clean_tx) { + sprintf(adapter->name[vector], "%s-%s-%d", + netdev->name, "tx", ti++); + } + else + sprintf(adapter->name[vector], "%s-%s-%d", + netdev->name, "TxRx", vector); + err = request_irq(adapter->msix_entries[vector].vector, handler, 0, adapter->name[vector], &(adapter->q_vector[vector])); @@ -1312,6 +1344,8 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter) { u32 mask; mask = IXGBE_EIMS_ENABLE_MASK; + if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) + mask |= IXGBE_EIMS_GPI_SDP1; IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask); IXGBE_WRITE_FLUSH(&adapter->hw); } @@ -1342,13 +1376,15 @@ static irqreturn_t ixgbe_intr(int irq, void *data) if (eicr & IXGBE_EICR_LSC) ixgbe_check_lsc(adapter); - if (netif_rx_schedule_prep(netdev, &adapter->q_vector[0].napi)) { + ixgbe_check_fan_failure(adapter, eicr); + + if (netif_rx_schedule_prep(&adapter->q_vector[0].napi)) { adapter->tx_ring[0].total_packets = 0; adapter->tx_ring[0].total_bytes = 0; adapter->rx_ring[0].total_packets = 0; adapter->rx_ring[0].total_bytes = 0; /* would disable interrupts here but EIAM disabled it */ - __netif_rx_schedule(netdev, &adapter->q_vector[0].napi); + __netif_rx_schedule(&adapter->q_vector[0].napi); } return IRQ_HANDLED; @@ -1651,10 +1687,12 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) * effects of setting this bit are only that SRRCTL must be * fully programmed [0..15] */ - rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); - rdrxctl |= IXGBE_RDRXCTL_MVMEN; - IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); - + if (adapter->flags & + (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_VMDQ_ENABLED)) { + rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL); + rdrxctl |= IXGBE_RDRXCTL_MVMEN; + IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl); + } if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { /* Fill out redirection table */ @@ -1713,6 +1751,16 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev, ixgbe_irq_disable(adapter); adapter->vlgrp = grp; + /* + * For a DCB driver, always enable VLAN tag stripping so we can + * still receive traffic from a DCB-enabled host even if we're + * not in DCB mode. + */ + ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); + ctrl |= IXGBE_VLNCTRL_VME; + ctrl &= ~IXGBE_VLNCTRL_CFIEN; + IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl); + if (grp) { /* enable VLAN tag insert/strip */ ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL); @@ -1877,6 +1925,44 @@ static void ixgbe_napi_disable_all(struct ixgbe_adapter *adapter) } } +#ifdef CONFIG_IXGBE_DCB +/* + * ixgbe_configure_dcb - Configure DCB hardware + * @adapter: ixgbe adapter struct + * + * This is called by the driver on open to configure the DCB hardware. + * This is also called by the gennetlink interface when reconfiguring + * the DCB state. + */ +static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) +{ + struct ixgbe_hw *hw = &adapter->hw; + u32 txdctl, vlnctrl; + int i, j; + + ixgbe_dcb_check_config(&adapter->dcb_cfg); + ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_TX_CONFIG); + ixgbe_dcb_calculate_tc_credits(&adapter->dcb_cfg, DCB_RX_CONFIG); + + /* reconfigure the hardware */ + ixgbe_dcb_hw_config(&adapter->hw, &adapter->dcb_cfg); + + for (i = 0; i < adapter->num_tx_queues; i++) { + j = adapter->tx_ring[i].reg_idx; + txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j)); + /* PThresh workaround for Tx hang with DFP enabled. */ + txdctl |= 32; + IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl); + } + /* Enable VLAN tag insert/strip */ + vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL); + vlnctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE; + vlnctrl &= ~IXGBE_VLNCTRL_CFIEN; + IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl); + hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true); +} + +#endif static void ixgbe_configure(struct ixgbe_adapter *adapter) { struct net_device *netdev = adapter->netdev; @@ -1885,6 +1971,16 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter) ixgbe_set_rx_mode(netdev); ixgbe_restore_vlan(adapter); +#ifdef CONFIG_IXGBE_DCB + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + netif_set_gso_max_size(netdev, 32768); + ixgbe_configure_dcb(adapter); + } else { + netif_set_gso_max_size(netdev, 65536); + } +#else + netif_set_gso_max_size(netdev, 65536); +#endif ixgbe_configure_tx(adapter); ixgbe_configure_rx(adapter); @@ -1924,6 +2020,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) IXGBE_WRITE_REG(hw, IXGBE_EIAM, IXGBE_EICS_RTX_QUEUE); } + /* Enable fan failure interrupt if media type is copper */ + if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE) { + gpie = IXGBE_READ_REG(hw, IXGBE_GPIE); + gpie |= IXGBE_SDP1_GPIEN; + IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie); + } + mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD); if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) { mhadd &= ~IXGBE_MHADD_MFS_MASK; @@ -1961,6 +2064,8 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter) else ixgbe_configure_msi_and_legacy(adapter); + ixgbe_napi_add_all(adapter); + clear_bit(__IXGBE_DOWN, &adapter->state); ixgbe_napi_enable_all(adapter); @@ -2205,7 +2310,7 @@ static int ixgbe_poll(struct napi_struct *napi, int budget) /* If budget not fully consumed, exit the polling mode */ if (work_done < budget) { - netif_rx_complete(adapter->netdev, napi); + netif_rx_complete(napi); if (adapter->itr_setting & 3) ixgbe_set_itr(adapter); if (!test_bit(__IXGBE_DOWN, &adapter->state)) @@ -2231,6 +2336,11 @@ static void ixgbe_reset_task(struct work_struct *work) struct ixgbe_adapter *adapter; adapter = container_of(work, struct ixgbe_adapter, reset_task); + /* If we're already down or resetting, just bail */ + if (test_bit(__IXGBE_DOWN, &adapter->state) || + test_bit(__IXGBE_RESETTING, &adapter->state)) + return; + adapter->tx_timeout_count++; ixgbe_reinit_locked(adapter); @@ -2240,15 +2350,31 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) { int nrq = 1, ntq = 1; int feature_mask = 0, rss_i, rss_m; + int dcb_i, dcb_m; /* Number of supported queues */ switch (adapter->hw.mac.type) { case ixgbe_mac_82598EB: + dcb_i = adapter->ring_feature[RING_F_DCB].indices; + dcb_m = 0; rss_i = adapter->ring_feature[RING_F_RSS].indices; rss_m = 0; feature_mask |= IXGBE_FLAG_RSS_ENABLED; + feature_mask |= IXGBE_FLAG_DCB_ENABLED; switch (adapter->flags & feature_mask) { + case (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_DCB_ENABLED): + dcb_m = 0x7 << 3; + rss_i = min(8, rss_i); + rss_m = 0x7; + nrq = dcb_i * rss_i; + ntq = min(MAX_TX_QUEUES, dcb_i * rss_i); + break; + case (IXGBE_FLAG_DCB_ENABLED): + dcb_m = 0x7 << 3; + nrq = dcb_i; + ntq = dcb_i; + break; case (IXGBE_FLAG_RSS_ENABLED): rss_m = 0xF; nrq = rss_i; @@ -2256,6 +2382,8 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) break; case 0: default: + dcb_i = 0; + dcb_m = 0; rss_i = 0; rss_m = 0; nrq = 1; @@ -2263,6 +2391,12 @@ static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter) break; } + /* Sanity check, we should never have zero queues */ + nrq = (nrq ?:1); + ntq = (ntq ?:1); + + adapter->ring_feature[RING_F_DCB].indices = dcb_i; + adapter->ring_feature[RING_F_DCB].mask = dcb_m; adapter->ring_feature[RING_F_RSS].indices = rss_i; adapter->ring_feature[RING_F_RSS].mask = rss_m; break; @@ -2314,6 +2448,7 @@ static void ixgbe_acquire_msix_vectors(struct ixgbe_adapter *adapter, adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; kfree(adapter->msix_entries); adapter->msix_entries = NULL; + adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; ixgbe_set_num_queues(adapter); } else { @@ -2333,15 +2468,42 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) { int feature_mask = 0, rss_i; int i, txr_idx, rxr_idx; + int dcb_i; /* Number of supported queues */ switch (adapter->hw.mac.type) { case ixgbe_mac_82598EB: + dcb_i = adapter->ring_feature[RING_F_DCB].indices; rss_i = adapter->ring_feature[RING_F_RSS].indices; txr_idx = 0; rxr_idx = 0; + feature_mask |= IXGBE_FLAG_DCB_ENABLED; feature_mask |= IXGBE_FLAG_RSS_ENABLED; switch (adapter->flags & feature_mask) { + case (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_DCB_ENABLED): + for (i = 0; i < dcb_i; i++) { + int j; + /* Rx first */ + for (j = 0; j < adapter->num_rx_queues; j++) { + adapter->rx_ring[rxr_idx].reg_idx = + i << 3 | j; + rxr_idx++; + } + /* Tx now */ + for (j = 0; j < adapter->num_tx_queues; j++) { + adapter->tx_ring[txr_idx].reg_idx = + i << 2 | (j >> 1); + if (j & 1) + txr_idx++; + } + } + case (IXGBE_FLAG_DCB_ENABLED): + /* the number of queues is assumed to be symmetric */ + for (i = 0; i < dcb_i; i++) { + adapter->rx_ring[i].reg_idx = i << 3; + adapter->tx_ring[i].reg_idx = i << 2; + } + break; case (IXGBE_FLAG_RSS_ENABLED): for (i = 0; i < adapter->num_rx_queues; i++) adapter->rx_ring[i].reg_idx = i; @@ -2363,8 +2525,7 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter) * @adapter: board private structure to initialize * * We allocate one ring per queue at run-time since we don't know the - * number of queues at compile-time. The polling_netdev array is - * intended for Multiqueue, but should work fine with a single queue. + * number of queues at compile-time. **/ static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter) { @@ -2435,6 +2596,7 @@ static int ixgbe_set_interrupt_capability(struct ixgbe_adapter *adapter) adapter->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry), GFP_KERNEL); if (!adapter->msix_entries) { + adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED; adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; ixgbe_set_num_queues(adapter); kfree(adapter->tx_ring); @@ -2475,7 +2637,7 @@ out: return err; } -static void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) +void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) { if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { adapter->flags &= ~IXGBE_FLAG_MSIX_ENABLED; @@ -2499,7 +2661,7 @@ static void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter) * - Hardware queue count (num_*_queues) * - defined by miscellaneous hardware support/features (RSS, etc.) **/ -static int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) +int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter) { int err; @@ -2534,6 +2696,57 @@ err_alloc_queues: return err; } +/** + * ixgbe_sfp_timer - worker thread to find a missing module + * @data: pointer to our adapter struct + **/ +static void ixgbe_sfp_timer(unsigned long data) +{ + struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data; + + /* Do the sfp_timer outside of interrupt context due to the + * delays that sfp+ detection requires + */ + schedule_work(&adapter->sfp_task); +} + +/** + * ixgbe_sfp_task - worker thread to find a missing module + * @work: pointer to work_struct containing our data + **/ +static void ixgbe_sfp_task(struct work_struct *work) +{ + struct ixgbe_adapter *adapter = container_of(work, + struct ixgbe_adapter, + sfp_task); + struct ixgbe_hw *hw = &adapter->hw; + + if ((hw->phy.type == ixgbe_phy_nl) && + (hw->phy.sfp_type == ixgbe_sfp_type_not_present)) { + s32 ret = hw->phy.ops.identify_sfp(hw); + if (ret) + goto reschedule; + ret = hw->phy.ops.reset(hw); + if (ret == IXGBE_ERR_SFP_NOT_SUPPORTED) { + DPRINTK(PROBE, ERR, "failed to initialize because an " + "unsupported SFP+ module type was detected.\n" + "Reload the driver after installing a " + "supported module.\n"); + unregister_netdev(adapter->netdev); + } else { + DPRINTK(PROBE, INFO, "detected SFP+: %d\n", + hw->phy.sfp_type); + } + /* don't need this routine any more */ + clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); + } + return; +reschedule: + if (test_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state)) + mod_timer(&adapter->sfp_timer, + round_jiffies(jiffies + (2 * HZ))); +} + /** * ixgbe_sw_init - Initialize general software structures (struct ixgbe_adapter) * @adapter: board private structure to initialize @@ -2547,6 +2760,10 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) struct ixgbe_hw *hw = &adapter->hw; struct pci_dev *pdev = adapter->pdev; unsigned int rss; +#ifdef CONFIG_IXGBE_DCB + int j; + struct tc_configuration *tc; +#endif /* PCI config space info */ @@ -2560,6 +2777,30 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter) rss = min(IXGBE_MAX_RSS_INDICES, (int)num_online_cpus()); adapter->ring_feature[RING_F_RSS].indices = rss; adapter->flags |= IXGBE_FLAG_RSS_ENABLED; + adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES; + +#ifdef CONFIG_IXGBE_DCB + /* Configure DCB traffic classes */ + for (j = 0; j < MAX_TRAFFIC_CLASS; j++) { + tc = &adapter->dcb_cfg.tc_config[j]; + tc->path[DCB_TX_CONFIG].bwg_id = 0; + tc->path[DCB_TX_CONFIG].bwg_percent = 12 + (j & 1); + tc->path[DCB_RX_CONFIG].bwg_id = 0; + tc->path[DCB_RX_CONFIG].bwg_percent = 12 + (j & 1); + tc->dcb_pfc = pfc_disabled; + } + adapter->dcb_cfg.bw_percentage[DCB_TX_CONFIG][0] = 100; + adapter->dcb_cfg.bw_percentage[DCB_RX_CONFIG][0] = 100; + adapter->dcb_cfg.rx_pba_cfg = pba_equal; + adapter->dcb_cfg.round_robin_enable = false; + adapter->dcb_set_bitmap = 0x00; + ixgbe_copy_dcb_cfg(&adapter->dcb_cfg, &adapter->temp_dcb_cfg, + adapter->ring_feature[RING_F_DCB].indices); + +#endif + if (hw->mac.ops.get_media_type && + (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper)) + adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE; /* default flow control settings */ hw->fc.original_type = ixgbe_fc_none; @@ -2934,11 +3175,16 @@ static int ixgbe_close(struct net_device *netdev) * @adapter: private struct * helper function to napi_add each possible q_vector->napi */ -static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) +void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) { int q_idx, q_vectors; + struct net_device *netdev = adapter->netdev; int (*poll)(struct napi_struct *, int); + /* check if we already have our netdev->napi_list populated */ + if (&netdev->napi_list != netdev->napi_list.next) + return; + if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) { poll = &ixgbe_clean_rxonly; /* Only enable as many vectors as we have rx queues. */ @@ -2955,7 +3201,7 @@ static void ixgbe_napi_add_all(struct ixgbe_adapter *adapter) } } -static void ixgbe_napi_del_all(struct ixgbe_adapter *adapter) +void ixgbe_napi_del_all(struct ixgbe_adapter *adapter) { int q_idx; int q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS; @@ -3032,6 +3278,7 @@ static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state) } ixgbe_reset_interrupt_capability(adapter); ixgbe_napi_del_all(adapter); + INIT_LIST_HEAD(&netdev->napi_list); kfree(adapter->tx_ring); kfree(adapter->rx_ring); @@ -3076,6 +3323,18 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter) adapter->stats.mpc[i] += mpc; total_mpc += adapter->stats.mpc[i]; adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i)); + adapter->stats.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i)); + adapter->stats.qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i)); + adapter->stats.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i)); + adapter->stats.qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i)); + adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw, + IXGBE_PXONRXC(i)); + adapter->stats.pxontxc[i] += IXGBE_READ_REG(hw, + IXGBE_PXONTXC(i)); + adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw, + IXGBE_PXOFFRXC(i)); + adapter->stats.pxofftxc[i] += IXGBE_READ_REG(hw, + IXGBE_PXOFFTXC(i)); } adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC); /* work around hardware counting issue */ @@ -3204,15 +3463,16 @@ static void ixgbe_watchdog_task(struct work_struct *work) u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS); #define FLOW_RX (frctl & IXGBE_FCTRL_RFCE) #define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X) - DPRINTK(LINK, INFO, "NIC Link is Up %s, " - "Flow Control: %s\n", - (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? - "10 Gbps" : - (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? - "1 Gbps" : "unknown speed")), - ((FLOW_RX && FLOW_TX) ? "RX/TX" : - (FLOW_RX ? "RX" : - (FLOW_TX ? "TX" : "None")))); + printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, " + "Flow Control: %s\n", + netdev->name, + (link_speed == IXGBE_LINK_SPEED_10GB_FULL ? + "10 Gbps" : + (link_speed == IXGBE_LINK_SPEED_1GB_FULL ? + "1 Gbps" : "unknown speed")), + ((FLOW_RX && FLOW_TX) ? "RX/TX" : + (FLOW_RX ? "RX" : + (FLOW_TX ? "TX" : "None")))); netif_carrier_on(netdev); netif_tx_wake_all_queues(netdev); @@ -3224,7 +3484,8 @@ static void ixgbe_watchdog_task(struct work_struct *work) adapter->link_up = false; adapter->link_speed = 0; if (netif_carrier_ok(netdev)) { - DPRINTK(LINK, INFO, "NIC Link is Down\n"); + printk(KERN_INFO "ixgbe: %s NIC Link is Down\n", + netdev->name); netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); } @@ -3573,6 +3834,14 @@ static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev) if (adapter->vlgrp && vlan_tx_tag_present(skb)) { tx_flags |= vlan_tx_tag_get(skb); + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + tx_flags &= ~IXGBE_TX_FLAGS_VLAN_PRIO_MASK; + tx_flags |= (skb->queue_mapping << 13); + } + tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; + tx_flags |= IXGBE_TX_FLAGS_VLAN; + } else if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) { + tx_flags |= (skb->queue_mapping << 13); tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT; tx_flags |= IXGBE_TX_FLAGS_VLAN; } @@ -3687,9 +3956,31 @@ static int ixgbe_link_config(struct ixgbe_hw *hw) /* must always autoneg for both 1G and 10G link */ hw->mac.autoneg = true; + if ((hw->mac.type == ixgbe_mac_82598EB) && + (hw->phy.media_type == ixgbe_media_type_copper)) + autoneg = IXGBE_LINK_SPEED_82598_AUTONEG; + return hw->mac.ops.setup_link_speed(hw, autoneg, true, true); } +static const struct net_device_ops ixgbe_netdev_ops = { + .ndo_open = ixgbe_open, + .ndo_stop = ixgbe_close, + .ndo_start_xmit = ixgbe_xmit_frame, + .ndo_get_stats = ixgbe_get_stats, + .ndo_set_multicast_list = ixgbe_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = ixgbe_set_mac, + .ndo_change_mtu = ixgbe_change_mtu, + .ndo_tx_timeout = ixgbe_tx_timeout, + .ndo_vlan_rx_register = ixgbe_vlan_rx_register, + .ndo_vlan_rx_add_vid = ixgbe_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ixgbe_netpoll, +#endif +}; + /** * ixgbe_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -3739,6 +4030,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, goto err_pci_reg; } + err = pci_enable_pcie_error_reporting(pdev); + if (err) { + dev_err(&pdev->dev, "pci_enable_pcie_error_reporting failed " + "0x%x\n", err); + /* non-fatal, continue */ + } + pci_set_master(pdev); pci_save_state(pdev); @@ -3771,23 +4069,9 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, continue; } - netdev->open = &ixgbe_open; - netdev->stop = &ixgbe_close; - netdev->hard_start_xmit = &ixgbe_xmit_frame; - netdev->get_stats = &ixgbe_get_stats; - netdev->set_rx_mode = &ixgbe_set_rx_mode; - netdev->set_multicast_list = &ixgbe_set_rx_mode; - netdev->set_mac_address = &ixgbe_set_mac; - netdev->change_mtu = &ixgbe_change_mtu; + netdev->netdev_ops = &ixgbe_netdev_ops; ixgbe_set_ethtool_ops(netdev); - netdev->tx_timeout = &ixgbe_tx_timeout; netdev->watchdog_timeo = 5 * HZ; - netdev->vlan_rx_register = ixgbe_vlan_rx_register; - netdev->vlan_rx_add_vid = ixgbe_vlan_rx_add_vid; - netdev->vlan_rx_kill_vid = ixgbe_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = ixgbe_netpoll; -#endif strcpy(netdev->name, pci_name(pdev)); adapter->bd_number = cards_found; @@ -3805,11 +4089,31 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, /* PHY */ memcpy(&hw->phy.ops, ii->phy_ops, sizeof(hw->phy.ops)); - /* phy->sfp_type = ixgbe_sfp_type_unknown; */ + hw->phy.sfp_type = ixgbe_sfp_type_unknown; + + /* set up this timer and work struct before calling get_invariants + * which might start the timer + */ + init_timer(&adapter->sfp_timer); + adapter->sfp_timer.function = &ixgbe_sfp_timer; + adapter->sfp_timer.data = (unsigned long) adapter; + + INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task); err = ii->get_invariants(hw); - if (err) + if (err == IXGBE_ERR_SFP_NOT_PRESENT) { + /* start a kernel thread to watch for a module to arrive */ + set_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); + mod_timer(&adapter->sfp_timer, + round_jiffies(jiffies + (2 * HZ))); + err = 0; + } else if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) { + DPRINTK(PROBE, ERR, "failed to load because an " + "unsupported SFP+ module type was detected.\n"); goto err_hw_init; + } else if (err) { + goto err_hw_init; + } /* setup the private structure */ err = ixgbe_sw_init(adapter); @@ -3839,6 +4143,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netdev->vlan_features |= NETIF_F_IP_CSUM; netdev->vlan_features |= NETIF_F_SG; + if (adapter->flags & IXGBE_FLAG_DCB_ENABLED) + adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED; + +#ifdef CONFIG_IXGBE_DCB + netdev->dcbnl_ops = &dcbnl_ops; +#endif + if (pci_using_dac) netdev->features |= NETIF_F_HIGHDMA; @@ -3873,8 +4184,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, pci_read_config_word(pdev, IXGBE_PCI_LINK_STATUS, &link_status); link_speed = link_status & IXGBE_PCI_LINK_SPEED; link_width = link_status & IXGBE_PCI_LINK_WIDTH; - dev_info(&pdev->dev, "(PCI Express:%s:%s) " - "%02x:%02x:%02x:%02x:%02x:%02x\n", + dev_info(&pdev->dev, "(PCI Express:%s:%s) %pM\n", ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" : (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" : "Unknown"), @@ -3883,8 +4193,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" : (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" : "Unknown"), - netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], - netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); + netdev->dev_addr); ixgbe_read_pba_num_generic(hw, &part_num); dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n", hw->mac.type, hw->phy.type, @@ -3911,8 +4220,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, netif_carrier_off(netdev); netif_tx_stop_all_queues(netdev); - ixgbe_napi_add_all(adapter); - strcpy(netdev->name, "eth%d"); err = register_netdev(netdev); if (err) @@ -3938,6 +4245,9 @@ err_hw_init: err_sw_init: ixgbe_reset_interrupt_capability(adapter); err_eeprom: + clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); + del_timer_sync(&adapter->sfp_timer); + cancel_work_sync(&adapter->sfp_task); iounmap(hw->hw_addr); err_ioremap: free_netdev(netdev); @@ -3962,10 +4272,18 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); struct ixgbe_adapter *adapter = netdev_priv(netdev); + int err; set_bit(__IXGBE_DOWN, &adapter->state); + /* clear the module not found bit to make sure the worker won't + * reschedule + */ + clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state); del_timer_sync(&adapter->watchdog_timer); + del_timer_sync(&adapter->sfp_timer); + cancel_work_sync(&adapter->watchdog_task); + cancel_work_sync(&adapter->sfp_task); flush_scheduled_work(); #ifdef CONFIG_IXGBE_DCA @@ -3976,7 +4294,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) } #endif - unregister_netdev(netdev); + if (netdev->reg_state == NETREG_REGISTERED) + unregister_netdev(netdev); ixgbe_reset_interrupt_capability(adapter); @@ -3986,12 +4305,16 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev) pci_release_regions(pdev); DPRINTK(PROBE, INFO, "complete\n"); - ixgbe_napi_del_all(adapter); kfree(adapter->tx_ring); kfree(adapter->rx_ring); free_netdev(netdev); + err = pci_disable_pcie_error_reporting(pdev); + if (err) + dev_err(&pdev->dev, + "pci_disable_pcie_error_reporting failed 0x%x\n", err); + pci_disable_device(pdev); } @@ -4007,7 +4330,7 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); - struct ixgbe_adapter *adapter = netdev->priv; + struct ixgbe_adapter *adapter = netdev_priv(netdev); netif_device_detach(netdev); @@ -4028,22 +4351,34 @@ static pci_ers_result_t ixgbe_io_error_detected(struct pci_dev *pdev, static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct ixgbe_adapter *adapter = netdev->priv; + struct ixgbe_adapter *adapter = netdev_priv(netdev); + pci_ers_result_t result; + int err; if (pci_enable_device(pdev)) { DPRINTK(PROBE, ERR, "Cannot re-enable PCI device after reset.\n"); - return PCI_ERS_RESULT_DISCONNECT; - } - pci_set_master(pdev); - pci_restore_state(pdev); + result = PCI_ERS_RESULT_DISCONNECT; + } else { + pci_set_master(pdev); + pci_restore_state(pdev); - pci_enable_wake(pdev, PCI_D3hot, 0); - pci_enable_wake(pdev, PCI_D3cold, 0); + pci_enable_wake(pdev, PCI_D3hot, 0); + pci_enable_wake(pdev, PCI_D3cold, 0); - ixgbe_reset(adapter); + ixgbe_reset(adapter); + + result = PCI_ERS_RESULT_RECOVERED; + } - return PCI_ERS_RESULT_RECOVERED; + err = pci_cleanup_aer_uncorrect_error_status(pdev); + if (err) { + dev_err(&pdev->dev, + "pci_cleanup_aer_uncorrect_error_status failed 0x%0x\n", err); + /* non-fatal, continue */ + } + + return result; } /** @@ -4056,7 +4391,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev) static void ixgbe_io_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct ixgbe_adapter *adapter = netdev->priv; + struct ixgbe_adapter *adapter = netdev_priv(netdev); if (netif_running(netdev)) { if (ixgbe_up(adapter)) { diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c index 764035a8c9a16b0d0ea99864899747ca2cb8c233..5a8669aedf6417a244b0b4908f91e1913b530a11 100644 --- a/drivers/net/ixgbe/ixgbe_phy.c +++ b/drivers/net/ixgbe/ixgbe_phy.c @@ -121,9 +121,15 @@ static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id) enum ixgbe_phy_type phy_type; switch (phy_id) { + case TN1010_PHY_ID: + phy_type = ixgbe_phy_tn; + break; case QT2022_PHY_ID: phy_type = ixgbe_phy_qt; break; + case ATH_PHY_ID: + phy_type = ixgbe_phy_nl; + break; default: phy_type = ixgbe_phy_unknown; break; @@ -426,3 +432,323 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, return 0; } +/** + * ixgbe_reset_phy_nl - Performs a PHY reset + * @hw: pointer to hardware structure + **/ +s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw) +{ + u16 phy_offset, control, eword, edata, block_crc; + bool end_data = false; + u16 list_offset, data_offset; + u16 phy_data = 0; + s32 ret_val = 0; + u32 i; + + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); + + /* reset the PHY and poll for completion */ + hw->phy.ops.write_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, + (phy_data | IXGBE_MDIO_PHY_XS_RESET)); + + for (i = 0; i < 100; i++) { + hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_XS_CONTROL, + IXGBE_MDIO_PHY_XS_DEV_TYPE, &phy_data); + if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) == 0) + break; + msleep(10); + } + + if ((phy_data & IXGBE_MDIO_PHY_XS_RESET) != 0) { + hw_dbg(hw, "PHY reset did not complete.\n"); + ret_val = IXGBE_ERR_PHY; + goto out; + } + + /* Get init offsets */ + ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset, + &data_offset); + if (ret_val != 0) + goto out; + + ret_val = hw->eeprom.ops.read(hw, data_offset, &block_crc); + data_offset++; + while (!end_data) { + /* + * Read control word from PHY init contents offset + */ + ret_val = hw->eeprom.ops.read(hw, data_offset, &eword); + control = (eword & IXGBE_CONTROL_MASK_NL) >> + IXGBE_CONTROL_SHIFT_NL; + edata = eword & IXGBE_DATA_MASK_NL; + switch (control) { + case IXGBE_DELAY_NL: + data_offset++; + hw_dbg(hw, "DELAY: %d MS\n", edata); + msleep(edata); + break; + case IXGBE_DATA_NL: + hw_dbg(hw, "DATA: \n"); + data_offset++; + hw->eeprom.ops.read(hw, data_offset++, + &phy_offset); + for (i = 0; i < edata; i++) { + hw->eeprom.ops.read(hw, data_offset, &eword); + hw->phy.ops.write_reg(hw, phy_offset, + IXGBE_TWINAX_DEV, eword); + hw_dbg(hw, "Wrote %4.4x to %4.4x\n", eword, + phy_offset); + data_offset++; + phy_offset++; + } + break; + case IXGBE_CONTROL_NL: + data_offset++; + hw_dbg(hw, "CONTROL: \n"); + if (edata == IXGBE_CONTROL_EOL_NL) { + hw_dbg(hw, "EOL\n"); + end_data = true; + } else if (edata == IXGBE_CONTROL_SOL_NL) { + hw_dbg(hw, "SOL\n"); + } else { + hw_dbg(hw, "Bad control value\n"); + ret_val = IXGBE_ERR_PHY; + goto out; + } + break; + default: + hw_dbg(hw, "Bad control type\n"); + ret_val = IXGBE_ERR_PHY; + goto out; + } + } + +out: + return ret_val; +} + +/** + * ixgbe_identify_sfp_module_generic - Identifies SFP module and assigns + * the PHY type. + * @hw: pointer to hardware structure + * + * Searches for and indentifies the SFP module. Assings appropriate PHY type. + **/ +s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw) +{ + s32 status = IXGBE_ERR_PHY_ADDR_INVALID; + u32 vendor_oui = 0; + u8 identifier = 0; + u8 comp_codes_1g = 0; + u8 comp_codes_10g = 0; + u8 oui_bytes[4] = {0, 0, 0, 0}; + u8 transmission_media = 0; + + status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER, + &identifier); + + if (status == IXGBE_ERR_SFP_NOT_PRESENT) { + hw->phy.sfp_type = ixgbe_sfp_type_not_present; + goto out; + } + + if (identifier == IXGBE_SFF_IDENTIFIER_SFP) { + hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_1GBE_COMP_CODES, + &comp_codes_1g); + hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_10GBE_COMP_CODES, + &comp_codes_10g); + hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_TRANSMISSION_MEDIA, + &transmission_media); + + /* ID Module + * ========= + * 0 SFP_DA_CU + * 1 SFP_SR + * 2 SFP_LR + */ + if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE) + hw->phy.sfp_type = ixgbe_sfp_type_da_cu; + else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE) + hw->phy.sfp_type = ixgbe_sfp_type_sr; + else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE) + hw->phy.sfp_type = ixgbe_sfp_type_lr; + else + hw->phy.sfp_type = ixgbe_sfp_type_unknown; + + /* Determine PHY vendor */ + if (hw->phy.type == ixgbe_phy_unknown) { + hw->phy.id = identifier; + hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_VENDOR_OUI_BYTE0, + &oui_bytes[0]); + hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_VENDOR_OUI_BYTE1, + &oui_bytes[1]); + hw->phy.ops.read_i2c_eeprom(hw, + IXGBE_SFF_VENDOR_OUI_BYTE2, + &oui_bytes[2]); + + vendor_oui = + ((oui_bytes[0] << IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT) | + (oui_bytes[1] << IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT) | + (oui_bytes[2] << IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT)); + + switch (vendor_oui) { + case IXGBE_SFF_VENDOR_OUI_TYCO: + if (transmission_media & + IXGBE_SFF_TWIN_AX_CAPABLE) + hw->phy.type = ixgbe_phy_tw_tyco; + break; + case IXGBE_SFF_VENDOR_OUI_FTL: + hw->phy.type = ixgbe_phy_sfp_ftl; + break; + case IXGBE_SFF_VENDOR_OUI_AVAGO: + hw->phy.type = ixgbe_phy_sfp_avago; + break; + default: + if (transmission_media & + IXGBE_SFF_TWIN_AX_CAPABLE) + hw->phy.type = ixgbe_phy_tw_unknown; + else + hw->phy.type = ixgbe_phy_sfp_unknown; + break; + } + } + status = 0; + } + +out: + return status; +} + +/** + * ixgbe_get_sfp_init_sequence_offsets - Checks the MAC's EEPROM to see + * if it supports a given SFP+ module type, if so it returns the offsets to the + * phy init sequence block. + * @hw: pointer to hardware structure + * @list_offset: offset to the SFP ID list + * @data_offset: offset to the SFP data block + **/ +s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, + u16 *list_offset, + u16 *data_offset) +{ + u16 sfp_id; + + if (hw->phy.sfp_type == ixgbe_sfp_type_unknown) + return IXGBE_ERR_SFP_NOT_SUPPORTED; + + if (hw->phy.sfp_type == ixgbe_sfp_type_not_present) + return IXGBE_ERR_SFP_NOT_PRESENT; + + if ((hw->device_id == IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM) && + (hw->phy.sfp_type == ixgbe_sfp_type_da_cu)) + return IXGBE_ERR_SFP_NOT_SUPPORTED; + + /* Read offset to PHY init contents */ + hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset); + + if ((!*list_offset) || (*list_offset == 0xFFFF)) + return IXGBE_ERR_PHY; + + /* Shift offset to first ID word */ + (*list_offset)++; + + /* + * Find the matching SFP ID in the EEPROM + * and program the init sequence + */ + hw->eeprom.ops.read(hw, *list_offset, &sfp_id); + + while (sfp_id != IXGBE_PHY_INIT_END_NL) { + if (sfp_id == hw->phy.sfp_type) { + (*list_offset)++; + hw->eeprom.ops.read(hw, *list_offset, data_offset); + if ((!*data_offset) || (*data_offset == 0xFFFF)) { + hw_dbg(hw, "SFP+ module not supported\n"); + return IXGBE_ERR_SFP_NOT_SUPPORTED; + } else { + break; + } + } else { + (*list_offset) += 2; + if (hw->eeprom.ops.read(hw, *list_offset, &sfp_id)) + return IXGBE_ERR_PHY; + } + } + + if (sfp_id == IXGBE_PHY_INIT_END_NL) { + hw_dbg(hw, "No matching SFP+ module found\n"); + return IXGBE_ERR_SFP_NOT_SUPPORTED; + } + + return 0; +} + +/** + * ixgbe_check_phy_link_tnx - Determine link and speed status + * @hw: pointer to hardware structure + * + * Reads the VS1 register to determine if link is up and the current speed for + * the PHY. + **/ +s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, ixgbe_link_speed *speed, + bool *link_up) +{ + s32 status = 0; + u32 time_out; + u32 max_time_out = 10; + u16 phy_link = 0; + u16 phy_speed = 0; + u16 phy_data = 0; + + /* Initialize speed and link to default case */ + *link_up = false; + *speed = IXGBE_LINK_SPEED_10GB_FULL; + + /* + * Check current speed and link status of the PHY register. + * This is a vendor specific register and may have to + * be changed for other copper PHYs. + */ + for (time_out = 0; time_out < max_time_out; time_out++) { + udelay(10); + status = hw->phy.ops.read_reg(hw, + IXGBE_MDIO_VENDOR_SPECIFIC_1_STATUS, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + &phy_data); + phy_link = phy_data & + IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS; + phy_speed = phy_data & + IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS; + if (phy_link == IXGBE_MDIO_VENDOR_SPECIFIC_1_LINK_STATUS) { + *link_up = true; + if (phy_speed == + IXGBE_MDIO_VENDOR_SPECIFIC_1_SPEED_STATUS) + *speed = IXGBE_LINK_SPEED_1GB_FULL; + break; + } + } + + return status; +} + +/** + * ixgbe_get_phy_firmware_version_tnx - Gets the PHY Firmware Version + * @hw: pointer to hardware structure + * @firmware_version: pointer to the PHY Firmware Version + **/ +s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, + u16 *firmware_version) +{ + s32 status = 0; + + status = hw->phy.ops.read_reg(hw, TNX_FW_REV, + IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE, + firmware_version); + + return status; +} + diff --git a/drivers/net/ixgbe/ixgbe_phy.h b/drivers/net/ixgbe/ixgbe_phy.h index 9bfe3f2b1d8f499f743890a846790150b9c5757a..43a97bc420f54c0dbda983bdcbb214aad955f94b 100644 --- a/drivers/net/ixgbe/ixgbe_phy.h +++ b/drivers/net/ixgbe/ixgbe_phy.h @@ -63,6 +63,18 @@ #define IXGBE_SFF_VENDOR_OUI_FTL 0x00906500 #define IXGBE_SFF_VENDOR_OUI_AVAGO 0x00176A00 +/* I2C SDA and SCL timing parameters for standard mode */ +#define IXGBE_I2C_T_HD_STA 4 +#define IXGBE_I2C_T_LOW 5 +#define IXGBE_I2C_T_HIGH 4 +#define IXGBE_I2C_T_SU_STA 5 +#define IXGBE_I2C_T_HD_DATA 5 +#define IXGBE_I2C_T_SU_DATA 1 +#define IXGBE_I2C_T_RISE 1 +#define IXGBE_I2C_T_FALL 1 +#define IXGBE_I2C_T_SU_STO 4 +#define IXGBE_I2C_T_BUF 5 + s32 ixgbe_init_phy_ops_generic(struct ixgbe_hw *hw); s32 ixgbe_identify_phy_generic(struct ixgbe_hw *hw); @@ -77,4 +89,17 @@ s32 ixgbe_setup_phy_link_speed_generic(struct ixgbe_hw *hw, bool autoneg, bool autoneg_wait_to_complete); +/* PHY specific */ +s32 ixgbe_check_phy_link_tnx(struct ixgbe_hw *hw, + ixgbe_link_speed *speed, + bool *link_up); +s32 ixgbe_get_phy_firmware_version_tnx(struct ixgbe_hw *hw, + u16 *firmware_version); + +s32 ixgbe_reset_phy_nl(struct ixgbe_hw *hw); +s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw); +s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw, + u16 *list_offset, + u16 *data_offset); + #endif /* _IXGBE_PHY_H_ */ diff --git a/drivers/net/ixgbe/ixgbe_type.h b/drivers/net/ixgbe/ixgbe_type.h index c6f8fa1c4e597909065c6189958af703ccfb26b3..83a11ff9ffd190f8aa2ec0db65c63f39d9349aba 100644 --- a/drivers/net/ixgbe/ixgbe_type.h +++ b/drivers/net/ixgbe/ixgbe_type.h @@ -36,8 +36,12 @@ /* Device IDs */ #define IXGBE_DEV_ID_82598AF_DUAL_PORT 0x10C6 #define IXGBE_DEV_ID_82598AF_SINGLE_PORT 0x10C7 +#define IXGBE_DEV_ID_82598EB_SFP_LOM 0x10DB +#define IXGBE_DEV_ID_82598AT 0x10C8 #define IXGBE_DEV_ID_82598EB_CX4 0x10DD #define IXGBE_DEV_ID_82598_CX4_DUAL_PORT 0x10EC +#define IXGBE_DEV_ID_82598_DA_DUAL_PORT 0x10F1 +#define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM 0x10E1 #define IXGBE_DEV_ID_82598EB_XF_LR 0x10F4 /* General Registers */ @@ -452,6 +456,7 @@ #define IXGBE_MDIO_PHY_XS_DEV_TYPE 0x4 #define IXGBE_MDIO_AUTO_NEG_DEV_TYPE 0x7 #define IXGBE_MDIO_VENDOR_SPECIFIC_1_DEV_TYPE 0x1E /* Device 30 */ +#define IXGBE_TWINAX_DEV 1 #define IXGBE_MDIO_COMMAND_TIMEOUT 100 /* PHY Timeout for 1 GB mode */ @@ -487,12 +492,27 @@ #define IXGBE_PHY_REVISION_MASK 0xFFFFFFF0 #define IXGBE_MAX_PHY_ADDR 32 -/* PHY IDs*/ +/* PHY IDs */ +#define TN1010_PHY_ID 0x00A19410 +#define TNX_FW_REV 0xB #define QT2022_PHY_ID 0x0043A400 +#define ATH_PHY_ID 0x03429050 /* PHY Types */ #define IXGBE_M88E1145_E_PHY_ID 0x01410CD0 +/* Special PHY Init Routine */ +#define IXGBE_PHY_INIT_OFFSET_NL 0x002B +#define IXGBE_PHY_INIT_END_NL 0xFFFF +#define IXGBE_CONTROL_MASK_NL 0xF000 +#define IXGBE_DATA_MASK_NL 0x0FFF +#define IXGBE_CONTROL_SHIFT_NL 12 +#define IXGBE_DELAY_NL 0 +#define IXGBE_DATA_NL 1 +#define IXGBE_CONTROL_NL 0x000F +#define IXGBE_CONTROL_EOL_NL 0x0FFF +#define IXGBE_CONTROL_SOL_NL 0x0000 + /* General purpose Interrupt Enable */ #define IXGBE_SDP0_GPIEN 0x00000001 /* SDP0 */ #define IXGBE_SDP1_GPIEN 0x00000002 /* SDP1 */ @@ -1202,8 +1222,10 @@ enum ixgbe_mac_type { enum ixgbe_phy_type { ixgbe_phy_unknown = 0, + ixgbe_phy_tn, ixgbe_phy_qt, ixgbe_phy_xaui, + ixgbe_phy_nl, ixgbe_phy_tw_tyco, ixgbe_phy_tw_unknown, ixgbe_phy_sfp_avago, @@ -1225,6 +1247,7 @@ enum ixgbe_sfp_type { ixgbe_sfp_type_da_cu = 0, ixgbe_sfp_type_sr = 1, ixgbe_sfp_type_lr = 2, + ixgbe_sfp_type_not_present = 0xFFFE, ixgbe_sfp_type_unknown = 0xFFFF }; @@ -1396,6 +1419,8 @@ struct ixgbe_phy_operations { s32 (*setup_link)(struct ixgbe_hw *); s32 (*setup_link_speed)(struct ixgbe_hw *, ixgbe_link_speed, bool, bool); + s32 (*check_link)(struct ixgbe_hw *, ixgbe_link_speed *, bool *); + s32 (*get_firmware_version)(struct ixgbe_hw *, u16 *); s32 (*read_i2c_byte)(struct ixgbe_hw *, u8, u8, u8 *); s32 (*write_i2c_byte)(struct ixgbe_hw *, u8, u8, u8); s32 (*read_i2c_eeprom)(struct ixgbe_hw *, u8 , u8 *); @@ -1486,6 +1511,7 @@ struct ixgbe_info { #define IXGBE_ERR_PHY_ADDR_INVALID -17 #define IXGBE_ERR_I2C -18 #define IXGBE_ERR_SFP_NOT_SUPPORTED -19 +#define IXGBE_ERR_SFP_NOT_PRESENT -20 #define IXGBE_NOT_IMPLEMENTED 0x7FFFFFFF #endif /* _IXGBE_TYPE_H_ */ diff --git a/drivers/net/ixp2000/ixpdev.c b/drivers/net/ixp2000/ixpdev.c index 7b70c66504a04fde3f177d92b085034486294349..014745720560df448b6654c0f051093505838e46 100644 --- a/drivers/net/ixp2000/ixpdev.c +++ b/drivers/net/ixp2000/ixpdev.c @@ -114,8 +114,6 @@ static int ixpdev_rx(struct net_device *dev, int processed, int budget) skb_put(skb, desc->pkt_length); skb->protocol = eth_type_trans(skb, nds[desc->channel]); - dev->last_rx = jiffies; - netif_receive_skb(skb); } @@ -143,7 +141,7 @@ static int ixpdev_poll(struct napi_struct *napi, int budget) break; } while (ixp2000_reg_read(IXP2000_IRQ_THD_RAW_STATUS_A_0) & 0x00ff); - netif_rx_complete(dev, napi); + netif_rx_complete(napi); ixp2000_reg_write(IXP2000_IRQ_THD_ENABLE_SET_A_0, 0x00ff); return rx; @@ -206,7 +204,7 @@ static irqreturn_t ixpdev_interrupt(int irq, void *dev_id) ixp2000_reg_wrb(IXP2000_IRQ_THD_ENABLE_CLEAR_A_0, 0x00ff); if (likely(napi_schedule_prep(&ip->napi))) { - __netif_rx_schedule(dev, &ip->napi); + __netif_rx_schedule(&ip->napi); } else { printk(KERN_CRIT "ixp2000: irq while polling!!\n"); } diff --git a/drivers/net/jazzsonic.c b/drivers/net/jazzsonic.c index 07944820f74582b5230c4a362acac0b81eccbec6..334ff9e12cdd25c5aa131ce98e10fd485a435189 100644 --- a/drivers/net/jazzsonic.c +++ b/drivers/net/jazzsonic.c @@ -208,7 +208,6 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) struct sonic_local *lp; struct resource *res; int err = 0; - DECLARE_MAC_BUF(mac); res = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!res) @@ -233,8 +232,7 @@ static int __init jazz_sonic_probe(struct platform_device *pdev) if (err) goto out1; - printk("%s: MAC %s IRQ %d\n", - dev->name, print_mac(mac, dev->dev_addr), dev->irq); + printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq); return 0; diff --git a/drivers/net/jme.c b/drivers/net/jme.c index 665e70d620fc3cc6b7337c825a7e41f6d422c4b6..08b34051c646d6e4028bb30847ad793c84aedd00 100644 --- a/drivers/net/jme.c +++ b/drivers/net/jme.c @@ -435,15 +435,18 @@ jme_check_link(struct net_device *netdev, int testonly) GHC_DPX); switch (phylink & PHY_LINK_SPEED_MASK) { case PHY_LINK_SPEED_10M: - ghc |= GHC_SPEED_10M; + ghc |= GHC_SPEED_10M | + GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE; strcat(linkmsg, "10 Mbps, "); break; case PHY_LINK_SPEED_100M: - ghc |= GHC_SPEED_100M; + ghc |= GHC_SPEED_100M | + GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE; strcat(linkmsg, "100 Mbps, "); break; case PHY_LINK_SPEED_1000M: - ghc |= GHC_SPEED_1000M; + ghc |= GHC_SPEED_1000M | + GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY; strcat(linkmsg, "1000 Mbps, "); break; default: @@ -463,14 +466,6 @@ jme_check_link(struct net_device *netdev, int testonly) TXTRHD_TXREN | ((8 << TXTRHD_TXRL_SHIFT) & TXTRHD_TXRL)); } - strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ? - "Full-Duplex, " : - "Half-Duplex, "); - - if (phylink & PHY_LINK_MDI_STAT) - strcat(linkmsg, "MDI-X"); - else - strcat(linkmsg, "MDI"); gpreg1 = GPREG1_DEFAULT; if (is_buggy250(jme->pdev->device, jme->chiprev)) { @@ -492,11 +487,17 @@ jme_check_link(struct net_device *netdev, int testonly) break; } } - jwrite32(jme, JME_GPREG1, gpreg1); - jme->reg_ghc = ghc; + jwrite32(jme, JME_GPREG1, gpreg1); jwrite32(jme, JME_GHC, ghc); + jme->reg_ghc = ghc; + strcat(linkmsg, (phylink & PHY_LINK_DUPLEX) ? + "Full-Duplex, " : + "Half-Duplex, "); + strcat(linkmsg, (phylink & PHY_LINK_MDI_STAT) ? + "MDI-X" : + "MDI"); msg_link(jme, "Link is up at %s.\n", linkmsg); netif_carrier_on(netdev); } else { @@ -931,7 +932,6 @@ jme_alloc_and_feed_skb(struct jme_adapter *jme, int idx) cpu_to_le16(RXWBFLAG_DEST_MUL)) ++(NET_STAT(jme).multicast); - jme->dev->last_rx = jiffies; NET_STAT(jme).rx_bytes += framesize; ++(NET_STAT(jme).rx_packets); } @@ -1250,7 +1250,6 @@ static int jme_poll(JME_NAPI_HOLDER(holder), JME_NAPI_WEIGHT(budget)) { struct jme_adapter *jme = jme_napi_priv(holder); - struct net_device *netdev = jme->dev; int rest; rest = jme_process_receive(jme, JME_NAPI_WEIGHT_VAL(budget)); @@ -2591,14 +2590,6 @@ static const struct ethtool_ops jme_ethtool_ops = { static int jme_pci_dma64(struct pci_dev *pdev) { - if (!pci_set_dma_mask(pdev, DMA_64BIT_MASK)) - if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK)) - return 1; - - if (!pci_set_dma_mask(pdev, DMA_40BIT_MASK)) - if (!pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK)) - return 1; - if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK)) if (!pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) return 0; @@ -2626,6 +2617,18 @@ jme_check_hw_ver(struct jme_adapter *jme) jme->chiprev = (chipmode & CM_CHIPREV_MASK) >> CM_CHIPREV_SHIFT; } +static const struct net_device_ops jme_netdev_ops = { + .ndo_open = jme_open, + .ndo_stop = jme_close, + .ndo_validate_addr = eth_validate_addr, + .ndo_start_xmit = jme_start_xmit, + .ndo_set_mac_address = jme_set_macaddr, + .ndo_set_multicast_list = jme_set_multi, + .ndo_change_mtu = jme_change_mtu, + .ndo_tx_timeout = jme_tx_timeout, + .ndo_vlan_rx_register = jme_vlan_rx_register, +}; + static int __devinit jme_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -2675,17 +2678,9 @@ jme_init_one(struct pci_dev *pdev, rc = -ENOMEM; goto err_out_release_regions; } - netdev->open = jme_open; - netdev->stop = jme_close; - netdev->hard_start_xmit = jme_start_xmit; - netdev->set_mac_address = jme_set_macaddr; - netdev->set_multicast_list = jme_set_multi; - netdev->change_mtu = jme_change_mtu; + netdev->netdev_ops = &jme_netdev_ops; netdev->ethtool_ops = &jme_ethtool_ops; - netdev->tx_timeout = jme_tx_timeout; netdev->watchdog_timeo = TX_TIMEOUT; - netdev->vlan_rx_register = jme_vlan_rx_register; - NETDEV_GET_STATS(netdev, &jme_get_stats); netdev->features = NETIF_F_HW_CSUM | NETIF_F_SG | NETIF_F_TSO | @@ -2861,18 +2856,10 @@ jme_init_one(struct pci_dev *pdev, goto err_out_free_shadow; } - msg_probe(jme, - "JMC250 gigabit%s ver:%x rev:%x " - "macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n", + msg_probe(jme, "JMC250 gigabit%s ver:%x rev:%x macaddr:%pM\n", (jme->fpgaver != 0) ? " (FPGA)" : "", (jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev, - jme->rev, - netdev->dev_addr[0], - netdev->dev_addr[1], - netdev->dev_addr[2], - netdev->dev_addr[3], - netdev->dev_addr[4], - netdev->dev_addr[5]); + jme->rev, netdev->dev_addr); return 0; diff --git a/drivers/net/jme.h b/drivers/net/jme.h index 3f5d91543246c88936d8fc086abf37c2cd3f6686..5154411b5e6b0821054cdefef093947bf99a8333 100644 --- a/drivers/net/jme.h +++ b/drivers/net/jme.h @@ -398,15 +398,15 @@ struct jme_ring { #define JME_NAPI_WEIGHT(w) int w #define JME_NAPI_WEIGHT_VAL(w) w #define JME_NAPI_WEIGHT_SET(w, r) -#define JME_RX_COMPLETE(dev, napis) netif_rx_complete(dev, napis) +#define JME_RX_COMPLETE(dev, napis) netif_rx_complete(napis) #define JME_NAPI_ENABLE(priv) napi_enable(&priv->napi); #define JME_NAPI_DISABLE(priv) \ if (!napi_disable_pending(&priv->napi)) \ napi_disable(&priv->napi); #define JME_RX_SCHEDULE_PREP(priv) \ - netif_rx_schedule_prep(priv->dev, &priv->napi) + netif_rx_schedule_prep(&priv->napi) #define JME_RX_SCHEDULE(priv) \ - __netif_rx_schedule(priv->dev, &priv->napi); + __netif_rx_schedule(&priv->napi); /* * Jmac Adapter Private data @@ -815,16 +815,30 @@ static inline u32 smi_phy_addr(int x) * Global Host Control */ enum jme_ghc_bit_mask { - GHC_SWRST = 0x40000000, - GHC_DPX = 0x00000040, - GHC_SPEED = 0x00000030, - GHC_LINK_POLL = 0x00000001, + GHC_SWRST = 0x40000000, + GHC_DPX = 0x00000040, + GHC_SPEED = 0x00000030, + GHC_LINK_POLL = 0x00000001, }; enum jme_ghc_speed_val { - GHC_SPEED_10M = 0x00000010, - GHC_SPEED_100M = 0x00000020, - GHC_SPEED_1000M = 0x00000030, + GHC_SPEED_10M = 0x00000010, + GHC_SPEED_100M = 0x00000020, + GHC_SPEED_1000M = 0x00000030, +}; + +enum jme_ghc_to_clk { + GHC_TO_CLK_OFF = 0x00000000, + GHC_TO_CLK_GPHY = 0x00400000, + GHC_TO_CLK_PCIE = 0x00800000, + GHC_TO_CLK_INVALID = 0x00C00000, +}; + +enum jme_ghc_txmac_clk { + GHC_TXMAC_CLK_OFF = 0x00000000, + GHC_TXMAC_CLK_GPHY = 0x00100000, + GHC_TXMAC_CLK_PCIE = 0x00200000, + GHC_TXMAC_CLK_INVALID = 0x00300000, }; /* diff --git a/drivers/net/korina.c b/drivers/net/korina.c index e18576316bda93050cdd5849da80ef67cd85333a..4a5580c1126a00b383e4588b4ab6a2fa5376845e 100644 --- a/drivers/net/korina.c +++ b/drivers/net/korina.c @@ -327,7 +327,7 @@ static irqreturn_t korina_rx_dma_interrupt(int irq, void *dev_id) dmas = readl(&lp->rx_dma_regs->dmas); if (dmas & (DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR)) { - netif_rx_schedule_prep(dev, &lp->napi); + netif_rx_schedule_prep(&lp->napi); dmasm = readl(&lp->rx_dma_regs->dmasm); writel(dmasm | (DMA_STAT_DONE | @@ -409,7 +409,6 @@ static int korina_rx(struct net_device *dev, int limit) /* Pass the packet to upper layers */ netif_receive_skb(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; @@ -467,7 +466,7 @@ static int korina_poll(struct napi_struct *napi, int budget) work_done = korina_rx(dev, budget); if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); writel(readl(&lp->rx_dma_regs->dmasm) & ~(DMA_STAT_DONE | DMA_STAT_HALT | DMA_STAT_ERR), diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 977ed3401bb34cd97d688800ba89340381d39e9e..d7afb938ea626ae3bdf2c3c005dfacab258f2696 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -359,7 +359,7 @@ int __init init_module(void) static void cleanup_card(struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; if (dev->dma != 4) free_dma(dev->dma); release_region(dev->base_addr, LANCE_TOTAL_SIZE); @@ -418,7 +418,7 @@ static int __init do_lance_probe(struct net_device *dev) if (card < NUM_CARDS) { /*Signature OK*/ result = lance_probe1(dev, ioaddr, 0, 0); if (!result) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int ver = lp->chip_version; r->name = chip_table[ver].name; @@ -466,7 +466,6 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int unsigned long flags; int err = -ENOMEM; void __iomem *bios; - DECLARE_MAC_BUF(mac); /* First we look for special cases. Check for HP's on-board ethernet by looking for 'HP' in the BIOS. @@ -520,7 +519,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int } } - /* We can't allocate dev->priv from alloc_etherdev() because it must + /* We can't allocate private data from alloc_etherdev() because it must a ISA DMA-able region. */ chipname = chip_table[lance_version].name; printk("%s: %s at %#3x, ", dev->name, chipname, ioaddr); @@ -529,7 +528,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int The first six bytes are the station address. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + i); - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); dev->base_addr = ioaddr; /* Make certain the data structures used by the LANCE are aligned and DMAble. */ @@ -538,7 +537,7 @@ static int __init lance_probe1(struct net_device *dev, int ioaddr, int irq, int if(lp==NULL) return -ENODEV; if (lance_debug > 6) printk(" (#0x%05lx)", (unsigned long)lp); - dev->priv = lp; + dev->ml_priv = lp; lp->name = chipname; lp->rx_buffs = (unsigned long)kmalloc(PKT_BUF_SZ*RX_RING_SIZE, GFP_DMA | GFP_KERNEL); @@ -742,7 +741,7 @@ out_lp: static int lance_open(struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int ioaddr = dev->base_addr; int i; @@ -830,7 +829,7 @@ lance_open(struct net_device *dev) static void lance_purge_ring(struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int i; /* Free all the skbuffs in the Rx and Tx queues. */ @@ -854,7 +853,7 @@ lance_purge_ring(struct net_device *dev) static void lance_init_ring(struct net_device *dev, gfp_t gfp) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int i; lp->cur_rx = lp->cur_tx = 0; @@ -896,7 +895,7 @@ lance_init_ring(struct net_device *dev, gfp_t gfp) static void lance_restart(struct net_device *dev, unsigned int csr0_bits, int must_reinit) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; if (must_reinit || (chip_table[lp->chip_version].flags & LANCE_MUST_REINIT_RING)) { @@ -910,7 +909,7 @@ lance_restart(struct net_device *dev, unsigned int csr0_bits, int must_reinit) static void lance_tx_timeout (struct net_device *dev) { - struct lance_private *lp = (struct lance_private *) dev->priv; + struct lance_private *lp = (struct lance_private *) dev->ml_priv; int ioaddr = dev->base_addr; outw (0, ioaddr + LANCE_ADDR); @@ -944,7 +943,7 @@ static void lance_tx_timeout (struct net_device *dev) static int lance_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int ioaddr = dev->base_addr; int entry; unsigned long flags; @@ -1021,7 +1020,7 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id) int must_restart; ioaddr = dev->base_addr; - lp = dev->priv; + lp = dev->ml_priv; spin_lock (&lp->devlock); @@ -1134,7 +1133,7 @@ static irqreturn_t lance_interrupt(int irq, void *dev_id) static int lance_rx(struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; int entry = lp->cur_rx & RX_RING_MOD_MASK; int i; @@ -1191,7 +1190,6 @@ lance_rx(struct net_device *dev) pkt_len); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes+=pkt_len; } @@ -1213,7 +1211,7 @@ static int lance_close(struct net_device *dev) { int ioaddr = dev->base_addr; - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; netif_stop_queue (dev); @@ -1246,7 +1244,7 @@ lance_close(struct net_device *dev) static struct net_device_stats *lance_get_stats(struct net_device *dev) { - struct lance_private *lp = dev->priv; + struct lance_private *lp = dev->ml_priv; if (chip_table[lp->chip_version].flags & LANCE_HAS_MISSED_FRAME) { short ioaddr = dev->base_addr; diff --git a/drivers/net/lib82596.c b/drivers/net/lib82596.c index b59f442bbf36e38885e6bf35570fe7a5b9138104..7415f517491d73a6bfb7817e7f07c14f842a1923 100644 --- a/drivers/net/lib82596.c +++ b/drivers/net/lib82596.c @@ -739,7 +739,6 @@ memory_squeeze: skb->len = pkt_len; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -1034,12 +1033,8 @@ static int i596_start_xmit(struct sk_buff *skb, struct net_device *dev) static void print_eth(unsigned char *add, char *str) { - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - - printk(KERN_DEBUG "i596 0x%p, %s --> %s %02X%02X, %s\n", - add, print_mac(mac, add + 6), print_mac(mac2, add), - add[12], add[13], str); + printk(KERN_DEBUG "i596 0x%p, %pM --> %pM %02X%02X, %s\n", + add, add + 6, add, add[12], add[13], str); } static int __devinit i82596_probe(struct net_device *dev) @@ -1343,7 +1338,6 @@ static void set_multicast_list(struct net_device *dev) struct i596_private *lp = netdev_priv(dev); struct i596_dma *dma = lp->dma; int config = 0, cnt; - DECLARE_MAC_BUF(mac); DEB(DEB_MULTI, printk(KERN_DEBUG @@ -1407,8 +1401,8 @@ static void set_multicast_list(struct net_device *dev) if (i596_debug > 1) DEB(DEB_MULTI, printk(KERN_DEBUG - "%s: Adding address %s\n", - dev->name, print_mac(mac, cp))); + "%s: Adding address %pM\n", + dev->name, cp)); } DMA_WBACK_INV(dev, &dma->mc_cmd, sizeof(struct mc_cmd)); i596_add_cmd(dev, &cmd->cmd); diff --git a/drivers/net/lib8390.c b/drivers/net/lib8390.c index f80dcc11fe26bad7f594fff1407d0e036fc84935..789b6cb744b284ee08d4c749ab9fa210dc34170e 100644 --- a/drivers/net/lib8390.c +++ b/drivers/net/lib8390.c @@ -108,14 +108,13 @@ int ei_debug = 1; /* Index to functions. */ static void ei_tx_intr(struct net_device *dev); static void ei_tx_err(struct net_device *dev); -static void ei_tx_timeout(struct net_device *dev); +void ei_tx_timeout(struct net_device *dev); static void ei_receive(struct net_device *dev); static void ei_rx_overrun(struct net_device *dev); /* Routines generic to NS8390-based boards. */ static void NS8390_trigger_send(struct net_device *dev, unsigned int length, int start_page); -static void set_multicast_list(struct net_device *dev); static void do_set_multicast_list(struct net_device *dev); static void __NS8390_init(struct net_device *dev, int startp); @@ -206,10 +205,6 @@ static int __ei_open(struct net_device *dev) unsigned long flags; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); - /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout - wrapper that does e.g. media check & then calls ei_tx_timeout. */ - if (dev->tx_timeout == NULL) - dev->tx_timeout = ei_tx_timeout; if (dev->watchdog_timeo <= 0) dev->watchdog_timeo = TX_TIMEOUT; @@ -258,7 +253,7 @@ static int __ei_close(struct net_device *dev) * completed (or failed) - i.e. never posted a Tx related interrupt. */ -static void ei_tx_timeout(struct net_device *dev) +static void __ei_tx_timeout(struct net_device *dev) { unsigned long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -304,7 +299,7 @@ static void ei_tx_timeout(struct net_device *dev) * Sends a packet to an 8390 network device. */ -static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int __ei_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -764,7 +759,6 @@ static void ei_receive(struct net_device *dev) ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame)); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; if (pkt_stat & ENRSR_PHY) @@ -883,7 +877,7 @@ static void ei_rx_overrun(struct net_device *dev) * Collect the stats. This is called unlocked and from several contexts. */ -static struct net_device_stats *get_stats(struct net_device *dev) +static struct net_device_stats *__ei_get_stats(struct net_device *dev) { unsigned long ioaddr = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -992,7 +986,7 @@ static void do_set_multicast_list(struct net_device *dev) * not called too often. Must protect against both bh and irq users */ -static void set_multicast_list(struct net_device *dev) +static void __ei_set_multicast_list(struct net_device *dev) { unsigned long flags; struct ei_device *ei_local = (struct ei_device*)netdev_priv(dev); @@ -1016,10 +1010,6 @@ static void ethdev_setup(struct net_device *dev) if (ei_debug > 1) printk(version); - dev->hard_start_xmit = &ei_start_xmit; - dev->get_stats = get_stats; - dev->set_multicast_list = &set_multicast_list; - ether_setup(dev); spin_lock_init(&ei_local->page_lock); diff --git a/drivers/net/lne390.c b/drivers/net/lne390.c index b36989097883bc7b800bfd00269dd245b55323ff..41cbaaef06548da3f8357afafea280807dfe24f5 100644 --- a/drivers/net/lne390.c +++ b/drivers/net/lne390.c @@ -53,9 +53,6 @@ static const char *version = static int lne390_probe1(struct net_device *dev, int ioaddr); -static int lne390_open(struct net_device *dev); -static int lne390_close(struct net_device *dev); - static void lne390_reset_8390(struct net_device *dev); static void lne390_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -169,7 +166,6 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) { int i, revision, ret; unsigned long eisa_id; - DECLARE_MAC_BUF(mac); if (inb_p(ioaddr + LNE390_ID_PORT) == 0xff) return -ENODEV; @@ -203,8 +199,8 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = inb(ioaddr + LNE390_SA_PROM + i); - printk("lne390.c: LNE390%X in EISA slot %d, address %s.\n", - 0xa+revision, ioaddr/0x1000, print_mac(mac, dev->dev_addr)); + printk("lne390.c: LNE390%X in EISA slot %d, address %pM.\n", + 0xa+revision, ioaddr/0x1000, dev->dev_addr); printk("lne390.c: "); @@ -279,11 +275,7 @@ static int __init lne390_probe1(struct net_device *dev, int ioaddr) ei_status.block_output = &lne390_block_output; ei_status.get_8390_hdr = &lne390_get_8390_hdr; - dev->open = &lne390_open; - dev->stop = &lne390_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + dev->netdev_ops = &ei_netdev_ops; NS8390_init(dev, 0); ret = register_netdev(dev); @@ -375,21 +367,6 @@ static void lne390_block_output(struct net_device *dev, int count, memcpy_toio(shmem, buf, count); } -static int lne390_open(struct net_device *dev) -{ - ei_open(dev); - return 0; -} - -static int lne390_close(struct net_device *dev) -{ - - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - - ei_close(dev); - return 0; -} #ifdef MODULE #define MAX_LNE_CARDS 4 /* Max number of LNE390 cards per module */ diff --git a/drivers/net/loopback.c b/drivers/net/loopback.c index b1ac63ab8c16052abd00affc855e4971f0417066..b7d438a367f36c15c495f1ff51ebb5b984cad5dc 100644 --- a/drivers/net/loopback.c +++ b/drivers/net/loopback.c @@ -76,8 +76,6 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); - dev->last_rx = jiffies; - /* it's OK to use per_cpu_ptr() because BHs are off */ pcpu_lstats = dev->ml_priv; lb_stats = per_cpu_ptr(pcpu_lstats, smp_processor_id()); @@ -89,7 +87,7 @@ static int loopback_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } -static struct net_device_stats *get_stats(struct net_device *dev) +static struct net_device_stats *loopback_get_stats(struct net_device *dev) { const struct pcpu_lstats *pcpu_lstats; struct net_device_stats *stats = &dev->stats; @@ -145,15 +143,19 @@ static void loopback_dev_free(struct net_device *dev) free_netdev(dev); } +static const struct net_device_ops loopback_ops = { + .ndo_init = loopback_dev_init, + .ndo_start_xmit= loopback_xmit, + .ndo_get_stats = loopback_get_stats, +}; + /* * The loopback device is special. There is only one instance * per network namespace. */ static void loopback_setup(struct net_device *dev) { - dev->get_stats = &get_stats; dev->mtu = (16 * 1024) + 20 + 20 + 12; - dev->hard_start_xmit = loopback_xmit; dev->hard_header_len = ETH_HLEN; /* 14 */ dev->addr_len = ETH_ALEN; /* 6 */ dev->tx_queue_len = 0; @@ -167,8 +169,8 @@ static void loopback_setup(struct net_device *dev) | NETIF_F_NETNS_LOCAL; dev->ethtool_ops = &loopback_ethtool_ops; dev->header_ops = ð_header_ops; - dev->init = loopback_dev_init; - dev->destructor = loopback_dev_free; + dev->netdev_ops = &loopback_ops; + dev->destructor = loopback_dev_free; } /* Setup and register the loopback device. */ @@ -206,17 +208,8 @@ static __net_exit void loopback_net_exit(struct net *net) unregister_netdev(dev); } -static struct pernet_operations __net_initdata loopback_net_ops = { +/* Registered in net/core/dev.c */ +struct pernet_operations __net_initdata loopback_net_ops = { .init = loopback_net_init, .exit = loopback_net_exit, }; - -static int __init loopback_init(void) -{ - return register_pernet_device(&loopback_net_ops); -} - -/* Loopback is special. It should be initialized before any other network - * device and network subsystem. - */ -fs_initcall(loopback_init); diff --git a/drivers/net/lp486e.c b/drivers/net/lp486e.c index 83fa9d82a004830cecad296d2403cc1dce70c767..4d1a059921c6413d419257327cc382207298a9e7 100644 --- a/drivers/net/lp486e.c +++ b/drivers/net/lp486e.c @@ -390,7 +390,7 @@ i596_timeout(struct net_device *dev, char *msg, int ct) { struct i596_private *lp; int boguscnt = ct; - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); while (lp->scb.command) { if (--boguscnt == 0) { printk("%s: %s timed out - stat %4.4x, cmd %4.4x\n", @@ -411,7 +411,7 @@ init_rx_bufs(struct net_device *dev, int num) { int i; // struct i596_rbd *rbd; - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); lp->scb.pa_rfd = I596_NULL; for (i = 0; i < num; i++) { @@ -468,7 +468,7 @@ remove_rx_bufs(struct net_device *dev) { struct i596_private *lp; struct i596_rfd *rfd; - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); lp->rx_tail->pa_next = I596_NULL; do { @@ -517,7 +517,7 @@ CLEAR_INT(void) { /* selftest or dump */ static void i596_port_do(struct net_device *dev, int portcmd, char *cmdname) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); u16 *outp; int i, m; @@ -541,7 +541,7 @@ i596_port_do(struct net_device *dev, int portcmd, char *cmdname) { static int i596_scp_setup(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); int boguscnt; /* Setup SCP, ISCP, SCB */ @@ -622,7 +622,7 @@ init_i596(struct net_device *dev) { if (i596_scp_setup(dev)) return 1; - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); lp->scb.command = 0; memcpy ((void *)lp->i596_config, init_setup, 14); @@ -676,7 +676,6 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp, skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } else { #if 0 @@ -705,7 +704,7 @@ i596_rx_one(struct net_device *dev, struct i596_private *lp, static int i596_rx(struct net_device *dev) { - struct i596_private *lp = (struct i596_private *) dev->priv; + struct i596_private *lp = netdev_priv(dev); struct i596_rfd *rfd; int frames = 0; @@ -738,7 +737,7 @@ i596_cleanup_cmd(struct net_device *dev) { struct i596_private *lp; struct i596_cmd *cmd; - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); while (lp->cmd_head) { cmd = (struct i596_cmd *)lp->cmd_head; @@ -806,7 +805,7 @@ static void i596_reset(struct net_device *dev, struct i596_private *lp, int ioad } static void i596_add_cmd(struct net_device *dev, struct i596_cmd *cmd) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; unsigned long flags; @@ -912,7 +911,7 @@ static int i596_start_xmit (struct sk_buff *skb, struct net_device *dev) { static void i596_tx_timeout (struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); int ioaddr = dev->base_addr; /* Transmitter timeout, serious problems. */ @@ -970,7 +969,7 @@ static int __init lp486e_probe(struct net_device *dev) { return -EBUSY; } - lp = (struct i596_private *) dev->priv; + lp = netdev_priv(dev); spin_lock_init(&lp->cmd_lock); /* @@ -1147,7 +1146,7 @@ static irqreturn_t i596_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); unsigned short status, ack_cmd = 0; int frames_in = 0; @@ -1215,7 +1214,7 @@ i596_interrupt(int irq, void *dev_instance) } static int i596_close(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); netif_stop_queue(dev); @@ -1242,7 +1241,7 @@ static int i596_close(struct net_device *dev) { */ static void set_multicast_list(struct net_device *dev) { - struct i596_private *lp = dev->priv; + struct i596_private *lp = netdev_priv(dev); struct i596_cmd *cmd; if (i596_debug > 1) diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 98e3eb2697c9b65a70adb0d9183efc3e6bf3e9be..57716e22660cc6091f7f99620bf5ee08e2624ede 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c @@ -304,7 +304,7 @@ struct net_device * __init mac8390_probe(int unit) if (!MACH_IS_MAC) return ERR_PTR(-ENODEV); - dev = ____alloc_ei_netdev(0); + dev = alloc_ei_netdev(); if (!dev) return ERR_PTR(-ENOMEM); @@ -478,6 +478,20 @@ void cleanup_module(void) #endif /* MODULE */ +static const struct net_device_ops mac8390_netdev_ops = { + .ndo_open = mac8390_open, + .ndo_stop = mac8390_close, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * ndev, enum mac8390_type type) { @@ -503,11 +517,7 @@ static int __init mac8390_initdev(struct net_device * dev, struct nubus_dev * nd int access_bitmode = 0; /* Now fill in our stuff */ - dev->open = &mac8390_open; - dev->stop = &mac8390_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = __ei_poll; -#endif + dev->netdev_ops = &mac8390_netdev_ops; /* GAR, ei_status is actually a macro even though it looks global */ ei_status.name = cardname[type]; diff --git a/drivers/net/mac89x0.c b/drivers/net/mac89x0.c index 4ce8afd481c3f13bd75caa570c5597c28b2a68cb..380a1a54d5301f1f3e95eb536423eb122bf84487 100644 --- a/drivers/net/mac89x0.c +++ b/drivers/net/mac89x0.c @@ -181,7 +181,6 @@ struct net_device * __init mac89x0_probe(int unit) unsigned long ioaddr; unsigned short sig; int err = -ENODEV; - DECLARE_MAC_BUF(mac); if (!MACH_IS_MAC) return ERR_PTR(-ENODEV); @@ -279,8 +278,7 @@ struct net_device * __init mac89x0_probe(int unit) /* print the IRQ and ethernet address. */ - printk(" IRQ %d ADDR %s\n", - dev->irq, print_mac(mac, dev->dev_addr)); + printk(" IRQ %d ADDR %pM\n", dev->irq, dev->dev_addr); dev->open = net_open; dev->stop = net_close; @@ -518,7 +516,6 @@ net_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += length; } @@ -628,14 +625,3 @@ cleanup_module(void) free_netdev(dev_cs89x0); } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "m68k-linux-gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -fno-strength-reduce -ffixed-a2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c -o mac89x0.o mac89x0.c" - * version-control: t - * kept-new-versions: 5 - * c-indent-level: 8 - * tab-width: 8 - * End: - * - */ diff --git a/drivers/net/macb.c b/drivers/net/macb.c index 01f7a31bac764134f623352a3894456c7192b205..a04da4ecaa8811a8be09450389e33288ebe2d80e 100644 --- a/drivers/net/macb.c +++ b/drivers/net/macb.c @@ -435,7 +435,6 @@ static int macb_rx_frame(struct macb *bp, unsigned int first_frag, bp->stats.rx_packets++; bp->stats.rx_bytes += len; - bp->dev->last_rx = jiffies; dev_dbg(&bp->pdev->dev, "received skb of length %u, csum: %08x\n", skb->len, skb->csum); netif_receive_skb(skb); @@ -520,7 +519,7 @@ static int macb_poll(struct napi_struct *napi, int budget) * this function was called last time, and no packets * have been received since. */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); goto out; } @@ -531,13 +530,13 @@ static int macb_poll(struct napi_struct *napi, int budget) dev_warn(&bp->pdev->dev, "No RX buffers complete, status = %02lx\n", (unsigned long)status); - netif_rx_complete(dev, napi); + netif_rx_complete(napi); goto out; } work_done = macb_rx(bp, budget); if (work_done < budget) - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /* * We've done what we can to clean the buffers. Make sure we @@ -572,7 +571,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) } if (status & MACB_RX_INT_FLAGS) { - if (netif_rx_schedule_prep(dev, &bp->napi)) { + if (netif_rx_schedule_prep(&bp->napi)) { /* * There's no point taking any more interrupts * until we have processed the buffers @@ -580,7 +579,7 @@ static irqreturn_t macb_interrupt(int irq, void *dev_id) macb_writel(bp, IDR, MACB_RX_INT_FLAGS); dev_dbg(&bp->pdev->dev, "scheduling RX softirq\n"); - __netif_rx_schedule(dev, &bp->napi); + __netif_rx_schedule(&bp->napi); } } @@ -1104,7 +1103,6 @@ static int __init macb_probe(struct platform_device *pdev) unsigned long pclk_hz; u32 config; int err = -ENXIO; - DECLARE_MAC_BUF(mac); regs = platform_get_resource(pdev, IORESOURCE_MEM, 0); if (!regs) { @@ -1223,10 +1221,8 @@ static int __init macb_probe(struct platform_device *pdev) platform_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d " - "(%s)\n", - dev->name, dev->base_addr, dev->irq, - print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Atmel MACB at 0x%08lx irq %d (%pM)\n", + dev->name, dev->base_addr, dev->irq, dev->dev_addr); phydev = bp->phy_dev; printk(KERN_INFO "%s: attached PHY driver [%s] " diff --git a/drivers/net/mace.c b/drivers/net/mace.c index 451acdca2a214a97068b46f597930b25d2e05f87..feebbd92aff2d3202d8e877cf31a6c6f13117140 100644 --- a/drivers/net/mace.c +++ b/drivers/net/mace.c @@ -101,7 +101,6 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i struct mace_data *mp; const unsigned char *addr; int j, rev, rc = -EBUSY; - DECLARE_MAC_BUF(mac); if (macio_resource_count(mdev) != 3 || macio_irq_count(mdev) != 3) { printk(KERN_ERR "can't use MACE %s: need 3 addrs and 3 irqs\n", @@ -144,7 +143,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i } SET_NETDEV_DEV(dev, &mdev->ofdev.dev); - mp = dev->priv; + mp = netdev_priv(dev); mp->mdev = mdev; macio_set_drvdata(mdev, dev); @@ -165,7 +164,7 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i in_8(&mp->mace->chipid_lo); - mp = (struct mace_data *) dev->priv; + mp = netdev_priv(dev); mp->maccc = ENXMT | ENRCV; mp->tx_dma = ioremap(macio_resource_start(mdev, 1), 0x1000); @@ -241,8 +240,8 @@ static int __devinit mace_probe(struct macio_dev *mdev, const struct of_device_i goto err_free_rx_irq; } - printk(KERN_INFO "%s: MACE at %s, chip revision %d.%d\n", - dev->name, print_mac(mac, dev->dev_addr), + printk(KERN_INFO "%s: MACE at %pM, chip revision %d.%d\n", + dev->name, dev->dev_addr, mp->chipid >> 8, mp->chipid & 0xff); return 0; @@ -276,7 +275,7 @@ static int __devexit mace_remove(struct macio_dev *mdev) macio_set_drvdata(mdev, NULL); - mp = dev->priv; + mp = netdev_priv(dev); unregister_netdev(dev); @@ -312,7 +311,7 @@ static void dbdma_reset(volatile struct dbdma_regs __iomem *dma) static void mace_reset(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; int i; @@ -367,7 +366,7 @@ static void mace_reset(struct net_device *dev) static void __mace_set_address(struct net_device *dev, void *addr) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; unsigned char *p = addr; int i; @@ -388,7 +387,7 @@ static void __mace_set_address(struct net_device *dev, void *addr) static int mace_set_address(struct net_device *dev, void *addr) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; unsigned long flags; @@ -423,7 +422,7 @@ static inline void mace_clean_rings(struct mace_data *mp) static int mace_open(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; volatile struct dbdma_regs __iomem *rd = mp->rx_dma; volatile struct dbdma_regs __iomem *td = mp->tx_dma; @@ -493,7 +492,7 @@ static int mace_open(struct net_device *dev) static int mace_close(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; volatile struct dbdma_regs __iomem *rd = mp->rx_dma; volatile struct dbdma_regs __iomem *td = mp->tx_dma; @@ -513,7 +512,7 @@ static int mace_close(struct net_device *dev) static inline void mace_set_timeout(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); if (mp->timeout_active) del_timer(&mp->tx_timeout); @@ -526,7 +525,7 @@ static inline void mace_set_timeout(struct net_device *dev) static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct dbdma_regs __iomem *td = mp->tx_dma; volatile struct dbdma_cmd *cp, *np; unsigned long flags; @@ -581,7 +580,7 @@ static int mace_xmit_start(struct sk_buff *skb, struct net_device *dev) static void mace_set_multicast(struct net_device *dev) { - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; int i, j; u32 crc; @@ -656,7 +655,7 @@ static void mace_handle_misc_intrs(struct mace_data *mp, int intr, struct net_de static irqreturn_t mace_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; volatile struct dbdma_regs __iomem *td = mp->tx_dma; volatile struct dbdma_cmd *cp; @@ -802,7 +801,7 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id) static void mace_tx_timeout(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct mace __iomem *mb = mp->mace; volatile struct dbdma_regs __iomem *td = mp->tx_dma; volatile struct dbdma_regs __iomem *rd = mp->rx_dma; @@ -873,7 +872,7 @@ static irqreturn_t mace_txdma_intr(int irq, void *dev_id) static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct mace_data *mp = (struct mace_data *) dev->priv; + struct mace_data *mp = netdev_priv(dev); volatile struct dbdma_regs __iomem *rd = mp->rx_dma; volatile struct dbdma_cmd *cp, *np; int i, nb, stat, next; @@ -929,7 +928,6 @@ static irqreturn_t mace_rxdma_intr(int irq, void *dev_id) skb->protocol = eth_type_trans(skb, dev); dev->stats.rx_bytes += skb->len; netif_rx(skb); - dev->last_rx = jiffies; mp->rx_bufs[i] = NULL; ++dev->stats.rx_packets; } diff --git a/drivers/net/macmace.c b/drivers/net/macmace.c index 85587a6667b9f170d3b55686a6474c20754a4c15..274e99bb63ac28857b568e339a46088065ecf6e2 100644 --- a/drivers/net/macmace.c +++ b/drivers/net/macmace.c @@ -194,7 +194,6 @@ static int __devinit mace_probe(struct platform_device *pdev) unsigned char checksum = 0; static int found = 0; int err; - DECLARE_MAC_BUF(mac); if (found || macintosh_config->ether_type != MAC_ETHER_MACE) return -ENODEV; @@ -249,8 +248,8 @@ static int __devinit mace_probe(struct platform_device *pdev) dev->set_multicast_list = mace_set_multicast; dev->set_mac_address = mace_set_address; - printk(KERN_INFO "%s: 68K MACE, hardware address %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: 68K MACE, hardware address %pM\n", + dev->name, dev->dev_addr); err = register_netdev(dev); if (!err) @@ -674,7 +673,6 @@ static void mace_dma_rx_frame(struct net_device *dev, struct mace_frame *mf) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += frame_length; } diff --git a/drivers/net/macsonic.c b/drivers/net/macsonic.c index e64c2086d33c7ea9fcd8834b408a34f46de79c67..205bb05c25d6f41a2eec0abfdb958348179d0e93 100644 --- a/drivers/net/macsonic.c +++ b/drivers/net/macsonic.c @@ -220,7 +220,6 @@ static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev) struct sonic_local *lp = netdev_priv(dev); const int prom_addr = ONBOARD_SONIC_PROM_BASE; int i; - DECLARE_MAC_BUF(mac); /* On NuBus boards we can sometimes look in the ROM resources. No such luck for comm-slot/onboard. */ @@ -264,8 +263,8 @@ static int __init mac_onboard_sonic_ethernet_addr(struct net_device *dev) dev->dev_addr[1] = val >> 8; dev->dev_addr[0] = val & 0xff; - printk(KERN_INFO "HW Address from CAM 15: %s\n", - print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "HW Address from CAM 15: %pM\n", + dev->dev_addr); } else return 0; if (memcmp(dev->dev_addr, "\x08\x00\x07", 3) && @@ -560,7 +559,6 @@ static int __init mac_sonic_probe(struct platform_device *pdev) struct net_device *dev; struct sonic_local *lp; int err; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof(struct sonic_local)); if (!dev) @@ -584,8 +582,7 @@ found: if (err) goto out; - printk("%s: MAC %s IRQ %d\n", - dev->name, print_mac(mac, dev->dev_addr), dev->irq); + printk("%s: MAC %pM IRQ %d\n", dev->name, dev->dev_addr, dev->irq); return 0; diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c index 590039cbb146f5a42b888055cc836ea576f23726..7e24b50486869c8295e19d8b7339b7d56d6ef909 100644 --- a/drivers/net/macvlan.c +++ b/drivers/net/macvlan.c @@ -87,7 +87,6 @@ static void macvlan_broadcast(struct sk_buff *skb, dev->stats.rx_bytes += skb->len + ETH_HLEN; dev->stats.rx_packets++; dev->stats.multicast++; - dev->last_rx = jiffies; nskb->dev = dev; if (!compare_ether_addr(eth->h_dest, dev->broadcast)) @@ -136,7 +135,6 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) dev->stats.rx_bytes += skb->len + ETH_HLEN; dev->stats.rx_packets++; - dev->last_rx = jiffies; skb->dev = dev; skb->pkt_type = PACKET_HOST; @@ -145,7 +143,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb) return NULL; } -static int macvlan_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int macvlan_start_xmit(struct sk_buff *skb, struct net_device *dev) { const struct macvlan_dev *vlan = netdev_priv(dev); unsigned int len = skb->len; @@ -336,24 +334,53 @@ static u32 macvlan_ethtool_get_rx_csum(struct net_device *dev) return lowerdev->ethtool_ops->get_rx_csum(lowerdev); } +static int macvlan_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + const struct macvlan_dev *vlan = netdev_priv(dev); + struct net_device *lowerdev = vlan->lowerdev; + + if (!lowerdev->ethtool_ops->get_settings) + return -EOPNOTSUPP; + + return lowerdev->ethtool_ops->get_settings(lowerdev, cmd); +} + +static u32 macvlan_ethtool_get_flags(struct net_device *dev) +{ + const struct macvlan_dev *vlan = netdev_priv(dev); + struct net_device *lowerdev = vlan->lowerdev; + + if (!lowerdev->ethtool_ops->get_flags) + return 0; + return lowerdev->ethtool_ops->get_flags(lowerdev); +} + static const struct ethtool_ops macvlan_ethtool_ops = { .get_link = ethtool_op_get_link, + .get_settings = macvlan_ethtool_get_settings, .get_rx_csum = macvlan_ethtool_get_rx_csum, .get_drvinfo = macvlan_ethtool_get_drvinfo, + .get_flags = macvlan_ethtool_get_flags, +}; + +static const struct net_device_ops macvlan_netdev_ops = { + .ndo_init = macvlan_init, + .ndo_open = macvlan_open, + .ndo_stop = macvlan_stop, + .ndo_start_xmit = macvlan_start_xmit, + .ndo_change_mtu = macvlan_change_mtu, + .ndo_change_rx_flags = macvlan_change_rx_flags, + .ndo_set_mac_address = macvlan_set_mac_address, + .ndo_set_multicast_list = macvlan_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, }; static void macvlan_setup(struct net_device *dev) { ether_setup(dev); - dev->init = macvlan_init; - dev->open = macvlan_open; - dev->stop = macvlan_stop; - dev->change_mtu = macvlan_change_mtu; - dev->change_rx_flags = macvlan_change_rx_flags; - dev->set_mac_address = macvlan_set_mac_address; - dev->set_multicast_list = macvlan_set_multicast_list; - dev->hard_start_xmit = macvlan_hard_start_xmit; + dev->netdev_ops = &macvlan_netdev_ops; dev->destructor = free_netdev; dev->header_ops = &macvlan_hard_header_ops, dev->ethtool_ops = &macvlan_ethtool_ops; diff --git a/drivers/net/meth.c b/drivers/net/meth.c index a1e22ed1f6ee5616ce9d88bde8a55940dc66fa16..c336a1f42510c09d5c9e690cc46c207f9f6880e3 100644 --- a/drivers/net/meth.c +++ b/drivers/net/meth.c @@ -94,10 +94,9 @@ char o2meth_eaddr[8]={0,0,0,0,0,0,0,0}; static inline void load_eaddr(struct net_device *dev) { int i; - DECLARE_MAC_BUF(mac); u64 macaddr; - DPRINTK("Loading MAC Address: %s\n", print_mac(mac, dev->dev_addr)); + DPRINTK("Loading MAC Address: %pM\n", dev->dev_addr); macaddr = 0; for (i = 0; i < 6; i++) macaddr |= (u64)dev->dev_addr[i] << ((5 - i) * 8); @@ -421,7 +420,6 @@ static void meth_rx(struct net_device* dev, unsigned long int_status) skb_put(skb_c, len); priv->rx_skbs[priv->rx_write] = skb; skb_c->protocol = eth_type_trans(skb_c, dev); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; netif_rx(skb_c); diff --git a/drivers/net/mlx4/en_cq.c b/drivers/net/mlx4/en_cq.c index 674f836e225b98ede4b6c1a4412b894722eb7064..91f50de84be9053422699e0856e6d6f003508ba7 100644 --- a/drivers/net/mlx4/en_cq.c +++ b/drivers/net/mlx4/en_cq.c @@ -71,6 +71,8 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv, err = mlx4_en_map_buffer(&cq->wqres.buf); if (err) mlx4_free_hwq_res(mdev->dev, &cq->wqres, cq->buf_size); + else + cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf; return err; } @@ -85,7 +87,6 @@ int mlx4_en_activate_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) cq->mcq.arm_db = cq->wqres.db.db + 1; *cq->mcq.set_ci_db = 0; *cq->mcq.arm_db = 0; - cq->buf = (struct mlx4_cqe *) cq->wqres.buf.direct.buf; memset(cq->buf, 0, cq->buf_size); err = mlx4_cq_alloc(mdev->dev, cq->size, &cq->wqres.mtt, &mdev->priv_uar, @@ -139,7 +140,6 @@ int mlx4_en_set_cq_moder(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) int mlx4_en_arm_cq(struct mlx4_en_priv *priv, struct mlx4_en_cq *cq) { - cq->armed = 1; mlx4_cq_arm(&cq->mcq, MLX4_CQ_DB_REQ_NOT, priv->mdev->uar_map, &priv->mdev->uar_lock); diff --git a/drivers/net/mlx4/en_netdev.c b/drivers/net/mlx4/en_netdev.c index 96e709d6440a459866b7d5d461113408031d7c23..ebada3c7aff2aee26ed5acbc306733be6e126bf6 100644 --- a/drivers/net/mlx4/en_netdev.c +++ b/drivers/net/mlx4/en_netdev.c @@ -369,7 +369,6 @@ static struct net_device_stats *mlx4_en_get_stats(struct net_device *dev) static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) { - struct mlx4_en_dev *mdev = priv->mdev; struct mlx4_en_cq *cq; int i; @@ -379,15 +378,8 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) * satisfy our coelsing target. * - moder_time is set to a fixed value. */ - priv->rx_frames = (mdev->profile.rx_moder_cnt == - MLX4_EN_AUTO_CONF) ? - MLX4_EN_RX_COAL_TARGET / - priv->dev->mtu + 1 : - mdev->profile.rx_moder_cnt; - priv->rx_usecs = (mdev->profile.rx_moder_time == - MLX4_EN_AUTO_CONF) ? - MLX4_EN_RX_COAL_TIME : - mdev->profile.rx_moder_time; + priv->rx_frames = MLX4_EN_RX_COAL_TARGET / priv->dev->mtu + 1; + priv->rx_usecs = MLX4_EN_RX_COAL_TIME; mlx4_dbg(INTR, priv, "Default coalesing params for mtu:%d - " "rx_frames:%d rx_usecs:%d\n", priv->dev->mtu, priv->rx_frames, priv->rx_usecs); @@ -411,7 +403,7 @@ static void mlx4_en_set_default_moderation(struct mlx4_en_priv *priv) priv->pkt_rate_high = MLX4_EN_RX_RATE_HIGH; priv->rx_usecs_high = MLX4_EN_RX_COAL_TIME_HIGH; priv->sample_interval = MLX4_EN_SAMPLE_INTERVAL; - priv->adaptive_rx_coal = mdev->profile.auto_moder; + priv->adaptive_rx_coal = 1; priv->last_moder_time = MLX4_EN_AUTO_CONF; priv->last_moder_jiffies = 0; priv->last_moder_packets = 0; @@ -953,6 +945,23 @@ static int mlx4_en_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static const struct net_device_ops mlx4_netdev_ops = { + .ndo_open = mlx4_en_open, + .ndo_stop = mlx4_en_close, + .ndo_start_xmit = mlx4_en_xmit, + .ndo_get_stats = mlx4_en_get_stats, + .ndo_set_multicast_list = mlx4_en_set_multicast, + .ndo_set_mac_address = mlx4_en_set_mac, + .ndo_change_mtu = mlx4_en_change_mtu, + .ndo_tx_timeout = mlx4_en_tx_timeout, + .ndo_vlan_rx_register = mlx4_en_vlan_rx_register, + .ndo_vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = mlx4_en_netpoll, +#endif +}; + int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, struct mlx4_en_port_profile *prof) { @@ -1029,22 +1038,9 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port, /* * Initialize netdev entry points */ - - dev->open = &mlx4_en_open; - dev->stop = &mlx4_en_close; - dev->hard_start_xmit = &mlx4_en_xmit; - dev->get_stats = &mlx4_en_get_stats; - dev->set_multicast_list = &mlx4_en_set_multicast; - dev->set_mac_address = &mlx4_en_set_mac; - dev->change_mtu = &mlx4_en_change_mtu; - dev->tx_timeout = &mlx4_en_tx_timeout; + dev->netdev_ops = &mlx4_netdev_ops; dev->watchdog_timeo = MLX4_EN_WATCHDOG_TIMEOUT; - dev->vlan_rx_register = mlx4_en_vlan_rx_register; - dev->vlan_rx_add_vid = mlx4_en_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = mlx4_en_vlan_rx_kill_vid; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = mlx4_en_netpoll; -#endif + SET_ETHTOOL_OPS(dev, &mlx4_en_ethtool_ops); /* Set defualt MAC */ diff --git a/drivers/net/mlx4/en_params.c b/drivers/net/mlx4/en_params.c index 95706ee1c01996898a255b210a7cf8efd14e5ab4..047b37f5a7474cc8137753590e3d85858e712ce6 100644 --- a/drivers/net/mlx4/en_params.c +++ b/drivers/net/mlx4/en_params.c @@ -60,24 +60,11 @@ MLX4_EN_PARM_INT(num_lro, MLX4_EN_MAX_LRO_DESCRIPTORS, "Number of LRO sessions per ring or disabled (0)"); /* Priority pausing */ -MLX4_EN_PARM_INT(pptx, MLX4_EN_DEF_TX_PAUSE, - "Pause policy on TX: 0 never generate pause frames " - "1 generate pause frames according to RX buffer threshold"); -MLX4_EN_PARM_INT(pprx, MLX4_EN_DEF_RX_PAUSE, - "Pause policy on RX: 0 ignore received pause frames " - "1 respect received pause frames"); MLX4_EN_PARM_INT(pfctx, 0, "Priority based Flow Control policy on TX[7:0]." " Per priority bit mask"); MLX4_EN_PARM_INT(pfcrx, 0, "Priority based Flow Control policy on RX[7:0]." " Per priority bit mask"); -/* Interrupt moderation tunning */ -MLX4_EN_PARM_INT(rx_moder_cnt, MLX4_EN_AUTO_CONF, - "Max coalesced descriptors for Rx interrupt moderation"); -MLX4_EN_PARM_INT(rx_moder_time, MLX4_EN_AUTO_CONF, - "Timeout following last packet for Rx interrupt moderation"); -MLX4_EN_PARM_INT(auto_moder, 1, "Enable dynamic interrupt moderation"); - MLX4_EN_PARM_INT(rx_ring_num1, 0, "Number or Rx rings for port 1 (0 = #cores)"); MLX4_EN_PARM_INT(rx_ring_num2, 0, "Number or Rx rings for port 2 (0 = #cores)"); @@ -92,16 +79,13 @@ int mlx4_en_get_profile(struct mlx4_en_dev *mdev) struct mlx4_en_profile *params = &mdev->profile; int i; - params->rx_moder_cnt = min_t(int, rx_moder_cnt, MLX4_EN_AUTO_CONF); - params->rx_moder_time = min_t(int, rx_moder_time, MLX4_EN_AUTO_CONF); - params->auto_moder = auto_moder; params->rss_xor = (rss_xor != 0); params->rss_mask = rss_mask & 0x1f; params->num_lro = min_t(int, num_lro , MLX4_EN_MAX_LRO_DESCRIPTORS); for (i = 1; i <= MLX4_MAX_PORTS; i++) { - params->prof[i].rx_pause = pprx; + params->prof[i].rx_pause = 1; params->prof[i].rx_ppp = pfcrx; - params->prof[i].tx_pause = pptx; + params->prof[i].tx_pause = 1; params->prof[i].tx_ppp = pfctx; } if (pfcrx || pfctx) { diff --git a/drivers/net/mlx4/en_rx.c b/drivers/net/mlx4/en_rx.c index 6232227f56c33a8cfd66e59d3ffafe7589b74791..c61b0bdca1a433c33771784d88fb8f6eae3f092d 100644 --- a/drivers/net/mlx4/en_rx.c +++ b/drivers/net/mlx4/en_rx.c @@ -443,7 +443,8 @@ int mlx4_en_activate_rx_rings(struct mlx4_en_priv *priv) /* Fill Rx buffers */ ring->full = 0; } - if (mlx4_en_fill_rx_buffers(priv)) + err = mlx4_en_fill_rx_buffers(priv); + if (err) goto err_buffers; for (ring_ind = 0; ring_ind < priv->rx_ring_num; ring_ind++) { @@ -776,8 +777,6 @@ int mlx4_en_process_rx_cq(struct net_device *dev, struct mlx4_en_cq *cq, int bud } else netif_receive_skb(skb); - dev->last_rx = jiffies; - next: ++cq->mcq.cons_index; index = (cq->mcq.cons_index) & ring->size_mask; @@ -815,7 +814,7 @@ void mlx4_en_rx_irq(struct mlx4_cq *mcq) struct mlx4_en_priv *priv = netdev_priv(cq->dev); if (priv->port_up) - netif_rx_schedule(cq->dev, &cq->napi); + netif_rx_schedule(&cq->napi); else mlx4_en_arm_cq(priv, cq); } @@ -835,7 +834,7 @@ int mlx4_en_poll_rx_cq(struct napi_struct *napi, int budget) INC_PERF_COUNTER(priv->pstats.napi_quota); else { /* Done for now */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); mlx4_en_arm_cq(priv, cq); } return done; diff --git a/drivers/net/mlx4/en_tx.c b/drivers/net/mlx4/en_tx.c index 8592f8fb847577c42ed5b964ff50be35b1e6840a..ff4d75205c25bac5c6acb91fe216320c98fc568b 100644 --- a/drivers/net/mlx4/en_tx.c +++ b/drivers/net/mlx4/en_tx.c @@ -379,8 +379,8 @@ static void mlx4_en_process_tx_cq(struct net_device *dev, struct mlx4_en_cq *cq) /* Wakeup Tx queue if this ring stopped it */ if (unlikely(ring->blocked)) { - if (((u32) (ring->prod - ring->cons) <= - ring->size - HEADROOM - MAX_DESC_TXBBS) && !cq->armed) { + if ((u32) (ring->prod - ring->cons) <= + ring->size - HEADROOM - MAX_DESC_TXBBS) { /* TODO: support multiqueue netdevs. Currently, we block * when *any* ring is full. Note that: @@ -404,14 +404,11 @@ void mlx4_en_tx_irq(struct mlx4_cq *mcq) struct mlx4_en_priv *priv = netdev_priv(cq->dev); struct mlx4_en_tx_ring *ring = &priv->tx_ring[cq->ring]; - spin_lock_irq(&ring->comp_lock); - cq->armed = 0; + if (!spin_trylock(&ring->comp_lock)) + return; mlx4_en_process_tx_cq(cq->dev, cq); - if (ring->blocked) - mlx4_en_arm_cq(priv, cq); - else - mod_timer(&cq->timer, jiffies + 1); - spin_unlock_irq(&ring->comp_lock); + mod_timer(&cq->timer, jiffies + 1); + spin_unlock(&ring->comp_lock); } @@ -424,8 +421,10 @@ void mlx4_en_poll_tx_cq(unsigned long data) INC_PERF_COUNTER(priv->pstats.tx_poll); - netif_tx_lock(priv->dev); - spin_lock_irq(&ring->comp_lock); + if (!spin_trylock(&ring->comp_lock)) { + mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); + return; + } mlx4_en_process_tx_cq(cq->dev, cq); inflight = (u32) (ring->prod - ring->cons - ring->last_nr_txbb); @@ -435,8 +434,7 @@ void mlx4_en_poll_tx_cq(unsigned long data) if (inflight && priv->port_up) mod_timer(&cq->timer, jiffies + MLX4_EN_TX_POLL_TIMEOUT); - spin_unlock_irq(&ring->comp_lock); - netif_tx_unlock(priv->dev); + spin_unlock(&ring->comp_lock); } static struct mlx4_en_tx_desc *mlx4_en_bounce_to_desc(struct mlx4_en_priv *priv, @@ -479,7 +477,10 @@ static inline void mlx4_en_xmit_poll(struct mlx4_en_priv *priv, int tx_ind) /* Poll the CQ every mlx4_en_TX_MODER_POLL packets */ if ((++ring->poll_cnt & (MLX4_EN_TX_POLL_MODER - 1)) == 0) - mlx4_en_process_tx_cq(priv->dev, cq); + if (spin_trylock(&ring->comp_lock)) { + mlx4_en_process_tx_cq(priv->dev, cq); + spin_unlock(&ring->comp_lock); + } } static void *get_frag_ptr(struct sk_buff *skb) diff --git a/drivers/net/mlx4/mcg.c b/drivers/net/mlx4/mcg.c index 592c01ae2c5dc119f6c6e213126099bf0557228e..6053c357a470c27bdc1cf827d24388269f413774 100644 --- a/drivers/net/mlx4/mcg.c +++ b/drivers/net/mlx4/mcg.c @@ -118,17 +118,7 @@ static int find_mgm(struct mlx4_dev *dev, return err; if (0) - mlx4_dbg(dev, "Hash for %04x:%04x:%04x:%04x:" - "%04x:%04x:%04x:%04x is %04x\n", - be16_to_cpu(((__be16 *) gid)[0]), - be16_to_cpu(((__be16 *) gid)[1]), - be16_to_cpu(((__be16 *) gid)[2]), - be16_to_cpu(((__be16 *) gid)[3]), - be16_to_cpu(((__be16 *) gid)[4]), - be16_to_cpu(((__be16 *) gid)[5]), - be16_to_cpu(((__be16 *) gid)[6]), - be16_to_cpu(((__be16 *) gid)[7]), - *hash); + mlx4_dbg(dev, "Hash for %pI6 is %04x\n", gid, *hash); *index = *hash; *prev = -1; @@ -215,7 +205,7 @@ int mlx4_multicast_attach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16], if (block_mcast_loopback) mgm->qp[members_count++] = cpu_to_be32((qp->qpn & MGM_QPN_MASK) | - (1 << MGM_BLCK_LB_BIT)); + (1U << MGM_BLCK_LB_BIT)); else mgm->qp[members_count++] = cpu_to_be32(qp->qpn & MGM_QPN_MASK); @@ -277,16 +267,7 @@ int mlx4_multicast_detach(struct mlx4_dev *dev, struct mlx4_qp *qp, u8 gid[16]) goto out; if (index == -1) { - mlx4_err(dev, "MGID %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x " - "not found\n", - be16_to_cpu(((__be16 *) gid)[0]), - be16_to_cpu(((__be16 *) gid)[1]), - be16_to_cpu(((__be16 *) gid)[2]), - be16_to_cpu(((__be16 *) gid)[3]), - be16_to_cpu(((__be16 *) gid)[4]), - be16_to_cpu(((__be16 *) gid)[5]), - be16_to_cpu(((__be16 *) gid)[6]), - be16_to_cpu(((__be16 *) gid)[7])); + mlx4_err(dev, "MGID %pI6 not found\n", gid); err = -EINVAL; goto out; } diff --git a/drivers/net/mlx4/mlx4_en.h b/drivers/net/mlx4/mlx4_en.h index 98ddc0811f93e78b13bd37303dd2a3c572610c67..e78209768def3d757547facacc79568cdb4a7c90 100644 --- a/drivers/net/mlx4/mlx4_en.h +++ b/drivers/net/mlx4/mlx4_en.h @@ -58,17 +58,17 @@ #define mlx4_dbg(mlevel, priv, format, arg...) \ if (NETIF_MSG_##mlevel & priv->msg_enable) \ printk(KERN_DEBUG "%s %s: " format , DRV_NAME ,\ - (&priv->mdev->pdev->dev)->bus_id , ## arg) + (dev_name(&priv->mdev->pdev->dev)) , ## arg) #define mlx4_err(mdev, format, arg...) \ printk(KERN_ERR "%s %s: " format , DRV_NAME ,\ - (&mdev->pdev->dev)->bus_id , ## arg) + (dev_name(&mdev->pdev->dev)) , ## arg) #define mlx4_info(mdev, format, arg...) \ printk(KERN_INFO "%s %s: " format , DRV_NAME ,\ - (&mdev->pdev->dev)->bus_id , ## arg) + (dev_name(&mdev->pdev->dev)) , ## arg) #define mlx4_warn(mdev, format, arg...) \ printk(KERN_WARNING "%s %s: " format , DRV_NAME ,\ - (&mdev->pdev->dev)->bus_id , ## arg) + (dev_name(&mdev->pdev->dev)) , ## arg) /* * Device constants @@ -311,7 +311,6 @@ struct mlx4_en_cq { enum cq_type is_tx; u16 moder_time; u16 moder_cnt; - int armed; struct mlx4_cqe *buf; #define MLX4_EN_OPCODE_ERROR 0x1e }; @@ -334,9 +333,6 @@ struct mlx4_en_profile { u8 rss_mask; u32 active_ports; u32 small_pkt_int; - int rx_moder_cnt; - int rx_moder_time; - int auto_moder; u8 no_reset; struct mlx4_en_port_profile prof[MLX4_MAX_PORTS + 1]; }; diff --git a/drivers/net/mv643xx_eth.c b/drivers/net/mv643xx_eth.c index e513f76f2a9f6d1cd55cc8d190d679b36f5872da..7253a499d9c86f3ec9832c3b0190fff6d0c0e24d 100644 --- a/drivers/net/mv643xx_eth.c +++ b/drivers/net/mv643xx_eth.c @@ -51,8 +51,8 @@ #include #include #include -#include -#include +#include +#include #include static char mv643xx_eth_driver_name[] = "mv643xx_eth"; @@ -78,16 +78,17 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define WINDOW_PROTECT(w) (0x0294 + ((w) << 4)) /* - * Per-port registers. + * Main per-port registers. These live at offset 0x0400 for + * port #0, 0x0800 for port #1, and 0x0c00 for port #2. */ -#define PORT_CONFIG(p) (0x0400 + ((p) << 10)) +#define PORT_CONFIG 0x0000 #define UNICAST_PROMISCUOUS_MODE 0x00000001 -#define PORT_CONFIG_EXT(p) (0x0404 + ((p) << 10)) -#define MAC_ADDR_LOW(p) (0x0414 + ((p) << 10)) -#define MAC_ADDR_HIGH(p) (0x0418 + ((p) << 10)) -#define SDMA_CONFIG(p) (0x041c + ((p) << 10)) -#define PORT_SERIAL_CONTROL(p) (0x043c + ((p) << 10)) -#define PORT_STATUS(p) (0x0444 + ((p) << 10)) +#define PORT_CONFIG_EXT 0x0004 +#define MAC_ADDR_LOW 0x0014 +#define MAC_ADDR_HIGH 0x0018 +#define SDMA_CONFIG 0x001c +#define PORT_SERIAL_CONTROL 0x003c +#define PORT_STATUS 0x0044 #define TX_FIFO_EMPTY 0x00000400 #define TX_IN_PROGRESS 0x00000080 #define PORT_SPEED_MASK 0x00000030 @@ -97,31 +98,35 @@ static char mv643xx_eth_driver_version[] = "1.4"; #define FLOW_CONTROL_ENABLED 0x00000008 #define FULL_DUPLEX 0x00000004 #define LINK_UP 0x00000002 -#define TXQ_COMMAND(p) (0x0448 + ((p) << 10)) -#define TXQ_FIX_PRIO_CONF(p) (0x044c + ((p) << 10)) -#define TX_BW_RATE(p) (0x0450 + ((p) << 10)) -#define TX_BW_MTU(p) (0x0458 + ((p) << 10)) -#define TX_BW_BURST(p) (0x045c + ((p) << 10)) -#define INT_CAUSE(p) (0x0460 + ((p) << 10)) +#define TXQ_COMMAND 0x0048 +#define TXQ_FIX_PRIO_CONF 0x004c +#define TX_BW_RATE 0x0050 +#define TX_BW_MTU 0x0058 +#define TX_BW_BURST 0x005c +#define INT_CAUSE 0x0060 #define INT_TX_END 0x07f80000 #define INT_RX 0x000003fc #define INT_EXT 0x00000002 -#define INT_CAUSE_EXT(p) (0x0464 + ((p) << 10)) +#define INT_CAUSE_EXT 0x0064 #define INT_EXT_LINK_PHY 0x00110000 #define INT_EXT_TX 0x000000ff -#define INT_MASK(p) (0x0468 + ((p) << 10)) -#define INT_MASK_EXT(p) (0x046c + ((p) << 10)) -#define TX_FIFO_URGENT_THRESHOLD(p) (0x0474 + ((p) << 10)) -#define TXQ_FIX_PRIO_CONF_MOVED(p) (0x04dc + ((p) << 10)) -#define TX_BW_RATE_MOVED(p) (0x04e0 + ((p) << 10)) -#define TX_BW_MTU_MOVED(p) (0x04e8 + ((p) << 10)) -#define TX_BW_BURST_MOVED(p) (0x04ec + ((p) << 10)) -#define RXQ_CURRENT_DESC_PTR(p, q) (0x060c + ((p) << 10) + ((q) << 4)) -#define RXQ_COMMAND(p) (0x0680 + ((p) << 10)) -#define TXQ_CURRENT_DESC_PTR(p, q) (0x06c0 + ((p) << 10) + ((q) << 2)) -#define TXQ_BW_TOKENS(p, q) (0x0700 + ((p) << 10) + ((q) << 4)) -#define TXQ_BW_CONF(p, q) (0x0704 + ((p) << 10) + ((q) << 4)) -#define TXQ_BW_WRR_CONF(p, q) (0x0708 + ((p) << 10) + ((q) << 4)) +#define INT_MASK 0x0068 +#define INT_MASK_EXT 0x006c +#define TX_FIFO_URGENT_THRESHOLD 0x0074 +#define TXQ_FIX_PRIO_CONF_MOVED 0x00dc +#define TX_BW_RATE_MOVED 0x00e0 +#define TX_BW_MTU_MOVED 0x00e8 +#define TX_BW_BURST_MOVED 0x00ec +#define RXQ_CURRENT_DESC_PTR(q) (0x020c + ((q) << 4)) +#define RXQ_COMMAND 0x0280 +#define TXQ_CURRENT_DESC_PTR(q) (0x02c0 + ((q) << 2)) +#define TXQ_BW_TOKENS(q) (0x0300 + ((q) << 4)) +#define TXQ_BW_CONF(q) (0x0304 + ((q) << 4)) +#define TXQ_BW_WRR_CONF(q) (0x0308 + ((q) << 4)) + +/* + * Misc per-port registers. + */ #define MIB_COUNTERS(p) (0x1000 + ((p) << 7)) #define SPECIAL_MCAST_TABLE(p) (0x1400 + ((p) << 10)) #define OTHER_MCAST_TABLE(p) (0x1500 + ((p) << 10)) @@ -138,14 +143,14 @@ static char mv643xx_eth_driver_version[] = "1.4"; #if defined(__BIG_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ - RX_BURST_SIZE_16_64BIT | \ - TX_BURST_SIZE_16_64BIT + (RX_BURST_SIZE_16_64BIT | \ + TX_BURST_SIZE_16_64BIT) #elif defined(__LITTLE_ENDIAN) #define PORT_SDMA_CONFIG_DEFAULT_VALUE \ - RX_BURST_SIZE_16_64BIT | \ + (RX_BURST_SIZE_16_64BIT | \ BLM_RX_NO_SWAP | \ BLM_TX_NO_SWAP | \ - TX_BURST_SIZE_16_64BIT + TX_BURST_SIZE_16_64BIT) #else #error One of __BIG_ENDIAN or __LITTLE_ENDIAN must be defined #endif @@ -351,6 +356,7 @@ struct tx_queue { struct mv643xx_eth_private { struct mv643xx_eth_shared_private *shared; + void __iomem *base; int port_num; struct net_device *dev; @@ -401,11 +407,21 @@ static inline u32 rdl(struct mv643xx_eth_private *mp, int offset) return readl(mp->shared->base + offset); } +static inline u32 rdlp(struct mv643xx_eth_private *mp, int offset) +{ + return readl(mp->base + offset); +} + static inline void wrl(struct mv643xx_eth_private *mp, int offset, u32 data) { writel(data, mp->shared->base + offset); } +static inline void wrlp(struct mv643xx_eth_private *mp, int offset, u32 data) +{ + writel(data, mp->base + offset); +} + /* rxq/txq helper functions *************************************************/ static struct mv643xx_eth_private *rxq_to_mp(struct rx_queue *rxq) @@ -421,7 +437,7 @@ static struct mv643xx_eth_private *txq_to_mp(struct tx_queue *txq) static void rxq_enable(struct rx_queue *rxq) { struct mv643xx_eth_private *mp = rxq_to_mp(rxq); - wrl(mp, RXQ_COMMAND(mp->port_num), 1 << rxq->index); + wrlp(mp, RXQ_COMMAND, 1 << rxq->index); } static void rxq_disable(struct rx_queue *rxq) @@ -429,26 +445,25 @@ static void rxq_disable(struct rx_queue *rxq) struct mv643xx_eth_private *mp = rxq_to_mp(rxq); u8 mask = 1 << rxq->index; - wrl(mp, RXQ_COMMAND(mp->port_num), mask << 8); - while (rdl(mp, RXQ_COMMAND(mp->port_num)) & mask) + wrlp(mp, RXQ_COMMAND, mask << 8); + while (rdlp(mp, RXQ_COMMAND) & mask) udelay(10); } static void txq_reset_hw_ptr(struct tx_queue *txq) { struct mv643xx_eth_private *mp = txq_to_mp(txq); - int off = TXQ_CURRENT_DESC_PTR(mp->port_num, txq->index); u32 addr; addr = (u32)txq->tx_desc_dma; addr += txq->tx_curr_desc * sizeof(struct tx_desc); - wrl(mp, off, addr); + wrlp(mp, TXQ_CURRENT_DESC_PTR(txq->index), addr); } static void txq_enable(struct tx_queue *txq) { struct mv643xx_eth_private *mp = txq_to_mp(txq); - wrl(mp, TXQ_COMMAND(mp->port_num), 1 << txq->index); + wrlp(mp, TXQ_COMMAND, 1 << txq->index); } static void txq_disable(struct tx_queue *txq) @@ -456,8 +471,8 @@ static void txq_disable(struct tx_queue *txq) struct mv643xx_eth_private *mp = txq_to_mp(txq); u8 mask = 1 << txq->index; - wrl(mp, TXQ_COMMAND(mp->port_num), mask << 8); - while (rdl(mp, TXQ_COMMAND(mp->port_num)) & mask) + wrlp(mp, TXQ_COMMAND, mask << 8); + while (rdlp(mp, TXQ_COMMAND) & mask) udelay(10); } @@ -528,37 +543,38 @@ static int rxq_process(struct rx_queue *rxq, int budget) * on, or the error summary bit is set, the packet needs * to be dropped. */ - if (((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != - (RX_FIRST_DESC | RX_LAST_DESC)) - || (cmd_sts & ERROR_SUMMARY)) { - stats->rx_dropped++; - - if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != - (RX_FIRST_DESC | RX_LAST_DESC)) { - if (net_ratelimit()) - dev_printk(KERN_ERR, &mp->dev->dev, - "received packet spanning " - "multiple descriptors\n"); - } + if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC | ERROR_SUMMARY)) + != (RX_FIRST_DESC | RX_LAST_DESC)) + goto err; - if (cmd_sts & ERROR_SUMMARY) - stats->rx_errors++; + /* + * The -4 is for the CRC in the trailer of the + * received packet + */ + skb_put(skb, byte_cnt - 2 - 4); - dev_kfree_skb(skb); - } else { - /* - * The -4 is for the CRC in the trailer of the - * received packet - */ - skb_put(skb, byte_cnt - 2 - 4); - - if (cmd_sts & LAYER_4_CHECKSUM_OK) - skb->ip_summed = CHECKSUM_UNNECESSARY; - skb->protocol = eth_type_trans(skb, mp->dev); - netif_receive_skb(skb); + if (cmd_sts & LAYER_4_CHECKSUM_OK) + skb->ip_summed = CHECKSUM_UNNECESSARY; + skb->protocol = eth_type_trans(skb, mp->dev); + netif_receive_skb(skb); + + continue; + +err: + stats->rx_dropped++; + + if ((cmd_sts & (RX_FIRST_DESC | RX_LAST_DESC)) != + (RX_FIRST_DESC | RX_LAST_DESC)) { + if (net_ratelimit()) + dev_printk(KERN_ERR, &mp->dev->dev, + "received packet spanning " + "multiple descriptors\n"); } - mp->dev->last_rx = jiffies; + if (cmd_sts & ERROR_SUMMARY) + stats->rx_errors++; + + dev_kfree_skb(skb); } if (rx < budget) @@ -577,6 +593,7 @@ static int rxq_refill(struct rx_queue *rxq, int budget) struct sk_buff *skb; int unaligned; int rx; + struct rx_desc *rx_desc; skb = __skb_dequeue(&mp->rx_recycle); if (skb == NULL) @@ -599,13 +616,14 @@ static int rxq_refill(struct rx_queue *rxq, int budget) if (rxq->rx_used_desc == rxq->rx_ring_size) rxq->rx_used_desc = 0; - rxq->rx_desc_area[rx].buf_ptr = dma_map_single(NULL, skb->data, - mp->skb_size, DMA_FROM_DEVICE); - rxq->rx_desc_area[rx].buf_size = mp->skb_size; + rx_desc = rxq->rx_desc_area + rx; + + rx_desc->buf_ptr = dma_map_single(NULL, skb->data, + mp->skb_size, DMA_FROM_DEVICE); + rx_desc->buf_size = mp->skb_size; rxq->rx_skb[rx] = skb; wmb(); - rxq->rx_desc_area[rx].cmd_sts = BUFFER_OWNED_BY_DMA | - RX_ENABLE_INTERRUPT; + rx_desc->cmd_sts = BUFFER_OWNED_BY_DMA | RX_ENABLE_INTERRUPT; wmb(); /* @@ -638,21 +656,6 @@ static inline unsigned int has_tiny_unaligned_frags(struct sk_buff *skb) return 0; } -static int txq_alloc_desc_index(struct tx_queue *txq) -{ - int tx_desc_curr; - - BUG_ON(txq->tx_desc_count >= txq->tx_ring_size); - - tx_desc_curr = txq->tx_curr_desc++; - if (txq->tx_curr_desc == txq->tx_ring_size) - txq->tx_curr_desc = 0; - - BUG_ON(txq->tx_curr_desc == txq->tx_used_desc); - - return tx_desc_curr; -} - static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb) { int nr_frags = skb_shinfo(skb)->nr_frags; @@ -664,7 +667,9 @@ static void txq_submit_frag_skb(struct tx_queue *txq, struct sk_buff *skb) struct tx_desc *desc; this_frag = &skb_shinfo(skb)->frags[frag]; - tx_index = txq_alloc_desc_index(txq); + tx_index = txq->tx_curr_desc++; + if (txq->tx_curr_desc == txq->tx_ring_size) + txq->tx_curr_desc = 0; desc = &txq->tx_desc_area[tx_index]; /* @@ -746,7 +751,9 @@ no_csum: cmd_sts |= 5 << TX_IHL_SHIFT; } - tx_index = txq_alloc_desc_index(txq); + tx_index = txq->tx_curr_desc++; + if (txq->tx_curr_desc == txq->tx_ring_size) + txq->tx_curr_desc = 0; desc = &txq->tx_desc_area[tx_index]; if (nr_frags) { @@ -831,10 +838,10 @@ static void txq_kick(struct tx_queue *txq) __netif_tx_lock(nq, smp_processor_id()); - if (rdl(mp, TXQ_COMMAND(mp->port_num)) & (1 << txq->index)) + if (rdlp(mp, TXQ_COMMAND) & (1 << txq->index)) goto out; - hw_desc_ptr = rdl(mp, TXQ_CURRENT_DESC_PTR(mp->port_num, txq->index)); + hw_desc_ptr = rdlp(mp, TXQ_CURRENT_DESC_PTR(txq->index)); expected_ptr = (u32)txq->tx_desc_dma + txq->tx_curr_desc * sizeof(struct tx_desc); @@ -941,14 +948,14 @@ static void tx_set_rate(struct mv643xx_eth_private *mp, int rate, int burst) switch (mp->shared->tx_bw_control) { case TX_BW_CONTROL_OLD_LAYOUT: - wrl(mp, TX_BW_RATE(mp->port_num), token_rate); - wrl(mp, TX_BW_MTU(mp->port_num), mtu); - wrl(mp, TX_BW_BURST(mp->port_num), bucket_size); + wrlp(mp, TX_BW_RATE, token_rate); + wrlp(mp, TX_BW_MTU, mtu); + wrlp(mp, TX_BW_BURST, bucket_size); break; case TX_BW_CONTROL_NEW_LAYOUT: - wrl(mp, TX_BW_RATE_MOVED(mp->port_num), token_rate); - wrl(mp, TX_BW_MTU_MOVED(mp->port_num), mtu); - wrl(mp, TX_BW_BURST_MOVED(mp->port_num), bucket_size); + wrlp(mp, TX_BW_RATE_MOVED, token_rate); + wrlp(mp, TX_BW_MTU_MOVED, mtu); + wrlp(mp, TX_BW_BURST_MOVED, bucket_size); break; } } @@ -967,9 +974,8 @@ static void txq_set_rate(struct tx_queue *txq, int rate, int burst) if (bucket_size > 65535) bucket_size = 65535; - wrl(mp, TXQ_BW_TOKENS(mp->port_num, txq->index), token_rate << 14); - wrl(mp, TXQ_BW_CONF(mp->port_num, txq->index), - (bucket_size << 10) | token_rate); + wrlp(mp, TXQ_BW_TOKENS(txq->index), token_rate << 14); + wrlp(mp, TXQ_BW_CONF(txq->index), (bucket_size << 10) | token_rate); } static void txq_set_fixed_prio_mode(struct tx_queue *txq) @@ -984,17 +990,17 @@ static void txq_set_fixed_prio_mode(struct tx_queue *txq) off = 0; switch (mp->shared->tx_bw_control) { case TX_BW_CONTROL_OLD_LAYOUT: - off = TXQ_FIX_PRIO_CONF(mp->port_num); + off = TXQ_FIX_PRIO_CONF; break; case TX_BW_CONTROL_NEW_LAYOUT: - off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num); + off = TXQ_FIX_PRIO_CONF_MOVED; break; } if (off) { - val = rdl(mp, off); + val = rdlp(mp, off); val |= 1 << txq->index; - wrl(mp, off, val); + wrlp(mp, off, val); } } @@ -1010,26 +1016,25 @@ static void txq_set_wrr(struct tx_queue *txq, int weight) off = 0; switch (mp->shared->tx_bw_control) { case TX_BW_CONTROL_OLD_LAYOUT: - off = TXQ_FIX_PRIO_CONF(mp->port_num); + off = TXQ_FIX_PRIO_CONF; break; case TX_BW_CONTROL_NEW_LAYOUT: - off = TXQ_FIX_PRIO_CONF_MOVED(mp->port_num); + off = TXQ_FIX_PRIO_CONF_MOVED; break; } if (off) { - val = rdl(mp, off); + val = rdlp(mp, off); val &= ~(1 << txq->index); - wrl(mp, off, val); + wrlp(mp, off, val); /* * Configure WRR weight for this queue. */ - off = TXQ_BW_WRR_CONF(mp->port_num, txq->index); - val = rdl(mp, off); + val = rdlp(mp, off); val = (val & ~0xff) | (weight & 0xff); - wrl(mp, off, val); + wrlp(mp, TXQ_BW_WRR_CONF(txq->index), val); } } @@ -1084,20 +1089,20 @@ static int smi_bus_read(struct mii_bus *bus, int addr, int reg) int ret; if (smi_wait_ready(msp)) { - printk("mv643xx_eth: SMI bus busy timeout\n"); + printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n"); return -ETIMEDOUT; } writel(SMI_OPCODE_READ | (reg << 21) | (addr << 16), smi_reg); if (smi_wait_ready(msp)) { - printk("mv643xx_eth: SMI bus busy timeout\n"); + printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n"); return -ETIMEDOUT; } ret = readl(smi_reg); if (!(ret & SMI_READ_VALID)) { - printk("mv643xx_eth: SMI bus read not valid\n"); + printk(KERN_WARNING "mv643xx_eth: SMI bus read not valid\n"); return -ENODEV; } @@ -1110,7 +1115,7 @@ static int smi_bus_write(struct mii_bus *bus, int addr, int reg, u16 val) void __iomem *smi_reg = msp->base + SMI_REG; if (smi_wait_ready(msp)) { - printk("mv643xx_eth: SMI bus busy timeout\n"); + printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n"); return -ETIMEDOUT; } @@ -1118,7 +1123,7 @@ static int smi_bus_write(struct mii_bus *bus, int addr, int reg, u16 val) (addr << 16) | (val & 0xffff), smi_reg); if (smi_wait_ready(msp)) { - printk("mv643xx_eth: SMI bus busy timeout\n"); + printk(KERN_WARNING "mv643xx_eth: SMI bus busy timeout\n"); return -ETIMEDOUT; } @@ -1271,7 +1276,8 @@ static const struct mv643xx_eth_stats mv643xx_eth_stats[] = { MIBSTAT(late_collision), }; -static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int +mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct mv643xx_eth_private *mp = netdev_priv(dev); int err; @@ -1289,12 +1295,14 @@ static int mv643xx_eth_get_settings(struct net_device *dev, struct ethtool_cmd * return err; } -static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd) +static int +mv643xx_eth_get_settings_phyless(struct net_device *dev, + struct ethtool_cmd *cmd) { struct mv643xx_eth_private *mp = netdev_priv(dev); u32 port_status; - port_status = rdl(mp, PORT_STATUS(mp->port_num)); + port_status = rdlp(mp, PORT_STATUS); cmd->supported = SUPPORTED_MII; cmd->advertising = ADVERTISED_MII; @@ -1323,7 +1331,8 @@ static int mv643xx_eth_get_settings_phyless(struct net_device *dev, struct ethto return 0; } -static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) +static int +mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { struct mv643xx_eth_private *mp = netdev_priv(dev); @@ -1335,7 +1344,9 @@ static int mv643xx_eth_set_settings(struct net_device *dev, struct ethtool_cmd * return phy_ethtool_sset(mp->phy, cmd); } -static int mv643xx_eth_set_settings_phyless(struct net_device *dev, struct ethtool_cmd *cmd) +static int +mv643xx_eth_set_settings_phyless(struct net_device *dev, + struct ethtool_cmd *cmd) { return -EINVAL; } @@ -1443,11 +1454,8 @@ static const struct ethtool_ops mv643xx_eth_ethtool_ops_phyless = { /* address handling *********************************************************/ static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) { - unsigned int mac_h; - unsigned int mac_l; - - mac_h = rdl(mp, MAC_ADDR_HIGH(mp->port_num)); - mac_l = rdl(mp, MAC_ADDR_LOW(mp->port_num)); + unsigned int mac_h = rdlp(mp, MAC_ADDR_HIGH); + unsigned int mac_l = rdlp(mp, MAC_ADDR_LOW); addr[0] = (mac_h >> 24) & 0xff; addr[1] = (mac_h >> 16) & 0xff; @@ -1457,57 +1465,71 @@ static void uc_addr_get(struct mv643xx_eth_private *mp, unsigned char *addr) addr[5] = mac_l & 0xff; } -static void init_mac_tables(struct mv643xx_eth_private *mp) +static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) { - int i; - - for (i = 0; i < 0x100; i += 4) { - wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0); - wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0); - } - - for (i = 0; i < 0x10; i += 4) - wrl(mp, UNICAST_TABLE(mp->port_num) + i, 0); + wrlp(mp, MAC_ADDR_HIGH, + (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]); + wrlp(mp, MAC_ADDR_LOW, (addr[4] << 8) | addr[5]); } -static void set_filter_table_entry(struct mv643xx_eth_private *mp, - int table, unsigned char entry) +static u32 uc_addr_filter_mask(struct net_device *dev) { - unsigned int table_reg; - - /* Set "accepts frame bit" at specified table entry */ - table_reg = rdl(mp, table + (entry & 0xfc)); - table_reg |= 0x01 << (8 * (entry & 3)); - wrl(mp, table + (entry & 0xfc), table_reg); -} + struct dev_addr_list *uc_ptr; + u32 nibbles; -static void uc_addr_set(struct mv643xx_eth_private *mp, unsigned char *addr) -{ - unsigned int mac_h; - unsigned int mac_l; - int table; + if (dev->flags & IFF_PROMISC) + return 0; - mac_l = (addr[4] << 8) | addr[5]; - mac_h = (addr[0] << 24) | (addr[1] << 16) | (addr[2] << 8) | addr[3]; + nibbles = 1 << (dev->dev_addr[5] & 0x0f); + for (uc_ptr = dev->uc_list; uc_ptr != NULL; uc_ptr = uc_ptr->next) { + if (memcmp(dev->dev_addr, uc_ptr->da_addr, 5)) + return 0; + if ((dev->dev_addr[5] ^ uc_ptr->da_addr[5]) & 0xf0) + return 0; - wrl(mp, MAC_ADDR_LOW(mp->port_num), mac_l); - wrl(mp, MAC_ADDR_HIGH(mp->port_num), mac_h); + nibbles |= 1 << (uc_ptr->da_addr[5] & 0x0f); + } - table = UNICAST_TABLE(mp->port_num); - set_filter_table_entry(mp, table, addr[5] & 0x0f); + return nibbles; } -static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr) +static void mv643xx_eth_program_unicast_filter(struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); + u32 port_config; + u32 nibbles; + int i; - /* +2 is for the offset of the HW addr type */ - memcpy(dev->dev_addr, addr + 2, 6); - - init_mac_tables(mp); uc_addr_set(mp, dev->dev_addr); - return 0; + port_config = rdlp(mp, PORT_CONFIG); + nibbles = uc_addr_filter_mask(dev); + if (!nibbles) { + port_config |= UNICAST_PROMISCUOUS_MODE; + wrlp(mp, PORT_CONFIG, port_config); + return; + } + + for (i = 0; i < 16; i += 4) { + int off = UNICAST_TABLE(mp->port_num) + i; + u32 v; + + v = 0; + if (nibbles & 1) + v |= 0x00000001; + if (nibbles & 2) + v |= 0x00000100; + if (nibbles & 4) + v |= 0x00010000; + if (nibbles & 8) + v |= 0x01000000; + nibbles >>= 4; + + wrl(mp, off, v); + } + + port_config &= ~UNICAST_PROMISCUOUS_MODE; + wrlp(mp, PORT_CONFIG, port_config); } static int addr_crc(unsigned char *addr) @@ -1528,24 +1550,22 @@ static int addr_crc(unsigned char *addr) return crc; } -static void mv643xx_eth_set_rx_mode(struct net_device *dev) +static void mv643xx_eth_program_multicast_filter(struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); - u32 port_config; + u32 *mc_spec; + u32 *mc_other; struct dev_addr_list *addr; int i; - port_config = rdl(mp, PORT_CONFIG(mp->port_num)); - if (dev->flags & IFF_PROMISC) - port_config |= UNICAST_PROMISCUOUS_MODE; - else - port_config &= ~UNICAST_PROMISCUOUS_MODE; - wrl(mp, PORT_CONFIG(mp->port_num), port_config); - if (dev->flags & (IFF_PROMISC | IFF_ALLMULTI)) { - int port_num = mp->port_num; - u32 accept = 0x01010101; + int port_num; + u32 accept; + int i; +oom: + port_num = mp->port_num; + accept = 0x01010101; for (i = 0; i < 0x100; i += 4) { wrl(mp, SPECIAL_MCAST_TABLE(port_num) + i, accept); wrl(mp, OTHER_MCAST_TABLE(port_num) + i, accept); @@ -1553,28 +1573,55 @@ static void mv643xx_eth_set_rx_mode(struct net_device *dev) return; } - for (i = 0; i < 0x100; i += 4) { - wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, 0); - wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, 0); - } + mc_spec = kmalloc(0x200, GFP_KERNEL); + if (mc_spec == NULL) + goto oom; + mc_other = mc_spec + (0x100 >> 2); + + memset(mc_spec, 0, 0x100); + memset(mc_other, 0, 0x100); for (addr = dev->mc_list; addr != NULL; addr = addr->next) { u8 *a = addr->da_addr; - int table; - - if (addr->da_addrlen != 6) - continue; + u32 *table; + int entry; if (memcmp(a, "\x01\x00\x5e\x00\x00", 5) == 0) { - table = SPECIAL_MCAST_TABLE(mp->port_num); - set_filter_table_entry(mp, table, a[5]); + table = mc_spec; + entry = a[5]; } else { - int crc = addr_crc(a); - - table = OTHER_MCAST_TABLE(mp->port_num); - set_filter_table_entry(mp, table, crc); + table = mc_other; + entry = addr_crc(a); } + + table[entry >> 2] |= 1 << (entry & 3); } + + for (i = 0; i < 0x100; i += 4) { + wrl(mp, SPECIAL_MCAST_TABLE(mp->port_num) + i, mc_spec[i >> 2]); + wrl(mp, OTHER_MCAST_TABLE(mp->port_num) + i, mc_other[i >> 2]); + } + + kfree(mc_spec); +} + +static void mv643xx_eth_set_rx_mode(struct net_device *dev) +{ + mv643xx_eth_program_unicast_filter(dev); + mv643xx_eth_program_multicast_filter(dev); +} + +static int mv643xx_eth_set_mac_address(struct net_device *dev, void *addr) +{ + struct sockaddr *sa = addr; + + memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); + + netif_addr_lock_bh(dev); + mv643xx_eth_program_unicast_filter(dev); + netif_addr_unlock_bh(dev); + + return 0; } @@ -1758,26 +1805,25 @@ static int mv643xx_eth_collect_events(struct mv643xx_eth_private *mp) u32 int_cause; u32 int_cause_ext; - int_cause = rdl(mp, INT_CAUSE(mp->port_num)) & - (INT_TX_END | INT_RX | INT_EXT); + int_cause = rdlp(mp, INT_CAUSE) & (INT_TX_END | INT_RX | INT_EXT); if (int_cause == 0) return 0; int_cause_ext = 0; if (int_cause & INT_EXT) - int_cause_ext = rdl(mp, INT_CAUSE_EXT(mp->port_num)); + int_cause_ext = rdlp(mp, INT_CAUSE_EXT); int_cause &= INT_TX_END | INT_RX; if (int_cause) { - wrl(mp, INT_CAUSE(mp->port_num), ~int_cause); + wrlp(mp, INT_CAUSE, ~int_cause); mp->work_tx_end |= ((int_cause & INT_TX_END) >> 19) & - ~(rdl(mp, TXQ_COMMAND(mp->port_num)) & 0xff); + ~(rdlp(mp, TXQ_COMMAND) & 0xff); mp->work_rx |= (int_cause & INT_RX) >> 2; } int_cause_ext &= INT_EXT_LINK_PHY | INT_EXT_TX; if (int_cause_ext) { - wrl(mp, INT_CAUSE_EXT(mp->port_num), ~int_cause_ext); + wrlp(mp, INT_CAUSE_EXT, ~int_cause_ext); if (int_cause_ext & INT_EXT_LINK_PHY) mp->work_link = 1; mp->work_tx |= int_cause_ext & INT_EXT_TX; @@ -1794,7 +1840,7 @@ static irqreturn_t mv643xx_eth_irq(int irq, void *dev_id) if (unlikely(!mv643xx_eth_collect_events(mp))) return IRQ_NONE; - wrl(mp, INT_MASK(mp->port_num), 0); + wrlp(mp, INT_MASK, 0); napi_schedule(&mp->napi); return IRQ_HANDLED; @@ -1808,7 +1854,7 @@ static void handle_link_event(struct mv643xx_eth_private *mp) int duplex; int fc; - port_status = rdl(mp, PORT_STATUS(mp->port_num)); + port_status = rdlp(mp, PORT_STATUS); if (!(port_status & LINK_UP)) { if (netif_carrier_ok(dev)) { int i; @@ -1908,7 +1954,7 @@ static int mv643xx_eth_poll(struct napi_struct *napi, int budget) if (mp->work_rx_oom) mod_timer(&mp->rx_oom, jiffies + (HZ / 10)); napi_complete(napi); - wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); } return work_done; @@ -1957,17 +2003,17 @@ static void port_start(struct mv643xx_eth_private *mp) /* * Configure basic link parameters. */ - pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); + pscr = rdlp(mp, PORT_SERIAL_CONTROL); pscr |= SERIAL_PORT_ENABLE; - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + wrlp(mp, PORT_SERIAL_CONTROL, pscr); pscr |= DO_NOT_FORCE_LINK_FAIL; if (mp->phy == NULL) pscr |= FORCE_LINK_PASS; - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + wrlp(mp, PORT_SERIAL_CONTROL, pscr); - wrl(mp, SDMA_CONFIG(mp->port_num), PORT_SDMA_CONFIG_DEFAULT_VALUE); + wrlp(mp, SDMA_CONFIG, PORT_SDMA_CONFIG_DEFAULT_VALUE); /* * Configure TX path and queues. @@ -1984,31 +2030,30 @@ static void port_start(struct mv643xx_eth_private *mp) /* * Add configured unicast address to address filter table. */ - uc_addr_set(mp, mp->dev->dev_addr); + mv643xx_eth_program_unicast_filter(mp->dev); /* * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast * frames to RX queue #0, and include the pseudo-header when * calculating receive checksums. */ - wrl(mp, PORT_CONFIG(mp->port_num), 0x02000000); + wrlp(mp, PORT_CONFIG, 0x02000000); /* * Treat BPDUs as normal multicasts, and disable partition mode. */ - wrl(mp, PORT_CONFIG_EXT(mp->port_num), 0x00000000); + wrlp(mp, PORT_CONFIG_EXT, 0x00000000); /* * Enable the receive queues. */ for (i = 0; i < mp->rxq_count; i++) { struct rx_queue *rxq = mp->rxq + i; - int off = RXQ_CURRENT_DESC_PTR(mp->port_num, i); u32 addr; addr = (u32)rxq->rx_desc_dma; addr += rxq->rx_curr_desc * sizeof(struct rx_desc); - wrl(mp, off, addr); + wrlp(mp, RXQ_CURRENT_DESC_PTR(i), addr); rxq_enable(rxq); } @@ -2019,7 +2064,7 @@ static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int delay) unsigned int coal = ((mp->shared->t_clk / 1000000) * delay) / 64; u32 val; - val = rdl(mp, SDMA_CONFIG(mp->port_num)); + val = rdlp(mp, SDMA_CONFIG); if (mp->shared->extended_rx_coal_limit) { if (coal > 0xffff) coal = 0xffff; @@ -2032,7 +2077,7 @@ static void set_rx_coal(struct mv643xx_eth_private *mp, unsigned int delay) val &= ~0x003fff00; val |= (coal & 0x3fff) << 8; } - wrl(mp, SDMA_CONFIG(mp->port_num), val); + wrlp(mp, SDMA_CONFIG, val); } static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay) @@ -2041,7 +2086,7 @@ static void set_tx_coal(struct mv643xx_eth_private *mp, unsigned int delay) if (coal > 0x3fff) coal = 0x3fff; - wrl(mp, TX_FIFO_URGENT_THRESHOLD(mp->port_num), (coal & 0x3fff) << 4); + wrlp(mp, TX_FIFO_URGENT_THRESHOLD, (coal & 0x3fff) << 4); } static void mv643xx_eth_recalc_skb_size(struct mv643xx_eth_private *mp) @@ -2070,9 +2115,9 @@ static int mv643xx_eth_open(struct net_device *dev) int err; int i; - wrl(mp, INT_CAUSE(mp->port_num), 0); - wrl(mp, INT_CAUSE_EXT(mp->port_num), 0); - rdl(mp, INT_CAUSE_EXT(mp->port_num)); + wrlp(mp, INT_CAUSE, 0); + wrlp(mp, INT_CAUSE_EXT, 0); + rdlp(mp, INT_CAUSE_EXT); err = request_irq(dev->irq, mv643xx_eth_irq, IRQF_SHARED, dev->name, dev); @@ -2081,8 +2126,6 @@ static int mv643xx_eth_open(struct net_device *dev) return -EAGAIN; } - init_mac_tables(mp); - mv643xx_eth_recalc_skb_size(mp); napi_enable(&mp->napi); @@ -2121,8 +2164,8 @@ static int mv643xx_eth_open(struct net_device *dev) set_rx_coal(mp, 0); set_tx_coal(mp, 0); - wrl(mp, INT_MASK_EXT(mp->port_num), INT_EXT_LINK_PHY | INT_EXT_TX); - wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK_EXT, INT_EXT_LINK_PHY | INT_EXT_TX); + wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); return 0; @@ -2147,7 +2190,7 @@ static void port_reset(struct mv643xx_eth_private *mp) txq_disable(mp->txq + i); while (1) { - u32 ps = rdl(mp, PORT_STATUS(mp->port_num)); + u32 ps = rdlp(mp, PORT_STATUS); if ((ps & (TX_IN_PROGRESS | TX_FIFO_EMPTY)) == TX_FIFO_EMPTY) break; @@ -2155,11 +2198,11 @@ static void port_reset(struct mv643xx_eth_private *mp) } /* Reset the Enable bit in the Configuration Register */ - data = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); + data = rdlp(mp, PORT_SERIAL_CONTROL); data &= ~(SERIAL_PORT_ENABLE | DO_NOT_FORCE_LINK_FAIL | FORCE_LINK_PASS); - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), data); + wrlp(mp, PORT_SERIAL_CONTROL, data); } static int mv643xx_eth_stop(struct net_device *dev) @@ -2167,8 +2210,8 @@ static int mv643xx_eth_stop(struct net_device *dev) struct mv643xx_eth_private *mp = netdev_priv(dev); int i; - wrl(mp, INT_MASK(mp->port_num), 0x00000000); - rdl(mp, INT_MASK(mp->port_num)); + wrlp(mp, INT_MASK, 0x00000000); + rdlp(mp, INT_MASK); del_timer_sync(&mp->mib_counters_timer); @@ -2261,12 +2304,12 @@ static void mv643xx_eth_netpoll(struct net_device *dev) { struct mv643xx_eth_private *mp = netdev_priv(dev); - wrl(mp, INT_MASK(mp->port_num), 0x00000000); - rdl(mp, INT_MASK(mp->port_num)); + wrlp(mp, INT_MASK, 0x00000000); + rdlp(mp, INT_MASK); mv643xx_eth_irq(dev->irq, dev); - wrl(mp, INT_MASK(mp->port_num), INT_TX_END | INT_RX | INT_EXT); + wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT); } #endif @@ -2314,8 +2357,8 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp) * [21:8], or a 16-bit coal limit in bits [25,21:7] of the * SDMA config register. */ - writel(0x02000000, msp->base + SDMA_CONFIG(0)); - if (readl(msp->base + SDMA_CONFIG(0)) & 0x02000000) + writel(0x02000000, msp->base + 0x0400 + SDMA_CONFIG); + if (readl(msp->base + 0x0400 + SDMA_CONFIG) & 0x02000000) msp->extended_rx_coal_limit = 1; else msp->extended_rx_coal_limit = 0; @@ -2325,12 +2368,12 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp) * yes, whether its associated registers are in the old or * the new place. */ - writel(1, msp->base + TX_BW_MTU_MOVED(0)); - if (readl(msp->base + TX_BW_MTU_MOVED(0)) & 1) { + writel(1, msp->base + 0x0400 + TX_BW_MTU_MOVED); + if (readl(msp->base + 0x0400 + TX_BW_MTU_MOVED) & 1) { msp->tx_bw_control = TX_BW_CONTROL_NEW_LAYOUT; } else { - writel(7, msp->base + TX_BW_RATE(0)); - if (readl(msp->base + TX_BW_RATE(0)) & 7) + writel(7, msp->base + 0x0400 + TX_BW_RATE); + if (readl(msp->base + 0x0400 + TX_BW_RATE) & 7) msp->tx_bw_control = TX_BW_CONTROL_OLD_LAYOUT; else msp->tx_bw_control = TX_BW_CONTROL_ABSENT; @@ -2339,7 +2382,7 @@ static void infer_hw_params(struct mv643xx_eth_shared_private *msp) static int mv643xx_eth_shared_probe(struct platform_device *pdev) { - static int mv643xx_eth_version_printed = 0; + static int mv643xx_eth_version_printed; struct mv643xx_eth_shared_platform_data *pd = pdev->dev.platform_data; struct mv643xx_eth_shared_private *msp; struct resource *res; @@ -2563,10 +2606,10 @@ static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex) { u32 pscr; - pscr = rdl(mp, PORT_SERIAL_CONTROL(mp->port_num)); + pscr = rdlp(mp, PORT_SERIAL_CONTROL); if (pscr & SERIAL_PORT_ENABLE) { pscr &= ~SERIAL_PORT_ENABLE; - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + wrlp(mp, PORT_SERIAL_CONTROL, pscr); } pscr = MAX_RX_PACKET_9700BYTE | SERIAL_PORT_CONTROL_RESERVED; @@ -2584,7 +2627,7 @@ static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex) pscr |= SET_FULL_DUPLEX_MODE; } - wrl(mp, PORT_SERIAL_CONTROL(mp->port_num), pscr); + wrlp(mp, PORT_SERIAL_CONTROL, pscr); } static int mv643xx_eth_probe(struct platform_device *pdev) @@ -2593,7 +2636,6 @@ static int mv643xx_eth_probe(struct platform_device *pdev) struct mv643xx_eth_private *mp; struct net_device *dev; struct resource *res; - DECLARE_MAC_BUF(mac); int err; pd = pdev->dev.platform_data; @@ -2617,6 +2659,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) platform_set_drvdata(pdev, mp); mp->shared = platform_get_drvdata(pd->shared); + mp->base = mp->shared->base + 0x0400 + (pd->port_number << 10); mp->port_num = pd->port_number; mp->dev = dev; @@ -2664,7 +2707,7 @@ static int mv643xx_eth_probe(struct platform_device *pdev) dev->hard_start_xmit = mv643xx_eth_xmit; dev->open = mv643xx_eth_open; dev->stop = mv643xx_eth_stop; - dev->set_multicast_list = mv643xx_eth_set_rx_mode; + dev->set_rx_mode = mv643xx_eth_set_rx_mode; dev->set_mac_address = mv643xx_eth_set_mac_address; dev->do_ioctl = mv643xx_eth_ioctl; dev->change_mtu = mv643xx_eth_change_mtu; @@ -2687,8 +2730,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev) if (err) goto out; - dev_printk(KERN_NOTICE, &dev->dev, "port %d with MAC address %s\n", - mp->port_num, print_mac(mac, dev->dev_addr)); + dev_printk(KERN_NOTICE, &dev->dev, "port %d with MAC address %pM\n", + mp->port_num, dev->dev_addr); if (mp->tx_desc_sram_size > 0) dev_printk(KERN_NOTICE, &dev->dev, "configured with sram\n"); @@ -2721,8 +2764,8 @@ static void mv643xx_eth_shutdown(struct platform_device *pdev) struct mv643xx_eth_private *mp = platform_get_drvdata(pdev); /* Mask all interrupts on ethernet port */ - wrl(mp, INT_MASK(mp->port_num), 0); - rdl(mp, INT_MASK(mp->port_num)); + wrlp(mp, INT_MASK, 0); + rdlp(mp, INT_MASK); if (netif_running(mp->dev)) port_reset(mp); diff --git a/drivers/net/mvme147.c b/drivers/net/mvme147.c index 06ca4252155f40920902acae2900b76516533f0d..435e5a847c43c972cc24e9c5ab179191c113dc43 100644 --- a/drivers/net/mvme147.c +++ b/drivers/net/mvme147.c @@ -67,7 +67,6 @@ struct net_device * __init mvme147lance_probe(int unit) u_long *addr; u_long address; int err; - DECLARE_MAC_BUF(mac); if (!MACH_IS_MVME147 || called) return ERR_PTR(-ENODEV); @@ -102,11 +101,11 @@ struct net_device * __init mvme147lance_probe(int unit) dev->dev_addr[3]=address&0xff; printk("%s: MVME147 at 0x%08lx, irq %d, " - "Hardware Address %s\n", + "Hardware Address %pM\n", dev->name, dev->base_addr, MVME147_LANCE_IRQ, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); - lp = (struct m147lance_private *)dev->priv; + lp = netdev_priv(dev); lp->ram = __get_dma_pages(GFP_ATOMIC, 3); /* 16K */ if (!lp->ram) { @@ -190,7 +189,7 @@ int __init init_module(void) void __exit cleanup_module(void) { - struct m147lance_private *lp = dev_mvme147_lance->priv; + struct m147lance_private *lp = netdev_priv(dev_mvme147_lance); unregister_netdev(dev_mvme147_lance); free_pages(lp->ram, 3); free_netdev(dev_mvme147_lance); diff --git a/drivers/net/myri10ge/myri10ge.c b/drivers/net/myri10ge/myri10ge.c index b3786709730811c2b6467cabda06c55d2203ddb1..5e70180bf5693bdf0096164c8bb26b9bf23d3634 100644 --- a/drivers/net/myri10ge/myri10ge.c +++ b/drivers/net/myri10ge/myri10ge.c @@ -75,7 +75,7 @@ #include "myri10ge_mcp.h" #include "myri10ge_mcp_gen_header.h" -#define MYRI10GE_VERSION_STR "1.4.3-1.378" +#define MYRI10GE_VERSION_STR "1.4.4-1.395" MODULE_DESCRIPTION("Myricom 10G driver (10GbE)"); MODULE_AUTHOR("Maintainer: help@myri.com"); @@ -1024,7 +1024,7 @@ static int myri10ge_reset(struct myri10ge_priv *mgp) ss->dca_tag = NULL; } } -#endif /* CONFIG_DCA */ +#endif /* CONFIG_MYRI10GE_DCA */ /* reset mcp/driver shared state back to 0 */ @@ -1121,7 +1121,7 @@ static int myri10ge_notify_dca_device(struct device *dev, void *data) myri10ge_teardown_dca(mgp); return 0; } -#endif /* CONFIG_DCA */ +#endif /* CONFIG_MYRI10GE_DCA */ static inline void myri10ge_submit_8rx(struct mcp_kreq_ether_recv __iomem * dst, @@ -1309,7 +1309,7 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, skb = netdev_alloc_skb(dev, MYRI10GE_HLEN + 16); if (unlikely(skb == NULL)) { - mgp->stats.rx_dropped++; + ss->stats.rx_dropped++; do { i--; put_page(rx_frags[i].page); @@ -1334,7 +1334,6 @@ myri10ge_rx_done(struct myri10ge_slice_state *ss, struct myri10ge_rx_buf *rx, myri10ge_vlan_ip_csum(skb, csum); } netif_receive_skb(skb); - dev->last_rx = jiffies; return 1; } @@ -1504,7 +1503,6 @@ static int myri10ge_poll(struct napi_struct *napi, int budget) { struct myri10ge_slice_state *ss = container_of(napi, struct myri10ge_slice_state, napi); - struct net_device *netdev = ss->mgp->dev; int work_done; #ifdef CONFIG_MYRI10GE_DCA @@ -1516,7 +1514,7 @@ static int myri10ge_poll(struct napi_struct *napi, int budget) work_done = myri10ge_clean_rx_done(ss, budget); if (work_done < budget) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); put_be32(htonl(3), ss->irq_claim); } return work_done; @@ -1534,7 +1532,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) /* an interrupt on a non-zero receive-only slice is implicitly * valid since MSI-X irqs are not shared */ if ((mgp->dev->real_num_tx_queues == 1) && (ss != mgp->ss)) { - netif_rx_schedule(ss->dev, &ss->napi); + netif_rx_schedule(&ss->napi); return (IRQ_HANDLED); } @@ -1545,7 +1543,7 @@ static irqreturn_t myri10ge_intr(int irq, void *arg) /* low bit indicates receives are present, so schedule * napi poll handler */ if (stats->valid & 1) - netif_rx_schedule(ss->dev, &ss->napi); + netif_rx_schedule(&ss->napi); if (!mgp->msi_enabled && !mgp->msix_enabled) { put_be32(0, mgp->irq_deassert); @@ -2230,6 +2228,8 @@ myri10ge_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr, *ip_hdr = iph; if (iph->protocol != IPPROTO_TCP) return -1; + if (iph->frag_off & htons(IP_MF | IP_OFFSET)) + return -1; *hdr_flags |= LRO_TCP; *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2); @@ -2927,6 +2927,7 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) { struct sk_buff *segs, *curr; struct myri10ge_priv *mgp = netdev_priv(dev); + struct myri10ge_slice_state *ss; int status; segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO6); @@ -2953,8 +2954,9 @@ static int myri10ge_sw_tso(struct sk_buff *skb, struct net_device *dev) return 0; drop: + ss = &mgp->ss[skb_get_queue_mapping(skb)]; dev_kfree_skb_any(skb); - mgp->stats.tx_dropped += 1; + ss->stats.tx_dropped += 1; return 0; } @@ -2985,7 +2987,6 @@ static void myri10ge_set_multicast_list(struct net_device *dev) struct dev_mc_list *mc_list; __be32 data[2] = { 0, 0 }; int err; - DECLARE_MAC_BUF(mac); /* can be called from atomic contexts, * pass 1 to force atomicity in myri10ge_send_cmd() */ @@ -3032,8 +3033,7 @@ static void myri10ge_set_multicast_list(struct net_device *dev) printk(KERN_ERR "myri10ge: %s: Failed " "MXGEFW_JOIN_MULTICAST_GROUP, error status:" "%d\t", dev->name, err); - printk(KERN_ERR "MAC %s\n", - print_mac(mac, mc_list->dmi_addr)); + printk(KERN_ERR "MAC %pM\n", mc_list->dmi_addr); goto abort; } } @@ -3732,6 +3732,17 @@ abort_with_fw: myri10ge_load_firmware(mgp, 0); } +static const struct net_device_ops myri10ge_netdev_ops = { + .ndo_open = myri10ge_open, + .ndo_stop = myri10ge_close, + .ndo_start_xmit = myri10ge_xmit, + .ndo_get_stats = myri10ge_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = myri10ge_change_mtu, + .ndo_set_multicast_list = myri10ge_set_multicast_list, + .ndo_set_mac_address = myri10ge_set_mac_address, +}; + static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { struct net_device *netdev; @@ -3740,6 +3751,7 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) int i; int status = -ENXIO; int dac_enabled; + unsigned hdr_offset, ss_offset; netdev = alloc_etherdev_mq(sizeof(*mgp), MYRI10GE_MAX_SLICES); if (netdev == NULL) { @@ -3807,14 +3819,6 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) if (mgp->mtrr >= 0) mgp->wc_enabled = 1; #endif - /* Hack. need to get rid of these magic numbers */ - mgp->sram_size = - 2 * 1024 * 1024 - (2 * (48 * 1024) + (32 * 1024)) - 0x100; - if (mgp->sram_size > mgp->board_span) { - dev_err(&pdev->dev, "board span %ld bytes too small\n", - mgp->board_span); - goto abort_with_mtrr; - } mgp->sram = ioremap_wc(mgp->iomem_base, mgp->board_span); if (mgp->sram == NULL) { dev_err(&pdev->dev, "ioremap failed for %ld bytes at 0x%lx\n", @@ -3822,9 +3826,19 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) status = -ENXIO; goto abort_with_mtrr; } + hdr_offset = + ntohl(__raw_readl(mgp->sram + MCP_HEADER_PTR_OFFSET)) & 0xffffc; + ss_offset = hdr_offset + offsetof(struct mcp_gen_header, string_specs); + mgp->sram_size = ntohl(__raw_readl(mgp->sram + ss_offset)); + if (mgp->sram_size > mgp->board_span || + mgp->sram_size <= MYRI10GE_FW_OFFSET) { + dev_err(&pdev->dev, + "invalid sram_size %dB or board span %ldB\n", + mgp->sram_size, mgp->board_span); + goto abort_with_ioremap; + } memcpy_fromio(mgp->eeprom_strings, - mgp->sram + mgp->sram_size - MYRI10GE_EEPROM_STRINGS_SIZE, - MYRI10GE_EEPROM_STRINGS_SIZE); + mgp->sram + mgp->sram_size, MYRI10GE_EEPROM_STRINGS_SIZE); memset(mgp->eeprom_strings + MYRI10GE_EEPROM_STRINGS_SIZE - 2, 0, 2); status = myri10ge_read_mac_addr(mgp); if (status) @@ -3860,15 +3874,10 @@ static int myri10ge_probe(struct pci_dev *pdev, const struct pci_device_id *ent) myri10ge_initial_mtu = MYRI10GE_MAX_ETHER_MTU - ETH_HLEN; if ((myri10ge_initial_mtu + ETH_HLEN) < 68) myri10ge_initial_mtu = 68; + + netdev->netdev_ops = &myri10ge_netdev_ops; netdev->mtu = myri10ge_initial_mtu; - netdev->open = myri10ge_open; - netdev->stop = myri10ge_close; - netdev->hard_start_xmit = myri10ge_xmit; - netdev->get_stats = myri10ge_get_stats; netdev->base_addr = mgp->iomem_base; - netdev->change_mtu = myri10ge_change_mtu; - netdev->set_multicast_list = myri10ge_set_multicast_list; - netdev->set_mac_address = myri10ge_set_mac_address; netdev->features = mgp->features; if (dac_enabled) @@ -4019,7 +4028,7 @@ static struct notifier_block myri10ge_dca_notifier = { .next = NULL, .priority = 0, }; -#endif /* CONFIG_DCA */ +#endif /* CONFIG_MYRI10GE_DCA */ static __init int myri10ge_init_module(void) { diff --git a/drivers/net/myri10ge/myri10ge_mcp.h b/drivers/net/myri10ge/myri10ge_mcp.h index 993721090777d62004b20686a6136095f6169f2f..11be150e4d67fc1cb70906535a9356dd38051ee6 100644 --- a/drivers/net/myri10ge/myri10ge_mcp.h +++ b/drivers/net/myri10ge/myri10ge_mcp.h @@ -111,61 +111,61 @@ enum myri10ge_mcp_cmd_type { MXGEFW_CMD_NONE = 0, /* Reset the mcp, it is left in a safe state, waiting * for the driver to set all its parameters */ - MXGEFW_CMD_RESET, + MXGEFW_CMD_RESET = 1, /* get the version number of the current firmware.. * (may be available in the eeprom strings..? */ - MXGEFW_GET_MCP_VERSION, + MXGEFW_GET_MCP_VERSION = 2, /* Parameters which must be set by the driver before it can * issue MXGEFW_CMD_ETHERNET_UP. They persist until the next * MXGEFW_CMD_RESET is issued */ - MXGEFW_CMD_SET_INTRQ_DMA, + MXGEFW_CMD_SET_INTRQ_DMA = 3, /* data0 = LSW of the host address * data1 = MSW of the host address * data2 = slice number if multiple slices are used */ - MXGEFW_CMD_SET_BIG_BUFFER_SIZE, /* in bytes, power of 2 */ - MXGEFW_CMD_SET_SMALL_BUFFER_SIZE, /* in bytes */ + MXGEFW_CMD_SET_BIG_BUFFER_SIZE = 4, /* in bytes, power of 2 */ + MXGEFW_CMD_SET_SMALL_BUFFER_SIZE = 5, /* in bytes */ /* Parameters which refer to lanai SRAM addresses where the * driver must issue PIO writes for various things */ - MXGEFW_CMD_GET_SEND_OFFSET, - MXGEFW_CMD_GET_SMALL_RX_OFFSET, - MXGEFW_CMD_GET_BIG_RX_OFFSET, + MXGEFW_CMD_GET_SEND_OFFSET = 6, + MXGEFW_CMD_GET_SMALL_RX_OFFSET = 7, + MXGEFW_CMD_GET_BIG_RX_OFFSET = 8, /* data0 = slice number if multiple slices are used */ - MXGEFW_CMD_GET_IRQ_ACK_OFFSET, - MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET, + MXGEFW_CMD_GET_IRQ_ACK_OFFSET = 9, + MXGEFW_CMD_GET_IRQ_DEASSERT_OFFSET = 10, /* Parameters which refer to rings stored on the MCP, * and whose size is controlled by the mcp */ - MXGEFW_CMD_GET_SEND_RING_SIZE, /* in bytes */ - MXGEFW_CMD_GET_RX_RING_SIZE, /* in bytes */ + MXGEFW_CMD_GET_SEND_RING_SIZE = 11, /* in bytes */ + MXGEFW_CMD_GET_RX_RING_SIZE = 12, /* in bytes */ /* Parameters which refer to rings stored in the host, * and whose size is controlled by the host. Note that * all must be physically contiguous and must contain * a power of 2 number of entries. */ - MXGEFW_CMD_SET_INTRQ_SIZE, /* in bytes */ + MXGEFW_CMD_SET_INTRQ_SIZE = 13, /* in bytes */ #define MXGEFW_CMD_SET_INTRQ_SIZE_FLAG_NO_STRICT_SIZE_CHECK (1 << 31) /* command to bring ethernet interface up. Above parameters * (plus mtu & mac address) must have been exchanged prior * to issuing this command */ - MXGEFW_CMD_ETHERNET_UP, + MXGEFW_CMD_ETHERNET_UP = 14, /* command to bring ethernet interface down. No further sends * or receives may be processed until an MXGEFW_CMD_ETHERNET_UP * is issued, and all interrupt queues must be flushed prior * to ack'ing this command */ - MXGEFW_CMD_ETHERNET_DOWN, + MXGEFW_CMD_ETHERNET_DOWN = 15, /* commands the driver may issue live, without resetting * the nic. Note that increasing the mtu "live" should @@ -173,40 +173,40 @@ enum myri10ge_mcp_cmd_type { * sufficiently large to handle the new mtu. Decreasing * the mtu live is safe */ - MXGEFW_CMD_SET_MTU, - MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET, /* in microseconds */ - MXGEFW_CMD_SET_STATS_INTERVAL, /* in microseconds */ - MXGEFW_CMD_SET_STATS_DMA_OBSOLETE, /* replaced by SET_STATS_DMA_V2 */ + MXGEFW_CMD_SET_MTU = 16, + MXGEFW_CMD_GET_INTR_COAL_DELAY_OFFSET = 17, /* in microseconds */ + MXGEFW_CMD_SET_STATS_INTERVAL = 18, /* in microseconds */ + MXGEFW_CMD_SET_STATS_DMA_OBSOLETE = 19, /* replaced by SET_STATS_DMA_V2 */ - MXGEFW_ENABLE_PROMISC, - MXGEFW_DISABLE_PROMISC, - MXGEFW_SET_MAC_ADDRESS, + MXGEFW_ENABLE_PROMISC = 20, + MXGEFW_DISABLE_PROMISC = 21, + MXGEFW_SET_MAC_ADDRESS = 22, - MXGEFW_ENABLE_FLOW_CONTROL, - MXGEFW_DISABLE_FLOW_CONTROL, + MXGEFW_ENABLE_FLOW_CONTROL = 23, + MXGEFW_DISABLE_FLOW_CONTROL = 24, /* do a DMA test * data0,data1 = DMA address * data2 = RDMA length (MSH), WDMA length (LSH) * command return data = repetitions (MSH), 0.5-ms ticks (LSH) */ - MXGEFW_DMA_TEST, + MXGEFW_DMA_TEST = 25, - MXGEFW_ENABLE_ALLMULTI, - MXGEFW_DISABLE_ALLMULTI, + MXGEFW_ENABLE_ALLMULTI = 26, + MXGEFW_DISABLE_ALLMULTI = 27, /* returns MXGEFW_CMD_ERROR_MULTICAST * if there is no room in the cache * data0,MSH(data1) = multicast group address */ - MXGEFW_JOIN_MULTICAST_GROUP, + MXGEFW_JOIN_MULTICAST_GROUP = 28, /* returns MXGEFW_CMD_ERROR_MULTICAST * if the address is not in the cache, * or is equal to FF-FF-FF-FF-FF-FF * data0,MSH(data1) = multicast group address */ - MXGEFW_LEAVE_MULTICAST_GROUP, - MXGEFW_LEAVE_ALL_MULTICAST_GROUPS, + MXGEFW_LEAVE_MULTICAST_GROUP = 29, + MXGEFW_LEAVE_ALL_MULTICAST_GROUPS = 30, - MXGEFW_CMD_SET_STATS_DMA_V2, + MXGEFW_CMD_SET_STATS_DMA_V2 = 31, /* data0, data1 = bus addr, * data2 = sizeof(struct mcp_irq_data) from driver point of view, allows * adding new stuff to mcp_irq_data without changing the ABI @@ -216,14 +216,14 @@ enum myri10ge_mcp_cmd_type { * (in the upper 16 bits). */ - MXGEFW_CMD_UNALIGNED_TEST, + MXGEFW_CMD_UNALIGNED_TEST = 32, /* same than DMA_TEST (same args) but abort with UNALIGNED on unaligned * chipset */ - MXGEFW_CMD_UNALIGNED_STATUS, + MXGEFW_CMD_UNALIGNED_STATUS = 33, /* return data = boolean, true if the chipset is known to be unaligned */ - MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS, + MXGEFW_CMD_ALWAYS_USE_N_BIG_BUFFERS = 34, /* data0 = number of big buffers to use. It must be 0 or a power of 2. * 0 indicates that the NIC consumes as many buffers as they are required * for packet. This is the default behavior. @@ -233,8 +233,8 @@ enum myri10ge_mcp_cmd_type { * the NIC to be able to receive maximum-sized packets. */ - MXGEFW_CMD_GET_MAX_RSS_QUEUES, - MXGEFW_CMD_ENABLE_RSS_QUEUES, + MXGEFW_CMD_GET_MAX_RSS_QUEUES = 35, + MXGEFW_CMD_ENABLE_RSS_QUEUES = 36, /* data0 = number of slices n (0, 1, ..., n-1) to enable * data1 = interrupt mode | use of multiple transmit queues. * 0=share one INTx/MSI. @@ -249,18 +249,18 @@ enum myri10ge_mcp_cmd_type { #define MXGEFW_SLICE_INTR_MODE_ONE_PER_SLICE 0x1 #define MXGEFW_SLICE_ENABLE_MULTIPLE_TX_QUEUES 0x2 - MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET, - MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA, + MXGEFW_CMD_GET_RSS_SHARED_INTERRUPT_MASK_OFFSET = 37, + MXGEFW_CMD_SET_RSS_SHARED_INTERRUPT_DMA = 38, /* data0, data1 = bus address lsw, msw */ - MXGEFW_CMD_GET_RSS_TABLE_OFFSET, + MXGEFW_CMD_GET_RSS_TABLE_OFFSET = 39, /* get the offset of the indirection table */ - MXGEFW_CMD_SET_RSS_TABLE_SIZE, + MXGEFW_CMD_SET_RSS_TABLE_SIZE = 40, /* set the size of the indirection table */ - MXGEFW_CMD_GET_RSS_KEY_OFFSET, + MXGEFW_CMD_GET_RSS_KEY_OFFSET = 41, /* get the offset of the secret key */ - MXGEFW_CMD_RSS_KEY_UPDATED, + MXGEFW_CMD_RSS_KEY_UPDATED = 42, /* tell nic that the secret key's been updated */ - MXGEFW_CMD_SET_RSS_ENABLE, + MXGEFW_CMD_SET_RSS_ENABLE = 43, /* data0 = enable/disable rss * 0: disable rss. nic does not distribute receive packets. * 1: enable rss. nic distributes receive packets among queues. @@ -277,7 +277,7 @@ enum myri10ge_mcp_cmd_type { #define MXGEFW_RSS_HASH_TYPE_SRC_DST_PORT 0x5 #define MXGEFW_RSS_HASH_TYPE_MAX 0x5 - MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE, + MXGEFW_CMD_GET_MAX_TSO6_HDR_SIZE = 44, /* Return data = the max. size of the entire headers of a IPv6 TSO packet. * If the header size of a IPv6 TSO packet is larger than the specified * value, then the driver must not use TSO. @@ -286,7 +286,7 @@ enum myri10ge_mcp_cmd_type { * always has enough header buffer to store maximum-sized headers. */ - MXGEFW_CMD_SET_TSO_MODE, + MXGEFW_CMD_SET_TSO_MODE = 45, /* data0 = TSO mode. * 0: Linux/FreeBSD style (NIC default) * 1: NDIS/NetBSD style @@ -294,33 +294,37 @@ enum myri10ge_mcp_cmd_type { #define MXGEFW_TSO_MODE_LINUX 0 #define MXGEFW_TSO_MODE_NDIS 1 - MXGEFW_CMD_MDIO_READ, + MXGEFW_CMD_MDIO_READ = 46, /* data0 = dev_addr (PMA/PMD or PCS ...), data1 = register/addr */ - MXGEFW_CMD_MDIO_WRITE, + MXGEFW_CMD_MDIO_WRITE = 47, /* data0 = dev_addr, data1 = register/addr, data2 = value */ - MXGEFW_CMD_XFP_I2C_READ, - /* Starts to get a fresh copy of one byte or of the whole xfp i2c table, the + MXGEFW_CMD_I2C_READ = 48, + /* Starts to get a fresh copy of one byte or of the module i2c table, the * obtained data is cached inside the xaui-xfi chip : - * data0 : "all" flag : 0 => get one byte, 1=> get 256 bytes, - * data1 : if (data0 == 0): index of byte to refresh [ not used otherwise ] + * data0 : 0 => get one byte, 1=> get 256 bytes + * data1 : If data0 == 0: location to refresh + * bit 7:0 register location + * bit 8:15 is the i2c slave addr (0 is interpreted as 0xA1) + * bit 23:16 is the i2c bus number (for multi-port NICs) + * If data0 == 1: unused * The operation might take ~1ms for a single byte or ~65ms when refreshing all 256 bytes - * During the i2c operation, MXGEFW_CMD_XFP_I2C_READ or MXGEFW_CMD_XFP_BYTE attempts + * During the i2c operation, MXGEFW_CMD_I2C_READ or MXGEFW_CMD_I2C_BYTE attempts * will return MXGEFW_CMD_ERROR_BUSY */ - MXGEFW_CMD_XFP_BYTE, + MXGEFW_CMD_I2C_BYTE = 49, /* Return the last obtained copy of a given byte in the xfp i2c table - * (copy cached during the last relevant MXGEFW_CMD_XFP_I2C_READ) + * (copy cached during the last relevant MXGEFW_CMD_I2C_READ) * data0 : index of the desired table entry * Return data = the byte stored at the requested index in the table */ - MXGEFW_CMD_GET_VPUMP_OFFSET, + MXGEFW_CMD_GET_VPUMP_OFFSET = 50, /* Return data = NIC memory offset of mcp_vpump_public_global */ - MXGEFW_CMD_RESET_VPUMP, + MXGEFW_CMD_RESET_VPUMP = 51, /* Resets the VPUMP state */ - MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE, + MXGEFW_CMD_SET_RSS_MCP_SLOT_TYPE = 52, /* data0 = mcp_slot type to use. * 0 = the default 4B mcp_slot * 1 = 8B mcp_slot_8 @@ -328,7 +332,7 @@ enum myri10ge_mcp_cmd_type { #define MXGEFW_RSS_MCP_SLOT_TYPE_MIN 0 #define MXGEFW_RSS_MCP_SLOT_TYPE_WITH_HASH 1 - MXGEFW_CMD_SET_THROTTLE_FACTOR, + MXGEFW_CMD_SET_THROTTLE_FACTOR = 53, /* set the throttle factor for ethp_z8e * data0 = throttle_factor * throttle_factor = 256 * pcie-raw-speed / tx_speed @@ -344,45 +348,50 @@ enum myri10ge_mcp_cmd_type { * with tx_boundary == 4096, max-throttle-factor == 4095 => min-speed == 1Gb/s */ - MXGEFW_CMD_VPUMP_UP, + MXGEFW_CMD_VPUMP_UP = 54, /* Allocates VPump Connection, Send Request and Zero copy buffer address tables */ - MXGEFW_CMD_GET_VPUMP_CLK, + MXGEFW_CMD_GET_VPUMP_CLK = 55, /* Get the lanai clock */ - MXGEFW_CMD_GET_DCA_OFFSET, + MXGEFW_CMD_GET_DCA_OFFSET = 56, /* offset of dca control for WDMAs */ /* VMWare NetQueue commands */ - MXGEFW_CMD_NETQ_GET_FILTERS_PER_QUEUE, - MXGEFW_CMD_NETQ_ADD_FILTER, + MXGEFW_CMD_NETQ_GET_FILTERS_PER_QUEUE = 57, + MXGEFW_CMD_NETQ_ADD_FILTER = 58, /* data0 = filter_id << 16 | queue << 8 | type */ /* data1 = MS4 of MAC Addr */ /* data2 = LS2_MAC << 16 | VLAN_tag */ - MXGEFW_CMD_NETQ_DEL_FILTER, + MXGEFW_CMD_NETQ_DEL_FILTER = 59, /* data0 = filter_id */ - MXGEFW_CMD_NETQ_QUERY1, - MXGEFW_CMD_NETQ_QUERY2, - MXGEFW_CMD_NETQ_QUERY3, - MXGEFW_CMD_NETQ_QUERY4, - + MXGEFW_CMD_NETQ_QUERY1 = 60, + MXGEFW_CMD_NETQ_QUERY2 = 61, + MXGEFW_CMD_NETQ_QUERY3 = 62, + MXGEFW_CMD_NETQ_QUERY4 = 63, + + MXGEFW_CMD_RELAX_RXBUFFER_ALIGNMENT = 64, + /* When set, small receive buffers can cross page boundaries. + * Both small and big receive buffers may start at any address. + * This option has performance implications, so use with caution. + */ }; enum myri10ge_mcp_cmd_status { MXGEFW_CMD_OK = 0, - MXGEFW_CMD_UNKNOWN, - MXGEFW_CMD_ERROR_RANGE, - MXGEFW_CMD_ERROR_BUSY, - MXGEFW_CMD_ERROR_EMPTY, - MXGEFW_CMD_ERROR_CLOSED, - MXGEFW_CMD_ERROR_HASH_ERROR, - MXGEFW_CMD_ERROR_BAD_PORT, - MXGEFW_CMD_ERROR_RESOURCES, - MXGEFW_CMD_ERROR_MULTICAST, - MXGEFW_CMD_ERROR_UNALIGNED, - MXGEFW_CMD_ERROR_NO_MDIO, - MXGEFW_CMD_ERROR_XFP_FAILURE, - MXGEFW_CMD_ERROR_XFP_ABSENT, - MXGEFW_CMD_ERROR_BAD_PCIE_LINK + MXGEFW_CMD_UNKNOWN = 1, + MXGEFW_CMD_ERROR_RANGE = 2, + MXGEFW_CMD_ERROR_BUSY = 3, + MXGEFW_CMD_ERROR_EMPTY = 4, + MXGEFW_CMD_ERROR_CLOSED = 5, + MXGEFW_CMD_ERROR_HASH_ERROR = 6, + MXGEFW_CMD_ERROR_BAD_PORT = 7, + MXGEFW_CMD_ERROR_RESOURCES = 8, + MXGEFW_CMD_ERROR_MULTICAST = 9, + MXGEFW_CMD_ERROR_UNALIGNED = 10, + MXGEFW_CMD_ERROR_NO_MDIO = 11, + MXGEFW_CMD_ERROR_I2C_FAILURE = 12, + MXGEFW_CMD_ERROR_I2C_ABSENT = 13, + MXGEFW_CMD_ERROR_BAD_PCIE_LINK = 14 }; #define MXGEFW_OLD_IRQ_DATA_LEN 40 diff --git a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h index a8662ea8079a6fdebc44a28d9b22ee5702e7c578..caa6cbbb631e557fa4074be08b4dac212f00a1aa 100644 --- a/drivers/net/myri10ge/myri10ge_mcp_gen_header.h +++ b/drivers/net/myri10ge/myri10ge_mcp_gen_header.h @@ -41,6 +41,8 @@ struct mcp_gen_header { unsigned short handoff_id_major; /* must be equal */ unsigned short handoff_id_caps; /* bitfield: new mcp must have superset */ unsigned msix_table_addr; /* start address of msix table in firmware */ + unsigned bss_addr; /* start of bss */ + unsigned features; /* 8 */ }; diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c index 3ad7589d6a1c36b341920e6a2c4548d34de3ff92..899ed065a1478dc7ef4303b445285954776eb282 100644 --- a/drivers/net/myri_sbus.c +++ b/drivers/net/myri_sbus.c @@ -318,13 +318,10 @@ static void myri_is_not_so_happy(struct myri_eth *mp) #ifdef DEBUG_HEADER static void dump_ehdr(struct ethhdr *ehdr) { - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - printk("ehdr[h_dst(%s)" - "h_source(%s)" + printk("ehdr[h_dst(%pM)" + "h_source(%pM)" "h_proto(%04x)]\n", - print_mac(mac, ehdr->h_dest), print_mac(mac2, ehdr->h_source), - ehdr->h_proto); + ehdr->h_dest, ehdr->h_source, ehdr->h_proto); } static void dump_ehdr_and_myripad(unsigned char *stuff) @@ -528,7 +525,6 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) DRX(("prot[%04x] netif_rx ", skb->protocol)); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; next: @@ -540,7 +536,7 @@ static void myri_rx(struct myri_eth *mp, struct net_device *dev) static irqreturn_t myri_interrupt(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct myri_eth *mp = (struct myri_eth *) dev->priv; + struct myri_eth *mp = netdev_priv(dev); void __iomem *lregs = mp->lregs; struct myri_channel __iomem *chan = &mp->shmem->channel; unsigned long flags; @@ -579,14 +575,14 @@ static irqreturn_t myri_interrupt(int irq, void *dev_id) static int myri_open(struct net_device *dev) { - struct myri_eth *mp = (struct myri_eth *) dev->priv; + struct myri_eth *mp = netdev_priv(dev); return myri_init(mp, in_interrupt()); } static int myri_close(struct net_device *dev) { - struct myri_eth *mp = (struct myri_eth *) dev->priv; + struct myri_eth *mp = netdev_priv(dev); myri_clean_rings(mp); return 0; @@ -594,7 +590,7 @@ static int myri_close(struct net_device *dev) static void myri_tx_timeout(struct net_device *dev) { - struct myri_eth *mp = (struct myri_eth *) dev->priv; + struct myri_eth *mp = netdev_priv(dev); printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); @@ -605,7 +601,7 @@ static void myri_tx_timeout(struct net_device *dev) static int myri_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct myri_eth *mp = (struct myri_eth *) dev->priv; + struct myri_eth *mp = netdev_priv(dev); struct sendq __iomem *sq = mp->sq; struct myri_txd __iomem *txd; unsigned long flags; @@ -905,7 +901,6 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic struct device_node *dp = op->node; static unsigned version_printed; struct net_device *dev; - DECLARE_MAC_BUF(mac); struct myri_eth *mp; const void *prop; static int num; @@ -1088,15 +1083,15 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic num++; - printk("%s: MyriCOM MyriNET Ethernet %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: MyriCOM MyriNET Ethernet %pM\n", + dev->name, dev->dev_addr); return 0; err_free_irq: free_irq(dev->irq, dev); err: - /* This will also free the co-allocated 'dev->priv' */ + /* This will also free the co-allocated private data*/ free_netdev(dev); return -ENODEV; } diff --git a/drivers/net/natsemi.c b/drivers/net/natsemi.c index f7fa3944659bab47cac4e516c104dad5fd58890d..478edb92bca35581509f80a7709354c00a2f3d17 100644 --- a/drivers/net/natsemi.c +++ b/drivers/net/natsemi.c @@ -792,7 +792,6 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, const int pcibar = 1; /* PCI base address register */ int prev_eedata; u32 tmp; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -948,10 +947,10 @@ static int __devinit natsemi_probe1 (struct pci_dev *pdev, if (netif_msg_drv(np)) { printk(KERN_INFO "natsemi %s: %s at %#08llx " - "(%s), %s, IRQ %d", + "(%s), %pM, IRQ %d", dev->name, natsemi_pci_info[chip_idx].name, (unsigned long long)iostart, pci_name(np->pci_dev), - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); if (dev->if_port == PORT_TP) printk(", port TP.\n"); else if (np->ignore_phy) @@ -2194,10 +2193,10 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]); - if (netif_rx_schedule_prep(dev, &np->napi)) { + if (netif_rx_schedule_prep(&np->napi)) { /* Disable interrupts and register for poll */ natsemi_irq_disable(dev); - __netif_rx_schedule(dev, &np->napi); + __netif_rx_schedule(&np->napi); } else printk(KERN_WARNING "%s: Ignoring interrupt, status %#08x, mask %#08x.\n", @@ -2249,7 +2248,7 @@ static int natsemi_poll(struct napi_struct *napi, int budget) np->intr_status = readl(ioaddr + IntrStatus); } while (np->intr_status); - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /* Reenable interrupts providing nothing is trying to shut * the chip down. */ @@ -2362,7 +2361,6 @@ static void netdev_rx(struct net_device *dev, int *work_done, int work_to_do) } skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/ne-h8300.c b/drivers/net/ne-h8300.c index fbc7531d3c7d8aed647056c905e4aa74a476b0e8..b57239171046a50cc04ff11d3682af1a42990e34 100644 --- a/drivers/net/ne-h8300.c +++ b/drivers/net/ne-h8300.c @@ -167,7 +167,7 @@ static void cleanup_card(struct net_device *dev) #ifndef MODULE struct net_device * __init ne_probe(int unit) { - struct net_device *dev = ____alloc_ei_netdev(0); + struct net_device *dev = alloc_ei_netdev(); int err; if (!dev) @@ -193,6 +193,21 @@ out: } #endif +static const struct net_device_ops ne_netdev_ops = { + .ndo_open = ne_open, + .ndo_stop = ne_close, + + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init ne_probe1(struct net_device *dev, int ioaddr) { int i; @@ -204,7 +219,6 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) static unsigned version_printed; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); unsigned char bus_width; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -299,7 +313,7 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - printk(" %s\n", print_mac(mac, dev->dev_addr)); + printk(" %pM\n", dev->dev_addr); printk("%s: %s found at %#x, using IRQ %d.\n", dev->name, name, ioaddr, dev->irq); @@ -320,11 +334,9 @@ static int __init ne_probe1(struct net_device *dev, int ioaddr) ei_status.block_output = &ne_block_output; ei_status.get_8390_hdr = &ne_get_8390_hdr; ei_status.priv = 0; - dev->open = &ne_open; - dev->stop = &ne_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = __ei_poll; -#endif + + dev->netdev_ops = &ne_netdev_ops; + __NS8390_init(dev, 0); ret = register_netdev(dev); @@ -625,7 +637,7 @@ int init_module(void) int err; for (this_dev = 0; this_dev < MAX_NE_CARDS; this_dev++) { - struct net_device *dev = ____alloc_ei_netdev(0); + struct net_device *dev = alloc_ei_netdev(); if (!dev) break; if (io[this_dev]) { diff --git a/drivers/net/ne.c b/drivers/net/ne.c index eb681c0d51ba1ef61b7537bd6974a9413eabf66e..5c3e242428f11a1b5ff2e98a782614031d00a9cf 100644 --- a/drivers/net/ne.c +++ b/drivers/net/ne.c @@ -174,9 +174,6 @@ bad_clone_list[] __initdata = { static int ne_probe1(struct net_device *dev, unsigned long ioaddr); static int ne_probe_isapnp(struct net_device *dev); -static int ne_open(struct net_device *dev); -static int ne_close(struct net_device *dev); - static void ne_reset_8390(struct net_device *dev); static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -297,7 +294,6 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) int neX000, ctron, copam, bad_card; int reg0, ret; static unsigned version_printed; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, NE_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -517,7 +513,7 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) } #endif - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); ei_status.name = name; ei_status.tx_start_page = start_page; @@ -537,11 +533,8 @@ static int __init ne_probe1(struct net_device *dev, unsigned long ioaddr) ei_status.block_output = &ne_block_output; ei_status.get_8390_hdr = &ne_get_8390_hdr; ei_status.priv = 0; - dev->open = &ne_open; - dev->stop = &ne_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = eip_poll; -#endif + + dev->netdev_ops = &eip_netdev_ops; NS8390p_init(dev, 0); ret = register_netdev(dev); @@ -558,20 +551,6 @@ err_out: return ret; } -static int ne_open(struct net_device *dev) -{ - eip_open(dev); - return 0; -} - -static int ne_close(struct net_device *dev) -{ - if (ei_debug > 1) - printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); - eip_close(dev); - return 0; -} - /* Hard reset the card. This used to pause for the same period that a 8390 reset command required, but that shouldn't be necessary. */ @@ -950,7 +929,7 @@ static void __init ne_add_devices(void) } #ifdef MODULE -int __init init_module() +int __init init_module(void) { int retval; ne_add_devices(); diff --git a/drivers/net/ne2.c b/drivers/net/ne2.c index 332df75a9ab66a06eb150ede9662d2f843807c0f..a53bb201d3c7612f92ba6015fbfd4ae15726ae32 100644 --- a/drivers/net/ne2.c +++ b/drivers/net/ne2.c @@ -137,9 +137,6 @@ extern int netcard_probe(struct net_device *dev); static int ne2_probe1(struct net_device *dev, int slot); -static int ne_open(struct net_device *dev); -static int ne_close(struct net_device *dev); - static void ne_reset_8390(struct net_device *dev); static void ne_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -302,7 +299,6 @@ out: static int ne2_procinfo(char *buf, int slot, struct net_device *dev) { int len=0; - DECLARE_MAC_BUF(mac); len += sprintf(buf+len, "The NE/2 Ethernet Adapter\n" ); len += sprintf(buf+len, "Driver written by Wim Dumon "); @@ -313,7 +309,7 @@ static int ne2_procinfo(char *buf, int slot, struct net_device *dev) len += sprintf(buf+len, "Based on the original NE2000 drivers\n" ); len += sprintf(buf+len, "Base IO: %#x\n", (unsigned int)dev->base_addr); len += sprintf(buf+len, "IRQ : %d\n", dev->irq); - len += sprintf(buf+len, "HW addr : %s\n", print_mac(mac, dev->dev_addr)); + len += sprintf(buf+len, "HW addr : %pM\n", dev->dev_addr); return len; } @@ -326,7 +322,6 @@ static int __init ne2_probe1(struct net_device *dev, int slot) const char *name = "NE/2"; int start_page, stop_page; static unsigned version_printed; - DECLARE_MAC_BUF(mac); if (ei_debug && version_printed++ == 0) printk(version); @@ -469,7 +464,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot) for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = SA_prom[i]; - printk(" %s\n", print_mac(mac, dev->dev_addr)); + printk(" %pM\n", dev->dev_addr); printk("%s: %s found at %#x, using IRQ %d.\n", dev->name, name, base_addr, dev->irq); @@ -494,11 +489,7 @@ static int __init ne2_probe1(struct net_device *dev, int slot) ei_status.priv = slot; - dev->open = &ne_open; - dev->stop = &ne_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = eip_poll; -#endif + dev->netdev_ops = &eip_netdev_ops; NS8390p_init(dev, 0); retval = register_netdev(dev); @@ -513,20 +504,6 @@ out: return retval; } -static int ne_open(struct net_device *dev) -{ - eip_open(dev); - return 0; -} - -static int ne_close(struct net_device *dev) -{ - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - eip_close(dev); - return 0; -} - /* Hard reset the card. This used to pause for the same period that a 8390 reset command required, but that shouldn't be necessary. */ static void ne_reset_8390(struct net_device *dev) diff --git a/drivers/net/ne2k-pci.c b/drivers/net/ne2k-pci.c index de0de744a8fa4e1fe961cc89e301046b862a8e51..62f20ba211cb7d0b98f78df1c8cea83166e152a7 100644 --- a/drivers/net/ne2k-pci.c +++ b/drivers/net/ne2k-pci.c @@ -200,6 +200,19 @@ struct ne2k_pci_card { in the 'dev' and 'ei_status' structures. */ +static const struct net_device_ops ne2k_netdev_ops = { + .ndo_open = ne2k_pci_open, + .ndo_stop = ne2k_pci_close, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -212,7 +225,6 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, static unsigned int fnd_cnt; long ioaddr; int flags = pci_clone_list[chip_idx].flags; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -266,6 +278,8 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, dev_err(&pdev->dev, "cannot allocate ethernet device\n"); goto err_out_free_res; } + dev->netdev_ops = &ne2k_netdev_ops; + SET_NETDEV_DEV(dev, &pdev->dev); /* Reset card. Who knows what dain-bramaged state it was left in. */ @@ -354,12 +368,8 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, ei_status.block_output = &ne2k_pci_block_output; ei_status.get_8390_hdr = &ne2k_pci_get_8390_hdr; ei_status.priv = (unsigned long) pdev; - dev->open = &ne2k_pci_open; - dev->stop = &ne2k_pci_close; + dev->ethtool_ops = &ne2k_pci_ethtool_ops; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif NS8390_init(dev, 0); i = register_netdev(dev); @@ -368,9 +378,9 @@ static int __devinit ne2k_pci_init_one (struct pci_dev *pdev, for(i = 0; i < 6; i++) dev->dev_addr[i] = SA_prom[i]; - printk("%s: %s found at %#lx, IRQ %d, %s.\n", + printk("%s: %s found at %#lx, IRQ %d, %pM.\n", dev->name, pci_clone_list[chip_idx].name, ioaddr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); @@ -626,7 +636,7 @@ static void ne2k_pci_block_output(struct net_device *dev, int count, static void ne2k_pci_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct ei_device *ei = dev->priv; + struct ei_device *ei = netdev_priv(dev); struct pci_dev *pci_dev = (struct pci_dev *) ei->priv; strcpy(info->driver, DRV_NAME); diff --git a/drivers/net/ne3210.c b/drivers/net/ne3210.c index 425043a88db9e9409d958006a30fafddcd200fbe..fac43fd6fc87782a42455b852cec62a56333849f 100644 --- a/drivers/net/ne3210.c +++ b/drivers/net/ne3210.c @@ -45,9 +45,6 @@ #define DRV_NAME "ne3210" -static int ne3210_open(struct net_device *dev); -static int ne3210_close(struct net_device *dev); - static void ne3210_reset_8390(struct net_device *dev); static void ne3210_get_8390_hdr(struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -99,7 +96,6 @@ static int __init ne3210_eisa_probe (struct device *device) int i, retval, port_index; struct eisa_device *edev = to_eisa_device (device); struct net_device *dev; - DECLARE_MAC_BUF(mac); /* Allocate dev->priv and fill in 8390 specific dev fields. */ if (!(dev = alloc_ei_netdev ())) { @@ -131,8 +127,8 @@ static int __init ne3210_eisa_probe (struct device *device) port_index = inb(ioaddr + NE3210_CFG2) >> 6; for(i = 0; i < ETHER_ADDR_LEN; i++) dev->dev_addr[i] = inb(ioaddr + NE3210_SA_PROM + i); - printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %s.\n", - edev->slot, ifmap[port_index], print_mac(mac, dev->dev_addr)); + printk("ne3210.c: NE3210 in EISA slot %d, media: %s, addr: %pM.\n", + edev->slot, ifmap[port_index], dev->dev_addr); /* Snarf the interrupt now. CFG file has them all listed as `edge' with share=NO */ dev->irq = irq_map[(inb(ioaddr + NE3210_CFG2) >> 3) & 0x07]; @@ -200,11 +196,8 @@ static int __init ne3210_eisa_probe (struct device *device) ei_status.block_output = &ne3210_block_output; ei_status.get_8390_hdr = &ne3210_get_8390_hdr; - dev->open = &ne3210_open; - dev->stop = &ne3210_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + dev->netdev_ops = &ei_netdev_ops; + dev->if_port = ifmap_val[port_index]; if ((retval = register_netdev (dev))) @@ -321,22 +314,6 @@ static void ne3210_block_output(struct net_device *dev, int count, memcpy_toio(shmem, buf, count); } -static int ne3210_open(struct net_device *dev) -{ - ei_open(dev); - return 0; -} - -static int ne3210_close(struct net_device *dev) -{ - - if (ei_debug > 1) - printk("%s: Shutting down ethercard.\n", dev->name); - - ei_close(dev); - return 0; -} - static struct eisa_device_id ne3210_ids[] = { { "EGL0101" }, { "NVL1801" }, diff --git a/drivers/net/netconsole.c b/drivers/net/netconsole.c index 9681618c32321912c522e9953cd71eac4db06443..d304d38cd5d1728c45587efa0a986ca207d21240 100644 --- a/drivers/net/netconsole.c +++ b/drivers/net/netconsole.c @@ -307,17 +307,14 @@ static ssize_t show_remote_ip(struct netconsole_target *nt, char *buf) static ssize_t show_local_mac(struct netconsole_target *nt, char *buf) { struct net_device *dev = nt->np.dev; + static const u8 bcast[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - DECLARE_MAC_BUF(mac); - return snprintf(buf, PAGE_SIZE, "%s\n", dev ? - print_mac(mac, dev->dev_addr) : "ff:ff:ff:ff:ff:ff"); + return snprintf(buf, PAGE_SIZE, "%pM\n", dev ? dev->dev_addr : bcast); } static ssize_t show_remote_mac(struct netconsole_target *nt, char *buf) { - DECLARE_MAC_BUF(mac); - return snprintf(buf, PAGE_SIZE, "%s\n", - print_mac(mac, nt->np.remote_mac)); + return snprintf(buf, PAGE_SIZE, "%pM\n", nt->np.remote_mac); } /* diff --git a/drivers/net/netx-eth.c b/drivers/net/netx-eth.c index b289a0a2b94563ea37b910c05deef15b6b61d0b6..1861d5bbd96ba01764a8ab6462a5ae1aaf5422c8 100644 --- a/drivers/net/netx-eth.c +++ b/drivers/net/netx-eth.c @@ -165,7 +165,6 @@ static void netx_eth_receive(struct net_device *ndev) pfifo_push(EMPTY_PTR_FIFO(priv->id), FIFO_PTR_SEGMENT(seg) | FIFO_PTR_FRAMENO(frameno)); - ndev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, ndev); netif_rx(skb); ndev->stats.rx_packets++; diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c index b974ca0fc530a45babd8962ec47a0f70c2820f9a..e45ce29517299a140ff4c8ee6dfb9c66768ef177 100644 --- a/drivers/net/netxen/netxen_nic_ethtool.c +++ b/drivers/net/netxen/netxen_nic_ethtool.c @@ -275,11 +275,11 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) } else return -EOPNOTSUPP; - if (netif_running(dev)) { - dev->stop(dev); - dev->open(dev); - } - return 0; + if (!netif_running(dev)) + return 0; + + dev->netdev_ops->ndo_stop(dev); + return dev->netdev_ops->ndo_open(dev); } static int netxen_nic_get_regs_len(struct net_device *dev) diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c index 84978f80f396e681eefa0e8cc76bac57e1ea232c..aa6e603bfcbf701e9a95b504ff00ea67f7afd04b 100644 --- a/drivers/net/netxen/netxen_nic_hw.c +++ b/drivers/net/netxen/netxen_nic_hw.c @@ -537,7 +537,7 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter, static int nx_p3_sre_macaddr_change(struct net_device *dev, u8 *addr, unsigned op) { - struct netxen_adapter *adapter = (struct netxen_adapter *)dev->priv; + struct netxen_adapter *adapter = netdev_priv(dev); nx_nic_req_t req; nx_mac_req_t mac_req; int rv; @@ -1459,7 +1459,7 @@ static int netxen_nic_pci_mem_read_direct(struct netxen_adapter *adapter, mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE * 2); else mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) { + if (mem_ptr == NULL) { *(uint8_t *)data = 0; return -1; } @@ -1533,7 +1533,7 @@ netxen_nic_pci_mem_write_direct(struct netxen_adapter *adapter, u64 off, mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE*2); else mem_ptr = ioremap(mem_base + mem_page, PAGE_SIZE); - if (mem_ptr == 0UL) + if (mem_ptr == NULL) return -1; addr = mem_ptr; addr += start & (PAGE_SIZE - 1); diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 5bba675d0504594fc340ab3223956d167d4ef0ea..d924468e506eb48af997a075ad3b51d69800b876 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c @@ -1285,9 +1285,7 @@ static void netxen_process_rcv(struct netxen_adapter *adapter, int ctxid, } adapter->stats.rxdropped++; } else { - netif_receive_skb(skb); - netdev->last_rx = jiffies; adapter->stats.no_rcv++; adapter->stats.rxbytes += length; diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index 6ef3f0d84bcf45e8704aaf21958508086df52ee1..ba01524b5531a46d7ced8efd6470ad825601c23e 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c @@ -439,7 +439,6 @@ netxen_read_mac_addr(struct netxen_adapter *adapter) int i; unsigned char *p; __le64 mac_addr; - DECLARE_MAC_BUF(mac); struct net_device *netdev = adapter->netdev; struct pci_dev *pdev = adapter->pdev; @@ -462,15 +461,39 @@ netxen_read_mac_addr(struct netxen_adapter *adapter) /* set station address */ - if (!is_valid_ether_addr(netdev->perm_addr)) { - dev_warn(&pdev->dev, "Bad MAC address %s.\n", - print_mac(mac, netdev->dev_addr)); - } else + if (!is_valid_ether_addr(netdev->perm_addr)) + dev_warn(&pdev->dev, "Bad MAC address %pM.\n", netdev->dev_addr); + else adapter->macaddr_set(adapter, netdev->dev_addr); return 0; } +static void netxen_set_multicast_list(struct net_device *dev) +{ + struct netxen_adapter *adapter = netdev_priv(dev); + + if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) + netxen_p3_nic_set_multi(dev); + else + netxen_p2_nic_set_multi(dev); +} + +static const struct net_device_ops netxen_netdev_ops = { + .ndo_open = netxen_nic_open, + .ndo_stop = netxen_nic_close, + .ndo_start_xmit = netxen_nic_xmit_frame, + .ndo_get_stats = netxen_nic_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = netxen_set_multicast_list, + .ndo_set_mac_address = netxen_nic_set_mac, + .ndo_change_mtu = netxen_nic_change_mtu, + .ndo_tx_timeout = netxen_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = netxen_nic_poll_controller, +#endif +}; + /* * netxen_nic_probe() * @@ -543,7 +566,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) SET_NETDEV_DEV(netdev, &pdev->dev); - adapter = netdev->priv; + adapter = netdev_priv(netdev); adapter->netdev = netdev; adapter->pdev = pdev; adapter->ahw.pci_func = pci_func_id; @@ -682,25 +705,13 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) else adapter->max_mc_count = 16; - netdev->open = netxen_nic_open; - netdev->stop = netxen_nic_close; - netdev->hard_start_xmit = netxen_nic_xmit_frame; - netdev->get_stats = netxen_nic_get_stats; - if (NX_IS_REVISION_P3(revision_id)) - netdev->set_multicast_list = netxen_p3_nic_set_multi; - else - netdev->set_multicast_list = netxen_p2_nic_set_multi; - netdev->set_mac_address = netxen_nic_set_mac; - netdev->change_mtu = netxen_nic_change_mtu; - netdev->tx_timeout = netxen_tx_timeout; + netdev->netdev_ops = &netxen_netdev_ops; netdev->watchdog_timeo = 2*HZ; netxen_nic_change_mtu(netdev, netdev->mtu); SET_ETHTOOL_OPS(netdev, &netxen_nic_ethtool_ops); -#ifdef CONFIG_NET_POLL_CONTROLLER - netdev->poll_controller = netxen_nic_poll_controller; -#endif + /* ScatterGather support */ netdev->features = NETIF_F_SG; netdev->features |= NETIF_F_IP_CSUM; @@ -988,7 +999,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev) */ static int netxen_nic_open(struct net_device *netdev) { - struct netxen_adapter *adapter = (struct netxen_adapter *)netdev->priv; + struct netxen_adapter *adapter = netdev_priv(netdev); int err = 0; int ctx, ring; irq_handler_t handler; @@ -1077,7 +1088,7 @@ static int netxen_nic_open(struct net_device *netdev) netxen_nic_set_link_parameters(adapter); - netdev->set_multicast_list(netdev); + netxen_set_multicast_list(netdev); if (adapter->set_mtu) adapter->set_mtu(adapter, netdev->mtu); @@ -1572,7 +1583,7 @@ static int netxen_nic_poll(struct napi_struct *napi, int budget) } if ((work_done < budget) && tx_complete) { - netif_rx_complete(adapter->netdev, &adapter->napi); + netif_rx_complete(&adapter->napi); netxen_nic_enable_int(adapter); } diff --git a/drivers/net/netxen/netxen_nic_niu.c b/drivers/net/netxen/netxen_nic_niu.c index 27f07f6a45b1229f8a53afd8c4026f59bbcdb055..c3b9c83b32fe5205925a4686e0874c2f4aa7e96b 100644 --- a/drivers/net/netxen/netxen_nic_niu.c +++ b/drivers/net/netxen/netxen_nic_niu.c @@ -608,7 +608,6 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, int phy = adapter->physical_port; unsigned char mac_addr[6]; int i; - DECLARE_MAC_BUF(mac); if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) return 0; @@ -636,10 +635,8 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter, if (i == 10) { printk(KERN_ERR "%s: cannot set Mac addr for %s\n", netxen_nic_driver_name, adapter->netdev->name); - printk(KERN_ERR "MAC address set: %s.\n", - print_mac(mac, addr)); - printk(KERN_ERR "MAC address get: %s.\n", - print_mac(mac, mac_addr)); + printk(KERN_ERR "MAC address set: %pM.\n", addr); + printk(KERN_ERR "MAC address get: %pM.\n", mac_addr); } return 0; } diff --git a/drivers/net/ni5010.c b/drivers/net/ni5010.c index 8e0ca9f4e40479f3fa6ff43c429d45cb69da1b52..539e18ab485cd5da15f1efe17061a5600b48baad 100644 --- a/drivers/net/ni5010.c +++ b/drivers/net/ni5010.c @@ -203,7 +203,6 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) unsigned int data = 0; int boguscount = 40; int err = -ENODEV; - DECLARE_MAC_BUF(mac); dev->base_addr = ioaddr; dev->irq = irq; @@ -271,7 +270,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) outw(i, IE_GP); dev->dev_addr[i] = inb(IE_SAPROM); } - printk("%s ", print_mac(mac, dev->dev_addr)); + printk("%pM ", dev->dev_addr); PRINTK2((KERN_DEBUG "%s: I/O #4 passed!\n", dev->name)); @@ -329,7 +328,7 @@ static int __init ni5010_probe1(struct net_device *dev, int ioaddr) outb(0, IE_RBUF); /* set buffer byte 0 to 0 again */ } printk("-> bufsize rcv/xmt=%d/%d\n", bufsize_rcv, NI5010_BUFSIZE); - memset(dev->priv, 0, sizeof(struct ni5010_local)); + memset(netdev_priv(dev), 0, sizeof(struct ni5010_local)); dev->open = ni5010_open; dev->stop = ni5010_close; @@ -570,7 +569,6 @@ static void ni5010_rx(struct net_device *dev) skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += i_pkt_size; @@ -768,12 +766,3 @@ module_init(ni5010_init_module); module_exit(ni5010_cleanup_module); #endif /* MODULE */ MODULE_LICENSE("GPL"); - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c ni5010.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/ni52.c b/drivers/net/ni52.c index b9a882d362da1f7bdbc34c76be0958815fc2c684..a8bcc00c3302bcb0a1b35cf9eba82a92dafb75a5 100644 --- a/drivers/net/ni52.c +++ b/drivers/net/ni52.c @@ -9,8 +9,6 @@ * [feel free to mail ....] * * when using as module: (no autoprobing!) - * compile with: - * gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ -DMODULE -c ni52.c * run with e.g: * insmod ni52.o io=0x360 irq=9 memstart=0xd0000 memend=0xd4000 * @@ -214,7 +212,7 @@ struct priv { /* wait for command with timeout: */ static void wait_for_scb_cmd(struct net_device *dev) { - struct priv *p = dev->priv; + struct priv *p = netdev_priv(dev); int i; for (i = 0; i < 16384; i++) { if (readb(&p->scb->cmd_cuc) == 0) @@ -233,7 +231,7 @@ static void wait_for_scb_cmd(struct net_device *dev) static void wait_for_scb_cmd_ruc(struct net_device *dev) { - struct priv *p = dev->priv; + struct priv *p = netdev_priv(dev); int i; for (i = 0; i < 16384; i++) { if (readb(&p->scb->cmd_ruc) == 0) @@ -298,7 +296,7 @@ static int ni52_open(struct net_device *dev) static int check_iscp(struct net_device *dev, void __iomem *addr) { struct iscp_struct __iomem *iscp = addr; - struct priv *p = dev->priv; + struct priv *p = netdev_priv(dev); memset_io(iscp, 0, sizeof(struct iscp_struct)); writel(make24(iscp), &p->scp->iscp); @@ -318,7 +316,7 @@ static int check_iscp(struct net_device *dev, void __iomem *addr) */ static int check586(struct net_device *dev, unsigned size) { - struct priv *p = dev->priv; + struct priv *p = netdev_priv(dev); int i; p->mapped = ioremap(dev->mem_start, size); @@ -354,7 +352,7 @@ Enodev: */ static void alloc586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); ni_reset586(); mdelay(32); @@ -400,7 +398,7 @@ struct net_device * __init ni52_probe(int unit) if (!dev) return ERR_PTR(-ENOMEM); - p = dev->priv; + p = netdev_priv(dev); if (unit >= 0) { sprintf(dev->name, "eth%d", unit); @@ -446,7 +444,7 @@ out: static int __init ni52_probe1(struct net_device *dev, int ioaddr) { int i, size, retval; - struct priv *priv = dev->priv; + struct priv *priv = netdev_priv(dev); dev->base_addr = ioaddr; dev->irq = irq; @@ -588,7 +586,7 @@ static int init586(struct net_device *dev) { void __iomem *ptr; int i, result = 0; - struct priv *p = (struct priv *)dev->priv; + struct priv *p = netdev_priv(dev); struct configure_cmd_struct __iomem *cfg_cmd; struct iasetup_cmd_struct __iomem *ias_cmd; struct tdr_cmd_struct __iomem *tdr_cmd; @@ -829,7 +827,7 @@ static void __iomem *alloc_rfa(struct net_device *dev, void __iomem *ptr) struct rfd_struct __iomem *rfd = ptr; struct rbd_struct __iomem *rbd; int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); memset_io(rfd, 0, sizeof(struct rfd_struct) * (p->num_recv_buffs + rfdadd)); @@ -878,7 +876,7 @@ static irqreturn_t ni52_interrupt(int irq, void *dev_id) int cnt = 0; struct priv *p; - p = (struct priv *) dev->priv; + p = netdev_priv(dev); if (debuglevel > 1) printk("I"); @@ -950,7 +948,7 @@ static void ni52_rcv_int(struct net_device *dev) unsigned short totlen; struct sk_buff *skb; struct rbd_struct __iomem *rbd; - struct priv *p = (struct priv *)dev->priv; + struct priv *p = netdev_priv(dev); if (debuglevel > 0) printk("R"); @@ -970,7 +968,6 @@ static void ni52_rcv_int(struct net_device *dev) memcpy_fromio(skb->data, p->base + readl(&rbd->buffer), totlen); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; p->stats.rx_packets++; p->stats.rx_bytes += totlen; } else @@ -1040,7 +1037,7 @@ static void ni52_rcv_int(struct net_device *dev) static void ni52_rnr_int(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); p->stats.rx_errors++; @@ -1065,7 +1062,7 @@ static void ni52_rnr_int(struct net_device *dev) static void ni52_xmt_int(struct net_device *dev) { int status; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); if (debuglevel > 0) printk("X"); @@ -1113,7 +1110,7 @@ static void ni52_xmt_int(struct net_device *dev) static void startrecv586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); wait_for_scb_cmd(dev); wait_for_scb_cmd_ruc(dev); @@ -1126,7 +1123,7 @@ static void startrecv586(struct net_device *dev) static void ni52_timeout(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); #ifndef NO_NOPCOMMANDS if (readb(&p->scb->cus) & CU_ACTIVE) { /* COMMAND-UNIT active? */ netif_wake_queue(dev); @@ -1177,7 +1174,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) #ifndef NO_NOPCOMMANDS int next_nop; #endif - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); if (skb->len > XMIT_BUFF_SIZE) { printk(KERN_ERR "%s: Sorry, max. framelength is %d bytes. The length of your frame is %d bytes.\n", dev->name, XMIT_BUFF_SIZE, skb->len); @@ -1274,7 +1271,7 @@ static int ni52_send_packet(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *ni52_get_stats(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); unsigned short crc, aln, rsc, ovrn; /* Get error-statistics from the ni82586 */ @@ -1337,7 +1334,7 @@ int __init init_module(void) void __exit cleanup_module(void) { - struct priv *p = dev_ni52->priv; + struct priv *p = netdev_priv(dev_ni52); unregister_netdev(dev_ni52); iounmap(p->mapped); release_region(dev_ni52->base_addr, NI52_TOTAL_SIZE); @@ -1346,7 +1343,3 @@ void __exit cleanup_module(void) #endif /* MODULE */ MODULE_LICENSE("GPL"); - -/* - * END: linux/drivers/net/ni52.c - */ diff --git a/drivers/net/ni65.c b/drivers/net/ni65.c index 3edc971d0ecabfba1ecfdee18af52bc5e1204682..254057275e0e32eccb17bd1c26cad8b5754e125a 100644 --- a/drivers/net/ni65.c +++ b/drivers/net/ni65.c @@ -7,8 +7,6 @@ * EtherBlaster. (probably it also works with every full NE2100 * compatible card) * - * To compile as module, type: - * gcc -O2 -fomit-frame-pointer -m486 -D__KERNEL__ -DMODULE -c ni65.c * driver probes: io: 0x360,0x300,0x320,0x340 / dma: 3,5,6,7 * * This is an extension to the Linux operating system, and is covered by the @@ -295,7 +293,7 @@ static void ni65_set_performance(struct priv *p) */ static int ni65_open(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; int irqval = request_irq(dev->irq, &ni65_interrupt,0, cards[p->cardno].cardname,dev); if (irqval) { @@ -321,7 +319,7 @@ static int ni65_open(struct net_device *dev) */ static int ni65_close(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; netif_stop_queue(dev); @@ -345,7 +343,7 @@ static int ni65_close(struct net_device *dev) static void cleanup_card(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; disable_dma(dev->dma); free_dma(dev->dma); release_region(dev->base_addr, cards[p->cardno].total_size); @@ -444,7 +442,7 @@ static int __init ni65_probe1(struct net_device *dev,int ioaddr) release_region(ioaddr, cards[i].total_size); return j; } - p = (struct priv *) dev->priv; + p = dev->ml_priv; p->cmdr_addr = ioaddr + cards[i].cmd_offset; p->cardno = i; spin_lock_init(&p->ring_lock); @@ -647,8 +645,8 @@ static int ni65_alloc_buffer(struct net_device *dev) if(!ptr) return -ENOMEM; - p = dev->priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7); - memset((char *) dev->priv,0,sizeof(struct priv)); + p = dev->ml_priv = (struct priv *) (((unsigned long) ptr + 7) & ~0x7); + memset((char *)p, 0, sizeof(struct priv)); p->self = ptr; for(i=0;ipriv; + struct priv *p = dev->ml_priv; unsigned long flags; p->lock = 0; @@ -876,7 +874,7 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id) struct priv *p; int bcnt = 32; - p = (struct priv *) dev->priv; + p = dev->ml_priv; spin_lock(&p->ring_lock); @@ -899,7 +897,7 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id) if(csr0 & CSR0_ERR) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; if(debuglevel > 1) printk(KERN_ERR "%s: general error: %04x.\n",dev->name,csr0); if(csr0 & CSR0_BABL) @@ -924,7 +922,7 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id) int j; for(j=0;jpriv; + struct priv *p = dev->ml_priv; int i,k,num1,num2; for(i=RMDNUM-1;i>0;i--) { num2 = (p->rmdnum + i) & (RMDNUM-1); @@ -982,7 +980,7 @@ static irqreturn_t ni65_interrupt(int irq, void * dev_id) */ static void ni65_xmit_intr(struct net_device *dev,int csr0) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; while(p->xmit_queued) { @@ -1049,7 +1047,7 @@ static void ni65_recv_intr(struct net_device *dev,int csr0) struct rmd *rmdp; int rmdstat,len; int cnt=0; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; rmdp = p->rmdhead + p->rmdnum; while(!( (rmdstat = rmdp->u.s.status) & RCV_OWN)) @@ -1113,7 +1111,6 @@ static void ni65_recv_intr(struct net_device *dev,int csr0) p->stats.rx_bytes += len; skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; } else { @@ -1140,7 +1137,7 @@ static void ni65_recv_intr(struct net_device *dev,int csr0) static void ni65_timeout(struct net_device *dev) { int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name); for(i=0;ipriv; + struct priv *p = dev->ml_priv; netif_stop_queue(dev); @@ -1222,7 +1219,7 @@ static struct net_device_stats *ni65_get_stats(struct net_device *dev) #if 0 int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = dev->ml_priv; for(i=0;irmdhead + ((p->rmdnum + i) & (RMDNUM-1)); @@ -1231,7 +1228,7 @@ static struct net_device_stats *ni65_get_stats(struct net_device *dev) printk("\n"); #endif - return &((struct priv *) dev->priv)->stats; + return &((struct priv *)dev->ml_priv)->stats; } static void set_multicast_list(struct net_device *dev) @@ -1266,7 +1263,3 @@ void __exit cleanup_module(void) #endif /* MODULE */ MODULE_LICENSE("GPL"); - -/* - * END of ni65.c - */ diff --git a/drivers/net/niu.c b/drivers/net/niu.c index 1b6f548c4411203a7666e0f1703de8fcec4aabf5..0c0b752315cae844c6944b912d8605032070e93c 100644 --- a/drivers/net/niu.c +++ b/drivers/net/niu.c @@ -448,7 +448,7 @@ static int serdes_init_niu_1g_serdes(struct niu *np) struct niu_link_config *lp = &np->link_config; u16 pll_cfg, pll_sts; int max_retry = 100; - u64 sig, mask, val; + u64 uninitialized_var(sig), mask, val; u32 tx_cfg, rx_cfg; unsigned long i; int err; @@ -547,7 +547,7 @@ static int serdes_init_niu_10g_serdes(struct niu *np) struct niu_link_config *lp = &np->link_config; u32 tx_cfg, rx_cfg, pll_cfg, pll_sts; int max_retry = 100; - u64 sig, mask, val; + u64 uninitialized_var(sig), mask, val; unsigned long i; int err; @@ -738,7 +738,7 @@ static int esr_write_glue0(struct niu *np, unsigned long chan, u32 val) static int esr_reset(struct niu *np) { - u32 reset; + u32 uninitialized_var(reset); int err; err = mdio_write(np, np->port, NIU_ESR_DEV_ADDR, @@ -3392,8 +3392,6 @@ static int niu_process_rx_pkt(struct niu *np, struct rx_ring_info *rp) skb->protocol = eth_type_trans(skb, np->dev); netif_receive_skb(skb); - np->dev->last_rx = jiffies; - return num_rcr; } @@ -3529,6 +3527,57 @@ out: } } +static inline void niu_sync_rx_discard_stats(struct niu *np, + struct rx_ring_info *rp, + const int limit) +{ + /* This elaborate scheme is needed for reading the RX discard + * counters, as they are only 16-bit and can overflow quickly, + * and because the overflow indication bit is not usable as + * the counter value does not wrap, but remains at max value + * 0xFFFF. + * + * In theory and in practice counters can be lost in between + * reading nr64() and clearing the counter nw64(). For this + * reason, the number of counter clearings nw64() is + * limited/reduced though the limit parameter. + */ + int rx_channel = rp->rx_channel; + u32 misc, wred; + + /* RXMISC (Receive Miscellaneous Discard Count), covers the + * following discard events: IPP (Input Port Process), + * FFLP/TCAM, Full RCR (Receive Completion Ring) RBR (Receive + * Block Ring) prefetch buffer is empty. + */ + misc = nr64(RXMISC(rx_channel)); + if (unlikely((misc & RXMISC_COUNT) > limit)) { + nw64(RXMISC(rx_channel), 0); + rp->rx_errors += misc & RXMISC_COUNT; + + if (unlikely(misc & RXMISC_OFLOW)) + dev_err(np->device, "rx-%d: Counter overflow " + "RXMISC discard\n", rx_channel); + + niudbg(RX_ERR, "%s-rx-%d: MISC drop=%u over=%u\n", + np->dev->name, rx_channel, misc, misc-limit); + } + + /* WRED (Weighted Random Early Discard) by hardware */ + wred = nr64(RED_DIS_CNT(rx_channel)); + if (unlikely((wred & RED_DIS_CNT_COUNT) > limit)) { + nw64(RED_DIS_CNT(rx_channel), 0); + rp->rx_dropped += wred & RED_DIS_CNT_COUNT; + + if (unlikely(wred & RED_DIS_CNT_OFLOW)) + dev_err(np->device, "rx-%d: Counter overflow " + "WRED discard\n", rx_channel); + + niudbg(RX_ERR, "%s-rx-%d: WRED drop=%u over=%u\n", + np->dev->name, rx_channel, wred, wred-limit); + } +} + static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget) { int qlen, rcr_done = 0, work_done = 0; @@ -3569,6 +3618,10 @@ static int niu_rx_work(struct niu *np, struct rx_ring_info *rp, int budget) nw64(RX_DMA_CTL_STAT(rp->rx_channel), stat); + /* Only sync discards stats when qlen indicate potential for drops */ + if (qlen > 10) + niu_sync_rx_discard_stats(np, rp, 0x7FFF); + return work_done; } @@ -3616,7 +3669,7 @@ static int niu_poll(struct napi_struct *napi, int budget) work_done = niu_poll_core(np, lp, budget); if (work_done < budget) { - netif_rx_complete(np->dev, napi); + netif_rx_complete(napi); niu_ldg_rearm(np, lp, 1); } return work_done; @@ -4035,12 +4088,12 @@ static void __niu_fastpath_interrupt(struct niu *np, int ldg, u64 v0) static void niu_schedule_napi(struct niu *np, struct niu_ldg *lp, u64 v0, u64 v1, u64 v2) { - if (likely(netif_rx_schedule_prep(np->dev, &lp->napi))) { + if (likely(netif_rx_schedule_prep(&lp->napi))) { lp->v0 = v0; lp->v1 = v1; lp->v2 = v2; __niu_fastpath_interrupt(np, lp->ldg_num, v0); - __netif_rx_schedule(np->dev, &lp->napi); + __netif_rx_schedule(&lp->napi); } } @@ -5849,17 +5902,42 @@ static void niu_stop_hw(struct niu *np) niu_reset_rx_channels(np); } +static void niu_set_irq_name(struct niu *np) +{ + int port = np->port; + int i, j = 1; + + sprintf(np->irq_name[0], "%s:MAC", np->dev->name); + + if (port == 0) { + sprintf(np->irq_name[1], "%s:MIF", np->dev->name); + sprintf(np->irq_name[2], "%s:SYSERR", np->dev->name); + j = 3; + } + + for (i = 0; i < np->num_ldg - j; i++) { + if (i < np->num_rx_rings) + sprintf(np->irq_name[i+j], "%s-rx-%d", + np->dev->name, i); + else if (i < np->num_tx_rings + np->num_rx_rings) + sprintf(np->irq_name[i+j], "%s-tx-%d", np->dev->name, + i - np->num_rx_rings); + } +} + static int niu_request_irq(struct niu *np) { int i, j, err; + niu_set_irq_name(np); + err = 0; for (i = 0; i < np->num_ldg; i++) { struct niu_ldg *lp = &np->ldg[i]; err = request_irq(lp->irq, niu_interrupt, IRQF_SHARED | IRQF_SAMPLE_RANDOM, - np->dev->name, lp); + np->irq_name[i], lp); if (err) goto out_free_irqs; @@ -6050,15 +6128,17 @@ static void niu_get_rx_stats(struct niu *np) for (i = 0; i < np->num_rx_rings; i++) { struct rx_ring_info *rp = &np->rx_rings[i]; + niu_sync_rx_discard_stats(np, rp, 0); + pkts += rp->rx_packets; bytes += rp->rx_bytes; dropped += rp->rx_dropped; errors += rp->rx_errors; } - np->net_stats.rx_packets = pkts; - np->net_stats.rx_bytes = bytes; - np->net_stats.rx_dropped = dropped; - np->net_stats.rx_errors = errors; + np->dev->stats.rx_packets = pkts; + np->dev->stats.rx_bytes = bytes; + np->dev->stats.rx_dropped = dropped; + np->dev->stats.rx_errors = errors; } static void niu_get_tx_stats(struct niu *np) @@ -6074,9 +6154,9 @@ static void niu_get_tx_stats(struct niu *np) bytes += rp->tx_bytes; errors += rp->tx_errors; } - np->net_stats.tx_packets = pkts; - np->net_stats.tx_bytes = bytes; - np->net_stats.tx_errors = errors; + np->dev->stats.tx_packets = pkts; + np->dev->stats.tx_bytes = bytes; + np->dev->stats.tx_errors = errors; } static struct net_device_stats *niu_get_stats(struct net_device *dev) @@ -6086,7 +6166,7 @@ static struct net_device_stats *niu_get_stats(struct net_device *dev) niu_get_rx_stats(np); niu_get_tx_stats(np); - return &np->net_stats; + return &dev->stats; } static void niu_load_hash_xmac(struct niu *np, u16 *hash) @@ -6991,6 +7071,8 @@ static void niu_get_ethtool_stats(struct net_device *dev, for (i = 0; i < np->num_rx_rings; i++) { struct rx_ring_info *rp = &np->rx_rings[i]; + niu_sync_rx_discard_stats(np, rp, 0); + data[0] = rp->rx_channel; data[1] = rp->rx_packets; data[2] = rp->rx_bytes; @@ -8824,7 +8906,7 @@ static u64 niu_pci_map_page(struct device *dev, struct page *page, static void niu_pci_unmap_page(struct device *dev, u64 dma_address, size_t size, enum dma_data_direction direction) { - return dma_unmap_page(dev, dma_address, size, direction); + dma_unmap_page(dev, dma_address, size, direction); } static u64 niu_pci_map_single(struct device *dev, void *cpu_addr, @@ -8891,28 +8973,31 @@ static struct net_device * __devinit niu_alloc_and_init( return dev; } +static const struct net_device_ops niu_netdev_ops = { + .ndo_open = niu_open, + .ndo_stop = niu_close, + .ndo_start_xmit = niu_start_xmit, + .ndo_get_stats = niu_get_stats, + .ndo_set_multicast_list = niu_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = niu_set_mac_addr, + .ndo_do_ioctl = niu_ioctl, + .ndo_tx_timeout = niu_tx_timeout, + .ndo_change_mtu = niu_change_mtu, +}; + static void __devinit niu_assign_netdev_ops(struct net_device *dev) { - dev->open = niu_open; - dev->stop = niu_close; - dev->get_stats = niu_get_stats; - dev->set_multicast_list = niu_set_rx_mode; - dev->set_mac_address = niu_set_mac_addr; - dev->do_ioctl = niu_ioctl; - dev->tx_timeout = niu_tx_timeout; - dev->hard_start_xmit = niu_start_xmit; + dev->netdev_ops = &niu_netdev_ops; dev->ethtool_ops = &niu_ethtool_ops; dev->watchdog_timeo = NIU_TX_TIMEOUT; - dev->change_mtu = niu_change_mtu; } static void __devinit niu_device_announce(struct niu *np) { struct net_device *dev = np->dev; - DECLARE_MAC_BUF(mac); - pr_info("%s: NIU Ethernet %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + pr_info("%s: NIU Ethernet %pM\n", dev->name, dev->dev_addr); if (np->parent->plat_type == PLAT_TYPE_ATCA_CP3220) { pr_info("%s: Port type[%s] mode[%s:%s] XCVR[%s] phy[%s]\n", diff --git a/drivers/net/niu.h b/drivers/net/niu.h index 180ca8ae93deabab7a6ddf201e4e2fb296487a2d..e1a7392e8d70a61bb7b4c6703f3e74bb9b0cd44e 100644 --- a/drivers/net/niu.h +++ b/drivers/net/niu.h @@ -3243,12 +3243,12 @@ struct niu { #define NIU_FLAGS_XMAC 0x00010000 /* 0=BMAC 1=XMAC */ u32 msg_enable; + char irq_name[NIU_NUM_RXCHAN+NIU_NUM_TXCHAN+3][IFNAMSIZ + 6]; /* Protects hw programming, and ring state. */ spinlock_t lock; const struct niu_ops *ops; - struct net_device_stats net_stats; union niu_mac_stats mac_stats; struct rx_ring_info *rx_rings; diff --git a/drivers/net/ns83820.c b/drivers/net/ns83820.c index ff449619f047e57fd36be41805b33bf6b66ec113..46b0772489e4d92b6298c6fcfdb51b95b8ac7c40 100644 --- a/drivers/net/ns83820.c +++ b/drivers/net/ns83820.c @@ -1948,14 +1948,25 @@ static void ns83820_probe_phy(struct net_device *ndev) } #endif -static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_device_id *id) +static const struct net_device_ops netdev_ops = { + .ndo_open = ns83820_open, + .ndo_stop = ns83820_stop, + .ndo_start_xmit = ns83820_hard_start_xmit, + .ndo_get_stats = ns83820_get_stats, + .ndo_change_mtu = ns83820_change_mtu, + .ndo_set_multicast_list = ns83820_set_multicast, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = ns83820_tx_timeout, +}; + +static int __devinit ns83820_init_one(struct pci_dev *pci_dev, + const struct pci_device_id *id) { struct net_device *ndev; struct ns83820 *dev; long addr; int err; int using_dac = 0; - DECLARE_MAC_BUF(mac); /* See if we can set the dma mask early on; failure is fatal. */ if (sizeof(dma_addr_t) == 8 && @@ -2041,14 +2052,8 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ndev->name, le32_to_cpu(readl(dev->base + 0x22c)), pci_dev->subsystem_vendor, pci_dev->subsystem_device); - ndev->open = ns83820_open; - ndev->stop = ns83820_stop; - ndev->hard_start_xmit = ns83820_hard_start_xmit; - ndev->get_stats = ns83820_get_stats; - ndev->change_mtu = ns83820_change_mtu; - ndev->set_multicast_list = ns83820_set_multicast; + ndev->netdev_ops = &netdev_ops; SET_ETHTOOL_OPS(ndev, &ops); - ndev->tx_timeout = ns83820_tx_timeout; ndev->watchdog_timeo = 5 * HZ; pci_set_drvdata(pci_dev, ndev); @@ -2220,12 +2225,11 @@ static int __devinit ns83820_init_one(struct pci_dev *pci_dev, const struct pci_ ndev->features |= NETIF_F_HIGHDMA; } - printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %s io=0x%08lx irq=%d f=%s\n", + printk(KERN_INFO "%s: ns83820 v" VERSION ": DP83820 v%u.%u: %pM io=0x%08lx irq=%d f=%s\n", ndev->name, (unsigned)readl(dev->base + SRR) >> 8, (unsigned)readl(dev->base + SRR) & 0xff, - print_mac(mac, ndev->dev_addr), - addr, pci_dev->irq, + ndev->dev_addr, addr, pci_dev->irq, (ndev->features & NETIF_F_HIGHDMA) ? "h,sg" : "sg" ); diff --git a/drivers/net/pasemi_mac.c b/drivers/net/pasemi_mac.c index edc0fd588985f51da906e325398ae36bac2f715c..dcd199045613f3bbc4921ae2bee71d92f743ff62 100644 --- a/drivers/net/pasemi_mac.c +++ b/drivers/net/pasemi_mac.c @@ -971,7 +971,7 @@ static irqreturn_t pasemi_mac_rx_intr(int irq, void *data) if (*chan->status & PAS_STATUS_ERROR) reg |= PAS_IOB_DMA_RXCH_RESET_DINTC; - netif_rx_schedule(dev, &mac->napi); + netif_rx_schedule(&mac->napi); write_iob_reg(PAS_IOB_DMA_RXCH_RESET(chan->chno), reg); @@ -1011,7 +1011,7 @@ static irqreturn_t pasemi_mac_tx_intr(int irq, void *data) mod_timer(&txring->clean_timer, jiffies + (TX_CLEAN_INTERVAL)*2); - netif_rx_schedule(mac->netdev, &mac->napi); + netif_rx_schedule(&mac->napi); if (reg) write_iob_reg(PAS_IOB_DMA_TXCH_RESET(chan->chno), reg); @@ -1105,7 +1105,8 @@ static int pasemi_mac_phy_init(struct net_device *dev) goto err; phy_id = *prop; - snprintf(mac->phy_id, BUS_ID_SIZE, "%x:%02x", (int)r.start, phy_id); + snprintf(mac->phy_id, sizeof(mac->phy_id), "%x:%02x", + (int)r.start, phy_id); of_node_put(phy_dn); @@ -1640,7 +1641,7 @@ static int pasemi_mac_poll(struct napi_struct *napi, int budget) pkts = pasemi_mac_clean_rx(rx_ring(mac), budget); if (pkts < budget) { /* all done, no more packets present */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); pasemi_mac_restart_rx_intr(mac); pasemi_mac_restart_tx_intr(mac); @@ -1742,7 +1743,6 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) struct net_device *dev; struct pasemi_mac *mac; int err; - DECLARE_MAC_BUF(mac_buf); err = pci_enable_device(pdev); if (err) @@ -1849,9 +1849,9 @@ pasemi_mac_probe(struct pci_dev *pdev, const struct pci_device_id *ent) err); goto out; } else if netif_msg_probe(mac) - printk(KERN_INFO "%s: PA Semi %s: intf %d, hw addr %s\n", + printk(KERN_INFO "%s: PA Semi %s: intf %d, hw addr %pM\n", dev->name, mac->type == MAC_TYPE_GMAC ? "GMAC" : "XAUI", - mac->dma_if, print_mac(mac_buf, dev->dev_addr)); + mac->dma_if, dev->dev_addr); return err; diff --git a/drivers/net/pasemi_mac_ethtool.c b/drivers/net/pasemi_mac_ethtool.c index 5e8df3afea64e9fedaa15333910d970365bffd87..064a4fe1dd90efcee86a805ed6e94e1037385c2b 100644 --- a/drivers/net/pasemi_mac_ethtool.c +++ b/drivers/net/pasemi_mac_ethtool.c @@ -109,7 +109,7 @@ static void pasemi_mac_ethtool_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ering) { - struct pasemi_mac *mac = netdev->priv; + struct pasemi_mac *mac = netdev_priv(netdev); ering->tx_max_pending = TX_RING_SIZE/2; ering->tx_pending = RING_USED(mac->tx)/2; @@ -130,7 +130,7 @@ static int pasemi_mac_get_sset_count(struct net_device *netdev, int sset) static void pasemi_mac_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { - struct pasemi_mac *mac = netdev->priv; + struct pasemi_mac *mac = netdev_priv(netdev); int i; data[0] = pasemi_read_dma_reg(PAS_DMA_RXINT_RCMDSTA(mac->dma_if)) diff --git a/drivers/net/pci-skeleton.c b/drivers/net/pci-skeleton.c index 0a575fef29e64521b727ce231ae0cd7510589795..c95fd72c3bb96886a9862d27533ef20d650e32be 100644 --- a/drivers/net/pci-skeleton.c +++ b/drivers/net/pci-skeleton.c @@ -737,7 +737,6 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, int i, addr_len, option; void *ioaddr = NULL; static int board_idx = -1; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -782,7 +781,7 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; - /* dev->priv/tp zeroed and aligned in alloc_etherdev */ + /* netdev_priv()/tp zeroed and aligned in alloc_etherdev */ tp = netdev_priv(dev); /* note: tp->chipset set in netdrv_init_board */ @@ -797,11 +796,11 @@ static int __devinit netdrv_init_one (struct pci_dev *pdev, tp->phys[0] = 32; - printk (KERN_INFO "%s: %s at 0x%lx, %sIRQ %d\n", + printk (KERN_INFO "%s: %s at 0x%lx, %pM IRQ %d\n", dev->name, board_info[ent->driver_data].name, dev->base_addr, - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); printk (KERN_DEBUG "%s: Identified 8139 chip type '%s'\n", @@ -1566,7 +1565,6 @@ static void netdrv_rx_interrupt (struct net_device *dev, skb->protocol = eth_type_trans (skb, dev); netif_rx (skb); - dev->last_rx = jiffies; dev->stats.rx_bytes += pkt_size; dev->stats.rx_packets++; } else { diff --git a/drivers/net/pcmcia/3c574_cs.c b/drivers/net/pcmcia/3c574_cs.c index 08c4dd896077b7199762821264c522cc721b065a..e5cb6b1f0ebd8be1aada0898403e79cb3a25d40f 100644 --- a/drivers/net/pcmcia/3c574_cs.c +++ b/drivers/net/pcmcia/3c574_cs.c @@ -345,7 +345,6 @@ static int tc574_config(struct pcmcia_device *link) __be16 *phys_addr; char *cardname; __u32 config; - DECLARE_MAC_BUF(mac); phys_addr = (__be16 *)dev->dev_addr; @@ -463,9 +462,9 @@ static int tc574_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); printk(KERN_INFO "%s: %s at io %#3lx, irq %d, " - "hw_addr %s.\n", + "hw_addr %pM.\n", dev->name, cardname, dev->base_addr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n", 8 << config & Ram_size, ram_split[(config & Ram_split) >> Ram_split_shift], @@ -1062,7 +1061,6 @@ static int el3_rx(struct net_device *dev, int worklimit) ((pkt_len+3)>>2)); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } else { diff --git a/drivers/net/pcmcia/3c589_cs.c b/drivers/net/pcmcia/3c589_cs.c index c235cdba69c6384d11b83ace2b2a1aac2f4a1905..73ecc657999d69e899e4ddb2537e6aa1db376b1d 100644 --- a/drivers/net/pcmcia/3c589_cs.c +++ b/drivers/net/pcmcia/3c589_cs.c @@ -255,7 +255,6 @@ static int tc589_config(struct pcmcia_device *link) int last_fn, last_ret, i, j, multi = 0, fifo; unsigned int ioaddr; char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"}; - DECLARE_MAC_BUF(mac); DEBUG(0, "3c589_config(0x%p)\n", link); @@ -333,9 +332,9 @@ static int tc589_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, " - "hw_addr %s\n", + "hw_addr %pM\n", dev->name, (multi ? "562" : "589"), dev->base_addr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); printk(KERN_INFO " %dK FIFO split %s Rx:Tx, %s xcvr\n", (fifo & 7) ? 32 : 8, ram_split[(fifo >> 16) & 3], if_names[dev->if_port]); @@ -884,7 +883,6 @@ static int el3_rx(struct net_device *dev) (pkt_len+3)>>2); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } else { diff --git a/drivers/net/pcmcia/axnet_cs.c b/drivers/net/pcmcia/axnet_cs.c index 0418045166c348f15431b94fbfa06af894bf6820..0afa72095810e0f9ace213d48f5858bcbf5c5cf7 100644 --- a/drivers/net/pcmcia/axnet_cs.c +++ b/drivers/net/pcmcia/axnet_cs.c @@ -321,7 +321,6 @@ static int axnet_config(struct pcmcia_device *link) struct net_device *dev = link->priv; axnet_dev_t *info = PRIV(dev); int i, j, last_ret, last_fn; - DECLARE_MAC_BUF(mac); DEBUG(0, "axnet_config(0x%p)\n", link); @@ -397,10 +396,10 @@ static int axnet_config(struct pcmcia_device *link) strcpy(info->node.dev_name, dev->name); printk(KERN_INFO "%s: Asix AX88%d90: io %#3lx, irq %d, " - "hw_addr %s\n", + "hw_addr %pM\n", dev->name, ((info->flags & IS_AX88790) ? 7 : 1), dev->base_addr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); if (info->phy_id != -1) { DEBUG(0, " MII transceiver at index %d, status %x.\n", info->phy_id, j); } else { @@ -906,7 +905,7 @@ int ei_debug = 1; /* Index to functions. */ static void ei_tx_intr(struct net_device *dev); static void ei_tx_err(struct net_device *dev); -static void ei_tx_timeout(struct net_device *dev); +static void axnet_tx_timeout(struct net_device *dev); static void ei_receive(struct net_device *dev); static void ei_rx_overrun(struct net_device *dev); @@ -957,9 +956,9 @@ static int ax_open(struct net_device *dev) #ifdef HAVE_TX_TIMEOUT /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout - wrapper that does e.g. media check & then calls ei_tx_timeout. */ + wrapper that does e.g. media check & then calls axnet_tx_timeout. */ if (dev->tx_timeout == NULL) - dev->tx_timeout = ei_tx_timeout; + dev->tx_timeout = axnet_tx_timeout; if (dev->watchdog_timeo <= 0) dev->watchdog_timeo = TX_TIMEOUT; #endif @@ -1003,14 +1002,14 @@ static int ax_close(struct net_device *dev) } /** - * ei_tx_timeout - handle transmit time out condition + * axnet_tx_timeout - handle transmit time out condition * @dev: network device which has apparently fallen asleep * * Called by kernel when device never acknowledges a transmit has * completed (or failed) - i.e. never posted a Tx related interrupt. */ -static void ei_tx_timeout(struct net_device *dev) +static void axnet_tx_timeout(struct net_device *dev) { long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -1047,14 +1046,14 @@ static void ei_tx_timeout(struct net_device *dev) } /** - * ei_start_xmit - begin packet transmission + * axnet_start_xmit - begin packet transmission * @skb: packet to be sent * @dev: network device to which packet is sent * * Sends a packet to an 8390 network device. */ -static int ei_start_xmit(struct sk_buff *skb, struct net_device *dev) +static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev) { long e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev); @@ -1493,7 +1492,6 @@ static void ei_receive(struct net_device *dev) ei_block_input(dev, pkt_len, skb, current_offset + sizeof(rx_frame)); skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; if (pkt_stat & ENRSR_PHY) @@ -1720,7 +1718,7 @@ static void axdev_setup(struct net_device *dev) ei_local = (struct ei_device *)netdev_priv(dev); spin_lock_init(&ei_local->page_lock); - dev->hard_start_xmit = &ei_start_xmit; + dev->hard_start_xmit = &axnet_start_xmit; dev->get_stats = get_stats; dev->set_multicast_list = &set_multicast_list; diff --git a/drivers/net/pcmcia/com20020_cs.c b/drivers/net/pcmcia/com20020_cs.c index 831090c756220fcc86743067d62eb36683517b57..7b5c77b7bd27ebc9185a99da37ac7bc0871c96fb 100644 --- a/drivers/net/pcmcia/com20020_cs.c +++ b/drivers/net/pcmcia/com20020_cs.c @@ -155,7 +155,7 @@ static int com20020_probe(struct pcmcia_device *p_dev) if (!dev) goto fail_alloc_dev; - lp = dev->priv; + lp = netdev_priv(dev); lp->timeout = timeout; lp->backplane = backplane; lp->clockp = clockp; @@ -303,7 +303,7 @@ static int com20020_config(struct pcmcia_device *link) goto failed; } - lp = dev->priv; + lp = netdev_priv(dev); lp->card_name = "PCMCIA COM20020"; lp->card_flags = ARC_CAN_10MBIT; /* pretend all of them can 10Mbit */ @@ -364,7 +364,7 @@ static int com20020_resume(struct pcmcia_device *link) if (link->open) { int ioaddr = dev->base_addr; - struct arcnet_local *lp = dev->priv; + struct arcnet_local *lp = netdev_priv(dev); ARCRESET; } diff --git a/drivers/net/pcmcia/fmvj18x_cs.c b/drivers/net/pcmcia/fmvj18x_cs.c index 69d916daa7bbb313440dbd4c2827a6779a715376..69dcfbbabe825229ca4f709315b9e29c9049cd76 100644 --- a/drivers/net/pcmcia/fmvj18x_cs.c +++ b/drivers/net/pcmcia/fmvj18x_cs.c @@ -125,6 +125,7 @@ typedef struct local_info_t { u_short tx_queue_len; cardtype_t cardtype; u_short sent; + u_char __iomem *base; } local_info_t; #define MC_FILTERBREAK 64 @@ -242,6 +243,7 @@ static int fmvj18x_probe(struct pcmcia_device *link) lp = netdev_priv(dev); link->priv = dev; lp->p_dev = link; + lp->base = NULL; /* The io structure describes IO port mapping */ link->io.NumPorts1 = 32; @@ -348,7 +350,6 @@ static int fmvj18x_config(struct pcmcia_device *link) cardtype_t cardtype; char *card_name = "unknown"; u_char *node_id; - DECLARE_MAC_BUF(mac); DEBUG(0, "fmvj18x_config(0x%p)\n", link); @@ -443,8 +444,10 @@ static int fmvj18x_config(struct pcmcia_device *link) dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; - if (link->io.BasePort2 != 0) - fmvj18x_setup_mfc(link); + if (link->io.BasePort2 != 0) { + ret = fmvj18x_setup_mfc(link); + if (ret != 0) goto failed; + } ioaddr = dev->base_addr; @@ -539,9 +542,9 @@ static int fmvj18x_config(struct pcmcia_device *link) /* print current configuration */ printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, " - "hw_addr %s\n", + "hw_addr %pM\n", dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", - dev->base_addr, dev->irq, print_mac(mac, dev->dev_addr)); + dev->base_addr, dev->irq, dev->dev_addr); return 0; @@ -611,10 +614,10 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) { win_req_t req; memreq_t mem; - u_char __iomem *base; - int i, j; + int i; struct net_device *dev = link->priv; unsigned int ioaddr; + local_info_t *lp = netdev_priv(dev); /* Allocate a small memory window */ req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE; @@ -626,25 +629,32 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) return -1; } - base = ioremap(req.Base, req.Size); + lp->base = ioremap(req.Base, req.Size); + if (lp->base == NULL) { + printk(KERN_NOTICE "fmvj18x_cs: ioremap failed\n"); + return -1; + } + mem.Page = 0; mem.CardOffset = 0; - pcmcia_map_mem_page(link->win, &mem); - + i = pcmcia_map_mem_page(link->win, &mem); + if (i != 0) { + iounmap(lp->base); + lp->base = NULL; + cs_error(link, MapMemPage, i); + return -1; + } + ioaddr = dev->base_addr; - writeb(0x47, base+0x800); /* Config Option Register of LAN */ - writeb(0x0, base+0x802); /* Config and Status Register */ + writeb(0x47, lp->base+0x800); /* Config Option Register of LAN */ + writeb(0x0, lp->base+0x802); /* Config and Status Register */ - writeb(ioaddr & 0xff, base+0x80a); /* I/O Base(Low) of LAN */ - writeb((ioaddr >> 8) & 0xff, base+0x80c); /* I/O Base(High) of LAN */ + writeb(ioaddr & 0xff, lp->base+0x80a); /* I/O Base(Low) of LAN */ + writeb((ioaddr >> 8) & 0xff, lp->base+0x80c); /* I/O Base(High) of LAN */ - writeb(0x45, base+0x820); /* Config Option Register of Modem */ - writeb(0x8, base+0x822); /* Config and Status Register */ + writeb(0x45, lp->base+0x820); /* Config Option Register of Modem */ + writeb(0x8, lp->base+0x822); /* Config and Status Register */ - iounmap(base); - j = pcmcia_release_window(link->win); - if (j != 0) - cs_error(link, ReleaseWindow, j); return 0; } @@ -652,8 +662,25 @@ static int fmvj18x_setup_mfc(struct pcmcia_device *link) static void fmvj18x_release(struct pcmcia_device *link) { - DEBUG(0, "fmvj18x_release(0x%p)\n", link); - pcmcia_disable_device(link); + + struct net_device *dev = link->priv; + local_info_t *lp = netdev_priv(dev); + u_char __iomem *tmp; + int j; + + DEBUG(0, "fmvj18x_release(0x%p)\n", link); + + if (lp->base != NULL) { + tmp = lp->base; + lp->base = NULL; /* set NULL before iounmap */ + iounmap(tmp); + j = pcmcia_release_window(link->win); + if (j != 0) + cs_error(link, ReleaseWindow, j); + } + + pcmcia_disable_device(link); + } static int fmvj18x_suspend(struct pcmcia_device *link) @@ -784,6 +811,13 @@ static irqreturn_t fjn_interrupt(int dummy, void *dev_id) outb(D_TX_INTR, ioaddr + TX_INTR); outb(D_RX_INTR, ioaddr + RX_INTR); + + if (lp->base != NULL) { + /* Ack interrupt for multifunction card */ + writeb(0x01, lp->base+0x802); + writeb(0x09, lp->base+0x822); + } + return IRQ_HANDLED; } /* fjn_interrupt */ @@ -1036,7 +1070,6 @@ static void fjn_rx(struct net_device *dev) #endif netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/pcmcia/nmclan_cs.c b/drivers/net/pcmcia/nmclan_cs.c index 448cd40aeba5ab37c2c913db34745ac87b2857fd..ec7c588c9ae5cf77eec416fa1c929a0f152a13af 100644 --- a/drivers/net/pcmcia/nmclan_cs.c +++ b/drivers/net/pcmcia/nmclan_cs.c @@ -659,7 +659,6 @@ static int nmclan_config(struct pcmcia_device *link) u_char buf[64]; int i, last_ret, last_fn; unsigned int ioaddr; - DECLARE_MAC_BUF(mac); DEBUG(0, "nmclan_config(0x%p)\n", link); @@ -719,9 +718,9 @@ static int nmclan_config(struct pcmcia_device *link) strcpy(lp->node.dev_name, dev->name); printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port," - " hw_addr %s\n", + " hw_addr %pM\n", dev->name, dev->base_addr, dev->irq, if_names[dev->if_port], - print_mac(mac, dev->dev_addr)); + dev->dev_addr); return 0; cs_failed: @@ -1193,7 +1192,6 @@ static int mace_rx(struct net_device *dev, unsigned char RxCnt) netif_rx(skb); /* Send the packet to the upper (protocol) layers. */ - dev->last_rx = jiffies; lp->linux_stats.rx_packets++; lp->linux_stats.rx_bytes += pkt_len; outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */ diff --git a/drivers/net/pcmcia/pcnet_cs.c b/drivers/net/pcmcia/pcnet_cs.c index ce486f09449215dc08baec27aeb723dd0484b371..c38ed777f0a890a60f6092bea0ec0efb197b8e98 100644 --- a/drivers/net/pcmcia/pcnet_cs.c +++ b/drivers/net/pcmcia/pcnet_cs.c @@ -554,7 +554,6 @@ static int pcnet_config(struct pcmcia_device *link) int last_ret, last_fn, start_pg, stop_pg, cm_offset; int has_shmem = 0; hw_info_t *local_hw_info; - DECLARE_MAC_BUF(mac); DEBUG(0, "pcnet_config(0x%p)\n", link); @@ -675,7 +674,7 @@ static int pcnet_config(struct pcmcia_device *link) printk (" mem %#5lx,", dev->mem_start); if (info->flags & HAS_MISC_REG) printk(" %s xcvr,", if_names[dev->if_port]); - printk(" hw_addr %s\n", print_mac(mac, dev->dev_addr)); + printk(" hw_addr %pM\n", dev->dev_addr); return 0; cs_failed: diff --git a/drivers/net/pcmcia/smc91c92_cs.c b/drivers/net/pcmcia/smc91c92_cs.c index c74d6656d2662bcf5b2d91dcea374c062404b4b1..fccd53ef3c64738c2cb7d5141895f3c5e3251d30 100644 --- a/drivers/net/pcmcia/smc91c92_cs.c +++ b/drivers/net/pcmcia/smc91c92_cs.c @@ -949,7 +949,6 @@ static int smc91c92_config(struct pcmcia_device *link) int i, j, rev; unsigned int ioaddr; u_long mir; - DECLARE_MAC_BUF(mac); DEBUG(0, "smc91c92_config(0x%p)\n", link); @@ -1062,9 +1061,9 @@ static int smc91c92_config(struct pcmcia_device *link) strcpy(smc->node.dev_name, dev->name); printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, " - "hw_addr %s\n", + "hw_addr %pM\n", dev->name, name, (rev & 0x0f), dev->base_addr, dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); if (rev > 0) { if (mir & 0x3ff) diff --git a/drivers/net/pcmcia/xirc2ps_cs.c b/drivers/net/pcmcia/xirc2ps_cs.c index e1fd585e71315ea15ec07a6ed9b2e675db1df4d2..fef7e1861d6a3fbf25922e92ed68b7f4e8924138 100644 --- a/drivers/net/pcmcia/xirc2ps_cs.c +++ b/drivers/net/pcmcia/xirc2ps_cs.c @@ -772,7 +772,6 @@ xirc2ps_config(struct pcmcia_device * link) int err, i; u_char buf[64]; cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data; - DECLARE_MAC_BUF(mac); local->dingo_ccr = NULL; @@ -1051,9 +1050,9 @@ xirc2ps_config(struct pcmcia_device * link) strcpy(local->node.dev_name, dev->name); /* give some infos about the hardware */ - printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %s\n", + printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr %pM\n", dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); return 0; @@ -1243,7 +1242,6 @@ xirc2ps_interrupt(int irq, void *dev_id) } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pktlen; if (!(rsr & PhyPkt)) diff --git a/drivers/net/pcnet32.c b/drivers/net/pcnet32.c index ca8c0e03740027980ded217605ea394f5c5c3ca0..044b7b07f5f48cf83ebbb8c7adce3134a3470f04 100644 --- a/drivers/net/pcnet32.c +++ b/drivers/net/pcnet32.c @@ -1246,7 +1246,6 @@ static void pcnet32_rx_entry(struct net_device *dev, dev->stats.rx_bytes += skb->len; skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; return; } @@ -1398,7 +1397,7 @@ static int pcnet32_poll(struct napi_struct *napi, int budget) if (work_done < budget) { spin_lock_irqsave(&lp->lock, flags); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); /* clear interrupt masks */ val = lp->a.read_csr(ioaddr, CSR3); @@ -1747,8 +1746,7 @@ pcnet32_probe1(unsigned long ioaddr, int shared, struct pci_dev *pdev) memset(dev->dev_addr, 0, sizeof(dev->dev_addr)); if (pcnet32_debug & NETIF_MSG_PROBE) { - DECLARE_MAC_BUF(mac); - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); /* Version 0x2623 and 0x2624 */ if (((chip_version + 1) & 0xfffe) == 0x2624) { @@ -2588,14 +2586,14 @@ pcnet32_interrupt(int irq, void *dev_id) dev->name, csr0); /* unlike for the lance, there is no restart needed */ } - if (netif_rx_schedule_prep(dev, &lp->napi)) { + if (netif_rx_schedule_prep(&lp->napi)) { u16 val; /* set interrupt masks */ val = lp->a.read_csr(ioaddr, CSR3); val |= 0x5f00; lp->a.write_csr(ioaddr, CSR3, val); mmiowb(); - __netif_rx_schedule(dev, &lp->napi); + __netif_rx_schedule(&lp->napi); break; } csr0 = lp->a.read_csr(ioaddr, CSR0); diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig index d55932acd887fc3b41c32a359c92077e9dfbd7b8..de9cf5136fdcc4367aa981d8fbb517f54270c00e 100644 --- a/drivers/net/phy/Kconfig +++ b/drivers/net/phy/Kconfig @@ -66,6 +66,22 @@ config REALTEK_PHY ---help--- Supports the Realtek 821x PHY. +config NATIONAL_PHY + tristate "Drivers for National Semiconductor PHYs" + ---help--- + Currently supports the DP83865 PHY. + +config STE10XP + depends on PHYLIB + tristate "Driver for STMicroelectronics STe10Xp PHYs" + ---help--- + This is the driver for the STe100p and STe101p PHYs. + +config LSI_ET1011C_PHY + tristate "Driver for LSI ET1011C PHY" + ---help--- + Supports the LSI ET1011C PHY. + config FIXED_PHY bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs" depends on PHYLIB=y @@ -84,10 +100,13 @@ config MDIO_BITBANG If in doubt, say N. -config MDIO_OF_GPIO +config MDIO_GPIO tristate "Support for GPIO lib-based bitbanged MDIO buses" - depends on MDIO_BITBANG && OF_GPIO + depends on MDIO_BITBANG && GENERIC_GPIO ---help--- Supports GPIO lib-based MDIO busses. + To compile this driver as a module, choose M here: the module + will be called mdio-gpio. + endif # PHYLIB diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile index eee329fa6f5355dfa1ef0817aa6ebc080553f8c5..3a1bfefefbc3b5d795f9716c6c7f1a086b8b81fe 100644 --- a/drivers/net/phy/Makefile +++ b/drivers/net/phy/Makefile @@ -13,6 +13,9 @@ obj-$(CONFIG_VITESSE_PHY) += vitesse.o obj-$(CONFIG_BROADCOM_PHY) += broadcom.o obj-$(CONFIG_ICPLUS_PHY) += icplus.o obj-$(CONFIG_REALTEK_PHY) += realtek.o +obj-$(CONFIG_LSI_ET1011C_PHY) += et1011c.o obj-$(CONFIG_FIXED_PHY) += fixed.o obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o -obj-$(CONFIG_MDIO_OF_GPIO) += mdio-ofgpio.o +obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o +obj-$(CONFIG_NATIONAL_PHY) += national.o +obj-$(CONFIG_STE10XP) += ste10Xp.o diff --git a/drivers/net/phy/broadcom.c b/drivers/net/phy/broadcom.c index 4b4dc98ad165df01b96dcd9753419d383132461d..190efc3301c6c4b815f47efe7013483a7b43e282 100644 --- a/drivers/net/phy/broadcom.c +++ b/drivers/net/phy/broadcom.c @@ -17,6 +17,8 @@ #include #include +#define PHY_ID_BCM50610 0x0143bd60 + #define MII_BCM54XX_ECR 0x10 /* BCM54xx extended control register */ #define MII_BCM54XX_ECR_IM 0x1000 /* Interrupt mask */ #define MII_BCM54XX_ECR_IF 0x0800 /* Interrupt force */ @@ -53,6 +55,21 @@ #define MII_BCM54XX_SHD_VAL(x) ((x & 0x1f) << 10) #define MII_BCM54XX_SHD_DATA(x) ((x & 0x3ff) << 0) +/* + * AUXILIARY CONTROL SHADOW ACCESS REGISTERS. (PHY REG 0x18) + */ +#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000 +#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB 0x0400 +#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA 0x0800 + +#define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000 +#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200 +#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000 +#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007 + +#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000 + + /* * Broadcom LED source encodings. These are used in BCM5461, BCM5481, * BCM5482, and possibly some others. @@ -87,6 +104,24 @@ #define BCM5482_SHD_MODE 0x1f /* 11111: Mode Control Register */ #define BCM5482_SHD_MODE_1000BX 0x0001 /* Enable 1000BASE-X registers */ +/* + * EXPANSION SHADOW ACCESS REGISTERS. (PHY REG 0x15, 0x16, and 0x17) + */ +#define MII_BCM54XX_EXP_AADJ1CH0 0x001f +#define MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN 0x0200 +#define MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF 0x0100 +#define MII_BCM54XX_EXP_AADJ1CH3 0x601f +#define MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ 0x0002 +#define MII_BCM54XX_EXP_EXP08 0x0F08 +#define MII_BCM54XX_EXP_EXP08_RJCT_2MHZ 0x0001 +#define MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE 0x0200 +#define MII_BCM54XX_EXP_EXP75 0x0f75 +#define MII_BCM54XX_EXP_EXP75_VDACCTRL 0x003c +#define MII_BCM54XX_EXP_EXP96 0x0f96 +#define MII_BCM54XX_EXP_EXP96_MYST 0x0010 +#define MII_BCM54XX_EXP_EXP97 0x0f97 +#define MII_BCM54XX_EXP_EXP97_MYST 0x0c0c + /* * BCM5482: Secondary SerDes registers */ @@ -128,40 +163,93 @@ static int bcm54xx_shadow_write(struct phy_device *phydev, u16 shadow, u16 val) MII_BCM54XX_SHD_DATA(val)); } -/* - * Indirect register access functions for the Expansion Registers - * and Secondary SerDes registers (when sec_serdes=1). - */ -static int bcm54xx_exp_read(struct phy_device *phydev, - int sec_serdes, u8 regnum) +/* Indirect register access functions for the Expansion Registers */ +static int bcm54xx_exp_read(struct phy_device *phydev, u8 regnum) { int val; - phy_write(phydev, MII_BCM54XX_EXP_SEL, - (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : - MII_BCM54XX_EXP_SEL_ER) | - regnum); + val = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + if (val < 0) + return val; + val = phy_read(phydev, MII_BCM54XX_EXP_DATA); - phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + + /* Restore default value. It's O.K. if this write fails. */ + phy_write(phydev, MII_BCM54XX_EXP_SEL, 0); return val; } -static int bcm54xx_exp_write(struct phy_device *phydev, - int sec_serdes, u8 regnum, u16 val) +static int bcm54xx_exp_write(struct phy_device *phydev, u16 regnum, u16 val) { int ret; - phy_write(phydev, MII_BCM54XX_EXP_SEL, - (sec_serdes ? MII_BCM54XX_EXP_SEL_SSD : - MII_BCM54XX_EXP_SEL_ER) | - regnum); + ret = phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + if (ret < 0) + return ret; + ret = phy_write(phydev, MII_BCM54XX_EXP_DATA, val); - phy_write(phydev, MII_BCM54XX_EXP_SEL, regnum); + + /* Restore default value. It's O.K. if this write fails. */ + phy_write(phydev, MII_BCM54XX_EXP_SEL, 0); return ret; } +static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val) +{ + return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val); +} + +static int bcm50610_a0_workaround(struct phy_device *phydev) +{ + int err; + + err = bcm54xx_auxctl_write(phydev, + MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, + MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA | + MII_BCM54XX_AUXCTL_ACTL_TX_6DB); + if (err < 0) + return err; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP08, + MII_BCM54XX_EXP_EXP08_RJCT_2MHZ | + MII_BCM54XX_EXP_EXP08_EARLY_DAC_WAKE); + if (err < 0) + goto error; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH0, + MII_BCM54XX_EXP_AADJ1CH0_SWP_ABCD_OEN | + MII_BCM54XX_EXP_AADJ1CH0_SWSEL_THPF); + if (err < 0) + goto error; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_AADJ1CH3, + MII_BCM54XX_EXP_AADJ1CH3_ADCCKADJ); + if (err < 0) + goto error; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP75, + MII_BCM54XX_EXP_EXP75_VDACCTRL); + if (err < 0) + goto error; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP96, + MII_BCM54XX_EXP_EXP96_MYST); + if (err < 0) + goto error; + + err = bcm54xx_exp_write(phydev, MII_BCM54XX_EXP_EXP97, + MII_BCM54XX_EXP_EXP97_MYST); + +error: + bcm54xx_auxctl_write(phydev, + MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL, + MII_BCM54XX_AUXCTL_ACTL_TX_6DB); + + return err; +} + static int bcm54xx_config_init(struct phy_device *phydev) { int reg, err; @@ -183,6 +271,13 @@ static int bcm54xx_config_init(struct phy_device *phydev) err = phy_write(phydev, MII_BCM54XX_IMR, reg); if (err < 0) return err; + + if (phydev->drv->phy_id == PHY_ID_BCM50610) { + err = bcm50610_a0_workaround(phydev); + if (err < 0) + return err; + } + return 0; } @@ -205,18 +300,27 @@ static int bcm5482_config_init(struct phy_device *phydev) /* * Enable SGMII slave mode and auto-detection */ - reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_SGMII_SLAVE); - bcm54xx_exp_write(phydev, 1, BCM5482_SSD_SGMII_SLAVE, - reg | - BCM5482_SSD_SGMII_SLAVE_EN | - BCM5482_SSD_SGMII_SLAVE_AD); + reg = BCM5482_SSD_SGMII_SLAVE | MII_BCM54XX_EXP_SEL_SSD; + err = bcm54xx_exp_read(phydev, reg); + if (err < 0) + return err; + err = bcm54xx_exp_write(phydev, reg, err | + BCM5482_SSD_SGMII_SLAVE_EN | + BCM5482_SSD_SGMII_SLAVE_AD); + if (err < 0) + return err; /* * Disable secondary SerDes powerdown */ - reg = bcm54xx_exp_read(phydev, 1, BCM5482_SSD_1000BX_CTL); - bcm54xx_exp_write(phydev, 1, BCM5482_SSD_1000BX_CTL, - reg & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); + reg = BCM5482_SSD_1000BX_CTL | MII_BCM54XX_EXP_SEL_SSD; + err = bcm54xx_exp_read(phydev, reg); + if (err < 0) + return err; + err = bcm54xx_exp_write(phydev, reg, + err & ~BCM5482_SSD_1000BX_CTL_PWRDOWN); + if (err < 0) + return err; /* * Select 1000BASE-X register set (primary SerDes) @@ -335,7 +439,8 @@ static struct phy_driver bcm5411_driver = { .phy_id = 0x00206070, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5411", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, @@ -349,7 +454,8 @@ static struct phy_driver bcm5421_driver = { .phy_id = 0x002060e0, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5421", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, @@ -363,7 +469,8 @@ static struct phy_driver bcm5461_driver = { .phy_id = 0x002060c0, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5461", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, @@ -377,7 +484,8 @@ static struct phy_driver bcm5464_driver = { .phy_id = 0x002060b0, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5464", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = genphy_config_aneg, @@ -391,7 +499,8 @@ static struct phy_driver bcm5481_driver = { .phy_id = 0x0143bca0, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5481", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm54xx_config_init, .config_aneg = bcm5481_config_aneg, @@ -405,7 +514,8 @@ static struct phy_driver bcm5482_driver = { .phy_id = 0x0143bcb0, .phy_id_mask = 0xfffffff0, .name = "Broadcom BCM5482", - .features = PHY_GBIT_FEATURES, + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, .config_init = bcm5482_config_init, .config_aneg = genphy_config_aneg, @@ -415,6 +525,36 @@ static struct phy_driver bcm5482_driver = { .driver = { .owner = THIS_MODULE }, }; +static struct phy_driver bcm50610_driver = { + .phy_id = PHY_ID_BCM50610, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM50610", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = bcm54xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm54xx_ack_interrupt, + .config_intr = bcm54xx_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + +static struct phy_driver bcm57780_driver = { + .phy_id = 0x03625d90, + .phy_id_mask = 0xfffffff0, + .name = "Broadcom BCM57780", + .features = PHY_GBIT_FEATURES | + SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT, + .config_init = bcm54xx_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = bcm54xx_ack_interrupt, + .config_intr = bcm54xx_config_intr, + .driver = { .owner = THIS_MODULE }, +}; + static int __init broadcom_init(void) { int ret; @@ -437,8 +577,18 @@ static int __init broadcom_init(void) ret = phy_driver_register(&bcm5482_driver); if (ret) goto out_5482; + ret = phy_driver_register(&bcm50610_driver); + if (ret) + goto out_50610; + ret = phy_driver_register(&bcm57780_driver); + if (ret) + goto out_57780; return ret; +out_57780: + phy_driver_unregister(&bcm50610_driver); +out_50610: + phy_driver_unregister(&bcm5482_driver); out_5482: phy_driver_unregister(&bcm5481_driver); out_5481: @@ -455,6 +605,8 @@ out_5411: static void __exit broadcom_exit(void) { + phy_driver_unregister(&bcm57780_driver); + phy_driver_unregister(&bcm50610_driver); phy_driver_unregister(&bcm5482_driver); phy_driver_unregister(&bcm5481_driver); phy_driver_unregister(&bcm5464_driver); diff --git a/drivers/net/phy/et1011c.c b/drivers/net/phy/et1011c.c new file mode 100644 index 0000000000000000000000000000000000000000..b031fa21f1aa0a6f4640e9a61099210ab0a88306 --- /dev/null +++ b/drivers/net/phy/et1011c.c @@ -0,0 +1,113 @@ +/* + * drivers/net/phy/et1011c.c + * + * Driver for LSI ET1011C PHYs + * + * Author: Chaithrika U S + * + * Copyright (c) 2008 Texas Instruments + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ET1011C_STATUS_REG (0x1A) +#define ET1011C_CONFIG_REG (0x16) +#define ET1011C_SPEED_MASK (0x0300) +#define ET1011C_GIGABIT_SPEED (0x0200) +#define ET1011C_TX_FIFO_MASK (0x3000) +#define ET1011C_TX_FIFO_DEPTH_8 (0x0000) +#define ET1011C_TX_FIFO_DEPTH_16 (0x1000) +#define ET1011C_INTERFACE_MASK (0x0007) +#define ET1011C_GMII_INTERFACE (0x0002) +#define ET1011C_SYS_CLK_EN (0x01 << 4) + + +MODULE_DESCRIPTION("LSI ET1011C PHY driver"); +MODULE_AUTHOR("Chaithrika U S"); +MODULE_LICENSE("GPL"); + +static int et1011c_config_aneg(struct phy_device *phydev) +{ + int ctl = 0; + ctl = phy_read(phydev, MII_BMCR); + if (ctl < 0) + return ctl; + ctl &= ~(BMCR_FULLDPLX | BMCR_SPEED100 | BMCR_SPEED1000 | + BMCR_ANENABLE); + /* First clear the PHY */ + phy_write(phydev, MII_BMCR, ctl | BMCR_RESET); + + return genphy_config_aneg(phydev); +} + +static int et1011c_read_status(struct phy_device *phydev) +{ + int ret; + u32 val; + static int speed; + ret = genphy_read_status(phydev); + + if (speed != phydev->speed) { + speed = phydev->speed; + val = phy_read(phydev, ET1011C_STATUS_REG); + if ((val & ET1011C_SPEED_MASK) == + ET1011C_GIGABIT_SPEED) { + val = phy_read(phydev, ET1011C_CONFIG_REG); + val &= ~ET1011C_TX_FIFO_MASK; + phy_write(phydev, ET1011C_CONFIG_REG, val\ + | ET1011C_GMII_INTERFACE\ + | ET1011C_SYS_CLK_EN\ + | ET1011C_TX_FIFO_DEPTH_16); + + } + } + return ret; +} + +static struct phy_driver et1011c_driver = { + .phy_id = 0x0282f014, + .name = "ET1011C", + .phy_id_mask = 0xfffffff0, + .features = (PHY_BASIC_FEATURES | SUPPORTED_1000baseT_Full), + .flags = PHY_POLL, + .config_aneg = et1011c_config_aneg, + .read_status = et1011c_read_status, + .driver = { .owner = THIS_MODULE,}, +}; + +static int __init et1011c_init(void) +{ + return phy_driver_register(&et1011c_driver); +} + +static void __exit et1011c_exit(void) +{ + phy_driver_unregister(&et1011c_driver); +} + +module_init(et1011c_init); +module_exit(et1011c_exit); diff --git a/drivers/net/phy/mdio-gpio.c b/drivers/net/phy/mdio-gpio.c new file mode 100644 index 0000000000000000000000000000000000000000..a439ebeb431926e7bec18d84dcd22a8bc30f5b53 --- /dev/null +++ b/drivers/net/phy/mdio-gpio.c @@ -0,0 +1,296 @@ +/* + * GPIO based MDIO bitbang driver. + * Supports OpenFirmware. + * + * Copyright (c) 2008 CSE Semaphore Belgium. + * by Laurent Pinchart + * + * Copyright (C) 2008, Paulius Zaleckas + * + * Based on earlier work by + * + * Copyright (c) 2003 Intracom S.A. + * by Pantelis Antoniou + * + * 2005 (c) MontaVista Software, Inc. + * Vitaly Bordug + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_OF_GPIO +#include +#include +#endif + +struct mdio_gpio_info { + struct mdiobb_ctrl ctrl; + int mdc, mdio; +}; + +static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + if (dir) + gpio_direction_output(bitbang->mdio, 1); + else + gpio_direction_input(bitbang->mdio); +} + +static int mdio_get(struct mdiobb_ctrl *ctrl) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + return gpio_get_value(bitbang->mdio); +} + +static void mdio_set(struct mdiobb_ctrl *ctrl, int what) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + gpio_set_value(bitbang->mdio, what); +} + +static void mdc_set(struct mdiobb_ctrl *ctrl, int what) +{ + struct mdio_gpio_info *bitbang = + container_of(ctrl, struct mdio_gpio_info, ctrl); + + gpio_set_value(bitbang->mdc, what); +} + +static struct mdiobb_ops mdio_gpio_ops = { + .owner = THIS_MODULE, + .set_mdc = mdc_set, + .set_mdio_dir = mdio_dir, + .set_mdio_data = mdio_set, + .get_mdio_data = mdio_get, +}; + +static int __devinit mdio_gpio_bus_init(struct device *dev, + struct mdio_gpio_platform_data *pdata, + int bus_id) +{ + struct mii_bus *new_bus; + struct mdio_gpio_info *bitbang; + int ret = -ENOMEM; + int i; + + bitbang = kzalloc(sizeof(*bitbang), GFP_KERNEL); + if (!bitbang) + goto out; + + bitbang->ctrl.ops = &mdio_gpio_ops; + bitbang->mdc = pdata->mdc; + bitbang->mdio = pdata->mdio; + + new_bus = alloc_mdio_bitbang(&bitbang->ctrl); + if (!new_bus) + goto out_free_bitbang; + + new_bus->name = "GPIO Bitbanged MDIO", + + ret = -ENODEV; + + new_bus->phy_mask = pdata->phy_mask; + new_bus->irq = pdata->irqs; + new_bus->parent = dev; + + if (new_bus->phy_mask == ~0) + goto out_free_bus; + + for (i = 0; i < PHY_MAX_ADDR; i++) + if (!new_bus->irq[i]) + new_bus->irq[i] = PHY_POLL; + + snprintf(new_bus->id, MII_BUS_ID_SIZE, "%x", bus_id); + + if (gpio_request(bitbang->mdc, "mdc")) + goto out_free_bus; + + if (gpio_request(bitbang->mdio, "mdio")) + goto out_free_mdc; + + dev_set_drvdata(dev, new_bus); + + ret = mdiobus_register(new_bus); + if (ret) + goto out_free_all; + + return 0; + +out_free_all: + dev_set_drvdata(dev, NULL); + gpio_free(bitbang->mdio); +out_free_mdc: + gpio_free(bitbang->mdc); +out_free_bus: + free_mdio_bitbang(new_bus); +out_free_bitbang: + kfree(bitbang); +out: + return ret; +} + +static void __devexit mdio_gpio_bus_destroy(struct device *dev) +{ + struct mii_bus *bus = dev_get_drvdata(dev); + struct mdio_gpio_info *bitbang = bus->priv; + + mdiobus_unregister(bus); + free_mdio_bitbang(bus); + dev_set_drvdata(dev, NULL); + gpio_free(bitbang->mdc); + gpio_free(bitbang->mdio); + kfree(bitbang); +} + +static int __devinit mdio_gpio_probe(struct platform_device *pdev) +{ + struct mdio_gpio_platform_data *pdata = pdev->dev.platform_data; + + if (!pdata) + return -ENODEV; + + return mdio_gpio_bus_init(&pdev->dev, pdata, pdev->id); +} + +static int __devexit mdio_gpio_remove(struct platform_device *pdev) +{ + mdio_gpio_bus_destroy(&pdev->dev); + + return 0; +} + +#ifdef CONFIG_OF_GPIO +static void __devinit add_phy(struct mdio_gpio_platform_data *pdata, + struct device_node *np) +{ + const u32 *data; + int len, id, irq; + + data = of_get_property(np, "reg", &len); + if (!data || len != 4) + return; + + id = *data; + pdata->phy_mask &= ~(1 << id); + + irq = of_irq_to_resource(np, 0, NULL); + if (irq) + pdata->irqs[id] = irq; +} + +static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, + const struct of_device_id *match) +{ + struct device_node *np = NULL; + struct mdio_gpio_platform_data *pdata; + + pdata = kzalloc(sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return -ENOMEM; + + pdata->mdc = of_get_gpio(ofdev->node, 0); + pdata->mdio = of_get_gpio(ofdev->node, 1); + + if (pdata->mdc < 0 || pdata->mdio < 0) + goto out_free; + + while ((np = of_get_next_child(ofdev->node, np))) + if (!strcmp(np->type, "ethernet-phy")) + add_phy(pdata, np); + + return mdio_gpio_bus_init(&ofdev->dev, pdata, pdata->mdc); + +out_free: + kfree(pdata); + return -ENODEV; +} + +static int __devexit mdio_ofgpio_remove(struct of_device *ofdev) +{ + mdio_gpio_bus_destroy(&ofdev->dev); + kfree(ofdev->dev.platform_data); + + return 0; +} + +static struct of_device_id mdio_ofgpio_match[] = { + { + .compatible = "virtual,mdio-gpio", + }, + {}, +}; + +static struct of_platform_driver mdio_ofgpio_driver = { + .name = "mdio-gpio", + .match_table = mdio_ofgpio_match, + .probe = mdio_ofgpio_probe, + .remove = __devexit_p(mdio_ofgpio_remove), +}; + +static inline int __init mdio_ofgpio_init(void) +{ + return of_register_platform_driver(&mdio_ofgpio_driver); +} + +static inline void __exit mdio_ofgpio_exit(void) +{ + of_unregister_platform_driver(&mdio_ofgpio_driver); +} +#else +static inline int __init mdio_ofgpio_init(void) { return 0; } +static inline void __exit mdio_ofgpio_exit(void) { } +#endif /* CONFIG_OF_GPIO */ + +static struct platform_driver mdio_gpio_driver = { + .probe = mdio_gpio_probe, + .remove = __devexit_p(mdio_gpio_remove), + .driver = { + .name = "mdio-gpio", + .owner = THIS_MODULE, + }, +}; + +static int __init mdio_gpio_init(void) +{ + int ret; + + ret = mdio_ofgpio_init(); + if (ret) + return ret; + + ret = platform_driver_register(&mdio_gpio_driver); + if (ret) + mdio_ofgpio_exit(); + + return ret; +} +module_init(mdio_gpio_init); + +static void __exit mdio_gpio_exit(void) +{ + platform_driver_unregister(&mdio_gpio_driver); + mdio_ofgpio_exit(); +} +module_exit(mdio_gpio_exit); + +MODULE_ALIAS("platform:mdio-gpio"); +MODULE_AUTHOR("Laurent Pinchart, Paulius Zaleckas"); +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Generic driver for MDIO bus emulation using GPIO"); diff --git a/drivers/net/phy/mdio-ofgpio.c b/drivers/net/phy/mdio-ofgpio.c deleted file mode 100644 index 2ff97754e574cffec278cb3a7188ca875524fd24..0000000000000000000000000000000000000000 --- a/drivers/net/phy/mdio-ofgpio.c +++ /dev/null @@ -1,204 +0,0 @@ -/* - * OpenFirmware GPIO based MDIO bitbang driver. - * - * Copyright (c) 2008 CSE Semaphore Belgium. - * by Laurent Pinchart - * - * Based on earlier work by - * - * Copyright (c) 2003 Intracom S.A. - * by Pantelis Antoniou - * - * 2005 (c) MontaVista Software, Inc. - * Vitaly Bordug - * - * This file is licensed under the terms of the GNU General Public License - * version 2. This program is licensed "as is" without any warranty of any - * kind, whether express or implied. - */ - -#include -#include -#include -#include -#include -#include -#include - -struct mdio_gpio_info { - struct mdiobb_ctrl ctrl; - int mdc, mdio; -}; - -static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - if (dir) - gpio_direction_output(bitbang->mdio, 1); - else - gpio_direction_input(bitbang->mdio); -} - -static int mdio_read(struct mdiobb_ctrl *ctrl) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - return gpio_get_value(bitbang->mdio); -} - -static void mdio(struct mdiobb_ctrl *ctrl, int what) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - gpio_set_value(bitbang->mdio, what); -} - -static void mdc(struct mdiobb_ctrl *ctrl, int what) -{ - struct mdio_gpio_info *bitbang = - container_of(ctrl, struct mdio_gpio_info, ctrl); - - gpio_set_value(bitbang->mdc, what); -} - -static struct mdiobb_ops mdio_gpio_ops = { - .owner = THIS_MODULE, - .set_mdc = mdc, - .set_mdio_dir = mdio_dir, - .set_mdio_data = mdio, - .get_mdio_data = mdio_read, -}; - -static int __devinit mdio_ofgpio_bitbang_init(struct mii_bus *bus, - struct device_node *np) -{ - struct mdio_gpio_info *bitbang = bus->priv; - - bitbang->mdc = of_get_gpio(np, 0); - bitbang->mdio = of_get_gpio(np, 1); - - if (bitbang->mdc < 0 || bitbang->mdio < 0) - return -ENODEV; - - snprintf(bus->id, MII_BUS_ID_SIZE, "%x", bitbang->mdc); - return 0; -} - -static void __devinit add_phy(struct mii_bus *bus, struct device_node *np) -{ - const u32 *data; - int len, id, irq; - - data = of_get_property(np, "reg", &len); - if (!data || len != 4) - return; - - id = *data; - bus->phy_mask &= ~(1 << id); - - irq = of_irq_to_resource(np, 0, NULL); - if (irq != NO_IRQ) - bus->irq[id] = irq; -} - -static int __devinit mdio_ofgpio_probe(struct of_device *ofdev, - const struct of_device_id *match) -{ - struct device_node *np = NULL; - struct mii_bus *new_bus; - struct mdio_gpio_info *bitbang; - int ret = -ENOMEM; - int i; - - bitbang = kzalloc(sizeof(struct mdio_gpio_info), GFP_KERNEL); - if (!bitbang) - goto out; - - bitbang->ctrl.ops = &mdio_gpio_ops; - - new_bus = alloc_mdio_bitbang(&bitbang->ctrl); - if (!new_bus) - goto out_free_bitbang; - - new_bus->name = "GPIO Bitbanged MII", - - ret = mdio_ofgpio_bitbang_init(new_bus, ofdev->node); - if (ret) - goto out_free_bus; - - new_bus->phy_mask = ~0; - new_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL); - if (!new_bus->irq) - goto out_free_bus; - - for (i = 0; i < PHY_MAX_ADDR; i++) - new_bus->irq[i] = -1; - - while ((np = of_get_next_child(ofdev->node, np))) - if (!strcmp(np->type, "ethernet-phy")) - add_phy(new_bus, np); - - new_bus->parent = &ofdev->dev; - dev_set_drvdata(&ofdev->dev, new_bus); - - ret = mdiobus_register(new_bus); - if (ret) - goto out_free_irqs; - - return 0; - -out_free_irqs: - dev_set_drvdata(&ofdev->dev, NULL); - kfree(new_bus->irq); -out_free_bus: - free_mdio_bitbang(new_bus); -out_free_bitbang: - kfree(bitbang); -out: - return ret; -} - -static int mdio_ofgpio_remove(struct of_device *ofdev) -{ - struct mii_bus *bus = dev_get_drvdata(&ofdev->dev); - struct mdio_gpio_info *bitbang = bus->priv; - - mdiobus_unregister(bus); - kfree(bus->irq); - free_mdio_bitbang(bus); - dev_set_drvdata(&ofdev->dev, NULL); - kfree(bitbang); - - return 0; -} - -static struct of_device_id mdio_ofgpio_match[] = { - { - .compatible = "virtual,mdio-gpio", - }, - {}, -}; - -static struct of_platform_driver mdio_ofgpio_driver = { - .name = "mdio-gpio", - .match_table = mdio_ofgpio_match, - .probe = mdio_ofgpio_probe, - .remove = mdio_ofgpio_remove, -}; - -static int mdio_ofgpio_init(void) -{ - return of_register_platform_driver(&mdio_ofgpio_driver); -} - -static void mdio_ofgpio_exit(void) -{ - of_unregister_platform_driver(&mdio_ofgpio_driver); -} - -module_init(mdio_ofgpio_init); -module_exit(mdio_ofgpio_exit); diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c index 289fc267edf30eb5094d24f416ca644c9494d401..11adf6ed46288cf1e48a329d555feda84d1d442b 100644 --- a/drivers/net/phy/mdio_bus.c +++ b/drivers/net/phy/mdio_bus.c @@ -63,7 +63,9 @@ EXPORT_SYMBOL(mdiobus_alloc); static void mdiobus_release(struct device *d) { struct mii_bus *bus = to_mii_bus(d); - BUG_ON(bus->state != MDIOBUS_RELEASED); + BUG_ON(bus->state != MDIOBUS_RELEASED && + /* for compatibility with error handling in drivers */ + bus->state != MDIOBUS_ALLOCATED); kfree(bus); } @@ -83,8 +85,7 @@ static struct class mdio_bus_class = { */ int mdiobus_register(struct mii_bus *bus) { - int i; - int err = 0; + int i, err; if (NULL == bus || NULL == bus->name || NULL == bus->read || @@ -97,7 +98,7 @@ int mdiobus_register(struct mii_bus *bus) bus->dev.parent = bus->parent; bus->dev.class = &mdio_bus_class; bus->dev.groups = NULL; - memcpy(bus->dev.bus_id, bus->id, MII_BUS_ID_SIZE); + dev_set_name(&bus->dev, bus->id); err = device_register(&bus->dev); if (err) { @@ -116,16 +117,23 @@ int mdiobus_register(struct mii_bus *bus) struct phy_device *phydev; phydev = mdiobus_scan(bus, i); - if (IS_ERR(phydev)) + if (IS_ERR(phydev)) { err = PTR_ERR(phydev); + goto error; + } } } - if (!err) - bus->state = MDIOBUS_REGISTERED; - + bus->state = MDIOBUS_REGISTERED; pr_info("%s: probed\n", bus->name); + return 0; +error: + while (--i >= 0) { + if (bus->phy_map[i]) + device_unregister(&bus->phy_map[i]->dev); + } + device_del(&bus->dev); return err; } EXPORT_SYMBOL(mdiobus_register); @@ -192,7 +200,7 @@ struct phy_device *mdiobus_scan(struct mii_bus *bus, int addr) phydev->dev.parent = bus->parent; phydev->dev.bus = &mdio_bus_type; - snprintf(phydev->dev.bus_id, BUS_ID_SIZE, PHY_ID_FMT, bus->id, addr); + dev_set_name(&phydev->dev, PHY_ID_FMT, bus->id, addr); phydev->bus = bus; @@ -285,9 +293,12 @@ static int mdio_bus_suspend(struct device * dev, pm_message_t state) { int ret = 0; struct device_driver *drv = dev->driver; + struct phy_driver *phydrv = to_phy_driver(drv); + struct phy_device *phydev = to_phy_device(dev); - if (drv && drv->suspend) - ret = drv->suspend(dev, state); + if ((!device_may_wakeup(phydev->dev.parent)) && + (phydrv && phydrv->suspend)) + ret = phydrv->suspend(phydev); return ret; } @@ -296,9 +307,12 @@ static int mdio_bus_resume(struct device * dev) { int ret = 0; struct device_driver *drv = dev->driver; + struct phy_driver *phydrv = to_phy_driver(drv); + struct phy_device *phydev = to_phy_device(dev); - if (drv && drv->resume) - ret = drv->resume(dev); + if ((!device_may_wakeup(phydev->dev.parent)) && + (phydrv && phydrv->resume)) + ret = phydrv->resume(phydev); return ret; } diff --git a/drivers/net/phy/national.c b/drivers/net/phy/national.c new file mode 100644 index 0000000000000000000000000000000000000000..6c636eb720896c79b0be943e16c1f2b743c10d46 --- /dev/null +++ b/drivers/net/phy/national.c @@ -0,0 +1,155 @@ +/* + * drivers/net/phy/national.c + * + * Driver for National Semiconductor PHYs + * + * Author: Stuart Menefy + * Maintainer: Giuseppe Cavallaro + * + * Copyright (c) 2008 STMicroelectronics Limited + * + * 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 +#include +#include +#include +#include +#include + +/* DP83865 phy identifier values */ +#define DP83865_PHY_ID 0x20005c7a + +#define DP83865_INT_MASK_REG 0x15 +#define DP83865_INT_MASK_STATUS 0x14 + +#define DP83865_INT_REMOTE_FAULT 0x0008 +#define DP83865_INT_ANE_COMPLETED 0x0010 +#define DP83865_INT_LINK_CHANGE 0xe000 +#define DP83865_INT_MASK_DEFAULT (DP83865_INT_REMOTE_FAULT | \ + DP83865_INT_ANE_COMPLETED | \ + DP83865_INT_LINK_CHANGE) + +/* Advanced proprietary configuration */ +#define NS_EXP_MEM_CTL 0x16 +#define NS_EXP_MEM_DATA 0x1d +#define NS_EXP_MEM_ADD 0x1e + +#define LED_CTRL_REG 0x13 +#define AN_FALLBACK_AN 0x0001 +#define AN_FALLBACK_CRC 0x0002 +#define AN_FALLBACK_IE 0x0004 +#define ALL_FALLBACK_ON (AN_FALLBACK_AN | AN_FALLBACK_CRC | AN_FALLBACK_IE) + +enum hdx_loopback { + hdx_loopback_on = 0, + hdx_loopback_off = 1, +}; + +static u8 ns_exp_read(struct phy_device *phydev, u16 reg) +{ + phy_write(phydev, NS_EXP_MEM_ADD, reg); + return phy_read(phydev, NS_EXP_MEM_DATA); +} + +static void ns_exp_write(struct phy_device *phydev, u16 reg, u8 data) +{ + phy_write(phydev, NS_EXP_MEM_ADD, reg); + phy_write(phydev, NS_EXP_MEM_DATA, data); +} + +static int ns_config_intr(struct phy_device *phydev) +{ + int err; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) + err = phy_write(phydev, DP83865_INT_MASK_REG, + DP83865_INT_MASK_DEFAULT); + else + err = phy_write(phydev, DP83865_INT_MASK_REG, 0); + + return err; +} + +static int ns_ack_interrupt(struct phy_device *phydev) +{ + int ret = phy_read(phydev, DP83865_INT_MASK_STATUS); + if (ret < 0) + return ret; + + return 0; +} + +static void ns_giga_speed_fallback(struct phy_device *phydev, int mode) +{ + int bmcr = phy_read(phydev, MII_BMCR); + + phy_write(phydev, MII_BMCR, (bmcr | BMCR_PDOWN)); + + /* Enable 8 bit expended memory read/write (no auto increment) */ + phy_write(phydev, NS_EXP_MEM_CTL, 0); + phy_write(phydev, NS_EXP_MEM_ADD, 0x1C0); + phy_write(phydev, NS_EXP_MEM_DATA, 0x0008); + phy_write(phydev, MII_BMCR, (bmcr & ~BMCR_PDOWN)); + phy_write(phydev, LED_CTRL_REG, mode); + return; +} + +static void ns_10_base_t_hdx_loopack(struct phy_device *phydev, int disable) +{ + if (disable) + ns_exp_write(phydev, 0x1c0, ns_exp_read(phydev, 0x1c0) | 1); + else + ns_exp_write(phydev, 0x1c0, + ns_exp_read(phydev, 0x1c0) & 0xfffe); + + printk(KERN_DEBUG "DP83865 PHY: 10BASE-T HDX loopback %s\n", + (ns_exp_read(phydev, 0x1c0) & 0x0001) ? "off" : "on"); + + return; +} + +static int ns_config_init(struct phy_device *phydev) +{ + ns_giga_speed_fallback(phydev, ALL_FALLBACK_ON); + /* In the latest MAC or switches design, the 10 Mbps loopback + is desired to be turned off. */ + ns_10_base_t_hdx_loopack(phydev, hdx_loopback_off); + return ns_ack_interrupt(phydev); +} + +static struct phy_driver dp83865_driver = { + .phy_id = DP83865_PHY_ID, + .phy_id_mask = 0xfffffff0, + .name = "NatSemi DP83865", + .features = PHY_GBIT_FEATURES | SUPPORTED_Pause | SUPPORTED_Asym_Pause, + .flags = PHY_HAS_INTERRUPT, + .config_init = ns_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = ns_ack_interrupt, + .config_intr = ns_config_intr, + .driver = {.owner = THIS_MODULE,} +}; + +static int __init ns_init(void) +{ + return phy_driver_register(&dp83865_driver); +} + +static void __exit ns_exit(void) +{ + phy_driver_unregister(&dp83865_driver); +} + +MODULE_DESCRIPTION("NatSemi PHY driver"); +MODULE_AUTHOR("Stuart Menefy"); +MODULE_LICENSE("GPL"); + +module_init(ns_init); +module_exit(ns_exit); diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c index df4e6257d4a77e3e9bba739db57dec8543315d79..e4ede6080c9dcd327acfa37530263c6382d050db 100644 --- a/drivers/net/phy/phy.c +++ b/drivers/net/phy/phy.c @@ -45,7 +45,7 @@ */ void phy_print_status(struct phy_device *phydev) { - pr_info("PHY: %s - Link is %s", phydev->dev.bus_id, + pr_info("PHY: %s - Link is %s", dev_name(&phydev->dev), phydev->link ? "Up" : "Down"); if (phydev->link) printk(" - %d/%s", phydev->speed, diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c index 25acbbde4a6009f9c34926c0e2f89ca4e8066d6e..e35460165bf76709211ffa16f969a3b1fb07dbe8 100644 --- a/drivers/net/phy/phy_device.c +++ b/drivers/net/phy/phy_device.c @@ -74,7 +74,7 @@ int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask, if (!fixup) return -ENOMEM; - strncpy(fixup->bus_id, bus_id, BUS_ID_SIZE); + strlcpy(fixup->bus_id, bus_id, sizeof(fixup->bus_id)); fixup->phy_uid = phy_uid; fixup->phy_uid_mask = phy_uid_mask; fixup->run = run; @@ -109,7 +109,7 @@ EXPORT_SYMBOL(phy_register_fixup_for_id); */ static int phy_needs_fixup(struct phy_device *phydev, struct phy_fixup *fixup) { - if (strcmp(fixup->bus_id, phydev->dev.bus_id) != 0) + if (strcmp(fixup->bus_id, dev_name(&phydev->dev)) != 0) if (strcmp(fixup->bus_id, PHY_ANY_ID) != 0) return 0; @@ -232,7 +232,7 @@ struct phy_device * get_phy_device(struct mii_bus *bus, int addr) return NULL; /* - * Broken hardware is sometimes missing the pull down resistor on the + * Broken hardware is sometimes missing the pull-up resistor on the * MDIO line, which results in reads to non-existent devices returning * 0 rather than 0xffff. Catch this here and treat 0 as a non-existent * device as well. @@ -517,23 +517,6 @@ int genphy_setup_forced(struct phy_device *phydev) err = phy_write(phydev, MII_BMCR, ctl); - if (err < 0) - return err; - - /* - * Run the fixups on this PHY, just in case the - * board code needs to change something after a reset - */ - err = phy_scan_fixups(phydev); - - if (err < 0) - return err; - - /* We just reset the device, so we'd better configure any - * settings the PHY requires to operate */ - if (phydev->drv->config_init) - err = phydev->drv->config_init(phydev); - return err; } @@ -779,7 +762,35 @@ static int genphy_config_init(struct phy_device *phydev) return 0; } +int genphy_suspend(struct phy_device *phydev) +{ + int value; + mutex_lock(&phydev->lock); + + value = phy_read(phydev, MII_BMCR); + phy_write(phydev, MII_BMCR, (value | BMCR_PDOWN)); + + mutex_unlock(&phydev->lock); + + return 0; +} +EXPORT_SYMBOL(genphy_suspend); + +int genphy_resume(struct phy_device *phydev) +{ + int value; + + mutex_lock(&phydev->lock); + + value = phy_read(phydev, MII_BMCR); + phy_write(phydev, MII_BMCR, (value & ~BMCR_PDOWN)); + + mutex_unlock(&phydev->lock); + + return 0; +} +EXPORT_SYMBOL(genphy_resume); /** * phy_probe - probe and init a PHY device @@ -855,7 +866,6 @@ int phy_driver_register(struct phy_driver *new_driver) { int retval; - memset(&new_driver->driver, 0, sizeof(new_driver->driver)); new_driver->driver.name = new_driver->name; new_driver->driver.bus = &mdio_bus_type; new_driver->driver.probe = phy_probe; @@ -890,6 +900,8 @@ static struct phy_driver genphy_driver = { .features = 0, .config_aneg = genphy_config_aneg, .read_status = genphy_read_status, + .suspend = genphy_suspend, + .resume = genphy_resume, .driver = {.owner= THIS_MODULE, }, }; diff --git a/drivers/net/phy/smsc.c b/drivers/net/phy/smsc.c index 73baa7a3bb0ee3c9d43e69bb01d45908ef3340f0..c05d38d4635042d539f50705becfa9149109a137 100644 --- a/drivers/net/phy/smsc.c +++ b/drivers/net/phy/smsc.c @@ -126,6 +126,27 @@ static struct phy_driver lan8700_driver = { .driver = { .owner = THIS_MODULE, } }; +static struct phy_driver lan911x_int_driver = { + .phy_id = 0x0007c0d0, /* OUI=0x00800f, Model#=0x0d */ + .phy_id_mask = 0xfffffff0, + .name = "SMSC LAN911x Internal PHY", + + .features = (PHY_BASIC_FEATURES | SUPPORTED_Pause + | SUPPORTED_Asym_Pause), + .flags = PHY_HAS_INTERRUPT | PHY_HAS_MAGICANEG, + + /* basic functions */ + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .config_init = smsc_phy_config_init, + + /* IRQ related */ + .ack_interrupt = smsc_phy_ack_interrupt, + .config_intr = smsc_phy_config_intr, + + .driver = { .owner = THIS_MODULE, } +}; + static int __init smsc_init(void) { int ret; @@ -142,8 +163,14 @@ static int __init smsc_init(void) if (ret) goto err3; + ret = phy_driver_register (&lan911x_int_driver); + if (ret) + goto err4; + return 0; +err4: + phy_driver_unregister (&lan8700_driver); err3: phy_driver_unregister (&lan8187_driver); err2: @@ -154,6 +181,7 @@ err1: static void __exit smsc_exit(void) { + phy_driver_unregister (&lan911x_int_driver); phy_driver_unregister (&lan8700_driver); phy_driver_unregister (&lan8187_driver); phy_driver_unregister (&lan83c185_driver); diff --git a/drivers/net/phy/ste10Xp.c b/drivers/net/phy/ste10Xp.c new file mode 100644 index 0000000000000000000000000000000000000000..6bdb0d53aaf9e6b1434f1ee61ff95e211291f4d2 --- /dev/null +++ b/drivers/net/phy/ste10Xp.c @@ -0,0 +1,137 @@ +/* + * drivers/net/phy/ste10Xp.c + * + * Driver for STMicroelectronics STe10Xp PHYs + * + * Author: Giuseppe Cavallaro + * + * Copyright (c) 2008 STMicroelectronics Limited + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MII_XCIIS 0x11 /* Configuration Info IRQ & Status Reg */ +#define MII_XIE 0x12 /* Interrupt Enable Register */ +#define MII_XIE_DEFAULT_MASK 0x0070 /* ANE complete, Remote Fault, Link Down */ + +#define STE101P_PHY_ID 0x00061c50 +#define STE100P_PHY_ID 0x1c040011 + +static int ste10Xp_config_init(struct phy_device *phydev) +{ + int value, err; + + /* Software Reset PHY */ + value = phy_read(phydev, MII_BMCR); + if (value < 0) + return value; + + value |= BMCR_RESET; + err = phy_write(phydev, MII_BMCR, value); + if (err < 0) + return err; + + do { + value = phy_read(phydev, MII_BMCR); + } while (value & BMCR_RESET); + + return 0; +} + +static int ste10Xp_config_intr(struct phy_device *phydev) +{ + int err, value; + + if (phydev->interrupts == PHY_INTERRUPT_ENABLED) { + /* Enable all STe101P interrupts (PR12) */ + err = phy_write(phydev, MII_XIE, MII_XIE_DEFAULT_MASK); + /* clear any pending interrupts */ + if (err == 0) { + value = phy_read(phydev, MII_XCIIS); + if (value < 0) + err = value; + } + } else + err = phy_write(phydev, MII_XIE, 0); + + return err; +} + +static int ste10Xp_ack_interrupt(struct phy_device *phydev) +{ + int err = phy_read(phydev, MII_XCIIS); + if (err < 0) + return err; + + return 0; +} + +static struct phy_driver ste101p_pdriver = { + .phy_id = STE101P_PHY_ID, + .phy_id_mask = 0xfffffff0, + .name = "STe101p", + .features = PHY_BASIC_FEATURES | SUPPORTED_Pause, + .flags = PHY_HAS_INTERRUPT, + .config_init = ste10Xp_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = ste10Xp_ack_interrupt, + .config_intr = ste10Xp_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, + .driver = {.owner = THIS_MODULE,} +}; + +static struct phy_driver ste100p_pdriver = { + .phy_id = STE100P_PHY_ID, + .phy_id_mask = 0xffffffff, + .name = "STe100p", + .features = PHY_BASIC_FEATURES | SUPPORTED_Pause, + .flags = PHY_HAS_INTERRUPT, + .config_init = ste10Xp_config_init, + .config_aneg = genphy_config_aneg, + .read_status = genphy_read_status, + .ack_interrupt = ste10Xp_ack_interrupt, + .config_intr = ste10Xp_config_intr, + .suspend = genphy_suspend, + .resume = genphy_resume, + .driver = {.owner = THIS_MODULE,} +}; + +static int __init ste10Xp_init(void) +{ + int retval; + + retval = phy_driver_register(&ste100p_pdriver); + if (retval < 0) + return retval; + return phy_driver_register(&ste101p_pdriver); +} + +static void __exit ste10Xp_exit(void) +{ + phy_driver_unregister(&ste100p_pdriver); + phy_driver_unregister(&ste101p_pdriver); +} + +module_init(ste10Xp_init); +module_exit(ste10Xp_exit); + +MODULE_DESCRIPTION("STMicroelectronics STe10Xp PHY driver"); +MODULE_AUTHOR("Giuseppe Cavallaro "); +MODULE_LICENSE("GPL"); diff --git a/drivers/net/plip.c b/drivers/net/plip.c index 1e965427b0e987faae6ae26bfe3d07e1aad8bfa7..0c46d603b8fe99985a558ec771e7d48924480709 100644 --- a/drivers/net/plip.c +++ b/drivers/net/plip.c @@ -229,7 +229,7 @@ static inline void enable_parport_interrupts (struct net_device *dev) if (dev->irq != -1) { struct parport *port = - ((struct net_local *)dev->priv)->pardev->port; + ((struct net_local *)netdev_priv(dev))->pardev->port; port->ops->enable_irq (port); } } @@ -239,7 +239,7 @@ static inline void disable_parport_interrupts (struct net_device *dev) if (dev->irq != -1) { struct parport *port = - ((struct net_local *)dev->priv)->pardev->port; + ((struct net_local *)netdev_priv(dev))->pardev->port; port->ops->disable_irq (port); } } @@ -247,7 +247,7 @@ static inline void disable_parport_interrupts (struct net_device *dev) static inline void write_data (struct net_device *dev, unsigned char data) { struct parport *port = - ((struct net_local *)dev->priv)->pardev->port; + ((struct net_local *)netdev_priv(dev))->pardev->port; port->ops->write_data (port, data); } @@ -255,7 +255,7 @@ static inline void write_data (struct net_device *dev, unsigned char data) static inline unsigned char read_status (struct net_device *dev) { struct parport *port = - ((struct net_local *)dev->priv)->pardev->port; + ((struct net_local *)netdev_priv(dev))->pardev->port; return port->ops->read_status (port); } @@ -638,14 +638,14 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl, case PLIP_PK_DATA: lbuf = rcv->skb->data; - do + do { if (plip_receive(nibble_timeout, dev, &rcv->nibble, &lbuf[rcv->byte])) return TIMEOUT; - while (++rcv->byte < rcv->length.h); - do + } while (++rcv->byte < rcv->length.h); + do { rcv->checksum += lbuf[--rcv->byte]; - while (rcv->byte); + } while (rcv->byte); rcv->state = PLIP_PK_CHECKSUM; case PLIP_PK_CHECKSUM: @@ -664,7 +664,6 @@ plip_receive_packet(struct net_device *dev, struct net_local *nl, /* Inform the upper layer for the arrival of a packet. */ rcv->skb->protocol=plip_type_trans(rcv->skb, dev); netif_rx_ni(rcv->skb); - dev->last_rx = jiffies; dev->stats.rx_bytes += rcv->length.h; dev->stats.rx_packets++; rcv->skb = NULL; @@ -817,14 +816,14 @@ plip_send_packet(struct net_device *dev, struct net_local *nl, snd->checksum = 0; case PLIP_PK_DATA: - do + do { if (plip_send(nibble_timeout, dev, &snd->nibble, lbuf[snd->byte])) return TIMEOUT; - while (++snd->byte < snd->length.h); - do + } while (++snd->byte < snd->length.h); + do { snd->checksum += lbuf[--snd->byte]; - while (snd->byte); + } while (snd->byte); snd->state = PLIP_PK_CHECKSUM; case PLIP_PK_CHECKSUM: @@ -1018,8 +1017,8 @@ plip_hard_header(struct sk_buff *skb, struct net_device *dev, return ret; } -int plip_hard_header_cache(const struct neighbour *neigh, - struct hh_cache *hh) +static int plip_hard_header_cache(const struct neighbour *neigh, + struct hh_cache *hh) { int ret; @@ -1397,9 +1396,3 @@ static int __init plip_init (void) module_init(plip_init); module_exit(plip_cleanup_module); MODULE_LICENSE("GPL"); - -/* - * Local variables: - * compile-command: "gcc -DMODULE -DMODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -c plip.c" - * End: - */ diff --git a/drivers/net/ppp_async.c b/drivers/net/ppp_async.c index 451bdb57d6fc98b5389a9067e52c49fff9df37c9..6567fabd2e132a4ab4296a8283d32632b299c9d0 100644 --- a/drivers/net/ppp_async.c +++ b/drivers/net/ppp_async.c @@ -293,9 +293,6 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, err = -EFAULT; switch (cmd) { case PPPIOCGCHAN: - err = -ENXIO; - if (!ap) - break; err = -EFAULT; if (put_user(ppp_channel_index(&ap->chan), p)) break; @@ -303,9 +300,6 @@ ppp_asynctty_ioctl(struct tty_struct *tty, struct file *file, break; case PPPIOCGUNIT: - err = -ENXIO; - if (!ap) - break; err = -EFAULT; if (put_user(ppp_unit_number(&ap->chan), p)) break; diff --git a/drivers/net/ppp_generic.c b/drivers/net/ppp_generic.c index 714a23035de1980a968c19a835712d587c007c17..06b448285eb5d0783c104383c12b0e4add6309ea 100644 --- a/drivers/net/ppp_generic.c +++ b/drivers/net/ppp_generic.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -172,36 +173,14 @@ struct channel { * channel.downl. */ -/* - * A cardmap represents a mapping from unsigned integers to pointers, - * and provides a fast "find lowest unused number" operation. - * It uses a broad (32-way) tree with a bitmap at each level. - * It is designed to be space-efficient for small numbers of entries - * and time-efficient for large numbers of entries. - */ -#define CARDMAP_ORDER 5 -#define CARDMAP_WIDTH (1U << CARDMAP_ORDER) -#define CARDMAP_MASK (CARDMAP_WIDTH - 1) - -struct cardmap { - int shift; - unsigned long inuse; - struct cardmap *parent; - void *ptr[CARDMAP_WIDTH]; -}; -static void *cardmap_get(struct cardmap *map, unsigned int nr); -static int cardmap_set(struct cardmap **map, unsigned int nr, void *ptr); -static unsigned int cardmap_find_first_free(struct cardmap *map); -static void cardmap_destroy(struct cardmap **map); - /* * all_ppp_mutex protects the all_ppp_units mapping. * It also ensures that finding a ppp unit in the all_ppp_units map * and updating its file.refcnt field is atomic. */ static DEFINE_MUTEX(all_ppp_mutex); -static struct cardmap *all_ppp_units; static atomic_t ppp_unit_count = ATOMIC_INIT(0); +static DEFINE_IDR(ppp_units_idr); /* * all_channels_lock protects all_channels and last_channel_index, @@ -270,6 +249,9 @@ static struct channel *ppp_find_channel(int unit); static int ppp_connect_channel(struct channel *pch, int unit); static int ppp_disconnect_channel(struct channel *pch); static void ppp_destroy_channel(struct channel *pch); +static int unit_get(struct idr *p, void *ptr); +static void unit_put(struct idr *p, int n); +static void *unit_find(struct idr *p, int n); static struct class *ppp_class; @@ -887,7 +869,7 @@ out_chrdev: static int ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct ppp *ppp = (struct ppp *) dev->priv; + struct ppp *ppp = netdev_priv(dev); int npi, proto; unsigned char *pp; @@ -932,7 +914,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev) static int ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct ppp *ppp = dev->priv; + struct ppp *ppp = netdev_priv(dev); int err = -EFAULT; void __user *addr = (void __user *) ifr->ifr_ifru.ifru_data; struct ppp_stats stats; @@ -972,8 +954,14 @@ ppp_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return err; } +static const struct net_device_ops ppp_netdev_ops = { + .ndo_start_xmit = ppp_start_xmit, + .ndo_do_ioctl = ppp_net_ioctl, +}; + static void ppp_setup(struct net_device *dev) { + dev->netdev_ops = &ppp_netdev_ops; dev->hard_header_len = PPP_HDRLEN; dev->mtu = PPP_MTU; dev->addr_len = 0; @@ -1684,7 +1672,6 @@ ppp_receive_nonmp_frame(struct ppp *ppp, struct sk_buff *skb) skb->protocol = htons(npindex_to_ethertype[npi]); skb_reset_mac_header(skb); netif_rx(skb); - ppp->dev->last_rx = jiffies; } } return; @@ -2414,13 +2401,12 @@ ppp_create_interface(int unit, int *retp) int ret = -ENOMEM; int i; - ppp = kzalloc(sizeof(struct ppp), GFP_KERNEL); - if (!ppp) - goto out; - dev = alloc_netdev(0, "", ppp_setup); + dev = alloc_netdev(sizeof(struct ppp), "", ppp_setup); if (!dev) goto out1; + ppp = netdev_priv(dev); + ppp->dev = dev; ppp->mru = PPP_MRU; init_ppp_file(&ppp->file, INTERFACE); ppp->file.hdrlen = PPP_HDRLEN - 2; /* don't count proto bytes */ @@ -2433,18 +2419,25 @@ ppp_create_interface(int unit, int *retp) ppp->minseq = -1; skb_queue_head_init(&ppp->mrq); #endif /* CONFIG_PPP_MULTILINK */ - ppp->dev = dev; - dev->priv = ppp; - - dev->hard_start_xmit = ppp_start_xmit; - dev->do_ioctl = ppp_net_ioctl; ret = -EEXIST; mutex_lock(&all_ppp_mutex); - if (unit < 0) - unit = cardmap_find_first_free(all_ppp_units); - else if (cardmap_get(all_ppp_units, unit) != NULL) - goto out2; /* unit already exists */ + + if (unit < 0) { + unit = unit_get(&ppp_units_idr, ppp); + if (unit < 0) { + *retp = unit; + goto out2; + } + } else { + if (unit_find(&ppp_units_idr, unit)) + goto out2; /* unit already exists */ + else { + /* darn, someone is cheating us? */ + *retp = -EINVAL; + goto out2; + } + } /* Initialize the new ppp unit */ ppp->file.index = unit; @@ -2452,29 +2445,22 @@ ppp_create_interface(int unit, int *retp) ret = register_netdev(dev); if (ret != 0) { + unit_put(&ppp_units_idr, unit); printk(KERN_ERR "PPP: couldn't register device %s (%d)\n", dev->name, ret); goto out2; } atomic_inc(&ppp_unit_count); - ret = cardmap_set(&all_ppp_units, unit, ppp); - if (ret != 0) - goto out3; - mutex_unlock(&all_ppp_mutex); + *retp = 0; return ppp; -out3: - atomic_dec(&ppp_unit_count); - unregister_netdev(dev); out2: mutex_unlock(&all_ppp_mutex); free_netdev(dev); out1: - kfree(ppp); -out: *retp = ret; return NULL; } @@ -2508,7 +2494,7 @@ static void ppp_shutdown_interface(struct ppp *ppp) } else ppp_unlock(ppp); - cardmap_set(&all_ppp_units, ppp->file.index, NULL); + unit_put(&ppp_units_idr, ppp->file.index); ppp->file.dead = 1; ppp->owner = NULL; wake_up_interruptible(&ppp->file.rwait); @@ -2562,7 +2548,7 @@ static void ppp_destroy_interface(struct ppp *ppp) static struct ppp * ppp_find_unit(int unit) { - return cardmap_get(all_ppp_units, unit); + return unit_find(&ppp_units_idr, unit); } /* @@ -2680,123 +2666,45 @@ static void __exit ppp_cleanup(void) /* should never happen */ if (atomic_read(&ppp_unit_count) || atomic_read(&channel_count)) printk(KERN_ERR "PPP: removing module but units remain!\n"); - cardmap_destroy(&all_ppp_units); unregister_chrdev(PPP_MAJOR, "ppp"); device_destroy(ppp_class, MKDEV(PPP_MAJOR, 0)); class_destroy(ppp_class); + idr_destroy(&ppp_units_idr); } /* - * Cardmap implementation. + * Units handling. Caller must protect concurrent access + * by holding all_ppp_mutex */ -static void *cardmap_get(struct cardmap *map, unsigned int nr) + +/* get new free unit number and associate pointer with it */ +static int unit_get(struct idr *p, void *ptr) { - struct cardmap *p; - int i; + int unit, err; - for (p = map; p != NULL; ) { - if ((i = nr >> p->shift) >= CARDMAP_WIDTH) - return NULL; - if (p->shift == 0) - return p->ptr[i]; - nr &= ~(CARDMAP_MASK << p->shift); - p = p->ptr[i]; +again: + if (idr_pre_get(p, GFP_KERNEL) == 0) { + printk(KERN_ERR "Out of memory expanding drawable idr\n"); + return -ENOMEM; } - return NULL; -} -static int cardmap_set(struct cardmap **pmap, unsigned int nr, void *ptr) -{ - struct cardmap *p; - int i; + err = idr_get_new_above(p, ptr, 0, &unit); + if (err == -EAGAIN) + goto again; - p = *pmap; - if (p == NULL || (nr >> p->shift) >= CARDMAP_WIDTH) { - do { - /* need a new top level */ - struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL); - if (!np) - goto enomem; - np->ptr[0] = p; - if (p != NULL) { - np->shift = p->shift + CARDMAP_ORDER; - p->parent = np; - } else - np->shift = 0; - p = np; - } while ((nr >> p->shift) >= CARDMAP_WIDTH); - *pmap = p; - } - while (p->shift > 0) { - i = (nr >> p->shift) & CARDMAP_MASK; - if (p->ptr[i] == NULL) { - struct cardmap *np = kzalloc(sizeof(*np), GFP_KERNEL); - if (!np) - goto enomem; - np->shift = p->shift - CARDMAP_ORDER; - np->parent = p; - p->ptr[i] = np; - } - if (ptr == NULL) - clear_bit(i, &p->inuse); - p = p->ptr[i]; - } - i = nr & CARDMAP_MASK; - p->ptr[i] = ptr; - if (ptr != NULL) - set_bit(i, &p->inuse); - else - clear_bit(i, &p->inuse); - return 0; - enomem: - return -ENOMEM; + return unit; } -static unsigned int cardmap_find_first_free(struct cardmap *map) +/* put unit number back to a pool */ +static void unit_put(struct idr *p, int n) { - struct cardmap *p; - unsigned int nr = 0; - int i; - - if ((p = map) == NULL) - return 0; - for (;;) { - i = find_first_zero_bit(&p->inuse, CARDMAP_WIDTH); - if (i >= CARDMAP_WIDTH) { - if (p->parent == NULL) - return CARDMAP_WIDTH << p->shift; - p = p->parent; - i = (nr >> p->shift) & CARDMAP_MASK; - set_bit(i, &p->inuse); - continue; - } - nr = (nr & (~CARDMAP_MASK << p->shift)) | (i << p->shift); - if (p->shift == 0 || p->ptr[i] == NULL) - return nr; - p = p->ptr[i]; - } + idr_remove(p, n); } -static void cardmap_destroy(struct cardmap **pmap) +/* get pointer associated with the number */ +static void *unit_find(struct idr *p, int n) { - struct cardmap *p, *np; - int i; - - for (p = *pmap; p != NULL; p = np) { - if (p->shift != 0) { - for (i = 0; i < CARDMAP_WIDTH; ++i) - if (p->ptr[i] != NULL) - break; - if (i < CARDMAP_WIDTH) { - np = p->ptr[i]; - p->ptr[i] = NULL; - continue; - } - } - np = p->parent; - kfree(p); - } - *pmap = NULL; + return idr_find(p, n); } /* Module/initialization stuff */ diff --git a/drivers/net/ppp_synctty.c b/drivers/net/ppp_synctty.c index 801d8f99d4714155e2f3b3f9c0879ec15d2de8ba..1e892b7b1f8cf997764e7a29ffe09bbf745f69ff 100644 --- a/drivers/net/ppp_synctty.c +++ b/drivers/net/ppp_synctty.c @@ -333,9 +333,6 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file, err = -EFAULT; switch (cmd) { case PPPIOCGCHAN: - err = -ENXIO; - if (!ap) - break; err = -EFAULT; if (put_user(ppp_channel_index(&ap->chan), p)) break; @@ -343,9 +340,6 @@ ppp_synctty_ioctl(struct tty_struct *tty, struct file *file, break; case PPPIOCGUNIT: - err = -ENXIO; - if (!ap) - break; err = -EFAULT; if (put_user(ppp_unit_number(&ap->chan), p)) break; diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c index b646e92134dc79a6bbfe6e55f7c80fd0ea19d3f1..c22b30533a14cb89eeeda69a83317f80e8c383b3 100644 --- a/drivers/net/pppoe.c +++ b/drivers/net/pppoe.c @@ -958,7 +958,6 @@ static int pppoe_seq_show(struct seq_file *seq, void *v) { struct pppox_sock *po; char *dev_name; - DECLARE_MAC_BUF(mac); if (v == SEQ_START_TOKEN) { seq_puts(seq, "Id Address Device\n"); @@ -968,8 +967,8 @@ static int pppoe_seq_show(struct seq_file *seq, void *v) po = v; dev_name = po->pppoe_pa.dev; - seq_printf(seq, "%08X %s %8s\n", - po->pppoe_pa.sid, print_mac(mac, po->pppoe_pa.remote), dev_name); + seq_printf(seq, "%08X %pM %8s\n", + po->pppoe_pa.sid, po->pppoe_pa.remote, dev_name); out: return 0; } diff --git a/drivers/net/pppol2tp.c b/drivers/net/pppol2tp.c index e98d9773158d287ba1ae35052dca968fc6cf5735..f1a946785c6aee3bf580ad6015d9b825318c6566 100644 --- a/drivers/net/pppol2tp.c +++ b/drivers/net/pppol2tp.c @@ -489,6 +489,30 @@ out: spin_unlock_bh(&session->reorder_q.lock); } +static inline int pppol2tp_verify_udp_checksum(struct sock *sk, + struct sk_buff *skb) +{ + struct udphdr *uh = udp_hdr(skb); + u16 ulen = ntohs(uh->len); + struct inet_sock *inet; + __wsum psum; + + if (sk->sk_no_check || skb_csum_unnecessary(skb) || !uh->check) + return 0; + + inet = inet_sk(sk); + psum = csum_tcpudp_nofold(inet->saddr, inet->daddr, ulen, + IPPROTO_UDP, 0); + + if ((skb->ip_summed == CHECKSUM_COMPLETE) && + !csum_fold(csum_add(psum, skb->csum))) + return 0; + + skb->csum = psum; + + return __skb_checksum_complete(skb); +} + /* Internal receive frame. Do the real work of receiving an L2TP data frame * here. The skb is not on a list when we get here. * Returns 0 if the packet was a data packet and was successfully passed on. @@ -509,6 +533,9 @@ static int pppol2tp_recv_core(struct sock *sock, struct sk_buff *skb) if (tunnel == NULL) goto no_tunnel; + if (tunnel->sock && pppol2tp_verify_udp_checksum(tunnel->sock, skb)) + goto discard_bad_csum; + /* UDP always verifies the packet length. */ __skb_pull(skb, sizeof(struct udphdr)); @@ -725,6 +752,14 @@ discard: return 0; +discard_bad_csum: + LIMIT_NETDEBUG("%s: UDP: bad checksum\n", tunnel->name); + UDP_INC_STATS_USER(&init_net, UDP_MIB_INERRORS, 0); + tunnel->stats.rx_errors++; + kfree_skb(skb); + + return 0; + error: /* Put UDP header back */ __skb_push(skb, sizeof(struct udphdr)); @@ -851,7 +886,7 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh static const unsigned char ppph[2] = { 0xff, 0x03 }; struct sock *sk = sock->sk; struct inet_sock *inet; - __wsum csum = 0; + __wsum csum; struct sk_buff *skb; int error; int hdr_len; @@ -859,6 +894,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh struct pppol2tp_tunnel *tunnel; struct udphdr *uh; unsigned int len; + struct sock *sk_tun; + u16 udp_len; error = -ENOTCONN; if (sock_flag(sk, SOCK_DEAD) || !(sk->sk_state & PPPOX_CONNECTED)) @@ -870,7 +907,8 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh if (session == NULL) goto error; - tunnel = pppol2tp_sock_to_tunnel(session->tunnel_sock); + sk_tun = session->tunnel_sock; + tunnel = pppol2tp_sock_to_tunnel(sk_tun); if (tunnel == NULL) goto error_put_sess; @@ -893,11 +931,12 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh skb_reset_transport_header(skb); /* Build UDP header */ - inet = inet_sk(session->tunnel_sock); + inet = inet_sk(sk_tun); + udp_len = hdr_len + sizeof(ppph) + total_len; uh = (struct udphdr *) skb->data; uh->source = inet->sport; uh->dest = inet->dport; - uh->len = htons(hdr_len + sizeof(ppph) + total_len); + uh->len = htons(udp_len); uh->check = 0; skb_put(skb, sizeof(struct udphdr)); @@ -919,8 +958,22 @@ static int pppol2tp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msgh skb_put(skb, total_len); /* Calculate UDP checksum if configured to do so */ - if (session->tunnel_sock->sk_no_check != UDP_CSUM_NOXMIT) - csum = udp_csum_outgoing(sk, skb); + if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) + skb->ip_summed = CHECKSUM_NONE; + else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { + skb->ip_summed = CHECKSUM_COMPLETE; + csum = skb_checksum(skb, 0, udp_len, 0); + uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, + udp_len, IPPROTO_UDP, csum); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + } else { + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr, + udp_len, IPPROTO_UDP, 0); + } /* Debug */ if (session->send_seq) @@ -1008,13 +1061,14 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) struct sock *sk = (struct sock *) chan->private; struct sock *sk_tun; int hdr_len; + u16 udp_len; struct pppol2tp_session *session; struct pppol2tp_tunnel *tunnel; int rc; int headroom; int data_len = skb->len; struct inet_sock *inet; - __wsum csum = 0; + __wsum csum; struct udphdr *uh; unsigned int len; int old_headroom; @@ -1060,6 +1114,8 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) /* Setup L2TP header */ pppol2tp_build_l2tp_header(session, __skb_push(skb, hdr_len)); + udp_len = sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len; + /* Setup UDP header */ inet = inet_sk(sk_tun); __skb_push(skb, sizeof(*uh)); @@ -1067,13 +1123,9 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) uh = udp_hdr(skb); uh->source = inet->sport; uh->dest = inet->dport; - uh->len = htons(sizeof(struct udphdr) + hdr_len + sizeof(ppph) + data_len); + uh->len = htons(udp_len); uh->check = 0; - /* *BROKEN* Calculate UDP checksum if configured to do so */ - if (sk_tun->sk_no_check != UDP_CSUM_NOXMIT) - csum = udp_csum_outgoing(sk_tun, skb); - /* Debug */ if (session->send_seq) PRINTK(session->debug, PPPOL2TP_MSG_DATA, KERN_DEBUG, @@ -1108,6 +1160,24 @@ static int pppol2tp_xmit(struct ppp_channel *chan, struct sk_buff *skb) skb->dst = dst_clone(__sk_dst_get(sk_tun)); pppol2tp_skb_set_owner_w(skb, sk_tun); + /* Calculate UDP checksum if configured to do so */ + if (sk_tun->sk_no_check == UDP_CSUM_NOXMIT) + skb->ip_summed = CHECKSUM_NONE; + else if (!(skb->dst->dev->features & NETIF_F_V4_CSUM)) { + skb->ip_summed = CHECKSUM_COMPLETE; + csum = skb_checksum(skb, 0, udp_len, 0); + uh->check = csum_tcpudp_magic(inet->saddr, inet->daddr, + udp_len, IPPROTO_UDP, csum); + if (uh->check == 0) + uh->check = CSUM_MANGLED_0; + } else { + skb->ip_summed = CHECKSUM_PARTIAL; + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct udphdr, check); + uh->check = ~csum_tcpudp_magic(inet->saddr, inet->daddr, + udp_len, IPPROTO_UDP, 0); + } + /* Queue the packet to IP for output */ len = skb->len; rc = ip_queue_xmit(skb, 1); diff --git a/drivers/net/ps3_gelic_net.c b/drivers/net/ps3_gelic_net.c index 2eb54fd7bed532153f4aafef049a97f5459caa02..4b564eda5bd932ef67f8b850c4b947761da31628 100644 --- a/drivers/net/ps3_gelic_net.c +++ b/drivers/net/ps3_gelic_net.c @@ -1443,7 +1443,6 @@ int gelic_net_setup_netdev(struct net_device *netdev, struct gelic_card *card) { int status; u64 v1, v2; - DECLARE_MAC_BUF(mac); netdev->features = NETIF_F_IP_CSUM; @@ -1474,9 +1473,8 @@ int gelic_net_setup_netdev(struct net_device *netdev, struct gelic_card *card) __func__, netdev->name, status); return status; } - dev_info(ctodev(card), "%s: MAC addr %s\n", - netdev->name, - print_mac(mac, netdev->dev_addr)); + dev_info(ctodev(card), "%s: MAC addr %pM\n", + netdev->name, netdev->dev_addr); return 0; } diff --git a/drivers/net/ps3_gelic_wireless.c b/drivers/net/ps3_gelic_wireless.c index a834b52a6a2c4019a36bb752b812566ae89c57c9..ec2314246682af0946bbe97475b3947670401383 100644 --- a/drivers/net/ps3_gelic_wireless.c +++ b/drivers/net/ps3_gelic_wireless.c @@ -30,10 +30,11 @@ #include #include #include +#include +#include #include #include #include -#include #include #include @@ -449,9 +450,9 @@ static size_t gelic_wl_synthesize_ie(u8 *buf, /* element id */ if (rsn) - *buf++ = MFIE_TYPE_RSN; + *buf++ = WLAN_EID_RSN; else - *buf++ = MFIE_TYPE_GENERIC; + *buf++ = WLAN_EID_GENERIC; /* length filed; set later */ buf++; @@ -539,7 +540,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len, break; switch (item_id) { - case MFIE_TYPE_GENERIC: + case WLAN_EID_GENERIC: if ((OUI_LEN + 1 <= item_len) && !memcmp(pos, wpa_oui, OUI_LEN) && pos[OUI_LEN] == 0x01) { @@ -547,7 +548,7 @@ static void gelic_wl_parse_ie(u8 *data, size_t len, ie_info->wpa.len = item_len + 2; } break; - case MFIE_TYPE_RSN: + case WLAN_EID_RSN: ie_info->rsn.data = pos - 2; /* length includes the header */ ie_info->rsn.len = item_len + 2; @@ -581,7 +582,7 @@ static char *gelic_wl_translate_scan(struct net_device *netdev, char *tmp; u8 rate; unsigned int i, j, len; - u8 buf[MAX_WPA_IE_LEN]; + u8 buf[64]; /* arbitrary size large enough */ pr_debug("%s: <-\n", __func__); @@ -763,7 +764,6 @@ static void scan_list_dump(struct gelic_wl_info *wl) { struct gelic_wl_scan_info *scan_info; int i; - DECLARE_MAC_BUF(mac); i = 0; list_for_each_entry(scan_info, &wl->network_list, list) { @@ -775,8 +775,7 @@ static void scan_list_dump(struct gelic_wl_info *wl) scan_info->rate_len, scan_info->rate_ext_len, scan_info->essid_len); /* -- */ - pr_debug("bssid=%s\n", - print_mac(mac, &scan_info->hwinfo->bssid[2])); + pr_debug("bssid=%pM\n", &scan_info->hwinfo->bssid[2]); pr_debug("essid=%s\n", scan_info->hwinfo->essid); } } @@ -1167,11 +1166,7 @@ static int gelic_wl_set_ap(struct net_device *netdev, ETH_ALEN); set_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat); set_bit(GELIC_WL_STAT_CONFIGURED, &wl->stat); - pr_debug("%s: bss=%02x:%02x:%02x:%02x:%02x:%02x\n", - __func__, - wl->bssid[0], wl->bssid[1], - wl->bssid[2], wl->bssid[3], - wl->bssid[4], wl->bssid[5]); + pr_debug("%s: bss=%pM\n", __func__, wl->bssid); } else { pr_debug("%s: clear bssid\n", __func__); clear_bit(GELIC_WL_STAT_BSSID_SET, &wl->stat); @@ -1632,7 +1627,6 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) unsigned long this_time = jiffies; unsigned int data_len, i, found, r; void *buf; - DECLARE_MAC_BUF(mac); pr_debug("%s:start\n", __func__); mutex_lock(&wl->scan_lock); @@ -1684,9 +1678,9 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) scan_info_size < data_len; i++, scan_info_size += be16_to_cpu(scan_info->size), scan_info = (void *)scan_info + be16_to_cpu(scan_info->size)) { - pr_debug("%s:size=%d bssid=%s scan_info=%p\n", __func__, + pr_debug("%s:size=%d bssid=%pM scan_info=%p\n", __func__, be16_to_cpu(scan_info->size), - print_mac(mac, &scan_info->bssid[2]), scan_info); + &scan_info->bssid[2], scan_info); /* * The wireless firmware may return invalid channel 0 and/or @@ -1741,14 +1735,14 @@ static void gelic_wl_scan_complete_event(struct gelic_wl_info *wl) target->essid_len = strnlen(scan_info->essid, sizeof(scan_info->essid)); target->rate_len = 0; - for (r = 0; r < MAX_RATES_LENGTH; r++) + for (r = 0; r < 12; r++) if (scan_info->rate[r]) target->rate_len++; if (8 < target->rate_len) pr_info("%s: AP returns %d rates\n", __func__, target->rate_len); target->rate_ext_len = 0; - for (r = 0; r < MAX_RATES_EX_LENGTH; r++) + for (r = 0; r < 16; r++) if (scan_info->ext_rate[r]) target->rate_ext_len++; list_move_tail(&target->list, &wl->network_list); @@ -1787,7 +1781,6 @@ struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl) struct gelic_wl_scan_info *best_bss; int weight, best_weight; u16 security; - DECLARE_MAC_BUF(mac); pr_debug("%s: <-\n", __func__); @@ -1857,8 +1850,8 @@ struct gelic_wl_scan_info *gelic_wl_find_best_bss(struct gelic_wl_info *wl) #ifdef DEBUG pr_debug("%s: -> bss=%p\n", __func__, best_bss); if (best_bss) { - pr_debug("%s:addr=%s\n", __func__, - print_mac(mac, &best_bss->hwinfo->bssid[2])); + pr_debug("%s:addr=%pM\n", __func__, + &best_bss->hwinfo->bssid[2]); } #endif return best_bss; diff --git a/drivers/net/ps3_gelic_wireless.h b/drivers/net/ps3_gelic_wireless.h index 5339e0078d180a885f53a622dddac4c4743c50ee..5b631c6c97759ec36f4d2296549f10b979a89158 100644 --- a/drivers/net/ps3_gelic_wireless.h +++ b/drivers/net/ps3_gelic_wireless.h @@ -164,8 +164,8 @@ struct gelic_eurus_scan_info { __be16 security; u8 bssid[8]; /* last ETH_ALEN are valid. bssid[0],[1] are unused */ u8 essid[32]; /* IW_ESSID_MAX_SIZE */ - u8 rate[16]; /* first MAX_RATES_LENGTH(12) are valid */ - u8 ext_rate[16]; /* first MAX_RATES_EX_LENGTH(16) are valid */ + u8 rate[16]; /* first 12 are valid */ + u8 ext_rate[16]; /* first 16 are valid */ __be32 reserved1; __be32 reserved2; __be32 reserved3; diff --git a/drivers/net/qla3xxx.c b/drivers/net/qla3xxx.c index 508452c0215144343a2aacbe37f44d20caedfbf3..189ec29ac7a40678787ed8eb3706257268a28e6f 100644 --- a/drivers/net/qla3xxx.c +++ b/drivers/net/qla3xxx.c @@ -2127,7 +2127,6 @@ static void ql_process_mac_rx_intr(struct ql3_adapter *qdev, skb->protocol = eth_type_trans(skb, qdev->ndev); netif_receive_skb(skb); - qdev->ndev->last_rx = jiffies; lrg_buf_cb2->skb = NULL; if (qdev->device_id == QL3022_DEVICE_ID) @@ -2201,7 +2200,6 @@ static void ql_process_macip_rx_intr(struct ql3_adapter *qdev, netif_receive_skb(skb2); ndev->stats.rx_packets++; ndev->stats.rx_bytes += length; - ndev->last_rx = jiffies; lrg_buf_cb2->skb = NULL; if (qdev->device_id == QL3022_DEVICE_ID) @@ -2286,7 +2284,6 @@ static int ql_tx_rx_clean(struct ql3_adapter *qdev, static int ql_poll(struct napi_struct *napi, int budget) { struct ql3_adapter *qdev = container_of(napi, struct ql3_adapter, napi); - struct net_device *ndev = qdev->ndev; int rx_cleaned = 0, tx_cleaned = 0; unsigned long hw_flags; struct ql3xxx_port_registers __iomem *port_regs = qdev->mem_map_registers; @@ -2295,7 +2292,7 @@ static int ql_poll(struct napi_struct *napi, int budget) if (tx_cleaned + rx_cleaned != budget) { spin_lock_irqsave(&qdev->hw_lock, hw_flags); - __netif_rx_complete(ndev, napi); + __netif_rx_complete(napi); ql_update_small_bufq_prod_index(qdev); ql_update_lrg_bufq_prod_index(qdev); writel(qdev->rsp_consumer_index, @@ -2354,8 +2351,8 @@ static irqreturn_t ql3xxx_isr(int irq, void *dev_id) spin_unlock(&qdev->adapter_lock); } else if (value & ISP_IMR_DISABLE_CMPL_INT) { ql_disable_interrupts(qdev); - if (likely(netif_rx_schedule_prep(ndev, &qdev->napi))) { - __netif_rx_schedule(ndev, &qdev->napi); + if (likely(netif_rx_schedule_prep(&qdev->napi))) { + __netif_rx_schedule(&qdev->napi); } } else { return IRQ_NONE; @@ -3520,7 +3517,6 @@ static void ql_display_dev_info(struct net_device *ndev) { struct ql3_adapter *qdev = (struct ql3_adapter *)netdev_priv(ndev); struct pci_dev *pdev = qdev->pdev; - DECLARE_MAC_BUF(mac); printk(KERN_INFO PFX "\n%s Adapter %d RevisionID %d found %s on PCI slot %d.\n", @@ -3546,8 +3542,8 @@ static void ql_display_dev_info(struct net_device *ndev) if (netif_msg_probe(qdev)) printk(KERN_INFO PFX - "%s: MAC address %s\n", - ndev->name, print_mac(mac, ndev->dev_addr)); + "%s: MAC address %pM\n", + ndev->name, ndev->dev_addr); } static int ql_adapter_down(struct ql3_adapter *qdev, int do_reset) @@ -3903,13 +3899,24 @@ static void ql3xxx_timer(unsigned long ptr) queue_delayed_work(qdev->workqueue, &qdev->link_state_work, 0); } +static const struct net_device_ops ql3xxx_netdev_ops = { + .ndo_open = ql3xxx_open, + .ndo_start_xmit = ql3xxx_send, + .ndo_stop = ql3xxx_close, + .ndo_set_multicast_list = NULL, /* not allowed on NIC side */ + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = ql3xxx_set_mac_address, + .ndo_tx_timeout = ql3xxx_tx_timeout, +}; + static int __devinit ql3xxx_probe(struct pci_dev *pdev, const struct pci_device_id *pci_entry) { struct net_device *ndev = NULL; struct ql3_adapter *qdev = NULL; static int cards_found = 0; - int pci_using_dac, err; + int uninitialized_var(pci_using_dac), err; err = pci_enable_device(pdev); if (err) { @@ -3969,9 +3976,7 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, if (qdev->device_id == QL3032_DEVICE_ID) ndev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - qdev->mem_map_registers = - ioremap_nocache(pci_resource_start(pdev, 1), - pci_resource_len(qdev->pdev, 1)); + qdev->mem_map_registers = pci_ioremap_bar(pdev, 1); if (!qdev->mem_map_registers) { printk(KERN_ERR PFX "%s: cannot map device registers\n", pci_name(pdev)); @@ -3983,17 +3988,8 @@ static int __devinit ql3xxx_probe(struct pci_dev *pdev, spin_lock_init(&qdev->hw_lock); /* Set driver entry points */ - ndev->open = ql3xxx_open; - ndev->hard_start_xmit = ql3xxx_send; - ndev->stop = ql3xxx_close; - /* ndev->set_multicast_list - * This device is one side of a two-function adapter - * (NIC and iSCSI). Promiscuous mode setting/clearing is - * not allowed from the NIC side. - */ + ndev->netdev_ops = &ql3xxx_netdev_ops; SET_ETHTOOL_OPS(ndev, &ql3xxx_ethtool_ops); - ndev->set_mac_address = ql3xxx_set_mac_address; - ndev->tx_timeout = ql3xxx_tx_timeout; ndev->watchdog_timeo = 5 * HZ; netif_napi_add(ndev, &qdev->napi, ql_poll, 64); diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c index b62fbd4bf00f5821fd2e2c81b9e2b5b76eb792b4..eefb81b137588d4b61ad94b568f811c4fb5f9382 100644 --- a/drivers/net/qlge/qlge_ethtool.c +++ b/drivers/net/qlge/qlge_ethtool.c @@ -97,7 +97,7 @@ exit: return status; } -void ql_update_stats(struct ql_adapter *qdev) +static void ql_update_stats(struct ql_adapter *qdev) { u32 i; u64 data; diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c index b83a9c9b6a9799e73d2cd3efdf4c5177734baa80..718a7bd0cd1a207f90a6aaf92ffe894fd5163d79 100644 --- a/drivers/net/qlge/qlge_main.c +++ b/drivers/net/qlge/qlge_main.c @@ -336,12 +336,11 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type, (addr[5]); QPRINTK(qdev, IFUP, INFO, - "Adding %s address %02x:%02x:%02x:%02x:%02x:%02x" + "Adding %s address %pM" " at index %d in the CAM.\n", ((type == MAC_ADDR_TYPE_MULTI_MAC) ? "MULTICAST" : - "UNICAST"), addr[0], addr[1], addr[2], addr[3], - addr[4], addr[5], index); + "UNICAST"), addr, index); status = ql_wait_reg_rdy(qdev, @@ -643,7 +642,7 @@ static void ql_enable_all_completion_interrupts(struct ql_adapter *qdev) } -int ql_read_flash_word(struct ql_adapter *qdev, int offset, u32 *data) +static int ql_read_flash_word(struct ql_adapter *qdev, int offset, u32 *data) { int status = 0; /* wait for reg to come ready */ @@ -833,7 +832,7 @@ end: } /* Get the next large buffer. */ -struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring) +static struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring) { struct bq_desc *lbq_desc = &rx_ring->lbq[rx_ring->lbq_curr_idx]; rx_ring->lbq_curr_idx++; @@ -844,7 +843,7 @@ struct bq_desc *ql_get_curr_lbuf(struct rx_ring *rx_ring) } /* Get the next small buffer. */ -struct bq_desc *ql_get_curr_sbuf(struct rx_ring *rx_ring) +static struct bq_desc *ql_get_curr_sbuf(struct rx_ring *rx_ring) { struct bq_desc *sbq_desc = &rx_ring->sbq[rx_ring->sbq_curr_idx]; rx_ring->sbq_curr_idx++; @@ -1167,7 +1166,7 @@ map_error: return NETDEV_TX_BUSY; } -void ql_realign_skb(struct sk_buff *skb, int len) +static void ql_realign_skb(struct sk_buff *skb, int len) { void *temp_addr = skb->data; @@ -1452,7 +1451,6 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev, "Passing a normal packet upstream.\n"); netif_rx(skb); } - ndev->last_rx = jiffies; } /* Process an outbound completion from an rx ring. */ @@ -1649,7 +1647,7 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget) rx_ring->cq_id); if (work_done < budget) { - __netif_rx_complete(qdev->ndev, napi); + __netif_rx_complete(napi); ql_enable_completion_interrupt(qdev, rx_ring->irq); } return work_done; @@ -1734,8 +1732,7 @@ static irqreturn_t qlge_msix_tx_isr(int irq, void *dev_id) static irqreturn_t qlge_msix_rx_isr(int irq, void *dev_id) { struct rx_ring *rx_ring = dev_id; - struct ql_adapter *qdev = rx_ring->qdev; - netif_rx_schedule(qdev->ndev, &rx_ring->napi); + netif_rx_schedule(&rx_ring->napi); return IRQ_HANDLED; } @@ -1821,8 +1818,7 @@ static irqreturn_t qlge_isr(int irq, void *dev_id) &rx_ring->rx_work, 0); else - netif_rx_schedule(qdev->ndev, - &rx_ring->napi); + netif_rx_schedule(&rx_ring->napi); work_done++; } } @@ -2071,7 +2067,7 @@ err: return -ENOMEM; } -void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) +static void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) { int i; struct bq_desc *lbq_desc; @@ -2134,7 +2130,7 @@ mem_error: return -ENOMEM; } -void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) +static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring) { int i; struct bq_desc *sbq_desc; @@ -2469,7 +2465,7 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) rx_ring->sbq_base_indirect_dma = shadow_reg_dma; /* PCI doorbell mem area + 0x00 for consumer index register */ - rx_ring->cnsmr_idx_db_reg = (u32 *) doorbell_area; + rx_ring->cnsmr_idx_db_reg = (u32 __iomem *) doorbell_area; rx_ring->cnsmr_idx = 0; rx_ring->curr_entry = rx_ring->cq_base; @@ -2477,10 +2473,10 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring) rx_ring->valid_db_reg = doorbell_area + 0x04; /* PCI doorbell mem area + 0x18 for large buffer consumer */ - rx_ring->lbq_prod_idx_db_reg = (u32 *) (doorbell_area + 0x18); + rx_ring->lbq_prod_idx_db_reg = (u32 __iomem *) (doorbell_area + 0x18); /* PCI doorbell mem area + 0x1c */ - rx_ring->sbq_prod_idx_db_reg = (u32 *) (doorbell_area + 0x1c); + rx_ring->sbq_prod_idx_db_reg = (u32 __iomem *) (doorbell_area + 0x1c); memset((void *)cqicb, 0, sizeof(struct cqicb)); cqicb->msix_vect = rx_ring->irq; @@ -2611,7 +2607,7 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring) * Assign doorbell registers for this tx_ring. */ /* TX PCI doorbell mem area for tx producer index */ - tx_ring->prod_idx_db_reg = (u32 *) doorbell_area; + tx_ring->prod_idx_db_reg = (u32 __iomem *) doorbell_area; tx_ring->prod_idx = 0; /* TX PCI doorbell mem area + 0x04 */ tx_ring->valid_db_reg = doorbell_area + 0x04; @@ -3127,11 +3123,7 @@ static void ql_display_dev_info(struct net_device *ndev) qdev->chip_rev_id >> 4 & 0x0000000f, qdev->chip_rev_id >> 8 & 0x0000000f, qdev->chip_rev_id >> 12 & 0x0000000f); - QPRINTK(qdev, PROBE, INFO, - "MAC address %02x:%02x:%02x:%02x:%02x:%02x\n", - ndev->dev_addr[0], ndev->dev_addr[1], - ndev->dev_addr[2], ndev->dev_addr[3], ndev->dev_addr[4], - ndev->dev_addr[5]); + QPRINTK(qdev, PROBE, INFO, "MAC address %pM\n", ndev->dev_addr); } static int ql_adapter_down(struct ql_adapter *qdev) @@ -3156,7 +3148,7 @@ static int ql_adapter_down(struct ql_adapter *qdev) * a workqueue only if it's a single interrupt * environment (MSI/Legacy). */ - for (i = 1; i > qdev->rx_ring_count; i++) { + for (i = 1; i < qdev->rx_ring_count; i++) { rx_ring = &qdev->rx_ring[i]; /* Only the RSS rings use NAPI on multi irq * environment. Outbound completion processing @@ -3526,6 +3518,7 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p) { struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev); struct sockaddr *addr = p; + int ret = 0; if (netif_running(ndev)) return -EBUSY; @@ -3538,11 +3531,11 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p) if (ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr, MAC_ADDR_TYPE_CAM_MAC, qdev->func)) {/* Unicast */ QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n"); - return -1; + ret = -1; } spin_unlock(&qdev->hw_lock); - return 0; + return ret; } static void qlge_tx_timeout(struct net_device *ndev) @@ -3592,7 +3585,7 @@ static void ql_release_all(struct pci_dev *pdev) qdev->q_workqueue = NULL; } if (qdev->reg_base) - iounmap((void *)qdev->reg_base); + iounmap(qdev->reg_base); if (qdev->doorbell_area) iounmap(qdev->doorbell_area); pci_release_regions(pdev); @@ -3721,6 +3714,22 @@ err_out: return err; } + +static const struct net_device_ops qlge_netdev_ops = { + .ndo_open = qlge_open, + .ndo_stop = qlge_close, + .ndo_start_xmit = qlge_send, + .ndo_change_mtu = qlge_change_mtu, + .ndo_get_stats = qlge_get_stats, + .ndo_set_multicast_list = qlge_set_multicast_list, + .ndo_set_mac_address = qlge_set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = qlge_tx_timeout, + .ndo_vlan_rx_register = ql_vlan_rx_register, + .ndo_vlan_rx_add_vid = ql_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = ql_vlan_rx_kill_vid, +}; + static int __devinit qlge_probe(struct pci_dev *pdev, const struct pci_device_id *pci_entry) { @@ -3758,19 +3767,11 @@ static int __devinit qlge_probe(struct pci_dev *pdev, */ ndev->tx_queue_len = qdev->tx_ring_size; ndev->irq = pdev->irq; - ndev->open = qlge_open; - ndev->stop = qlge_close; - ndev->hard_start_xmit = qlge_send; + + ndev->netdev_ops = &qlge_netdev_ops; SET_ETHTOOL_OPS(ndev, &qlge_ethtool_ops); - ndev->change_mtu = qlge_change_mtu; - ndev->get_stats = qlge_get_stats; - ndev->set_multicast_list = qlge_set_multicast_list; - ndev->set_mac_address = qlge_set_mac_address; - ndev->tx_timeout = qlge_tx_timeout; ndev->watchdog_timeo = 10 * HZ; - ndev->vlan_rx_register = ql_vlan_rx_register; - ndev->vlan_rx_add_vid = ql_vlan_rx_add_vid; - ndev->vlan_rx_kill_vid = ql_vlan_rx_kill_vid; + err = register_netdev(ndev); if (err) { dev_err(&pdev->dev, "net device registration failed.\n"); diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index 24fe344bcf1f9ef48ce39672f5bbe1cfd0a65d0d..fa31891b6e624bf00c47c78a4d9e986804c4728c 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c @@ -19,7 +19,7 @@ exit: return status; } -int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) +static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) { int i, status; diff --git a/drivers/net/r6040.c b/drivers/net/r6040.c index 34fe7ef8e5edf637c1f3c5f301c944e08f598076..53bbddfc8c954ec17381230a4a491374f4a7404e 100644 --- a/drivers/net/r6040.c +++ b/drivers/net/r6040.c @@ -49,8 +49,8 @@ #include #define DRV_NAME "r6040" -#define DRV_VERSION "0.18" -#define DRV_RELDATE "13Jul2008" +#define DRV_VERSION "0.19" +#define DRV_RELDATE "18Dec2008" /* PHY CHIP Address */ #define PHY1_ADDR 1 /* For MAC1 */ @@ -214,7 +214,7 @@ static int r6040_phy_read(void __iomem *ioaddr, int phy_addr, int reg) /* Wait for the read bit to be cleared */ while (limit--) { cmd = ioread16(ioaddr + MMDIO); - if (cmd & MDIO_READ) + if (!(cmd & MDIO_READ)) break; } @@ -233,7 +233,7 @@ static void r6040_phy_write(void __iomem *ioaddr, int phy_addr, int reg, u16 val /* Wait for the write bit to be cleared */ while (limit--) { cmd = ioread16(ioaddr + MMDIO); - if (cmd & MDIO_WRITE) + if (!(cmd & MDIO_WRITE)) break; } } @@ -598,7 +598,6 @@ static int r6040_rx(struct net_device *dev, int limit) /* Send to upper layer */ netif_receive_skb(skb_ptr); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += descptr->len - 4; @@ -668,7 +667,7 @@ static int r6040_poll(struct napi_struct *napi, int budget) work_done = r6040_rx(dev, budget); if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /* Enable RX interrupt */ iowrite16(ioread16(ioaddr + MIER) | RX_INTS, ioaddr + MIER); } @@ -681,8 +680,10 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id) struct net_device *dev = dev_id; struct r6040_private *lp = netdev_priv(dev); void __iomem *ioaddr = lp->base; - u16 status; + u16 misr, status; + /* Save MIER */ + misr = ioread16(ioaddr + MIER); /* Mask off RDC MAC interrupt */ iowrite16(MSK_INT, ioaddr + MIER); /* Read MISR status and clear */ @@ -702,14 +703,17 @@ static irqreturn_t r6040_interrupt(int irq, void *dev_id) dev->stats.rx_fifo_errors++; /* Mask off RX interrupt */ - iowrite16(ioread16(ioaddr + MIER) & ~RX_INTS, ioaddr + MIER); - netif_rx_schedule(dev, &lp->napi); + misr &= ~RX_INTS; + netif_rx_schedule(&lp->napi); } /* TX interrupt request */ if (status & TX_INTS) r6040_tx(dev); + /* Restore RDC MAC interrupt */ + iowrite16(misr, ioaddr + MIER); + return IRQ_HANDLED; } @@ -1030,13 +1034,28 @@ static u32 netdev_get_link(struct net_device *dev) return mii_link_ok(&rp->mii_if); } -static struct ethtool_ops netdev_ethtool_ops = { +static const struct ethtool_ops netdev_ethtool_ops = { .get_drvinfo = netdev_get_drvinfo, .get_settings = netdev_get_settings, .set_settings = netdev_set_settings, .get_link = netdev_get_link, }; +static const struct net_device_ops r6040_netdev_ops = { + .ndo_open = r6040_open, + .ndo_stop = r6040_close, + .ndo_start_xmit = r6040_start_xmit, + .ndo_get_stats = r6040_get_stats, + .ndo_set_multicast_list = r6040_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = r6040_ioctl, + .ndo_tx_timeout = r6040_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = r6040_poll_controller, +#endif +}; + static int __devinit r6040_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1128,18 +1147,10 @@ static int __devinit r6040_init_one(struct pci_dev *pdev, lp->switch_sig = 0; /* The RDC-specific entries in the device structure. */ - dev->open = &r6040_open; - dev->hard_start_xmit = &r6040_start_xmit; - dev->stop = &r6040_close; - dev->get_stats = r6040_get_stats; - dev->set_multicast_list = &r6040_multicast_list; - dev->do_ioctl = &r6040_ioctl; + dev->netdev_ops = &r6040_netdev_ops; dev->ethtool_ops = &netdev_ethtool_ops; - dev->tx_timeout = &r6040_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = r6040_poll_controller; -#endif + netif_napi_add(dev, &lp->napi, r6040_poll, 64); lp->mii_if.dev = dev; lp->mii_if.mdio_read = r6040_mdio_read; diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 4b7cb389dc4989edaf2f70ce9da55420484767bd..2c73ca606b35e0942e31a033791f550ed4db481c 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c @@ -474,6 +474,7 @@ struct rtl8169_private { void (*hw_start)(struct net_device *); unsigned int (*phy_reset_pending)(void __iomem *); unsigned int (*link_ok)(void __iomem *); + int (*do_ioctl)(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd); int pcie_cap; struct delayed_work task; unsigned features; @@ -1829,9 +1830,11 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct rtl8169_private *tp = netdev_priv(dev); struct mii_ioctl_data *data = if_mii(ifr); - if (!netif_running(dev)) - return -ENODEV; + return netif_running(dev) ? tp->do_ioctl(tp, data, cmd) : -ENODEV; +} +static int rtl_xmii_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd) +{ switch (cmd) { case SIOCGMIIPHY: data->phy_id = 32; /* Internal PHY */ @@ -1850,6 +1853,11 @@ static int rtl8169_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) return -EOPNOTSUPP; } +static int rtl_tbi_ioctl(struct rtl8169_private *tp, struct mii_ioctl_data *data, int cmd) +{ + return -EOPNOTSUPP; +} + static const struct rtl_cfg_info { void (*hw_start)(struct net_device *); unsigned int region; @@ -1915,6 +1923,26 @@ static void rtl_disable_msi(struct pci_dev *pdev, struct rtl8169_private *tp) } } +static const struct net_device_ops rtl8169_netdev_ops = { + .ndo_open = rtl8169_open, + .ndo_stop = rtl8169_close, + .ndo_get_stats = rtl8169_get_stats, + .ndo_start_xmit = rtl8169_start_xmit, + .ndo_tx_timeout = rtl8169_tx_timeout, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = rtl8169_change_mtu, + .ndo_set_mac_address = rtl_set_mac_address, + .ndo_do_ioctl = rtl8169_ioctl, + .ndo_set_multicast_list = rtl_set_rx_mode, +#ifdef CONFIG_R8169_VLAN + .ndo_vlan_rx_register = rtl8169_vlan_rx_register, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = rtl8169_netpoll, +#endif + +}; + static int __devinit rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -1941,6 +1969,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) } SET_NETDEV_DEV(dev, &pdev->dev); + dev->netdev_ops = &rtl8169_netdev_ops; tp = netdev_priv(dev); tp->dev = dev; tp->pci_dev = pdev; @@ -2076,6 +2105,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->phy_reset_enable = rtl8169_tbi_reset_enable; tp->phy_reset_pending = rtl8169_tbi_reset_pending; tp->link_ok = rtl8169_tbi_link_ok; + tp->do_ioctl = rtl_tbi_ioctl; tp->phy_1000_ctrl_reg = ADVERTISE_1000FULL; /* Implied by TBI */ } else { @@ -2084,8 +2114,7 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) tp->phy_reset_enable = rtl8169_xmii_reset_enable; tp->phy_reset_pending = rtl8169_xmii_reset_pending; tp->link_ok = rtl8169_xmii_link_ok; - - dev->do_ioctl = rtl8169_ioctl; + tp->do_ioctl = rtl_xmii_ioctl; } spin_lock_init(&tp->lock); @@ -2097,28 +2126,15 @@ rtl8169_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) dev->dev_addr[i] = RTL_R8(MAC0 + i); memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - dev->open = rtl8169_open; - dev->hard_start_xmit = rtl8169_start_xmit; - dev->get_stats = rtl8169_get_stats; SET_ETHTOOL_OPS(dev, &rtl8169_ethtool_ops); - dev->stop = rtl8169_close; - dev->tx_timeout = rtl8169_tx_timeout; - dev->set_multicast_list = rtl_set_rx_mode; dev->watchdog_timeo = RTL8169_TX_TIMEOUT; dev->irq = pdev->irq; dev->base_addr = (unsigned long) ioaddr; - dev->change_mtu = rtl8169_change_mtu; - dev->set_mac_address = rtl_set_mac_address; netif_napi_add(dev, &tp->napi, rtl8169_poll, R8169_NAPI_WEIGHT); #ifdef CONFIG_R8169_VLAN dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = rtl8169_vlan_rx_register; -#endif - -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = rtl8169_netpoll; #endif tp->intr_mask = 0xffff; @@ -3484,7 +3500,6 @@ static int rtl8169_rx_interrupt(struct net_device *dev, if (rtl8169_rx_vlan_skb(tp, desc, skb) < 0) netif_receive_skb(skb); - dev->last_rx = jiffies; dev->stats.rx_bytes += pkt_size; dev->stats.rx_packets++; } @@ -3566,8 +3581,8 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); tp->intr_mask = ~tp->napi_event; - if (likely(netif_rx_schedule_prep(dev, &tp->napi))) - __netif_rx_schedule(dev, &tp->napi); + if (likely(netif_rx_schedule_prep(&tp->napi))) + __netif_rx_schedule(&tp->napi); else if (netif_msg_intr(tp)) { printk(KERN_INFO "%s: interrupt %04x in poll\n", dev->name, status); @@ -3588,7 +3603,7 @@ static int rtl8169_poll(struct napi_struct *napi, int budget) rtl8169_tx_interrupt(dev, tp, ioaddr); if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); tp->intr_mask = 0xffff; /* * 20040426: the barrier is not strictly required but the diff --git a/drivers/net/rionet.c b/drivers/net/rionet.c index 2b8fd68bc5163b49a09b373fb1913d6793bc051e..a6fd27a2cc3d25b4808ae5c85ba8c7a8e6e9da4b 100644 --- a/drivers/net/rionet.c +++ b/drivers/net/rionet.c @@ -94,7 +94,7 @@ static int rionet_rx_clean(struct net_device *ndev) { int i; int error = 0; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); void *data; i = rnet->rx_slot; @@ -132,7 +132,7 @@ static int rionet_rx_clean(struct net_device *ndev) static void rionet_rx_fill(struct net_device *ndev, int end) { int i; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); i = rnet->rx_slot; do { @@ -151,7 +151,7 @@ static void rionet_rx_fill(struct net_device *ndev, int end) static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev, struct rio_dev *rdev) { - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); rio_add_outb_message(rnet->mport, rdev, 0, skb->data, skb->len); rnet->tx_skb[rnet->tx_slot] = skb; @@ -175,7 +175,7 @@ static int rionet_queue_tx_msg(struct sk_buff *skb, struct net_device *ndev, static int rionet_start_xmit(struct sk_buff *skb, struct net_device *ndev) { int i; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); struct ethhdr *eth = (struct ethhdr *)skb->data; u16 destid; unsigned long flags; @@ -215,7 +215,7 @@ static void rionet_dbell_event(struct rio_mport *mport, void *dev_id, u16 sid, u u16 info) { struct net_device *ndev = dev_id; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); struct rionet_peer *peer; if (netif_msg_intr(rnet)) @@ -243,7 +243,7 @@ static void rionet_inb_msg_event(struct rio_mport *mport, void *dev_id, int mbox { int n; struct net_device *ndev = dev_id; - struct rionet_private *rnet = (struct rionet_private *)ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); if (netif_msg_intr(rnet)) printk(KERN_INFO "%s: inbound message event, mbox %d slot %d\n", @@ -258,7 +258,7 @@ static void rionet_inb_msg_event(struct rio_mport *mport, void *dev_id, int mbox static void rionet_outb_msg_event(struct rio_mport *mport, void *dev_id, int mbox, int slot) { struct net_device *ndev = dev_id; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); spin_lock(&rnet->lock); @@ -287,7 +287,7 @@ static int rionet_open(struct net_device *ndev) int i, rc = 0; struct rionet_peer *peer, *tmp; u32 pwdcsr; - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); if (netif_msg_ifup(rnet)) printk(KERN_INFO "%s: open\n", DRV_NAME); @@ -351,7 +351,7 @@ static int rionet_open(struct net_device *ndev) static int rionet_close(struct net_device *ndev) { - struct rionet_private *rnet = (struct rionet_private *)ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); struct rionet_peer *peer, *tmp; int i; @@ -400,7 +400,7 @@ static void rionet_remove(struct rio_dev *rdev) static void rionet_get_drvinfo(struct net_device *ndev, struct ethtool_drvinfo *info) { - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -410,14 +410,14 @@ static void rionet_get_drvinfo(struct net_device *ndev, static u32 rionet_get_msglevel(struct net_device *ndev) { - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); return rnet->msg_enable; } static void rionet_set_msglevel(struct net_device *ndev, u32 value) { - struct rionet_private *rnet = ndev->priv; + struct rionet_private *rnet = netdev_priv(ndev); rnet->msg_enable = value; } @@ -435,7 +435,6 @@ static int rionet_setup_netdev(struct rio_mport *mport) struct net_device *ndev = NULL; struct rionet_private *rnet; u16 device_id; - DECLARE_MAC_BUF(mac); /* Allocate our net_device structure */ ndev = alloc_etherdev(sizeof(struct rionet_private)); @@ -456,7 +455,7 @@ static int rionet_setup_netdev(struct rio_mport *mport) RIO_MAX_ROUTE_ENTRIES(mport->sys_size)); /* Set up private area */ - rnet = (struct rionet_private *)ndev->priv; + rnet = netdev_priv(ndev); rnet->mport = mport; /* Set the default MAC address */ @@ -485,12 +484,12 @@ static int rionet_setup_netdev(struct rio_mport *mport) if (rc != 0) goto out; - printk("%s: %s %s Version %s, MAC %s\n", + printk("%s: %s %s Version %s, MAC %pM\n", ndev->name, DRV_NAME, DRV_DESC, DRV_VERSION, - print_mac(mac, ndev->dev_addr)); + ndev->dev_addr); out: return rc; diff --git a/drivers/net/rrunner.c b/drivers/net/rrunner.c index 3dd8f1342f70c58eb83ffb01cbb0f40576666076..d890829a9acc61f678e06c273a031976603f010f 100644 --- a/drivers/net/rrunner.c +++ b/drivers/net/rrunner.c @@ -63,6 +63,16 @@ MODULE_LICENSE("GPL"); static char version[] __devinitdata = "rrunner.c: v0.50 11/11/2002 Jes Sorensen (jes@wildopensource.com)\n"; + +static const struct net_device_ops rr_netdev_ops = { + .ndo_open = rr_open, + .ndo_stop = rr_close, + .ndo_do_ioctl = rr_ioctl, + .ndo_start_xmit = rr_start_xmit, + .ndo_change_mtu = hippi_change_mtu, + .ndo_set_mac_address = hippi_mac_addr, +}; + /* * Implementation notes: * @@ -115,10 +125,7 @@ static int __devinit rr_init_one(struct pci_dev *pdev, spin_lock_init(&rrpriv->lock); dev->irq = pdev->irq; - dev->open = &rr_open; - dev->hard_start_xmit = &rr_start_xmit; - dev->stop = &rr_close; - dev->do_ioctl = &rr_ioctl; + dev->netdev_ops = &rr_netdev_ops; dev->base_addr = pci_resource_start(pdev, 0); @@ -511,7 +518,6 @@ static int __devinit rr_init(struct net_device *dev) struct rr_private *rrpriv; struct rr_regs __iomem *regs; u32 sram_size, rev; - DECLARE_MAC_BUF(mac); rrpriv = netdev_priv(dev); regs = rrpriv->regs; @@ -549,7 +555,7 @@ static int __devinit rr_init(struct net_device *dev) *(__be32 *)(dev->dev_addr+2) = htonl(rr_read_eeprom_word(rrpriv, offsetof(struct eeprom, manf.BoardULA[4]))); - printk(" MAC: %s\n", print_mac(mac, dev->dev_addr)); + printk(" MAC: %pM\n", dev->dev_addr); sram_size = rr_read_eeprom_word(rrpriv, 8); printk(" SRAM size 0x%06x\n", sram_size); @@ -1006,7 +1012,6 @@ static void rx_int(struct net_device *dev, u32 rxlimit, u32 index) netif_rx(skb); /* send it up */ - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -1708,9 +1713,3 @@ static void __exit rr_cleanup_module(void) module_init(rr_init_module); module_exit(rr_cleanup_module); - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c" - * End: - */ diff --git a/drivers/net/s2io.c b/drivers/net/s2io.c index 6a1375f9cbb81e2c627f2fe1f6606839b9c0c16c..f5c57c059bca15c7d9e35f0b26c39fb0551bc718 100644 --- a/drivers/net/s2io.c +++ b/drivers/net/s2io.c @@ -352,12 +352,13 @@ static void do_s2io_copy_mac_addr(struct s2io_nic *sp, int offset, u64 mac_addr) sp->def_mac_addr[offset].mac_addr[1] = (u8) (mac_addr >> 32); sp->def_mac_addr[offset].mac_addr[0] = (u8) (mac_addr >> 40); } + /* Add the vlan */ static void s2io_vlan_rx_register(struct net_device *dev, - struct vlan_group *grp) + struct vlan_group *grp) { int i; - struct s2io_nic *nic = dev->priv; + struct s2io_nic *nic = netdev_priv(dev); unsigned long flags[MAX_TX_FIFOS]; struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; @@ -372,10 +373,10 @@ static void s2io_vlan_rx_register(struct net_device *dev, } /* Unregister the vlan */ -static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned long vid) +static void s2io_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) { int i; - struct s2io_nic *nic = dev->priv; + struct s2io_nic *nic = netdev_priv(dev); unsigned long flags[MAX_TX_FIFOS]; struct mac_info *mac_control = &nic->mac_control; struct config_param *config = &nic->config; @@ -2837,7 +2838,7 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) int pkts_processed = 0; u8 __iomem *addr = NULL; u8 val8 = 0; - struct s2io_nic *nic = dev->priv; + struct s2io_nic *nic = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = nic->bar0; int budget_org = budget; @@ -2851,7 +2852,7 @@ static int s2io_poll_msix(struct napi_struct *napi, int budget) s2io_chk_rx_buffers(nic, ring); if (pkts_processed < budget_org) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /*Re Enable MSI-Rx Vector*/ addr = (u8 __iomem *)&bar0->xmsi_mask_reg; addr += 7 - ring->ring_no; @@ -2865,7 +2866,6 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) { struct s2io_nic *nic = container_of(napi, struct s2io_nic, napi); struct ring_info *ring; - struct net_device *dev = nic->dev; struct config_param *config; struct mac_info *mac_control; int pkts_processed = 0; @@ -2889,7 +2889,7 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) break; } if (pkts_processed < budget_org) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /* Re enable the Rx interrupts for the ring */ writeq(0, &bar0->rx_traffic_mask); readl(&bar0->rx_traffic_mask); @@ -2909,7 +2909,7 @@ static int s2io_poll_inta(struct napi_struct *napi, int budget) */ static void s2io_netpoll(struct net_device *dev) { - struct s2io_nic *nic = dev->priv; + struct s2io_nic *nic = netdev_priv(dev); struct mac_info *mac_control; struct config_param *config; struct XENA_dev_config __iomem *bar0 = nic->bar0; @@ -3171,7 +3171,7 @@ static void tx_intr_handler(struct fifo_info *fifo_data) static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device *dev) { u64 val64 = 0x0; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; //address transaction @@ -3220,7 +3220,7 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev) { u64 val64 = 0x0; u64 rval64 = 0x0; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; /* address transaction */ @@ -3324,7 +3324,7 @@ static void s2io_updt_xpak_counter(struct net_device *dev) u64 val64 = 0x0; u64 addr = 0x0; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct stat_block *stat_info = sp->mac_control.stats_info; /* Check the communication with the MDIO slave */ @@ -3990,7 +3990,7 @@ static void remove_inta_isr(struct s2io_nic *sp) static int s2io_open(struct net_device *dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); int err = 0; /* @@ -4048,7 +4048,7 @@ hw_init_failed: static int s2io_close(struct net_device *dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct config_param *config = &sp->config; u64 tmp64; int offset; @@ -4087,7 +4087,7 @@ static int s2io_close(struct net_device *dev) static int s2io_xmit(struct sk_buff *skb, struct net_device *dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); u16 frg_cnt, frg_len, i, queue, queue_len, put_off, get_off; register u64 val64; struct TxD *txdp; @@ -4329,7 +4329,6 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) struct ring_info *ring = (struct ring_info *)dev_id; struct s2io_nic *sp = ring->nic; struct XENA_dev_config __iomem *bar0 = sp->bar0; - struct net_device *dev = sp->dev; if (unlikely(!is_s2io_card_up(sp))) return IRQ_HANDLED; @@ -4343,7 +4342,7 @@ static irqreturn_t s2io_msix_ring_handle(int irq, void *dev_id) val8 = (ring->ring_no == 0) ? 0x7f : 0xff; writeb(val8, addr); val8 = readb(addr); - netif_rx_schedule(dev, &ring->napi); + netif_rx_schedule(&ring->napi); } else { rx_intr_handler(ring, 0); s2io_chk_rx_buffers(sp, ring); @@ -4485,7 +4484,7 @@ static int do_s2io_chk_alarm_bit(u64 value, void __iomem * addr, static void s2io_handle_errors(void * dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 temp64 = 0,val64=0; int i = 0; @@ -4752,7 +4751,7 @@ reset: static irqreturn_t s2io_isr(int irq, void *dev_id) { struct net_device *dev = (struct net_device *) dev_id; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; int i; u64 reason = 0; @@ -4790,7 +4789,7 @@ static irqreturn_t s2io_isr(int irq, void *dev_id) if (config->napi) { if (reason & GEN_INTR_RXTRAFFIC) { - netif_rx_schedule(dev, &sp->napi); + netif_rx_schedule(&sp->napi); writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_mask); writeq(S2IO_MINUS_ONE, &bar0->rx_traffic_int); readl(&bar0->rx_traffic_int); @@ -4881,7 +4880,7 @@ static void s2io_updt_stats(struct s2io_nic *sp) static struct net_device_stats *s2io_get_stats(struct net_device *dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct mac_info *mac_control; struct config_param *config; int i; @@ -4948,7 +4947,7 @@ static void s2io_set_multicast(struct net_device *dev) { int i, j, prev_cnt; struct dev_mc_list *mclist; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; u64 val64 = 0, multi_mac = 0x010203040506ULL, mask = 0xfeffffffffffULL; @@ -5112,7 +5111,7 @@ static void s2io_set_multicast(struct net_device *dev) /* read from CAM unicast & multicast addresses and store it in * def_mac_addr structure */ -void do_s2io_store_unicast_mc(struct s2io_nic *sp) +static void do_s2io_store_unicast_mc(struct s2io_nic *sp) { int offset; u64 mac_addr = 0x0; @@ -5277,7 +5276,7 @@ static int s2io_set_mac_addr(struct net_device *dev, void *p) static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); register u64 mac_addr = 0, perm_addr = 0; int i; u64 tmp64; @@ -5336,7 +5335,7 @@ static int do_s2io_prog_unicast(struct net_device *dev, u8 *addr) static int s2io_ethtool_sset(struct net_device *dev, struct ethtool_cmd *info) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); if ((info->autoneg == AUTONEG_ENABLE) || (info->speed != SPEED_10000) || (info->duplex != DUPLEX_FULL)) return -EINVAL; @@ -5362,7 +5361,7 @@ static int s2io_ethtool_sset(struct net_device *dev, static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); info->supported = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->advertising = (SUPPORTED_10000baseT_Full | SUPPORTED_FIBRE); info->port = PORT_FIBRE; @@ -5397,7 +5396,7 @@ static int s2io_ethtool_gset(struct net_device *dev, struct ethtool_cmd *info) static void s2io_ethtool_gdrvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); strncpy(info->driver, s2io_driver_name, sizeof(info->driver)); strncpy(info->version, s2io_driver_version, sizeof(info->version)); @@ -5427,7 +5426,7 @@ static void s2io_ethtool_gregs(struct net_device *dev, int i; u64 reg; u8 *reg_space = (u8 *) space; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); regs->len = XENA_REG_SPACE; regs->version = sp->pdev->subsystem_device; @@ -5487,7 +5486,7 @@ static void s2io_phy_id(unsigned long data) static int s2io_ethtool_idnic(struct net_device *dev, u32 data) { u64 val64 = 0, last_gpio_ctrl_val; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; u16 subid; @@ -5525,7 +5524,7 @@ static int s2io_ethtool_idnic(struct net_device *dev, u32 data) static void s2io_ethtool_gringparam(struct net_device *dev, struct ethtool_ringparam *ering) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); int i,tx_desc_count=0,rx_desc_count=0; if (sp->rxd_mode == RXD_MODE_1) @@ -5568,7 +5567,7 @@ static void s2io_ethtool_getpause_data(struct net_device *dev, struct ethtool_pauseparam *ep) { u64 val64; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; val64 = readq(&bar0->rmac_pause_cfg); @@ -5595,7 +5594,7 @@ static int s2io_ethtool_setpause_data(struct net_device *dev, struct ethtool_pauseparam *ep) { u64 val64; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct XENA_dev_config __iomem *bar0 = sp->bar0; val64 = readq(&bar0->rmac_pause_cfg); @@ -5825,7 +5824,7 @@ static int s2io_ethtool_geeprom(struct net_device *dev, { u32 i, valid; u64 data; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); eeprom->magic = sp->pdev->vendor | (sp->pdev->device << 16); @@ -5863,7 +5862,7 @@ static int s2io_ethtool_seeprom(struct net_device *dev, { int len = eeprom->len, cnt = 0; u64 valid = 0, data; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); if (eeprom->magic != (sp->pdev->vendor | (sp->pdev->device << 16))) { DBG_PRINT(ERR_DBG, @@ -6243,7 +6242,7 @@ static void s2io_ethtool_test(struct net_device *dev, struct ethtool_test *ethtest, uint64_t * data) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); int orig_state = netif_running(sp->dev); if (ethtest->flags == ETH_TEST_FL_OFFLINE) { @@ -6299,7 +6298,7 @@ static void s2io_get_ethtool_stats(struct net_device *dev, u64 * tmp_stats) { int i = 0, k; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); struct stat_block *stat_info = sp->mac_control.stats_info; s2io_updt_stats(sp); @@ -6578,14 +6577,14 @@ static int s2io_ethtool_get_regs_len(struct net_device *dev) static u32 s2io_ethtool_get_rx_csum(struct net_device * dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); return (sp->rx_csum); } static int s2io_ethtool_set_rx_csum(struct net_device *dev, u32 data) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); if (data) sp->rx_csum = 1; @@ -6602,7 +6601,7 @@ static int s2io_get_eeprom_len(struct net_device *dev) static int s2io_get_sset_count(struct net_device *dev, int sset) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); switch (sset) { case ETH_SS_TEST: @@ -6625,7 +6624,7 @@ static void s2io_ethtool_get_strings(struct net_device *dev, u32 stringset, u8 * data) { int stat_size = 0; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); switch (stringset) { case ETH_SS_TEST: @@ -6727,7 +6726,7 @@ static int s2io_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) static int s2io_change_mtu(struct net_device *dev, int new_mtu) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); int ret = 0; if ((new_mtu < MIN_MTU) || (new_mtu > S2IO_JUMBO_SIZE)) { @@ -7331,7 +7330,7 @@ out_unlock: static void s2io_tx_watchdog(struct net_device *dev) { - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); if (netif_carrier_ok(dev)) { sp->mac_control.stats_info->sw_stat.watchdog_timer_cnt++; @@ -7366,7 +7365,7 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) int ring_no = ring_data->ring_no; u16 l3_csum, l4_csum; unsigned long long err = rxdp->Control_1 & RXD_T_CODE; - struct lro *lro; + struct lro *uninitialized_var(lro); u8 err_mask; skb->dev = dev; @@ -7544,7 +7543,6 @@ static int rx_osm_handler(struct ring_info *ring_data, struct RxD_t * rxdp) sp->mac_control.stats_info->sw_stat.mem_freed += skb->truesize; send_up: queue_rx_frame(skb, RXD_GET_VLAN_TAG(rxdp->Control_2)); - dev->last_rx = jiffies; aggregate: sp->mac_control.rings[ring_no].rx_bufs_left -= 1; return SUCCESS; @@ -7718,6 +7716,24 @@ static int rts_ds_steer(struct s2io_nic *nic, u8 ds_codepoint, u8 ring) S2IO_BIT_RESET); } +static const struct net_device_ops s2io_netdev_ops = { + .ndo_open = s2io_open, + .ndo_stop = s2io_close, + .ndo_get_stats = s2io_get_stats, + .ndo_start_xmit = s2io_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = s2io_set_multicast, + .ndo_do_ioctl = s2io_ioctl, + .ndo_set_mac_address = s2io_set_mac_addr, + .ndo_change_mtu = s2io_change_mtu, + .ndo_vlan_rx_register = s2io_vlan_rx_register, + .ndo_vlan_rx_kill_vid = s2io_vlan_rx_kill_vid, + .ndo_tx_timeout = s2io_tx_watchdog, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = s2io_netpoll, +#endif +}; + /** * s2io_init_nic - Initialization of the adapter . * @pdev : structure containing the PCI related information of the device. @@ -7748,7 +7764,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) int mode; u8 dev_intr_type = intr_type; u8 dev_multiq = 0; - DECLARE_MAC_BUF(mac); ret = s2io_verify_parm(pdev, &dev_intr_type, &dev_multiq); if (ret) @@ -7798,7 +7813,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) SET_NETDEV_DEV(dev, &pdev->dev); /* Private member variable initialized to s2io NIC structure */ - sp = dev->priv; + sp = netdev_priv(dev); memset(sp, 0, sizeof(struct s2io_nic)); sp->dev = dev; sp->pdev = pdev; @@ -7918,8 +7933,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto mem_alloc_failed; } - sp->bar0 = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); + sp->bar0 = pci_ioremap_bar(pdev, 0); if (!sp->bar0) { DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem1\n", dev->name); @@ -7927,8 +7941,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) goto bar0_remap_failed; } - sp->bar1 = ioremap(pci_resource_start(pdev, 2), - pci_resource_len(pdev, 2)); + sp->bar1 = pci_ioremap_bar(pdev, 2); if (!sp->bar1) { DBG_PRINT(ERR_DBG, "%s: Neterion: cannot remap io mem2\n", dev->name); @@ -7946,26 +7959,9 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) } /* Driver entry points */ - dev->open = &s2io_open; - dev->stop = &s2io_close; - dev->hard_start_xmit = &s2io_xmit; - dev->get_stats = &s2io_get_stats; - dev->set_multicast_list = &s2io_set_multicast; - dev->do_ioctl = &s2io_ioctl; - dev->set_mac_address = &s2io_set_mac_addr; - dev->change_mtu = &s2io_change_mtu; + dev->netdev_ops = &s2io_netdev_ops; SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops); dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = s2io_vlan_rx_register; - dev->vlan_rx_kill_vid = (void *)s2io_vlan_rx_kill_vid; - - /* - * will use eth_mac_addr() for dev->set_mac_address - * mac address will be set every time dev->open() is called - */ -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = s2io_netpoll; -#endif dev->features |= NETIF_F_SG | NETIF_F_IP_CSUM; if (sp->high_dma_flag == TRUE) @@ -7976,7 +7972,6 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) dev->features |= NETIF_F_UFO; dev->features |= NETIF_F_HW_CSUM; } - dev->tx_timeout = &s2io_tx_watchdog; dev->watchdog_timeo = WATCH_DOG_TIMEOUT; INIT_WORK(&sp->rst_timer_task, s2io_restart_nic); INIT_WORK(&sp->set_link_task, s2io_set_link); @@ -8125,8 +8120,7 @@ s2io_init_nic(struct pci_dev *pdev, const struct pci_device_id *pre) sp->product_name, pdev->revision); DBG_PRINT(ERR_DBG, "%s: Driver version %s\n", dev->name, s2io_driver_version); - DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + DBG_PRINT(ERR_DBG, "%s: MAC ADDR: %pM\n", dev->name, dev->dev_addr); DBG_PRINT(ERR_DBG, "SERIAL NUMBER: %s\n", sp->serial_num); if (sp->device_type & XFRAME_II_DEVICE) { mode = s2io_print_pci_mode(sp); @@ -8255,7 +8249,7 @@ static void __devexit s2io_rem_nic(struct pci_dev *pdev) flush_scheduled_work(); - sp = dev->priv; + sp = netdev_priv(dev); unregister_netdev(dev); free_shared_mem(sp); @@ -8590,7 +8584,7 @@ static void clear_lro_session(struct lro *lro) static void queue_rx_frame(struct sk_buff *skb, u16 vlan_tag) { struct net_device *dev = skb->dev; - struct s2io_nic *sp = dev->priv; + struct s2io_nic *sp = netdev_priv(dev); skb->protocol = eth_type_trans(skb, dev); if (sp->vlgrp && vlan_tag @@ -8639,7 +8633,7 @@ static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, pci_channel_state_t state) { struct net_device *netdev = pci_get_drvdata(pdev); - struct s2io_nic *sp = netdev->priv; + struct s2io_nic *sp = netdev_priv(netdev); netif_device_detach(netdev); @@ -8664,7 +8658,7 @@ static pci_ers_result_t s2io_io_error_detected(struct pci_dev *pdev, static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct s2io_nic *sp = netdev->priv; + struct s2io_nic *sp = netdev_priv(netdev); if (pci_enable_device(pdev)) { printk(KERN_ERR "s2io: " @@ -8688,7 +8682,7 @@ static pci_ers_result_t s2io_io_slot_reset(struct pci_dev *pdev) static void s2io_io_resume(struct pci_dev *pdev) { struct net_device *netdev = pci_get_drvdata(pdev); - struct s2io_nic *sp = netdev->priv; + struct s2io_nic *sp = netdev_priv(netdev); if (netif_running(netdev)) { if (s2io_card_up(sp)) { diff --git a/drivers/net/sb1000.c b/drivers/net/sb1000.c index 5986cec17f19eff6b3aa06ba9f4d500ef953b8bd..be3025310e90c1eb3e3c2f15316b24fda8d8cd42 100644 --- a/drivers/net/sb1000.c +++ b/drivers/net/sb1000.c @@ -869,7 +869,6 @@ printk("cm0: IP identification: %02x%02x fragment offset: %02x%02x\n", buffer[3 /* datagram completed: send to upper level */ skb_trim(skb, dlen); netif_rx(skb); - dev->last_rx = jiffies; stats->rx_bytes+=dlen; stats->rx_packets++; lp->rx_skb[ns] = NULL; diff --git a/drivers/net/sb1250-mac.c b/drivers/net/sb1250-mac.c index 2615d46e6e503c08fdcdbad4fcb1b8a3873d16e8..31e38fae017f8def7273d568089914599a1b54d6 100644 --- a/drivers/net/sb1250-mac.c +++ b/drivers/net/sb1250-mac.c @@ -2039,9 +2039,9 @@ static irqreturn_t sbmac_intr(int irq,void *dev_instance) sbdma_tx_process(sc,&(sc->sbm_txdma), 0); if (isr & (M_MAC_INT_CHANNEL << S_MAC_RX_CH0)) { - if (netif_rx_schedule_prep(dev, &sc->napi)) { + if (netif_rx_schedule_prep(&sc->napi)) { __raw_writeq(0, sc->sbm_imr); - __netif_rx_schedule(dev, &sc->napi); + __netif_rx_schedule(&sc->napi); /* Depend on the exit from poll to reenable intr */ } else { @@ -2292,7 +2292,6 @@ static int sbmac_init(struct platform_device *pldev, long long base) uint64_t ea_reg; int i; int err; - DECLARE_MAC_BUF(mac); sc->sbm_dev = dev; sc->sbe_idx = idx; @@ -2373,8 +2372,8 @@ static int sbmac_init(struct platform_device *pldev, long long base) * process so we need to finish off the config message that * was being displayed) */ - pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %s\n", - dev->name, base, print_mac(mac, eaddr)); + pr_info("%s: SiByte Ethernet at 0x%08Lx, address: %pM\n", + dev->name, base, eaddr); sc->mii_bus->name = sbmac_mdio_string; snprintf(sc->mii_bus->id, MII_BUS_ID_SIZE, "%x", idx); @@ -2668,7 +2667,7 @@ static int sbmac_poll(struct napi_struct *napi, int budget) sbdma_tx_process(sc, &(sc->sbm_txdma), 1); if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); #ifdef CONFIG_SBMAC_COALESCE __raw_writeq(((M_MAC_INT_EOP_COUNT | M_MAC_INT_EOP_TIMER) << S_MAC_TX_CH0) | diff --git a/drivers/net/sc92031.c b/drivers/net/sc92031.c index 61955f8d80119705806b9fd8ab9714cd56bcff2c..42fd31276602a6b15c90ea405238cf26bb97a345 100644 --- a/drivers/net/sc92031.c +++ b/drivers/net/sc92031.c @@ -816,7 +816,6 @@ static void _sc92031_rx_tasklet(struct net_device *dev) } skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; netif_rx(skb); dev->stats.rx_bytes += pkt_size; @@ -1387,7 +1386,7 @@ static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev, spin_unlock_bh(&priv->lock); } -static struct ethtool_ops sc92031_ethtool_ops = { +static const struct ethtool_ops sc92031_ethtool_ops = { .get_settings = sc92031_ethtool_get_settings, .set_settings = sc92031_ethtool_set_settings, .get_drvinfo = sc92031_ethtool_get_drvinfo, @@ -1400,6 +1399,21 @@ static struct ethtool_ops sc92031_ethtool_ops = { .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats, }; + +static const struct net_device_ops sc92031_netdev_ops = { + .ndo_get_stats = sc92031_get_stats, + .ndo_start_xmit = sc92031_start_xmit, + .ndo_open = sc92031_open, + .ndo_stop = sc92031_stop, + .ndo_set_multicast_list = sc92031_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_tx_timeout = sc92031_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = sc92031_poll_controller, +#endif +}; + static int __devinit sc92031_probe(struct pci_dev *pdev, const struct pci_device_id *id) { @@ -1453,17 +1467,9 @@ static int __devinit sc92031_probe(struct pci_dev *pdev, /* faked with skb_copy_and_csum_dev */ dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA; - dev->get_stats = sc92031_get_stats; - dev->ethtool_ops = &sc92031_ethtool_ops; - dev->hard_start_xmit = sc92031_start_xmit; + dev->netdev_ops = &sc92031_netdev_ops; dev->watchdog_timeo = TX_TIMEOUT; - dev->open = sc92031_open; - dev->stop = sc92031_stop; - dev->set_multicast_list = sc92031_set_multicast_list; - dev->tx_timeout = sc92031_tx_timeout; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = sc92031_poll_controller; -#endif + dev->ethtool_ops = &sc92031_ethtool_ops; priv = netdev_priv(dev); spin_lock_init(&priv->lock); diff --git a/drivers/net/seeq8005.c b/drivers/net/seeq8005.c index 48c64fb20eecf164b9022aae727e6dc86e8f5290..12a8ffffeb03d3e448c8cab167f80c7d42a3dbf9 100644 --- a/drivers/net/seeq8005.c +++ b/drivers/net/seeq8005.c @@ -158,7 +158,6 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr) int old_dmaar; int old_rear; int retval; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, SEEQ8005_IO_EXTENT, "seeq8005")) return -ENODEV; @@ -303,7 +302,7 @@ static int __init seeq8005_probe1(struct net_device *dev, int ioaddr) /* Retrieve and print the ethernet address. */ for (i = 0; i < 6; i++) dev->dev_addr[i] = SA_prom[i+6]; - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); if (dev->irq == 0xff) ; /* Do nothing: a user-level program will set it. */ @@ -564,7 +563,6 @@ static void seeq8005_rx(struct net_device *dev) skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -746,12 +744,3 @@ void __exit cleanup_module(void) } #endif /* MODULE */ - -/* - * Local variables: - * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c" - * version-control: t - * kept-new-versions: 5 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/sfc/Kconfig b/drivers/net/sfc/Kconfig index 3be13b592b4dbb0f7c1382ec745d8684f57c8cb6..c535408ad6bef520262118f0283c0d004ee6cc56 100644 --- a/drivers/net/sfc/Kconfig +++ b/drivers/net/sfc/Kconfig @@ -12,3 +12,11 @@ config SFC To compile this driver as a module, choose M here. The module will be called sfc. +config SFC_MTD + bool "Solarflare Solarstorm SFC4000 flash MTD support" + depends on SFC && MTD && !(SFC=y && MTD=m) + default y + help + This exposes the on-board flash memory as an MTD device (e.g. + /dev/mtd1). This makes it possible to upload new boot code + to the NIC. diff --git a/drivers/net/sfc/Makefile b/drivers/net/sfc/Makefile index c8f5704c8fb18adf946e8b1bc66afea50c76a12b..b89f9be3cb1308c5f9b1c940e9177940171d219a 100644 --- a/drivers/net/sfc/Makefile +++ b/drivers/net/sfc/Makefile @@ -1,5 +1,6 @@ -sfc-y += efx.o falcon.o tx.o rx.o falcon_xmac.o \ - selftest.o ethtool.o xfp_phy.o \ +sfc-y += efx.o falcon.o tx.o rx.o falcon_gmac.o \ + falcon_xmac.o selftest.o ethtool.o xfp_phy.o \ mdio_10g.o tenxpress.o boards.o sfe4001.o +sfc-$(CONFIG_SFC_MTD) += mtd.o obj-$(CONFIG_SFC) += sfc.o diff --git a/drivers/net/sfc/boards.c b/drivers/net/sfc/boards.c index 99e6023732691c08cf6060abff318b2331201b35..64903496aa9af1b256f0fcc062007f2cd8842472 100644 --- a/drivers/net/sfc/boards.c +++ b/drivers/net/sfc/boards.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007 Solarflare Communications Inc. + * Copyright 2007-2008 Solarflare Communications 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 @@ -11,6 +11,7 @@ #include "phy.h" #include "boards.h" #include "efx.h" +#include "workarounds.h" /* Macros for unpacking the board revision */ /* The revision info is in host byte order. */ @@ -51,10 +52,129 @@ static void board_blink(struct efx_nic *efx, bool blink) } } +/***************************************************************************** + * Support for LM87 sensor chip used on several boards + */ +#define LM87_REG_ALARMS1 0x41 +#define LM87_REG_ALARMS2 0x42 +#define LM87_IN_LIMITS(nr, _min, _max) \ + 0x2B + (nr) * 2, _max, 0x2C + (nr) * 2, _min +#define LM87_AIN_LIMITS(nr, _min, _max) \ + 0x3B + (nr), _max, 0x1A + (nr), _min +#define LM87_TEMP_INT_LIMITS(_min, _max) \ + 0x39, _max, 0x3A, _min +#define LM87_TEMP_EXT1_LIMITS(_min, _max) \ + 0x37, _max, 0x38, _min + +#define LM87_ALARM_TEMP_INT 0x10 +#define LM87_ALARM_TEMP_EXT1 0x20 + +#if defined(CONFIG_SENSORS_LM87) || defined(CONFIG_SENSORS_LM87_MODULE) + +static int efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, + const u8 *reg_values) +{ + struct i2c_client *client = i2c_new_device(&efx->i2c_adap, info); + int rc; + + if (!client) + return -EIO; + + while (*reg_values) { + u8 reg = *reg_values++; + u8 value = *reg_values++; + rc = i2c_smbus_write_byte_data(client, reg, value); + if (rc) + goto err; + } + + efx->board_info.hwmon_client = client; + return 0; + +err: + i2c_unregister_device(client); + return rc; +} + +static void efx_fini_lm87(struct efx_nic *efx) +{ + i2c_unregister_device(efx->board_info.hwmon_client); +} + +static int efx_check_lm87(struct efx_nic *efx, unsigned mask) +{ + struct i2c_client *client = efx->board_info.hwmon_client; + s32 alarms1, alarms2; + + /* If link is up then do not monitor temperature */ + if (EFX_WORKAROUND_7884(efx) && efx->link_up) + return 0; + + alarms1 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS1); + alarms2 = i2c_smbus_read_byte_data(client, LM87_REG_ALARMS2); + if (alarms1 < 0) + return alarms1; + if (alarms2 < 0) + return alarms2; + alarms1 &= mask; + alarms2 &= mask >> 8; + if (alarms1 || alarms2) { + EFX_ERR(efx, + "LM87 detected a hardware failure (status %02x:%02x)" + "%s%s\n", + alarms1, alarms2, + (alarms1 & LM87_ALARM_TEMP_INT) ? " INTERNAL" : "", + (alarms1 & LM87_ALARM_TEMP_EXT1) ? " EXTERNAL" : ""); + return -ERANGE; + } + + return 0; +} + +#else /* !CONFIG_SENSORS_LM87 */ + +static inline int +efx_init_lm87(struct efx_nic *efx, struct i2c_board_info *info, + const u8 *reg_values) +{ + return 0; +} +static inline void efx_fini_lm87(struct efx_nic *efx) +{ +} +static inline int efx_check_lm87(struct efx_nic *efx, unsigned mask) +{ + return 0; +} + +#endif /* CONFIG_SENSORS_LM87 */ + /***************************************************************************** * Support for the SFE4002 * */ +static u8 sfe4002_lm87_channel = 0x03; /* use AIN not FAN inputs */ + +static const u8 sfe4002_lm87_regs[] = { + LM87_IN_LIMITS(0, 0x83, 0x91), /* 2.5V: 1.8V +/- 5% */ + LM87_IN_LIMITS(1, 0x51, 0x5a), /* Vccp1: 1.2V +/- 5% */ + LM87_IN_LIMITS(2, 0xb6, 0xca), /* 3.3V: 3.3V +/- 5% */ + LM87_IN_LIMITS(3, 0xb0, 0xc9), /* 5V: 4.6-5.2V */ + LM87_IN_LIMITS(4, 0xb0, 0xe0), /* 12V: 11-14V */ + LM87_IN_LIMITS(5, 0x44, 0x4b), /* Vccp2: 1.0V +/- 5% */ + LM87_AIN_LIMITS(0, 0xa0, 0xb2), /* AIN1: 1.66V +/- 5% */ + LM87_AIN_LIMITS(1, 0x91, 0xa1), /* AIN2: 1.5V +/- 5% */ + LM87_TEMP_INT_LIMITS(10, 60), /* board */ + LM87_TEMP_EXT1_LIMITS(10, 70), /* Falcon */ + 0 +}; + +static struct i2c_board_info sfe4002_hwmon_info = { + I2C_BOARD_INFO("lm87", 0x2e), + .platform_data = &sfe4002_lm87_channel, + .irq = -1, +}; + /****************************************************************************/ /* LED allocations. Note that on rev A0 boards the schematic and the reality * differ: red and green are swapped. Below is the fixed (A1) layout (there @@ -84,81 +204,67 @@ static void sfe4002_fault_led(struct efx_nic *efx, bool state) QUAKE_LED_OFF); } +static int sfe4002_check_hw(struct efx_nic *efx) +{ + /* A0 board rev. 4002s report a temperature fault the whole time + * (bad sensor) so we mask it out. */ + unsigned alarm_mask = + (efx->board_info.major == 0 && efx->board_info.minor == 0) ? + ~LM87_ALARM_TEMP_EXT1 : ~0; + + return efx_check_lm87(efx, alarm_mask); +} + static int sfe4002_init(struct efx_nic *efx) { + int rc = efx_init_lm87(efx, &sfe4002_hwmon_info, sfe4002_lm87_regs); + if (rc) + return rc; + efx->board_info.monitor = sfe4002_check_hw; efx->board_info.init_leds = sfe4002_init_leds; efx->board_info.set_fault_led = sfe4002_fault_led; efx->board_info.blink = board_blink; + efx->board_info.fini = efx_fini_lm87; return 0; } /* This will get expanded as board-specific details get moved out of the * PHY drivers. */ struct efx_board_data { + enum efx_board_type type; const char *ref_model; const char *gen_type; int (*init) (struct efx_nic *nic); }; -static int dummy_init(struct efx_nic *nic) -{ - return 0; -} static struct efx_board_data board_data[] = { - [EFX_BOARD_INVALID] = - {NULL, NULL, dummy_init}, - [EFX_BOARD_SFE4001] = - {"SFE4001", "10GBASE-T adapter", sfe4001_init}, - [EFX_BOARD_SFE4002] = - {"SFE4002", "XFP adapter", sfe4002_init}, + { EFX_BOARD_SFE4001, "SFE4001", "10GBASE-T adapter", sfe4001_init }, + { EFX_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init }, + { EFX_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter", + sfn4111t_init }, }; -int efx_set_board_info(struct efx_nic *efx, u16 revision_info) +void efx_set_board_info(struct efx_nic *efx, u16 revision_info) { - int rc = 0; - struct efx_board_data *data; - - if (BOARD_TYPE(revision_info) >= EFX_BOARD_MAX) { - EFX_ERR(efx, "squashing unknown board type %d\n", - BOARD_TYPE(revision_info)); - revision_info = 0; - } + struct efx_board_data *data = NULL; + int i; - if (BOARD_TYPE(revision_info) == 0) { - efx->board_info.major = 0; - efx->board_info.minor = 0; - /* For early boards that don't have revision info. there is - * only 1 board for each PHY type, so we can work it out, with - * the exception of the PHY-less boards. */ - switch (efx->phy_type) { - case PHY_TYPE_10XPRESS: - efx->board_info.type = EFX_BOARD_SFE4001; - break; - case PHY_TYPE_XFP: - efx->board_info.type = EFX_BOARD_SFE4002; - break; - default: - efx->board_info.type = 0; - break; - } - } else { - efx->board_info.type = BOARD_TYPE(revision_info); - efx->board_info.major = BOARD_MAJOR(revision_info); - efx->board_info.minor = BOARD_MINOR(revision_info); - } + efx->board_info.type = BOARD_TYPE(revision_info); + efx->board_info.major = BOARD_MAJOR(revision_info); + efx->board_info.minor = BOARD_MINOR(revision_info); - data = &board_data[efx->board_info.type]; + for (i = 0; i < ARRAY_SIZE(board_data); i++) + if (board_data[i].type == efx->board_info.type) + data = &board_data[i]; - /* Report the board model number or generic type for recognisable - * boards. */ - if (efx->board_info.type != 0) + if (data) { EFX_INFO(efx, "board is %s rev %c%d\n", (efx->pci_dev->subsystem_vendor == EFX_VENDID_SFC) ? data->ref_model : data->gen_type, 'A' + efx->board_info.major, efx->board_info.minor); - - efx->board_info.init = data->init; - - return rc; + efx->board_info.init = data->init; + } else { + EFX_ERR(efx, "unknown board type %d\n", efx->board_info.type); + } } diff --git a/drivers/net/sfc/boards.h b/drivers/net/sfc/boards.h index c6e01b64bfb471ff57ce99cc33c0ef3622771d7f..d93c6c6a754864bfef4b80326b6086a8947fe350 100644 --- a/drivers/net/sfc/boards.h +++ b/drivers/net/sfc/boards.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007 Solarflare Communications Inc. + * Copyright 2007-2008 Solarflare Communications 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 @@ -12,14 +12,16 @@ /* Board IDs (must fit in 8 bits) */ enum efx_board_type { - EFX_BOARD_INVALID = 0, - EFX_BOARD_SFE4001 = 1, /* SFE4001 (10GBASE-T) */ + EFX_BOARD_SFE4001 = 1, EFX_BOARD_SFE4002 = 2, - /* Insert new types before here */ - EFX_BOARD_MAX + EFX_BOARD_SFN4111T = 0x51, }; -extern int efx_set_board_info(struct efx_nic *efx, u16 revision_info); +extern void efx_set_board_info(struct efx_nic *efx, u16 revision_info); + +/* SFE4001 (10GBASE-T) */ extern int sfe4001_init(struct efx_nic *efx); +/* SFN4111T (100/1000/10GBASE-T) */ +extern int sfn4111t_init(struct efx_nic *efx); #endif diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c index 06ea71c7e34ecb58bd117781eab7c09360381294..7673fd92eaf5f15f413ecd50d56f914d5de078c7 100644 --- a/drivers/net/sfc/efx.c +++ b/drivers/net/sfc/efx.c @@ -21,14 +21,12 @@ #include #include #include "net_driver.h" -#include "gmii.h" #include "ethtool.h" #include "tx.h" #include "rx.h" #include "efx.h" #include "mdio_10g.h" #include "falcon.h" -#include "mac.h" #define EFX_MAX_MTU (9 * 1024) @@ -39,6 +37,12 @@ */ static struct workqueue_struct *refill_workqueue; +/* Reset workqueue. If any NIC has a hardware failure then a reset will be + * queued onto this work queue. This is not a per-nic work queue, because + * efx_reset_work() acquires the rtnl lock, so resets are naturally serialised. + */ +static struct workqueue_struct *reset_workqueue; + /************************************************************************** * * Configurable values @@ -58,13 +62,15 @@ MODULE_PARM_DESC(lro, "Large receive offload acceleration"); /* * Use separate channels for TX and RX events * - * Set this to 1 to use separate channels for TX and RX. It allows us to - * apply a higher level of interrupt moderation to TX events. + * Set this to 1 to use separate channels for TX and RX. It allows us + * to control interrupt affinity separately for TX and RX. * - * This is forced to 0 for MSI interrupt mode as the interrupt vector - * is not written + * This is only used in MSI-X interrupt mode */ -static unsigned int separate_tx_and_rx_channels = true; +static unsigned int separate_tx_channels; +module_param(separate_tx_channels, uint, 0644); +MODULE_PARM_DESC(separate_tx_channels, + "Use separate channels for TX and RX"); /* This is the weight assigned to each of the (per-channel) virtual * NAPI devices. @@ -77,11 +83,6 @@ static int napi_weight = 64; */ unsigned int efx_monitor_interval = 1 * HZ; -/* This controls whether or not the hardware monitor will trigger a - * reset when it detects an error condition. - */ -static unsigned int monitor_reset = true; - /* This controls whether or not the driver will initialise devices * with invalid MAC addresses stored in the EEPROM or flash. If true, * such devices will be initialised with a random locally-generated @@ -128,6 +129,10 @@ static unsigned int rss_cpus; module_param(rss_cpus, uint, 0444); MODULE_PARM_DESC(rss_cpus, "Number of CPUs to use for Receive-Side Scaling"); +static int phy_flash_cfg; +module_param(phy_flash_cfg, int, 0644); +MODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially"); + /************************************************************************** * * Utility functions and prototypes @@ -211,7 +216,6 @@ static int efx_poll(struct napi_struct *napi, int budget) { struct efx_channel *channel = container_of(napi, struct efx_channel, napi_str); - struct net_device *napi_dev = channel->napi_dev; int rx_packets; EFX_TRACE(channel->efx, "channel %d NAPI poll executing on CPU %d\n", @@ -225,7 +229,7 @@ static int efx_poll(struct napi_struct *napi, int budget) * since efx_channel_processed() will have no effect if * interrupts have already been disabled. */ - netif_rx_complete(napi_dev, napi); + netif_rx_complete(napi); efx_channel_processed(channel); } @@ -349,6 +353,27 @@ static int efx_probe_channel(struct efx_channel *channel) } +static void efx_set_channel_names(struct efx_nic *efx) +{ + struct efx_channel *channel; + const char *type = ""; + int number; + + efx_for_each_channel(channel, efx) { + number = channel->channel; + if (efx->n_channels > efx->n_rx_queues) { + if (channel->channel < efx->n_rx_queues) { + type = "-rx"; + } else { + type = "-tx"; + number -= efx->n_rx_queues; + } + } + snprintf(channel->name, sizeof(channel->name), + "%s%s-%d", efx->name, type, number); + } +} + /* Channels are shutdown and reinitialised whilst the NIC is running * to propagate configuration changes (mtu, checksum offload), or * to clear hardware error conditions @@ -523,26 +548,8 @@ static void efx_link_status_changed(struct efx_nic *efx) /* Status message for kernel log */ if (efx->link_up) { - struct mii_if_info *gmii = &efx->mii; - unsigned adv, lpa; - /* NONE here means direct XAUI from the controller, with no - * MDIO-attached device we can query. */ - if (efx->phy_type != PHY_TYPE_NONE) { - adv = gmii_advertised(gmii); - lpa = gmii_lpa(gmii); - } else { - lpa = GM_LPA_10000 | LPA_DUPLEX; - adv = lpa; - } - EFX_INFO(efx, "link up at %dMbps %s-duplex " - "(adv %04x lpa %04x) (MTU %d)%s\n", - (efx->link_options & GM_LPA_10000 ? 10000 : - (efx->link_options & GM_LPA_1000 ? 1000 : - (efx->link_options & GM_LPA_100 ? 100 : - 10))), - (efx->link_options & GM_LPA_DUPLEX ? - "full" : "half"), - adv, lpa, + EFX_INFO(efx, "link up at %uMbps %s-duplex (MTU %d)%s\n", + efx->link_speed, efx->link_fd ? "full" : "half", efx->net_dev->mtu, (efx->promiscuous ? " [PROMISC]" : "")); } else { @@ -566,10 +573,28 @@ void __efx_reconfigure_port(struct efx_nic *efx) netif_addr_unlock_bh(efx->net_dev); } - falcon_reconfigure_xmac(efx); + falcon_deconfigure_mac_wrapper(efx); + + /* Reconfigure the PHY, disabling transmit in mac level loopback. */ + if (LOOPBACK_INTERNAL(efx)) + efx->phy_mode |= PHY_MODE_TX_DISABLED; + else + efx->phy_mode &= ~PHY_MODE_TX_DISABLED; + efx->phy_op->reconfigure(efx); + + if (falcon_switch_mac(efx)) + goto fail; + + efx->mac_op->reconfigure(efx); /* Inform kernel of loss/gain of carrier */ efx_link_status_changed(efx); + return; + +fail: + EFX_ERR(efx, "failed to reconfigure MAC\n"); + efx->phy_op->fini(efx); + efx->port_initialized = false; } /* Reinitialise the MAC to pick up new PHY settings, even if the port is @@ -586,10 +611,9 @@ void efx_reconfigure_port(struct efx_nic *efx) /* Asynchronous efx_reconfigure_port work item. To speed up efx_flush_all() * we don't efx_reconfigure_port() if the port is disabled. Care is taken * in efx_stop_all() and efx_start_port() to prevent PHY events being lost */ -static void efx_reconfigure_work(struct work_struct *data) +static void efx_phy_work(struct work_struct *data) { - struct efx_nic *efx = container_of(data, struct efx_nic, - reconfigure_work); + struct efx_nic *efx = container_of(data, struct efx_nic, phy_work); mutex_lock(&efx->mac_lock); if (efx->port_enabled) @@ -597,6 +621,16 @@ static void efx_reconfigure_work(struct work_struct *data) mutex_unlock(&efx->mac_lock); } +static void efx_mac_work(struct work_struct *data) +{ + struct efx_nic *efx = container_of(data, struct efx_nic, mac_work); + + mutex_lock(&efx->mac_lock); + if (efx->port_enabled) + efx->mac_op->irq(efx); + mutex_unlock(&efx->mac_lock); +} + static int efx_probe_port(struct efx_nic *efx) { int rc; @@ -608,21 +642,22 @@ static int efx_probe_port(struct efx_nic *efx) if (rc) goto err; + if (phy_flash_cfg) + efx->phy_mode = PHY_MODE_SPECIAL; + /* Sanity check MAC address */ if (is_valid_ether_addr(efx->mac_address)) { memcpy(efx->net_dev->dev_addr, efx->mac_address, ETH_ALEN); } else { - DECLARE_MAC_BUF(mac); - - EFX_ERR(efx, "invalid MAC address %s\n", - print_mac(mac, efx->mac_address)); + EFX_ERR(efx, "invalid MAC address %pM\n", + efx->mac_address); if (!allow_bad_hwaddr) { rc = -EINVAL; goto err; } random_ether_addr(efx->net_dev->dev_addr); - EFX_INFO(efx, "using locally-generated MAC %s\n", - print_mac(mac, efx->net_dev->dev_addr)); + EFX_INFO(efx, "using locally-generated MAC %pM\n", + efx->net_dev->dev_addr); } return 0; @@ -638,23 +673,30 @@ static int efx_init_port(struct efx_nic *efx) EFX_LOG(efx, "init port\n"); - /* Initialise the MAC and PHY */ - rc = falcon_init_xmac(efx); + rc = efx->phy_op->init(efx); if (rc) return rc; + efx->phy_op->reconfigure(efx); + + mutex_lock(&efx->mac_lock); + rc = falcon_switch_mac(efx); + mutex_unlock(&efx->mac_lock); + if (rc) + goto fail; + efx->mac_op->reconfigure(efx); efx->port_initialized = true; efx->stats_enabled = true; - - /* Reconfigure port to program MAC registers */ - falcon_reconfigure_xmac(efx); - return 0; + +fail: + efx->phy_op->fini(efx); + return rc; } /* Allow efx_reconfigure_port() to be scheduled, and close the window * between efx_stop_port and efx_flush_all whereby a previously scheduled - * efx_reconfigure_port() may have been cancelled */ + * efx_phy_work()/efx_mac_work() may have been cancelled */ static void efx_start_port(struct efx_nic *efx) { EFX_LOG(efx, "start port\n"); @@ -663,13 +705,14 @@ static void efx_start_port(struct efx_nic *efx) mutex_lock(&efx->mac_lock); efx->port_enabled = true; __efx_reconfigure_port(efx); + efx->mac_op->irq(efx); mutex_unlock(&efx->mac_lock); } -/* Prevent efx_reconfigure_work and efx_monitor() from executing, and - * efx_set_multicast_list() from scheduling efx_reconfigure_work. - * efx_reconfigure_work can still be scheduled via NAPI processing - * until efx_flush_all() is called */ +/* Prevent efx_phy_work, efx_mac_work, and efx_monitor() from executing, + * and efx_set_multicast_list() from scheduling efx_phy_work. efx_phy_work + * and efx_mac_work may still be scheduled via NAPI processing until + * efx_flush_all() is called */ static void efx_stop_port(struct efx_nic *efx) { EFX_LOG(efx, "stop port\n"); @@ -692,7 +735,7 @@ static void efx_fini_port(struct efx_nic *efx) if (!efx->port_initialized) return; - falcon_fini_xmac(efx); + efx->phy_op->fini(efx); efx->port_initialized = false; efx->link_up = false; @@ -840,26 +883,33 @@ static void efx_probe_interrupts(struct efx_nic *efx) if (efx->interrupt_mode == EFX_INT_MODE_MSIX) { struct msix_entry xentries[EFX_MAX_CHANNELS]; int wanted_ints; + int rx_queues; /* We want one RX queue and interrupt per CPU package * (or as specified by the rss_cpus module parameter). * We will need one channel per interrupt. */ - wanted_ints = rss_cpus ? rss_cpus : efx_wanted_rx_queues(); - efx->n_rx_queues = min(wanted_ints, max_channels); + rx_queues = rss_cpus ? rss_cpus : efx_wanted_rx_queues(); + wanted_ints = rx_queues + (separate_tx_channels ? 1 : 0); + wanted_ints = min(wanted_ints, max_channels); - for (i = 0; i < efx->n_rx_queues; i++) + for (i = 0; i < wanted_ints; i++) xentries[i].entry = i; - rc = pci_enable_msix(efx->pci_dev, xentries, efx->n_rx_queues); + rc = pci_enable_msix(efx->pci_dev, xentries, wanted_ints); if (rc > 0) { - EFX_BUG_ON_PARANOID(rc >= efx->n_rx_queues); - efx->n_rx_queues = rc; + EFX_ERR(efx, "WARNING: Insufficient MSI-X vectors" + " available (%d < %d).\n", rc, wanted_ints); + EFX_ERR(efx, "WARNING: Performance may be reduced.\n"); + EFX_BUG_ON_PARANOID(rc >= wanted_ints); + wanted_ints = rc; rc = pci_enable_msix(efx->pci_dev, xentries, - efx->n_rx_queues); + wanted_ints); } if (rc == 0) { - for (i = 0; i < efx->n_rx_queues; i++) + efx->n_rx_queues = min(rx_queues, wanted_ints); + efx->n_channels = wanted_ints; + for (i = 0; i < wanted_ints; i++) efx->channel[i].irq = xentries[i].vector; } else { /* Fall back to single channel MSI */ @@ -871,6 +921,7 @@ static void efx_probe_interrupts(struct efx_nic *efx) /* Try single interrupt MSI */ if (efx->interrupt_mode == EFX_INT_MODE_MSI) { efx->n_rx_queues = 1; + efx->n_channels = 1; rc = pci_enable_msi(efx->pci_dev); if (rc == 0) { efx->channel[0].irq = efx->pci_dev->irq; @@ -883,6 +934,7 @@ static void efx_probe_interrupts(struct efx_nic *efx) /* Assume legacy interrupts */ if (efx->interrupt_mode == EFX_INT_MODE_LEGACY) { efx->n_rx_queues = 1; + efx->n_channels = 1 + (separate_tx_channels ? 1 : 0); efx->legacy_irq = efx->pci_dev->irq; } } @@ -907,8 +959,8 @@ static void efx_set_channels(struct efx_nic *efx) struct efx_rx_queue *rx_queue; efx_for_each_tx_queue(tx_queue, efx) { - if (!EFX_INT_MODE_USE_MSI(efx) && separate_tx_and_rx_channels) - tx_queue->channel = &efx->channel[1]; + if (separate_tx_channels) + tx_queue->channel = &efx->channel[efx->n_channels-1]; else tx_queue->channel = &efx->channel[0]; tx_queue->channel->used_flags |= EFX_USED_BY_TX; @@ -985,6 +1037,7 @@ static int efx_probe_all(struct efx_nic *efx) goto fail3; } } + efx_set_channel_names(efx); return 0; @@ -1050,7 +1103,8 @@ static void efx_flush_all(struct efx_nic *efx) cancel_delayed_work_sync(&rx_queue->work); /* Stop scheduled port reconfigurations */ - cancel_work_sync(&efx->reconfigure_work); + cancel_work_sync(&efx->mac_work); + cancel_work_sync(&efx->phy_work); } @@ -1087,7 +1141,7 @@ static void efx_stop_all(struct efx_nic *efx) * window to loose phy events */ efx_stop_port(efx); - /* Flush reconfigure_work, refill_workqueue, monitor_work */ + /* Flush efx_phy_work, efx_mac_work, refill_workqueue, monitor_work */ efx_flush_all(efx); /* Isolate the MAC from the TX and RX engines, so that queue @@ -1159,36 +1213,31 @@ static void efx_monitor(struct work_struct *data) { struct efx_nic *efx = container_of(data, struct efx_nic, monitor_work.work); - int rc = 0; + int rc; EFX_TRACE(efx, "hardware monitor executing on CPU %d\n", raw_smp_processor_id()); - /* If the mac_lock is already held then it is likely a port * reconfiguration is already in place, which will likely do * most of the work of check_hw() anyway. */ - if (!mutex_trylock(&efx->mac_lock)) { - queue_delayed_work(efx->workqueue, &efx->monitor_work, - efx_monitor_interval); - return; - } - - if (efx->port_enabled) - rc = falcon_check_xmac(efx); - mutex_unlock(&efx->mac_lock); - + if (!mutex_trylock(&efx->mac_lock)) + goto out_requeue; + if (!efx->port_enabled) + goto out_unlock; + rc = efx->board_info.monitor(efx); if (rc) { - if (monitor_reset) { - EFX_ERR(efx, "hardware monitor detected a fault: " - "triggering reset\n"); - efx_schedule_reset(efx, RESET_TYPE_MONITOR); - } else { - EFX_ERR(efx, "hardware monitor detected a fault, " - "skipping reset\n"); - } + EFX_ERR(efx, "Board sensor %s; shutting down PHY\n", + (rc == -ERANGE) ? "reported fault" : "failed"); + efx->phy_mode |= PHY_MODE_LOW_POWER; + falcon_sim_phy_event(efx); } + efx->phy_op->poll(efx); + efx->mac_op->poll(efx); +out_unlock: + mutex_unlock(&efx->mac_lock); +out_requeue: queue_delayed_work(efx->workqueue, &efx->monitor_work, efx_monitor_interval); } @@ -1282,6 +1331,8 @@ static int efx_net_open(struct net_device *net_dev) EFX_LOG(efx, "opening device %s on CPU %d\n", net_dev->name, raw_smp_processor_id()); + if (efx->state == STATE_DISABLED) + return -EIO; if (efx->phy_mode & PHY_MODE_SPECIAL) return -EBUSY; @@ -1300,10 +1351,12 @@ static int efx_net_stop(struct net_device *net_dev) EFX_LOG(efx, "closing %s on CPU %d\n", net_dev->name, raw_smp_processor_id()); - /* Stop the device and flush all the channels */ - efx_stop_all(efx); - efx_fini_channels(efx); - efx_init_channels(efx); + if (efx->state != STATE_DISABLED) { + /* Stop the device and flush all the channels */ + efx_stop_all(efx); + efx_fini_channels(efx); + efx_init_channels(efx); + } return 0; } @@ -1322,7 +1375,7 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev) if (!spin_trylock(&efx->stats_lock)) return stats; if (efx->stats_enabled) { - falcon_update_stats_xmac(efx); + efx->mac_op->update_stats(efx); falcon_update_nic_stats(efx); } spin_unlock(&efx->stats_lock); @@ -1360,12 +1413,11 @@ static void efx_watchdog(struct net_device *net_dev) { struct efx_nic *efx = netdev_priv(net_dev); - EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d: %s\n", - atomic_read(&efx->netif_stop_count), efx->port_enabled, - monitor_reset ? "resetting channels" : "skipping reset"); + EFX_ERR(efx, "TX stuck with stop_count=%d port_enabled=%d:" + " resetting channels\n", + atomic_read(&efx->netif_stop_count), efx->port_enabled); - if (monitor_reset) - efx_schedule_reset(efx, RESET_TYPE_MONITOR); + efx_schedule_reset(efx, RESET_TYPE_TX_WATCHDOG); } @@ -1401,9 +1453,8 @@ static int efx_set_mac_address(struct net_device *net_dev, void *data) EFX_ASSERT_RESET_SERIALISED(efx); if (!is_valid_ether_addr(new_addr)) { - DECLARE_MAC_BUF(mac); - EFX_ERR(efx, "invalid ethernet MAC address requested: %s\n", - print_mac(mac, new_addr)); + EFX_ERR(efx, "invalid ethernet MAC address requested: %pM\n", + new_addr); return -EINVAL; } @@ -1447,22 +1498,43 @@ static void efx_set_multicast_list(struct net_device *net_dev) return; if (changed) - queue_work(efx->workqueue, &efx->reconfigure_work); + queue_work(efx->workqueue, &efx->phy_work); /* Create and activate new global multicast hash table */ falcon_set_multicast_hash(efx); } +static const struct net_device_ops efx_netdev_ops = { + .ndo_open = efx_net_open, + .ndo_stop = efx_net_stop, + .ndo_get_stats = efx_net_stats, + .ndo_tx_timeout = efx_watchdog, + .ndo_start_xmit = efx_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = efx_ioctl, + .ndo_change_mtu = efx_change_mtu, + .ndo_set_mac_address = efx_set_mac_address, + .ndo_set_multicast_list = efx_set_multicast_list, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = efx_netpoll, +#endif +}; + +static void efx_update_name(struct efx_nic *efx) +{ + strcpy(efx->name, efx->net_dev->name); + efx_mtd_rename(efx); + efx_set_channel_names(efx); +} + static int efx_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *net_dev = ptr; - if (net_dev->open == efx_net_open && event == NETDEV_CHANGENAME) { - struct efx_nic *efx = netdev_priv(net_dev); - - strcpy(efx->name, net_dev->name); - } + if (net_dev->netdev_ops == &efx_netdev_ops && + event == NETDEV_CHANGENAME) + efx_update_name(netdev_priv(net_dev)); return NOTIFY_DONE; } @@ -1471,6 +1543,14 @@ static struct notifier_block efx_netdev_notifier = { .notifier_call = efx_netdev_event, }; +static ssize_t +show_phy_type(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + return sprintf(buf, "%d\n", efx->phy_type); +} +static DEVICE_ATTR(phy_type, 0644, show_phy_type, NULL); + static int efx_register_netdev(struct efx_nic *efx) { struct net_device *net_dev = efx->net_dev; @@ -1478,18 +1558,7 @@ static int efx_register_netdev(struct efx_nic *efx) net_dev->watchdog_timeo = 5 * HZ; net_dev->irq = efx->pci_dev->irq; - net_dev->open = efx_net_open; - net_dev->stop = efx_net_stop; - net_dev->get_stats = efx_net_stats; - net_dev->tx_timeout = &efx_watchdog; - net_dev->hard_start_xmit = efx_hard_start_xmit; - net_dev->do_ioctl = efx_ioctl; - net_dev->change_mtu = efx_change_mtu; - net_dev->set_mac_address = efx_set_mac_address; - net_dev->set_multicast_list = efx_set_multicast_list; -#ifdef CONFIG_NET_POLL_CONTROLLER - net_dev->poll_controller = efx_netpoll; -#endif + net_dev->netdev_ops = &efx_netdev_ops; SET_NETDEV_DEV(net_dev, &efx->pci_dev->dev); SET_ETHTOOL_OPS(net_dev, &efx_ethtool_ops); @@ -1497,7 +1566,7 @@ static int efx_register_netdev(struct efx_nic *efx) netif_carrier_off(efx->net_dev); /* Clear MAC statistics */ - falcon_update_stats_xmac(efx); + efx->mac_op->update_stats(efx); memset(&efx->mac_stats, 0, sizeof(efx->mac_stats)); rc = register_netdev(net_dev); @@ -1505,9 +1574,22 @@ static int efx_register_netdev(struct efx_nic *efx) EFX_ERR(efx, "could not register net dev\n"); return rc; } - strcpy(efx->name, net_dev->name); + + rtnl_lock(); + efx_update_name(efx); + rtnl_unlock(); + + rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_type); + if (rc) { + EFX_ERR(efx, "failed to init net dev attributes\n"); + goto fail_registered; + } return 0; + +fail_registered: + unregister_netdev(net_dev); + return rc; } static void efx_unregister_netdev(struct efx_nic *efx) @@ -1527,6 +1609,7 @@ static void efx_unregister_netdev(struct efx_nic *efx) if (efx_dev_registered(efx)) { strlcpy(efx->name, pci_name(efx->pci_dev), sizeof(efx->name)); + device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_type); unregister_netdev(efx->net_dev); } } @@ -1541,8 +1624,6 @@ static void efx_unregister_netdev(struct efx_nic *efx) * before reset. */ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int rc; - EFX_ASSERT_RESET_SERIALISED(efx); /* The net_dev->get_stats handler is quite slow, and will fail @@ -1553,10 +1634,9 @@ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd) efx_stop_all(efx); mutex_lock(&efx->mac_lock); + mutex_lock(&efx->spi_lock); - rc = falcon_xmac_get_settings(efx, ecmd); - if (rc) - EFX_ERR(efx, "could not back up PHY settings\n"); + efx->phy_op->get_settings(efx, ecmd); efx_fini_channels(efx); } @@ -1581,10 +1661,11 @@ int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok) if (ok) { efx_init_channels(efx); - if (falcon_xmac_set_settings(efx, ecmd)) + if (efx->phy_op->set_settings(efx, ecmd)) EFX_ERR(efx, "could not restore PHY settings\n"); } + mutex_unlock(&efx->spi_lock); mutex_unlock(&efx->mac_lock); if (ok) { @@ -1607,7 +1688,7 @@ static int efx_reset(struct efx_nic *efx) { struct ethtool_cmd ecmd; enum reset_type method = efx->reset_pending; - int rc; + int rc = 0; /* Serialise with kernel interfaces */ rtnl_lock(); @@ -1616,7 +1697,7 @@ static int efx_reset(struct efx_nic *efx) * flag set so that efx_pci_probe_main will be retried */ if (efx->state != STATE_RUNNING) { EFX_INFO(efx, "scheduled reset quenched. NIC not RUNNING\n"); - goto unlock_rtnl; + goto out_unlock; } EFX_INFO(efx, "resetting (%d)\n", method); @@ -1626,7 +1707,7 @@ static int efx_reset(struct efx_nic *efx) rc = falcon_reset_hw(efx, method); if (rc) { EFX_ERR(efx, "failed to reset hardware\n"); - goto fail; + goto out_disable; } /* Allow resets to be rescheduled. */ @@ -1640,28 +1721,23 @@ static int efx_reset(struct efx_nic *efx) /* Leave device stopped if necessary */ if (method == RESET_TYPE_DISABLE) { + efx_reset_up(efx, &ecmd, false); rc = -EIO; - goto fail; + } else { + rc = efx_reset_up(efx, &ecmd, true); } - rc = efx_reset_up(efx, &ecmd, true); - if (rc) - goto disable; - - EFX_LOG(efx, "reset complete\n"); - unlock_rtnl: - rtnl_unlock(); - return 0; - - fail: - efx_reset_up(efx, &ecmd, false); - disable: - EFX_ERR(efx, "has been disabled\n"); - efx->state = STATE_DISABLED; +out_disable: + if (rc) { + EFX_ERR(efx, "has been disabled\n"); + efx->state = STATE_DISABLED; + dev_close(efx->net_dev); + } else { + EFX_LOG(efx, "reset complete\n"); + } +out_unlock: rtnl_unlock(); - efx_unregister_netdev(efx); - efx_fini_port(efx); return rc; } @@ -1709,7 +1785,7 @@ void efx_schedule_reset(struct efx_nic *efx, enum reset_type type) efx->reset_pending = method; - queue_work(efx->reset_workqueue, &efx->reset_work); + queue_work(reset_workqueue, &efx->reset_work); } /************************************************************************** @@ -1743,10 +1819,16 @@ int efx_port_dummy_op_int(struct efx_nic *efx) void efx_port_dummy_op_void(struct efx_nic *efx) {} void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {} +static struct efx_mac_operations efx_dummy_mac_operations = { + .reconfigure = efx_port_dummy_op_void, + .poll = efx_port_dummy_op_void, + .irq = efx_port_dummy_op_void, +}; + static struct efx_phy_operations efx_dummy_phy_operations = { .init = efx_port_dummy_op_int, .reconfigure = efx_port_dummy_op_void, - .check_hw = efx_port_dummy_op_int, + .poll = efx_port_dummy_op_void, .fini = efx_port_dummy_op_void, .clear_interrupt = efx_port_dummy_op_void, }; @@ -1755,6 +1837,7 @@ static struct efx_board efx_dummy_board_info = { .init = efx_port_dummy_op_int, .init_leds = efx_port_dummy_op_int, .set_fault_led = efx_port_dummy_op_blink, + .monitor = efx_port_dummy_op_int, .blink = efx_port_dummy_op_blink, .fini = efx_port_dummy_op_void, }; @@ -1774,12 +1857,13 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, struct efx_channel *channel; struct efx_tx_queue *tx_queue; struct efx_rx_queue *rx_queue; - int i, rc; + int i; /* Initialise common structures */ memset(efx, 0, sizeof(*efx)); spin_lock_init(&efx->biu_lock); spin_lock_init(&efx->phy_lock); + mutex_init(&efx->spi_lock); INIT_WORK(&efx->reset_work, efx_reset_work); INIT_DELAYED_WORK(&efx->monitor_work, efx_monitor); efx->pci_dev = pci_dev; @@ -1793,9 +1877,11 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, spin_lock_init(&efx->netif_stop_lock); spin_lock_init(&efx->stats_lock); mutex_init(&efx->mac_lock); + efx->mac_op = &efx_dummy_mac_operations; efx->phy_op = &efx_dummy_phy_operations; efx->mii.dev = net_dev; - INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work); + INIT_WORK(&efx->phy_work, efx_phy_work); + INIT_WORK(&efx->mac_work, efx_mac_work); atomic_set(&efx->netif_stop_count, 1); for (i = 0; i < EFX_MAX_CHANNELS; i++) { @@ -1841,34 +1927,18 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type, efx->interrupt_mode = max(efx->type->max_interrupt_mode, interrupt_mode); - efx->workqueue = create_singlethread_workqueue("sfc_work"); - if (!efx->workqueue) { - rc = -ENOMEM; - goto fail1; - } - - efx->reset_workqueue = create_singlethread_workqueue("sfc_reset"); - if (!efx->reset_workqueue) { - rc = -ENOMEM; - goto fail2; - } + /* Would be good to use the net_dev name, but we're too early */ + snprintf(efx->workqueue_name, sizeof(efx->workqueue_name), "sfc%s", + pci_name(pci_dev)); + efx->workqueue = create_singlethread_workqueue(efx->workqueue_name); + if (!efx->workqueue) + return -ENOMEM; return 0; - - fail2: - destroy_workqueue(efx->workqueue); - efx->workqueue = NULL; - - fail1: - return rc; } static void efx_fini_struct(struct efx_nic *efx) { - if (efx->reset_workqueue) { - destroy_workqueue(efx->reset_workqueue); - efx->reset_workqueue = NULL; - } if (efx->workqueue) { destroy_workqueue(efx->workqueue); efx->workqueue = NULL; @@ -1927,11 +1997,13 @@ static void efx_pci_remove(struct pci_dev *pci_dev) efx_unregister_netdev(efx); + efx_mtd_remove(efx); + /* Wait for any scheduled resets to complete. No more will be * scheduled from this point because efx_stop_all() has been * called, we are no longer registered with driverlink, and * the net_device's have been removed. */ - flush_workqueue(efx->reset_workqueue); + cancel_work_sync(&efx->reset_work); efx_pci_remove_main(efx); @@ -1992,6 +2064,7 @@ static int efx_pci_probe_main(struct efx_nic *efx) efx_fini_port(efx); fail5: fail4: + efx->board_info.fini(efx); fail3: efx_fini_napi(efx); fail2: @@ -2045,14 +2118,23 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, * we're in STATE_INIT. */ for (i = 0; i < 5; i++) { rc = efx_pci_probe_main(efx); - if (rc == 0) - break; /* Serialise against efx_reset(). No more resets will be * scheduled since efx_stop_all() has been called, and we * have not and never have been registered with either * the rtnetlink or driverlink layers. */ - flush_workqueue(efx->reset_workqueue); + cancel_work_sync(&efx->reset_work); + + if (rc == 0) { + if (efx->reset_pending != RESET_TYPE_NONE) { + /* If there was a scheduled reset during + * probe, the NIC is probably hosed anyway */ + efx_pci_remove_main(efx); + rc = -EIO; + } else { + break; + } + } /* Retry if a recoverably reset event has been scheduled */ if ((efx->reset_pending != RESET_TYPE_INVISIBLE) && @@ -2070,16 +2152,15 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev, /* Switch to the running state before we expose the device to * the OS. This is to ensure that the initial gathering of * MAC stats succeeds. */ - rtnl_lock(); efx->state = STATE_RUNNING; - rtnl_unlock(); + + efx_mtd_probe(efx); /* allowed to fail */ rc = efx_register_netdev(efx); if (rc) goto fail5; EFX_LOG(efx, "initialisation successful\n"); - return 0; fail5: @@ -2127,6 +2208,11 @@ static int __init efx_init_module(void) rc = -ENOMEM; goto err_refill; } + reset_workqueue = create_singlethread_workqueue("sfc_reset"); + if (!reset_workqueue) { + rc = -ENOMEM; + goto err_reset; + } rc = pci_register_driver(&efx_pci_driver); if (rc < 0) @@ -2135,6 +2221,8 @@ static int __init efx_init_module(void) return 0; err_pci: + destroy_workqueue(reset_workqueue); + err_reset: destroy_workqueue(refill_workqueue); err_refill: unregister_netdevice_notifier(&efx_netdev_notifier); @@ -2147,6 +2235,7 @@ static void __exit efx_exit_module(void) printk(KERN_INFO "Solarflare NET driver unloading\n"); pci_unregister_driver(&efx_pci_driver); + destroy_workqueue(reset_workqueue); destroy_workqueue(refill_workqueue); unregister_netdevice_notifier(&efx_netdev_notifier); diff --git a/drivers/net/sfc/efx.h b/drivers/net/sfc/efx.h index d02937b70eeefc504e49e2cdff620c3fa656df58..0dd7a532c78a4b06a5c92209d763313570983556 100644 --- a/drivers/net/sfc/efx.h +++ b/drivers/net/sfc/efx.h @@ -58,6 +58,16 @@ extern int efx_port_dummy_op_int(struct efx_nic *efx); extern void efx_port_dummy_op_void(struct efx_nic *efx); extern void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink); +/* MTD */ +#ifdef CONFIG_SFC_MTD +extern int efx_mtd_probe(struct efx_nic *efx); +extern void efx_mtd_rename(struct efx_nic *efx); +extern void efx_mtd_remove(struct efx_nic *efx); +#else +static inline int efx_mtd_probe(struct efx_nic *efx) { return 0; } +static inline void efx_mtd_rename(struct efx_nic *efx) {} +static inline void efx_mtd_remove(struct efx_nic *efx) {} +#endif extern unsigned int efx_monitor_interval; @@ -67,7 +77,7 @@ static inline void efx_schedule_channel(struct efx_channel *channel) channel->channel, raw_smp_processor_id()); channel->work_pending = true; - netif_rx_schedule(channel->napi_dev, &channel->napi_str); + netif_rx_schedule(&channel->napi_str); } #endif /* EFX_EFX_H */ diff --git a/drivers/net/sfc/enum.h b/drivers/net/sfc/enum.h index cec15dbb88e474b4705d0141e6b264d2c79ec606..60cbc6e1e66b1e001b30bab735644794f3d8dce8 100644 --- a/drivers/net/sfc/enum.h +++ b/drivers/net/sfc/enum.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007 Solarflare Communications Inc. + * Copyright 2007-2008 Solarflare Communications 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 @@ -13,22 +13,24 @@ /** * enum efx_loopback_mode - loopback modes * @LOOPBACK_NONE: no loopback - * @LOOPBACK_XGMII: loopback within MAC at XGMII level - * @LOOPBACK_XGXS: loopback within MAC at XGXS level - * @LOOPBACK_XAUI: loopback within MAC at XAUI level - * @LOOPBACK_PHYXS: loopback within PHY at PHYXS level - * @LOOPBACK_PCS: loopback within PHY at PCS level - * @LOOPBACK_PMAPMD: loopback within PHY at PMAPMD level + * @LOOPBACK_GMAC: loopback within GMAC at unspecified level + * @LOOPBACK_XGMII: loopback within XMAC at XGMII level + * @LOOPBACK_XGXS: loopback within XMAC at XGXS level + * @LOOPBACK_XAUI: loopback within XMAC at XAUI level + * @LOOPBACK_GPHY: loopback within 1G PHY at unspecified level + * @LOOPBACK_PHYXS: loopback within 10G PHY at PHYXS level + * @LOOPBACK_PCS: loopback within 10G PHY at PCS level + * @LOOPBACK_PMAPMD: loopback within 10G PHY at PMAPMD level * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!) */ /* Please keep in order and up-to-date w.r.t the following two #defines */ enum efx_loopback_mode { LOOPBACK_NONE = 0, - LOOPBACK_MAC = 1, + LOOPBACK_GMAC = 1, LOOPBACK_XGMII = 2, LOOPBACK_XGXS = 3, LOOPBACK_XAUI = 4, - LOOPBACK_PHY = 5, + LOOPBACK_GPHY = 5, LOOPBACK_PHYXS = 6, LOOPBACK_PCS = 7, LOOPBACK_PMAPMD = 8, @@ -45,15 +47,19 @@ extern const char *efx_loopback_mode_names[]; LOOPBACK_MODE_NAME(efx->loopback_mode) /* These loopbacks occur within the controller */ -#define LOOPBACKS_10G_INTERNAL ((1 << LOOPBACK_XGMII)| \ - (1 << LOOPBACK_XGXS) | \ - (1 << LOOPBACK_XAUI)) +#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_GMAC) | \ + (1 << LOOPBACK_XGMII)| \ + (1 << LOOPBACK_XGXS) | \ + (1 << LOOPBACK_XAUI)) #define LOOPBACK_MASK(_efx) \ (1 << (_efx)->loopback_mode) #define LOOPBACK_INTERNAL(_efx) \ - (!!(LOOPBACKS_10G_INTERNAL & LOOPBACK_MASK(_efx))) + (!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx))) + +#define LOOPBACK_CHANGED(_from, _to, _mask) \ + (!!((LOOPBACK_MASK(_from) ^ LOOPBACK_MASK(_to)) & (_mask))) #define LOOPBACK_OUT_OF(_from, _to, _mask) \ ((LOOPBACK_MASK(_from) & (_mask)) && !(LOOPBACK_MASK(_to) & (_mask))) @@ -72,7 +78,7 @@ extern const char *efx_loopback_mode_names[]; * @RESET_TYPE_ALL: reset everything but PCI core blocks * @RESET_TYPE_WORLD: reset everything, save & restore PCI config * @RESET_TYPE_DISABLE: disable NIC - * @RESET_TYPE_MONITOR: reset due to hardware monitor + * @RESET_TYPE_TX_WATCHDOG: reset due to TX watchdog * @RESET_TYPE_INT_ERROR: reset due to internal error * @RESET_TYPE_RX_RECOVERY: reset to recover from RX datapath errors * @RESET_TYPE_RX_DESC_FETCH: pcie error during rx descriptor fetch @@ -86,7 +92,7 @@ enum reset_type { RESET_TYPE_WORLD = 2, RESET_TYPE_DISABLE = 3, RESET_TYPE_MAX_METHOD, - RESET_TYPE_MONITOR, + RESET_TYPE_TX_WATCHDOG, RESET_TYPE_INT_ERROR, RESET_TYPE_RX_RECOVERY, RESET_TYPE_RX_DESC_FETCH, diff --git a/drivers/net/sfc/ethtool.c b/drivers/net/sfc/ethtool.c index cd0d0873d9782a358e1c835c6a51967071a780d5..53d259e90187ae8017c664ef55579329a745608b 100644 --- a/drivers/net/sfc/ethtool.c +++ b/drivers/net/sfc/ethtool.c @@ -12,24 +12,24 @@ #include #include #include "net_driver.h" +#include "workarounds.h" #include "selftest.h" #include "efx.h" #include "ethtool.h" #include "falcon.h" -#include "gmii.h" #include "spi.h" -#include "mac.h" +#include "mdio_10g.h" const char *efx_loopback_mode_names[] = { [LOOPBACK_NONE] = "NONE", - [LOOPBACK_MAC] = "MAC", + [LOOPBACK_GMAC] = "GMAC", [LOOPBACK_XGMII] = "XGMII", [LOOPBACK_XGXS] = "XGXS", [LOOPBACK_XAUI] = "XAUI", - [LOOPBACK_PHY] = "PHY", - [LOOPBACK_PHYXS] = "PHY(XS)", - [LOOPBACK_PCS] = "PHY(PCS)", - [LOOPBACK_PMAPMD] = "PHY(PMAPMD)", + [LOOPBACK_GPHY] = "GPHY", + [LOOPBACK_PHYXS] = "PHYXS", + [LOOPBACK_PCS] = "PCS", + [LOOPBACK_PMAPMD] = "PMA/PMD", [LOOPBACK_NETWORK] = "NETWORK", }; @@ -172,10 +172,7 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { /* Number of ethtool statistics */ #define EFX_ETHTOOL_NUM_STATS ARRAY_SIZE(efx_ethtool_stats) -/* EEPROM range with gPXE configuration */ #define EFX_ETHTOOL_EEPROM_MAGIC 0xEFAB -#define EFX_ETHTOOL_EEPROM_MIN 0x800U -#define EFX_ETHTOOL_EEPROM_MAX 0x1800U /************************************************************************** * @@ -185,12 +182,16 @@ static struct efx_ethtool_stat efx_ethtool_stats[] = { */ /* Identify device by flashing LEDs */ -static int efx_ethtool_phys_id(struct net_device *net_dev, u32 seconds) +static int efx_ethtool_phys_id(struct net_device *net_dev, u32 count) { struct efx_nic *efx = netdev_priv(net_dev); efx->board_info.blink(efx, 1); - schedule_timeout_interruptible(seconds * HZ); + set_current_state(TASK_INTERRUPTIBLE); + if (count) + schedule_timeout(count * HZ); + else + schedule(); efx->board_info.blink(efx, 0); return 0; } @@ -200,13 +201,15 @@ int efx_ethtool_get_settings(struct net_device *net_dev, struct ethtool_cmd *ecmd) { struct efx_nic *efx = netdev_priv(net_dev); - int rc; mutex_lock(&efx->mac_lock); - rc = falcon_xmac_get_settings(efx, ecmd); + efx->phy_op->get_settings(efx, ecmd); mutex_unlock(&efx->mac_lock); - return rc; + /* Falcon GMAC does not support 1000Mbps HD */ + ecmd->supported &= ~SUPPORTED_1000baseT_Half; + + return 0; } /* This must be called with rtnl_lock held. */ @@ -216,8 +219,18 @@ int efx_ethtool_set_settings(struct net_device *net_dev, struct efx_nic *efx = netdev_priv(net_dev); int rc; + if (EFX_WORKAROUND_13963(efx) && !ecmd->autoneg) + return -EINVAL; + + /* Falcon GMAC does not support 1000Mbps HD */ + if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) { + EFX_LOG(efx, "rejecting unsupported 1000Mbps HD" + " setting\n"); + return -EINVAL; + } + mutex_lock(&efx->mac_lock); - rc = falcon_xmac_set_settings(efx, ecmd); + rc = efx->phy_op->set_settings(efx, ecmd); mutex_unlock(&efx->mac_lock); if (!rc) efx_reconfigure_port(efx); @@ -241,10 +254,10 @@ static void efx_ethtool_get_drvinfo(struct net_device *net_dev, * @strings: Ethtool strings, or %NULL * @data: Ethtool test results, or %NULL * @test: Pointer to test result (used only if data != %NULL) - * @unit_format: Unit name format (e.g. "channel\%d") - * @unit_id: Unit id (e.g. 0 for "channel0") + * @unit_format: Unit name format (e.g. "chan\%d") + * @unit_id: Unit id (e.g. 0 for "chan0") * @test_format: Test name format (e.g. "loopback.\%s.tx.sent") - * @test_id: Test id (e.g. "PHY" for "loopback.PHY.tx_sent") + * @test_id: Test id (e.g. "PHYXS" for "loopback.PHYXS.tx_sent") * * Fill in an individual self-test entry. */ @@ -261,18 +274,20 @@ static void efx_fill_test(unsigned int test_index, /* Fill string, if applicable */ if (strings) { - snprintf(unit_str.name, sizeof(unit_str.name), - unit_format, unit_id); + if (strchr(unit_format, '%')) + snprintf(unit_str.name, sizeof(unit_str.name), + unit_format, unit_id); + else + strcpy(unit_str.name, unit_format); snprintf(test_str.name, sizeof(test_str.name), test_format, test_id); snprintf(strings[test_index].name, sizeof(strings[test_index].name), - "%-9s%-17s", unit_str.name, test_str.name); + "%-6s %-24s", unit_str.name, test_str.name); } } -#define EFX_PORT_NAME "port%d", 0 -#define EFX_CHANNEL_NAME(_channel) "channel%d", _channel->channel +#define EFX_CHANNEL_NAME(_channel) "chan%d", _channel->channel #define EFX_TX_QUEUE_NAME(_tx_queue) "txq%d", _tx_queue->queue #define EFX_RX_QUEUE_NAME(_rx_queue) "rxq%d", _rx_queue->queue #define EFX_LOOPBACK_NAME(_mode, _counter) \ @@ -307,11 +322,11 @@ static int efx_fill_loopback_test(struct efx_nic *efx, } efx_fill_test(test_index++, strings, data, &lb_tests->rx_good, - EFX_PORT_NAME, + "rx", 0, EFX_LOOPBACK_NAME(mode, "rx_good")); efx_fill_test(test_index++, strings, data, &lb_tests->rx_bad, - EFX_PORT_NAME, + "rx", 0, EFX_LOOPBACK_NAME(mode, "rx_bad")); return test_index; @@ -330,7 +345,7 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, u64 *data) { struct efx_channel *channel; - unsigned int n = 0; + unsigned int n = 0, i; enum efx_loopback_mode mode; efx_fill_test(n++, strings, data, &tests->mii, @@ -358,14 +373,12 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx, efx_fill_test(n++, strings, data, &tests->registers, "core", 0, "registers", NULL); - efx_fill_test(n++, strings, data, &tests->phy, - EFX_PORT_NAME, "phy", NULL); + + for (i = 0; i < efx->phy_op->num_tests; i++) + efx_fill_test(n++, strings, data, &tests->phy[i], + "phy", 0, efx->phy_op->test_names[i], NULL); /* Loopback tests */ - efx_fill_test(n++, strings, data, &tests->loopback_speed, - EFX_PORT_NAME, "loopback.speed", NULL); - efx_fill_test(n++, strings, data, &tests->loopback_full_duplex, - EFX_PORT_NAME, "loopback.full_duplex", NULL); for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) { if (!(efx->loopback_modes & (1 << mode))) continue; @@ -429,7 +442,7 @@ static void efx_ethtool_get_stats(struct net_device *net_dev, EFX_BUG_ON_PARANOID(stats->n_stats != EFX_ETHTOOL_NUM_STATS); /* Update MAC and NIC statistics */ - net_dev->get_stats(net_dev); + dev_get_stats(net_dev); /* Fill detailed statistics buffer */ for (i = 0; i < EFX_ETHTOOL_NUM_STATS; i++) { @@ -476,7 +489,7 @@ static void efx_ethtool_self_test(struct net_device *net_dev, { struct efx_nic *efx = netdev_priv(net_dev); struct efx_self_tests efx_tests; - int offline, already_up; + int already_up; int rc; ASSERT_RTNL(); @@ -496,24 +509,15 @@ static void efx_ethtool_self_test(struct net_device *net_dev, } memset(&efx_tests, 0, sizeof(efx_tests)); - offline = (test->flags & ETH_TEST_FL_OFFLINE); - - /* Perform online self tests first */ - rc = efx_online_test(efx, &efx_tests); - if (rc) - goto out; - /* Perform offline tests only if online tests passed */ - if (offline) - rc = efx_offline_test(efx, &efx_tests, - efx->loopback_modes); + rc = efx_selftest(efx, &efx_tests, test->flags); - out: if (!already_up) dev_close(efx->net_dev); - EFX_LOG(efx, "%s all %sline self-tests\n", - rc == 0 ? "passed" : "failed", offline ? "off" : "on"); + EFX_LOG(efx, "%s %sline self-tests\n", + rc == 0 ? "passed" : "failed", + (test->flags & ETH_TEST_FL_OFFLINE) ? "off" : "on"); fail2: fail1: @@ -545,8 +549,8 @@ static int efx_ethtool_get_eeprom_len(struct net_device *net_dev) if (!spi) return 0; - return min(spi->size, EFX_ETHTOOL_EEPROM_MAX) - - min(spi->size, EFX_ETHTOOL_EEPROM_MIN); + return min(spi->size, EFX_EEPROM_BOOTCONFIG_END) - + min(spi->size, EFX_EEPROM_BOOTCONFIG_START); } static int efx_ethtool_get_eeprom(struct net_device *net_dev, @@ -557,8 +561,13 @@ static int efx_ethtool_get_eeprom(struct net_device *net_dev, size_t len; int rc; - rc = falcon_spi_read(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN, + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; + rc = falcon_spi_read(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, eeprom->len, &len, buf); + mutex_unlock(&efx->spi_lock); + eeprom->magic = EFX_ETHTOOL_EEPROM_MAGIC; eeprom->len = len; return rc; @@ -575,8 +584,13 @@ static int efx_ethtool_set_eeprom(struct net_device *net_dev, if (eeprom->magic != EFX_ETHTOOL_EEPROM_MAGIC) return -EINVAL; - rc = falcon_spi_write(spi, eeprom->offset + EFX_ETHTOOL_EEPROM_MIN, + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; + rc = falcon_spi_write(spi, eeprom->offset + EFX_EEPROM_BOOTCONFIG_START, eeprom->len, &len, buf); + mutex_unlock(&efx->spi_lock); + eeprom->len = len; return rc; } @@ -666,23 +680,52 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev, struct ethtool_pauseparam *pause) { struct efx_nic *efx = netdev_priv(net_dev); - enum efx_fc_type flow_control = efx->flow_control; - int rc; + enum efx_fc_type wanted_fc; + bool reset; - flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO); - flow_control |= pause->rx_pause ? EFX_FC_RX : 0; - flow_control |= pause->tx_pause ? EFX_FC_TX : 0; - flow_control |= pause->autoneg ? EFX_FC_AUTO : 0; + wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) | + (pause->tx_pause ? EFX_FC_TX : 0) | + (pause->autoneg ? EFX_FC_AUTO : 0)); + + if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) { + EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n"); + return -EINVAL; + } + + if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) && + (wanted_fc & EFX_FC_AUTO)) { + EFX_LOG(efx, "PHY does not support flow control " + "autonegotiation\n"); + return -EINVAL; + } + + /* TX flow control may automatically turn itself off if the + * link partner (intermittently) stops responding to pause + * frames. There isn't any indication that this has happened, + * so the best we do is leave it up to the user to spot this + * and fix it be cycling transmit flow control on this end. */ + reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX); + if (EFX_WORKAROUND_11482(efx) && reset) { + if (falcon_rev(efx) >= FALCON_REV_B0) { + /* Recover by resetting the EM block */ + if (efx->link_up) + falcon_drain_tx_fifo(efx); + } else { + /* Schedule a reset to recover */ + efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); + } + } /* Try to push the pause parameters */ mutex_lock(&efx->mac_lock); - rc = falcon_xmac_set_pause(efx, flow_control); - mutex_unlock(&efx->mac_lock); - if (!rc) - efx_reconfigure_port(efx); + efx->wanted_fc = wanted_fc; + mdio_clause45_set_pause(efx); + __efx_reconfigure_port(efx); - return rc; + mutex_unlock(&efx->mac_lock); + + return 0; } static void efx_ethtool_get_pauseparam(struct net_device *net_dev, @@ -690,9 +733,9 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev, { struct efx_nic *efx = netdev_priv(net_dev); - pause->rx_pause = !!(efx->flow_control & EFX_FC_RX); - pause->tx_pause = !!(efx->flow_control & EFX_FC_TX); - pause->autoneg = !!(efx->flow_control & EFX_FC_AUTO); + pause->rx_pause = !!(efx->wanted_fc & EFX_FC_RX); + pause->tx_pause = !!(efx->wanted_fc & EFX_FC_TX); + pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO); } diff --git a/drivers/net/sfc/falcon.c b/drivers/net/sfc/falcon.c index 31ed1f49de008a547e61828174a39331d00c2512..6884dc8c1f8259a69421a65b7a1f81df8ff57a97 100644 --- a/drivers/net/sfc/falcon.c +++ b/drivers/net/sfc/falcon.c @@ -15,11 +15,11 @@ #include #include #include +#include #include "net_driver.h" #include "bitfield.h" #include "efx.h" #include "mac.h" -#include "gmii.h" #include "spi.h" #include "falcon.h" #include "falcon_hwdefs.h" @@ -70,6 +70,20 @@ static int disable_dma_stats; #define RX_DC_ENTRIES_ORDER 2 #define RX_DC_BASE 0x100000 +static const unsigned int +/* "Large" EEPROM device: Atmel AT25640 or similar + * 8 KB, 16-bit address, 32 B write block */ +large_eeprom_type = ((13 << SPI_DEV_TYPE_SIZE_LBN) + | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN) + | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)), +/* Default flash device: Atmel AT25F1024 + * 128 KB, 24-bit address, 32 KB erase block, 256 B write block */ +default_flash_type = ((17 << SPI_DEV_TYPE_SIZE_LBN) + | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN) + | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN) + | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN) + | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN)); + /* RX FIFO XOFF watermark * * When the amount of the RX FIFO increases used increases past this @@ -770,15 +784,18 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, rx_ev_buf_owner_id_err | rx_ev_eth_crc_err | rx_ev_frm_trunc | rx_ev_ip_hdr_chksum_err); - /* Count errors that are not in MAC stats. */ + /* Count errors that are not in MAC stats. Ignore expected + * checksum errors during self-test. */ if (rx_ev_frm_trunc) ++rx_queue->channel->n_rx_frm_trunc; else if (rx_ev_tobe_disc) ++rx_queue->channel->n_rx_tobe_disc; - else if (rx_ev_ip_hdr_chksum_err) - ++rx_queue->channel->n_rx_ip_hdr_chksum_err; - else if (rx_ev_tcp_udp_chksum_err) - ++rx_queue->channel->n_rx_tcp_udp_chksum_err; + else if (!efx->loopback_selftest) { + if (rx_ev_ip_hdr_chksum_err) + ++rx_queue->channel->n_rx_ip_hdr_chksum_err; + else if (rx_ev_tcp_udp_chksum_err) + ++rx_queue->channel->n_rx_tcp_udp_chksum_err; + } if (rx_ev_ip_frag_err) ++rx_queue->channel->n_rx_ip_frag_err; @@ -809,7 +826,7 @@ static void falcon_handle_rx_not_ok(struct efx_rx_queue *rx_queue, #endif if (unlikely(rx_ev_eth_crc_err && EFX_WORKAROUND_10750(efx) && - efx->phy_type == PHY_TYPE_10XPRESS)) + efx->phy_type == PHY_TYPE_SFX7101)) tenxpress_crc_err(efx); } @@ -893,22 +910,20 @@ static void falcon_handle_global_event(struct efx_channel *channel, efx_qword_t *event) { struct efx_nic *efx = channel->efx; - bool is_phy_event = false, handled = false; + bool handled = false; - /* Check for interrupt on either port. Some boards have a - * single PHY wired to the interrupt line for port 1. */ if (EFX_QWORD_FIELD(*event, G_PHY0_INTR) || EFX_QWORD_FIELD(*event, G_PHY1_INTR) || - EFX_QWORD_FIELD(*event, XG_PHY_INTR)) - is_phy_event = true; + EFX_QWORD_FIELD(*event, XG_PHY_INTR) || + EFX_QWORD_FIELD(*event, XFP_PHY_INTR)) { + efx->phy_op->clear_interrupt(efx); + queue_work(efx->workqueue, &efx->phy_work); + handled = true; + } if ((falcon_rev(efx) >= FALCON_REV_B0) && - EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0)) - is_phy_event = true; - - if (is_phy_event) { - efx->phy_op->clear_interrupt(efx); - queue_work(efx->workqueue, &efx->reconfigure_work); + EFX_QWORD_FIELD(*event, XG_MNT_INTR_B0)) { + queue_work(efx->workqueue, &efx->mac_work); handled = true; } @@ -1151,6 +1166,19 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic) falcon_generate_event(channel, &test_event); } +void falcon_sim_phy_event(struct efx_nic *efx) +{ + efx_qword_t phy_event; + + EFX_POPULATE_QWORD_1(phy_event, EV_CODE, GLOBAL_EV_DECODE); + if (EFX_IS10G(efx)) + EFX_SET_OWORD_FIELD(phy_event, XG_PHY_INTR, 1); + else + EFX_SET_OWORD_FIELD(phy_event, G_PHY0_INTR, 1); + + falcon_generate_event(&efx->channel[0], &phy_event); +} + /************************************************************************** * * Flush handling @@ -1560,7 +1588,7 @@ int falcon_init_interrupt(struct efx_nic *efx) efx_for_each_channel(channel, efx) { rc = request_irq(channel->irq, falcon_msi_interrupt, IRQF_PROBE_SHARED, /* Not shared */ - efx->name, channel); + channel->name, channel); if (rc) { EFX_ERR(efx, "failed to hook IRQ %d\n", channel->irq); goto fail2; @@ -1605,32 +1633,45 @@ void falcon_fini_interrupt(struct efx_nic *efx) ************************************************************************** */ -#define FALCON_SPI_MAX_LEN ((unsigned) sizeof(efx_oword_t)) +#define FALCON_SPI_MAX_LEN sizeof(efx_oword_t) + +static int falcon_spi_poll(struct efx_nic *efx) +{ + efx_oword_t reg; + falcon_read(efx, ®, EE_SPI_HCMD_REG_KER); + return EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN) ? -EBUSY : 0; +} /* Wait for SPI command completion */ static int falcon_spi_wait(struct efx_nic *efx) { - unsigned long timeout = jiffies + DIV_ROUND_UP(HZ, 10); - efx_oword_t reg; - bool cmd_en, timer_active; + /* Most commands will finish quickly, so we start polling at + * very short intervals. Sometimes the command may have to + * wait for VPD or expansion ROM access outside of our + * control, so we allow up to 100 ms. */ + unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 10); + int i; + + for (i = 0; i < 10; i++) { + if (!falcon_spi_poll(efx)) + return 0; + udelay(10); + } for (;;) { - falcon_read(efx, ®, EE_SPI_HCMD_REG_KER); - cmd_en = EFX_OWORD_FIELD(reg, EE_SPI_HCMD_CMD_EN); - timer_active = EFX_OWORD_FIELD(reg, EE_WR_TIMER_ACTIVE); - if (!cmd_en && !timer_active) + if (!falcon_spi_poll(efx)) return 0; if (time_after_eq(jiffies, timeout)) { EFX_ERR(efx, "timed out waiting for SPI\n"); return -ETIMEDOUT; } - cpu_relax(); + schedule_timeout_uninterruptible(1); } } -static int falcon_spi_cmd(const struct efx_spi_device *spi, - unsigned int command, int address, - const void *in, void *out, unsigned int len) +int falcon_spi_cmd(const struct efx_spi_device *spi, + unsigned int command, int address, + const void *in, void *out, size_t len) { struct efx_nic *efx = spi->efx; bool addressed = (address >= 0); @@ -1641,9 +1682,10 @@ static int falcon_spi_cmd(const struct efx_spi_device *spi, /* Input validation */ if (len > FALCON_SPI_MAX_LEN) return -EINVAL; + BUG_ON(!mutex_is_locked(&efx->spi_lock)); - /* Check SPI not currently being accessed */ - rc = falcon_spi_wait(efx); + /* Check that previous command is not still running */ + rc = falcon_spi_poll(efx); if (rc) return rc; @@ -1685,8 +1727,8 @@ static int falcon_spi_cmd(const struct efx_spi_device *spi, return 0; } -static unsigned int -falcon_spi_write_limit(const struct efx_spi_device *spi, unsigned int start) +static size_t +falcon_spi_write_limit(const struct efx_spi_device *spi, size_t start) { return min(FALCON_SPI_MAX_LEN, (spi->block_size - (start & (spi->block_size - 1)))); @@ -1699,38 +1741,40 @@ efx_spi_munge_command(const struct efx_spi_device *spi, return command | (((address >> 8) & spi->munge_address) << 3); } - -static int falcon_spi_fast_wait(const struct efx_spi_device *spi) +/* Wait up to 10 ms for buffered write completion */ +int falcon_spi_wait_write(const struct efx_spi_device *spi) { + struct efx_nic *efx = spi->efx; + unsigned long timeout = jiffies + 1 + DIV_ROUND_UP(HZ, 100); u8 status; - int i, rc; - - /* Wait up to 1000us for flash/EEPROM to finish a fast operation. */ - for (i = 0; i < 50; i++) { - udelay(20); + int rc; + for (;;) { rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); if (rc) return rc; if (!(status & SPI_STATUS_NRDY)) return 0; + if (time_after_eq(jiffies, timeout)) { + EFX_ERR(efx, "SPI write timeout on device %d" + " last status=0x%02x\n", + spi->device_id, status); + return -ETIMEDOUT; + } + schedule_timeout_uninterruptible(1); } - EFX_ERR(spi->efx, - "timed out waiting for device %d last status=0x%02x\n", - spi->device_id, status); - return -ETIMEDOUT; } int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, u8 *buffer) { - unsigned int command, block_len, pos = 0; + size_t block_len, pos = 0; + unsigned int command; int rc = 0; while (pos < len) { - block_len = min((unsigned int)len - pos, - FALCON_SPI_MAX_LEN); + block_len = min(len - pos, FALCON_SPI_MAX_LEN); command = efx_spi_munge_command(spi, SPI_READ, start + pos); rc = falcon_spi_cmd(spi, command, start + pos, NULL, @@ -1756,7 +1800,8 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, const u8 *buffer) { u8 verify_buffer[FALCON_SPI_MAX_LEN]; - unsigned int command, block_len, pos = 0; + size_t block_len, pos = 0; + unsigned int command; int rc = 0; while (pos < len) { @@ -1764,7 +1809,7 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, if (rc) break; - block_len = min((unsigned int)len - pos, + block_len = min(len - pos, falcon_spi_write_limit(spi, start + pos)); command = efx_spi_munge_command(spi, SPI_WRITE, start + pos); rc = falcon_spi_cmd(spi, command, start + pos, @@ -1772,7 +1817,7 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, if (rc) break; - rc = falcon_spi_fast_wait(spi); + rc = falcon_spi_wait_write(spi); if (rc) break; @@ -1805,40 +1850,61 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, * ************************************************************************** */ -void falcon_drain_tx_fifo(struct efx_nic *efx) + +static int falcon_reset_macs(struct efx_nic *efx) { - efx_oword_t temp; + efx_oword_t reg; int count; - if ((falcon_rev(efx) < FALCON_REV_B0) || - (efx->loopback_mode != LOOPBACK_NONE)) - return; + if (falcon_rev(efx) < FALCON_REV_B0) { + /* It's not safe to use GLB_CTL_REG to reset the + * macs, so instead use the internal MAC resets + */ + if (!EFX_IS10G(efx)) { + EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 1); + falcon_write(efx, ®, GM_CFG1_REG); + udelay(1000); + + EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 0); + falcon_write(efx, ®, GM_CFG1_REG); + udelay(1000); + return 0; + } else { + EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1); + falcon_write(efx, ®, XM_GLB_CFG_REG); + + for (count = 0; count < 10000; count++) { + falcon_read(efx, ®, XM_GLB_CFG_REG); + if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0) + return 0; + udelay(10); + } - falcon_read(efx, &temp, MAC0_CTRL_REG_KER); - /* There is no point in draining more than once */ - if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0)) - return; + EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); + return -ETIMEDOUT; + } + } /* MAC stats will fail whilst the TX fifo is draining. Serialise * the drain sequence with the statistics fetch */ spin_lock(&efx->stats_lock); - EFX_SET_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0, 1); - falcon_write(efx, &temp, MAC0_CTRL_REG_KER); + falcon_read(efx, ®, MAC0_CTRL_REG_KER); + EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1); + falcon_write(efx, ®, MAC0_CTRL_REG_KER); - /* Reset the MAC and EM block. */ - falcon_read(efx, &temp, GLB_CTL_REG_KER); - EFX_SET_OWORD_FIELD(temp, RST_XGTX, 1); - EFX_SET_OWORD_FIELD(temp, RST_XGRX, 1); - EFX_SET_OWORD_FIELD(temp, RST_EM, 1); - falcon_write(efx, &temp, GLB_CTL_REG_KER); + falcon_read(efx, ®, GLB_CTL_REG_KER); + EFX_SET_OWORD_FIELD(reg, RST_XGTX, 1); + EFX_SET_OWORD_FIELD(reg, RST_XGRX, 1); + EFX_SET_OWORD_FIELD(reg, RST_EM, 1); + falcon_write(efx, ®, GLB_CTL_REG_KER); count = 0; while (1) { - falcon_read(efx, &temp, GLB_CTL_REG_KER); - if (!EFX_OWORD_FIELD(temp, RST_XGTX) && - !EFX_OWORD_FIELD(temp, RST_XGRX) && - !EFX_OWORD_FIELD(temp, RST_EM)) { + falcon_read(efx, ®, GLB_CTL_REG_KER); + if (!EFX_OWORD_FIELD(reg, RST_XGTX) && + !EFX_OWORD_FIELD(reg, RST_XGRX) && + !EFX_OWORD_FIELD(reg, RST_EM)) { EFX_LOG(efx, "Completed MAC reset after %d loops\n", count); break; @@ -1855,21 +1921,39 @@ void falcon_drain_tx_fifo(struct efx_nic *efx) /* If we've reset the EM block and the link is up, then * we'll have to kick the XAUI link so the PHY can recover */ - if (efx->link_up && EFX_WORKAROUND_5147(efx)) + if (efx->link_up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx)) falcon_reset_xaui(efx); + + return 0; +} + +void falcon_drain_tx_fifo(struct efx_nic *efx) +{ + efx_oword_t reg; + + if ((falcon_rev(efx) < FALCON_REV_B0) || + (efx->loopback_mode != LOOPBACK_NONE)) + return; + + falcon_read(efx, ®, MAC0_CTRL_REG_KER); + /* There is no point in draining more than once */ + if (EFX_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0)) + return; + + falcon_reset_macs(efx); } void falcon_deconfigure_mac_wrapper(struct efx_nic *efx) { - efx_oword_t temp; + efx_oword_t reg; if (falcon_rev(efx) < FALCON_REV_B0) return; /* Isolate the MAC -> RX */ - falcon_read(efx, &temp, RX_CFG_REG_KER); - EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 0); - falcon_write(efx, &temp, RX_CFG_REG_KER); + falcon_read(efx, ®, RX_CFG_REG_KER); + EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 0); + falcon_write(efx, ®, RX_CFG_REG_KER); if (!efx->link_up) falcon_drain_tx_fifo(efx); @@ -1881,14 +1965,12 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) int link_speed; bool tx_fc; - if (efx->link_options & GM_LPA_10000) - link_speed = 0x3; - else if (efx->link_options & GM_LPA_1000) - link_speed = 0x2; - else if (efx->link_options & GM_LPA_100) - link_speed = 0x1; - else - link_speed = 0x0; + switch (efx->link_speed) { + case 10000: link_speed = 3; break; + case 1000: link_speed = 2; break; + case 100: link_speed = 1; break; + default: link_speed = 0; break; + } /* MAC_LINK_STATUS controls MAC backpressure but doesn't work * as advertised. Disable to ensure packets are not * indefinitely held and TX queue can be flushed at any point @@ -1914,7 +1996,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx) /* Transmission of pause frames when RX crosses the threshold is * covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL. * Action on receipt of pause frames is controller by XM_DIS_FCNTL */ - tx_fc = !!(efx->flow_control & EFX_FC_TX); + tx_fc = !!(efx->link_fc & EFX_FC_TX); falcon_read(efx, ®, RX_CFG_REG_KER); EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc); @@ -1998,7 +2080,8 @@ static int falcon_gmii_wait(struct efx_nic *efx) efx_dword_t md_stat; int count; - for (count = 0; count < 1000; count++) { /* wait upto 10ms */ + /* wait upto 50ms - taken max from datasheet */ + for (count = 0; count < 5000; count++) { falcon_readl(efx, &md_stat, MD_STAT_REG_KER); if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) { if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 || @@ -2162,10 +2245,14 @@ static void falcon_init_mdio(struct mii_if_info *gmii) static int falcon_probe_phy(struct efx_nic *efx) { switch (efx->phy_type) { - case PHY_TYPE_10XPRESS: - efx->phy_op = &falcon_tenxpress_phy_ops; + case PHY_TYPE_SFX7101: + efx->phy_op = &falcon_sfx7101_phy_ops; + break; + case PHY_TYPE_SFT9001A: + case PHY_TYPE_SFT9001B: + efx->phy_op = &falcon_sft9001_phy_ops; break; - case PHY_TYPE_XFP: + case PHY_TYPE_QT2022C2: efx->phy_op = &falcon_xfp_phy_ops; break; default: @@ -2174,10 +2261,59 @@ static int falcon_probe_phy(struct efx_nic *efx) return -1; } - efx->loopback_modes = LOOPBACKS_10G_INTERNAL | efx->phy_op->loopbacks; + if (efx->phy_op->macs & EFX_XMAC) + efx->loopback_modes |= ((1 << LOOPBACK_XGMII) | + (1 << LOOPBACK_XGXS) | + (1 << LOOPBACK_XAUI)); + if (efx->phy_op->macs & EFX_GMAC) + efx->loopback_modes |= (1 << LOOPBACK_GMAC); + efx->loopback_modes |= efx->phy_op->loopbacks; + return 0; } +int falcon_switch_mac(struct efx_nic *efx) +{ + struct efx_mac_operations *old_mac_op = efx->mac_op; + efx_oword_t nic_stat; + unsigned strap_val; + + /* Internal loopbacks override the phy speed setting */ + if (efx->loopback_mode == LOOPBACK_GMAC) { + efx->link_speed = 1000; + efx->link_fd = true; + } else if (LOOPBACK_INTERNAL(efx)) { + efx->link_speed = 10000; + efx->link_fd = true; + } + + efx->mac_op = (EFX_IS10G(efx) ? + &falcon_xmac_operations : &falcon_gmac_operations); + if (old_mac_op == efx->mac_op) + return 0; + + WARN_ON(!mutex_is_locked(&efx->mac_lock)); + + /* Not all macs support a mac-level link state */ + efx->mac_up = true; + + falcon_read(efx, &nic_stat, NIC_STAT_REG); + strap_val = EFX_IS10G(efx) ? 5 : 3; + if (falcon_rev(efx) >= FALCON_REV_B0) { + EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_EN, 1); + EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_OVR, strap_val); + falcon_write(efx, &nic_stat, NIC_STAT_REG); + } else { + /* Falcon A1 does not support 1G/10G speed switching + * and must not be used with a PHY that does. */ + BUG_ON(EFX_OWORD_FIELD(nic_stat, STRAP_PINS) != strap_val); + } + + + EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G'); + return falcon_reset_macs(efx); +} + /* This call is responsible for hooking in the MAC and PHY operations */ int falcon_probe_port(struct efx_nic *efx) { @@ -2194,9 +2330,9 @@ int falcon_probe_port(struct efx_nic *efx) /* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */ if (falcon_rev(efx) >= FALCON_REV_B0) - efx->flow_control = EFX_FC_RX | EFX_FC_TX; + efx->wanted_fc = EFX_FC_RX | EFX_FC_TX; else - efx->flow_control = EFX_FC_RX; + efx->wanted_fc = EFX_FC_RX; /* Allocate buffer for stats */ rc = falcon_alloc_buffer(efx, &efx->stats_buffer, @@ -2253,13 +2389,18 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) __le16 *word, *limit; u32 csum; - region = kmalloc(NVCONFIG_END, GFP_KERNEL); + spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom; + if (!spi) + return -EINVAL; + + region = kmalloc(FALCON_NVCONFIG_END, GFP_KERNEL); if (!region) return -ENOMEM; nvconfig = region + NVCONFIG_OFFSET; - spi = efx->spi_flash ? efx->spi_flash : efx->spi_eeprom; - rc = falcon_spi_read(spi, 0, NVCONFIG_END, NULL, region); + mutex_lock(&efx->spi_lock); + rc = falcon_spi_read(spi, 0, FALCON_NVCONFIG_END, NULL, region); + mutex_unlock(&efx->spi_lock); if (rc) { EFX_ERR(efx, "Failed to read %s\n", efx->spi_flash ? "flash" : "EEPROM"); @@ -2283,7 +2424,7 @@ int falcon_read_nvram(struct efx_nic *efx, struct falcon_nvconfig *nvconfig_out) limit = (__le16 *) (nvconfig + 1); } else { word = region; - limit = region + NVCONFIG_END; + limit = region + FALCON_NVCONFIG_END; } for (csum = 0; word < limit; ++word) csum += le16_to_cpu(*word); @@ -2325,6 +2466,10 @@ static struct { EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) }, { DP_CTRL_REG, EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) }, + { GM_CFG2_REG, + EFX_OWORD32(0x00007337, 0x00000000, 0x00000000, 0x00000000) }, + { GMF_CFG0_REG, + EFX_OWORD32(0x00001F1F, 0x00000000, 0x00000000, 0x00000000) }, { XM_GLB_CFG_REG, EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) }, { XM_TX_CFG_REG, @@ -2545,7 +2690,7 @@ static int falcon_spi_device_init(struct efx_nic *efx, struct efx_spi_device *spi_device; if (device_type != 0) { - spi_device = kmalloc(sizeof(*spi_device), GFP_KERNEL); + spi_device = kzalloc(sizeof(*spi_device), GFP_KERNEL); if (!spi_device) return -ENOMEM; spi_device->device_id = device_id; @@ -2555,6 +2700,11 @@ static int falcon_spi_device_init(struct efx_nic *efx, SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ADDR_LEN); spi_device->munge_address = (spi_device->size == 1 << 9 && spi_device->addr_len == 1); + spi_device->erase_command = + SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_ERASE_CMD); + spi_device->erase_size = + 1 << SPI_DEV_TYPE_FIELD(device_type, + SPI_DEV_TYPE_ERASE_SIZE); spi_device->block_size = 1 << SPI_DEV_TYPE_FIELD(device_type, SPI_DEV_TYPE_BLOCK_SIZE); @@ -2645,6 +2795,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx) static int falcon_probe_nic_variant(struct efx_nic *efx) { efx_oword_t altera_build; + efx_oword_t nic_stat; falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER); if (EFX_OWORD_FIELD(altera_build, VER_ALL)) { @@ -2652,27 +2803,20 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) return -ENODEV; } + falcon_read(efx, &nic_stat, NIC_STAT_REG); + switch (falcon_rev(efx)) { case FALCON_REV_A0: case 0xff: EFX_ERR(efx, "Falcon rev A0 not supported\n"); return -ENODEV; - case FALCON_REV_A1:{ - efx_oword_t nic_stat; - - falcon_read(efx, &nic_stat, NIC_STAT_REG); - + case FALCON_REV_A1: if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) { EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n"); return -ENODEV; } - if (!EFX_OWORD_FIELD(nic_stat, STRAP_10G)) { - EFX_ERR(efx, "1G mode not supported\n"); - return -ENODEV; - } break; - } case FALCON_REV_B0: break; @@ -2682,6 +2826,9 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) return -ENODEV; } + /* Initial assumed speed */ + efx->link_speed = EFX_OWORD_FIELD(nic_stat, STRAP_10G) ? 10000 : 1000; + return 0; } @@ -2689,80 +2836,37 @@ static int falcon_probe_nic_variant(struct efx_nic *efx) static void falcon_probe_spi_devices(struct efx_nic *efx) { efx_oword_t nic_stat, gpio_ctl, ee_vpd_cfg; - bool has_flash, has_eeprom, boot_is_external; + int boot_dev; falcon_read(efx, &gpio_ctl, GPIO_CTL_REG_KER); falcon_read(efx, &nic_stat, NIC_STAT_REG); falcon_read(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); - has_flash = EFX_OWORD_FIELD(nic_stat, SF_PRST); - has_eeprom = EFX_OWORD_FIELD(nic_stat, EE_PRST); - boot_is_external = EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE); - - if (has_flash) { - /* Default flash SPI device: Atmel AT25F1024 - * 128 KB, 24-bit address, 32 KB erase block, - * 256 B write block - */ - u32 flash_device_type = - (17 << SPI_DEV_TYPE_SIZE_LBN) - | (3 << SPI_DEV_TYPE_ADDR_LEN_LBN) - | (0x52 << SPI_DEV_TYPE_ERASE_CMD_LBN) - | (15 << SPI_DEV_TYPE_ERASE_SIZE_LBN) - | (8 << SPI_DEV_TYPE_BLOCK_SIZE_LBN); - - falcon_spi_device_init(efx, &efx->spi_flash, - EE_SPI_FLASH, flash_device_type); - - if (!boot_is_external) { - /* Disable VPD and set clock dividers to safe - * values for initial programming. - */ - EFX_LOG(efx, "Booted from internal ASIC settings;" - " setting SPI config\n"); - EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0, - /* 125 MHz / 7 ~= 20 MHz */ - EE_SF_CLOCK_DIV, 7, - /* 125 MHz / 63 ~= 2 MHz */ - EE_EE_CLOCK_DIV, 63); - falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); - } - } - - if (has_eeprom) { - u32 eeprom_device_type; - - /* If it has no flash, it must have a large EEPROM - * for chip config; otherwise check whether 9-bit - * addressing is used for VPD configuration - */ - if (has_flash && - (!boot_is_external || - EFX_OWORD_FIELD(ee_vpd_cfg, EE_VPD_EN_AD9_MODE))) { - /* Default SPI device: Atmel AT25040 or similar - * 512 B, 9-bit address, 8 B write block - */ - eeprom_device_type = - (9 << SPI_DEV_TYPE_SIZE_LBN) - | (1 << SPI_DEV_TYPE_ADDR_LEN_LBN) - | (3 << SPI_DEV_TYPE_BLOCK_SIZE_LBN); - } else { - /* "Large" SPI device: Atmel AT25640 or similar - * 8 KB, 16-bit address, 32 B write block - */ - eeprom_device_type = - (13 << SPI_DEV_TYPE_SIZE_LBN) - | (2 << SPI_DEV_TYPE_ADDR_LEN_LBN) - | (5 << SPI_DEV_TYPE_BLOCK_SIZE_LBN); - } - - falcon_spi_device_init(efx, &efx->spi_eeprom, - EE_SPI_EEPROM, eeprom_device_type); - } - - EFX_LOG(efx, "flash is %s, EEPROM is %s\n", - (has_flash ? "present" : "absent"), - (has_eeprom ? "present" : "absent")); + if (EFX_OWORD_FIELD(gpio_ctl, BOOTED_USING_NVDEVICE)) { + boot_dev = (EFX_OWORD_FIELD(nic_stat, SF_PRST) ? + EE_SPI_FLASH : EE_SPI_EEPROM); + EFX_LOG(efx, "Booted from %s\n", + boot_dev == EE_SPI_FLASH ? "flash" : "EEPROM"); + } else { + /* Disable VPD and set clock dividers to safe + * values for initial programming. */ + boot_dev = -1; + EFX_LOG(efx, "Booted from internal ASIC settings;" + " setting SPI config\n"); + EFX_POPULATE_OWORD_3(ee_vpd_cfg, EE_VPD_EN, 0, + /* 125 MHz / 7 ~= 20 MHz */ + EE_SF_CLOCK_DIV, 7, + /* 125 MHz / 63 ~= 2 MHz */ + EE_EE_CLOCK_DIV, 63); + falcon_write(efx, &ee_vpd_cfg, EE_VPD_CFG_REG_KER); + } + + if (boot_dev == EE_SPI_FLASH) + falcon_spi_device_init(efx, &efx->spi_flash, EE_SPI_FLASH, + default_flash_type); + if (boot_dev == EE_SPI_EEPROM) + falcon_spi_device_init(efx, &efx->spi_eeprom, EE_SPI_EEPROM, + large_eeprom_type); } int falcon_probe_nic(struct efx_nic *efx) @@ -2825,10 +2929,10 @@ int falcon_probe_nic(struct efx_nic *efx) goto fail5; /* Initialise I2C adapter */ - efx->i2c_adap.owner = THIS_MODULE; + efx->i2c_adap.owner = THIS_MODULE; nic_data->i2c_data = falcon_i2c_bit_operations; nic_data->i2c_data.data = efx; - efx->i2c_adap.algo_data = &nic_data->i2c_data; + efx->i2c_adap.algo_data = &nic_data->i2c_data; efx->i2c_adap.dev.parent = &efx->pci_dev->dev; strlcpy(efx->i2c_adap.name, "SFC4000 GPIO", sizeof(efx->i2c_adap.name)); rc = i2c_bit_add_bus(&efx->i2c_adap); @@ -2862,20 +2966,18 @@ int falcon_init_nic(struct efx_nic *efx) unsigned thresh; int rc; - /* Set up the address region register. This is only needed - * for the B0 FPGA, but since we are just pushing in the - * reset defaults this may as well be unconditional. */ - EFX_POPULATE_OWORD_4(temp, ADR_REGION0, 0, - ADR_REGION1, (1 << 16), - ADR_REGION2, (2 << 16), - ADR_REGION3, (3 << 16)); - falcon_write(efx, &temp, ADR_REGION_REG_KER); - /* Use on-chip SRAM */ falcon_read(efx, &temp, NIC_STAT_REG); EFX_SET_OWORD_FIELD(temp, ONCHIP_SRAM, 1); falcon_write(efx, &temp, NIC_STAT_REG); + /* Set the source of the GMAC clock */ + if (falcon_rev(efx) == FALCON_REV_B0) { + falcon_read(efx, &temp, GPIO_CTL_REG_KER); + EFX_SET_OWORD_FIELD(temp, GPIO_USE_NIC_CLK, true); + falcon_write(efx, &temp, GPIO_CTL_REG_KER); + } + /* Set buffer table mode */ EFX_POPULATE_OWORD_1(temp, BUF_TBL_MODE, BUF_TBL_MODE_FULL); falcon_write(efx, &temp, BUF_TBL_CFG_REG_KER); diff --git a/drivers/net/sfc/falcon.h b/drivers/net/sfc/falcon.h index be025ba7a6c6215c0ae2a2e8a3d166cc8f73063c..7869c3d74383cc971e818bda22ec5fc78cbf2395 100644 --- a/drivers/net/sfc/falcon.h +++ b/drivers/net/sfc/falcon.h @@ -12,6 +12,7 @@ #define EFX_FALCON_H #include "net_driver.h" +#include "efx.h" /* * Falcon hardware control @@ -65,6 +66,7 @@ extern int falcon_probe_port(struct efx_nic *efx); extern void falcon_remove_port(struct efx_nic *efx); /* MAC/PHY */ +extern int falcon_switch_mac(struct efx_nic *efx); extern bool falcon_xaui_link_ok(struct efx_nic *efx); extern int falcon_dma_stats(struct efx_nic *efx, unsigned int done_offset); @@ -77,6 +79,7 @@ extern int falcon_init_interrupt(struct efx_nic *efx); extern void falcon_enable_interrupts(struct efx_nic *efx); extern void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic); +extern void falcon_sim_phy_event(struct efx_nic *efx); extern void falcon_generate_interrupt(struct efx_nic *efx); extern void falcon_set_int_moderation(struct efx_channel *channel); extern void falcon_disable_interrupts(struct efx_nic *efx); diff --git a/drivers/net/sfc/falcon_gmac.c b/drivers/net/sfc/falcon_gmac.c new file mode 100644 index 0000000000000000000000000000000000000000..8865eae20ac51ef0c40b6032ff38906e3f46b16d --- /dev/null +++ b/drivers/net/sfc/falcon_gmac.c @@ -0,0 +1,229 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2006-2008 Solarflare Communications 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, incorporated herein by reference. + */ + +#include +#include "net_driver.h" +#include "efx.h" +#include "falcon.h" +#include "mac.h" +#include "falcon_hwdefs.h" +#include "falcon_io.h" +#include "gmii.h" + +/************************************************************************** + * + * MAC operations + * + *************************************************************************/ + +static void falcon_reconfigure_gmac(struct efx_nic *efx) +{ + bool loopback, tx_fc, rx_fc, bytemode; + int if_mode; + unsigned int max_frame_len; + efx_oword_t reg; + + /* Configuration register 1 */ + tx_fc = (efx->link_fc & EFX_FC_TX) || !efx->link_fd; + rx_fc = !!(efx->link_fc & EFX_FC_RX); + loopback = (efx->loopback_mode == LOOPBACK_GMAC); + bytemode = (efx->link_speed == 1000); + + EFX_POPULATE_OWORD_5(reg, + GM_LOOP, loopback, + GM_TX_EN, 1, + GM_TX_FC_EN, tx_fc, + GM_RX_EN, 1, + GM_RX_FC_EN, rx_fc); + falcon_write(efx, ®, GM_CFG1_REG); + udelay(10); + + /* Configuration register 2 */ + if_mode = (bytemode) ? 2 : 1; + EFX_POPULATE_OWORD_5(reg, + GM_IF_MODE, if_mode, + GM_PAD_CRC_EN, 1, + GM_LEN_CHK, 1, + GM_FD, efx->link_fd, + GM_PAMBL_LEN, 0x7/*datasheet recommended */); + + falcon_write(efx, ®, GM_CFG2_REG); + udelay(10); + + /* Max frame len register */ + max_frame_len = EFX_MAX_FRAME_LEN(efx->net_dev->mtu); + EFX_POPULATE_OWORD_1(reg, GM_MAX_FLEN, max_frame_len); + falcon_write(efx, ®, GM_MAX_FLEN_REG); + udelay(10); + + /* FIFO configuration register 0 */ + EFX_POPULATE_OWORD_5(reg, + GMF_FTFENREQ, 1, + GMF_STFENREQ, 1, + GMF_FRFENREQ, 1, + GMF_SRFENREQ, 1, + GMF_WTMENREQ, 1); + falcon_write(efx, ®, GMF_CFG0_REG); + udelay(10); + + /* FIFO configuration register 1 */ + EFX_POPULATE_OWORD_2(reg, + GMF_CFGFRTH, 0x12, + GMF_CFGXOFFRTX, 0xffff); + falcon_write(efx, ®, GMF_CFG1_REG); + udelay(10); + + /* FIFO configuration register 2 */ + EFX_POPULATE_OWORD_2(reg, + GMF_CFGHWM, 0x3f, + GMF_CFGLWM, 0xa); + falcon_write(efx, ®, GMF_CFG2_REG); + udelay(10); + + /* FIFO configuration register 3 */ + EFX_POPULATE_OWORD_2(reg, + GMF_CFGHWMFT, 0x1c, + GMF_CFGFTTH, 0x08); + falcon_write(efx, ®, GMF_CFG3_REG); + udelay(10); + + /* FIFO configuration register 4 */ + EFX_POPULATE_OWORD_1(reg, GMF_HSTFLTRFRM_PAUSE, 1); + falcon_write(efx, ®, GMF_CFG4_REG); + udelay(10); + + /* FIFO configuration register 5 */ + falcon_read(efx, ®, GMF_CFG5_REG); + EFX_SET_OWORD_FIELD(reg, GMF_CFGBYTMODE, bytemode); + EFX_SET_OWORD_FIELD(reg, GMF_CFGHDPLX, !efx->link_fd); + EFX_SET_OWORD_FIELD(reg, GMF_HSTDRPLT64, !efx->link_fd); + EFX_SET_OWORD_FIELD(reg, GMF_HSTFLTRFRMDC_PAUSE, 0); + falcon_write(efx, ®, GMF_CFG5_REG); + udelay(10); + + /* MAC address */ + EFX_POPULATE_OWORD_4(reg, + GM_HWADDR_5, efx->net_dev->dev_addr[5], + GM_HWADDR_4, efx->net_dev->dev_addr[4], + GM_HWADDR_3, efx->net_dev->dev_addr[3], + GM_HWADDR_2, efx->net_dev->dev_addr[2]); + falcon_write(efx, ®, GM_ADR1_REG); + udelay(10); + EFX_POPULATE_OWORD_2(reg, + GM_HWADDR_1, efx->net_dev->dev_addr[1], + GM_HWADDR_0, efx->net_dev->dev_addr[0]); + falcon_write(efx, ®, GM_ADR2_REG); + udelay(10); + + falcon_reconfigure_mac_wrapper(efx); +} + +static void falcon_update_stats_gmac(struct efx_nic *efx) +{ + struct efx_mac_stats *mac_stats = &efx->mac_stats; + unsigned long old_rx_pause, old_tx_pause; + unsigned long new_rx_pause, new_tx_pause; + int rc; + + rc = falcon_dma_stats(efx, GDmaDone_offset); + if (rc) + return; + + /* Pause frames are erroneously counted as errors (SFC bug 3269) */ + old_rx_pause = mac_stats->rx_pause; + old_tx_pause = mac_stats->tx_pause; + + /* Update MAC stats from DMAed values */ + FALCON_STAT(efx, GRxGoodOct, rx_good_bytes); + FALCON_STAT(efx, GRxBadOct, rx_bad_bytes); + FALCON_STAT(efx, GRxMissPkt, rx_missed); + FALCON_STAT(efx, GRxFalseCRS, rx_false_carrier); + FALCON_STAT(efx, GRxPausePkt, rx_pause); + FALCON_STAT(efx, GRxBadPkt, rx_bad); + FALCON_STAT(efx, GRxUcastPkt, rx_unicast); + FALCON_STAT(efx, GRxMcastPkt, rx_multicast); + FALCON_STAT(efx, GRxBcastPkt, rx_broadcast); + FALCON_STAT(efx, GRxGoodLt64Pkt, rx_good_lt64); + FALCON_STAT(efx, GRxBadLt64Pkt, rx_bad_lt64); + FALCON_STAT(efx, GRx64Pkt, rx_64); + FALCON_STAT(efx, GRx65to127Pkt, rx_65_to_127); + FALCON_STAT(efx, GRx128to255Pkt, rx_128_to_255); + FALCON_STAT(efx, GRx256to511Pkt, rx_256_to_511); + FALCON_STAT(efx, GRx512to1023Pkt, rx_512_to_1023); + FALCON_STAT(efx, GRx1024to15xxPkt, rx_1024_to_15xx); + FALCON_STAT(efx, GRx15xxtoJumboPkt, rx_15xx_to_jumbo); + FALCON_STAT(efx, GRxGtJumboPkt, rx_gtjumbo); + FALCON_STAT(efx, GRxFcsErr64to15xxPkt, rx_bad_64_to_15xx); + FALCON_STAT(efx, GRxFcsErr15xxtoJumboPkt, rx_bad_15xx_to_jumbo); + FALCON_STAT(efx, GRxFcsErrGtJumboPkt, rx_bad_gtjumbo); + FALCON_STAT(efx, GTxGoodBadOct, tx_bytes); + FALCON_STAT(efx, GTxGoodOct, tx_good_bytes); + FALCON_STAT(efx, GTxSglColPkt, tx_single_collision); + FALCON_STAT(efx, GTxMultColPkt, tx_multiple_collision); + FALCON_STAT(efx, GTxExColPkt, tx_excessive_collision); + FALCON_STAT(efx, GTxDefPkt, tx_deferred); + FALCON_STAT(efx, GTxLateCol, tx_late_collision); + FALCON_STAT(efx, GTxExDefPkt, tx_excessive_deferred); + FALCON_STAT(efx, GTxPausePkt, tx_pause); + FALCON_STAT(efx, GTxBadPkt, tx_bad); + FALCON_STAT(efx, GTxUcastPkt, tx_unicast); + FALCON_STAT(efx, GTxMcastPkt, tx_multicast); + FALCON_STAT(efx, GTxBcastPkt, tx_broadcast); + FALCON_STAT(efx, GTxLt64Pkt, tx_lt64); + FALCON_STAT(efx, GTx64Pkt, tx_64); + FALCON_STAT(efx, GTx65to127Pkt, tx_65_to_127); + FALCON_STAT(efx, GTx128to255Pkt, tx_128_to_255); + FALCON_STAT(efx, GTx256to511Pkt, tx_256_to_511); + FALCON_STAT(efx, GTx512to1023Pkt, tx_512_to_1023); + FALCON_STAT(efx, GTx1024to15xxPkt, tx_1024_to_15xx); + FALCON_STAT(efx, GTx15xxtoJumboPkt, tx_15xx_to_jumbo); + FALCON_STAT(efx, GTxGtJumboPkt, tx_gtjumbo); + FALCON_STAT(efx, GTxNonTcpUdpPkt, tx_non_tcpudp); + FALCON_STAT(efx, GTxMacSrcErrPkt, tx_mac_src_error); + FALCON_STAT(efx, GTxIpSrcErrPkt, tx_ip_src_error); + + /* Pause frames are erroneously counted as errors (SFC bug 3269) */ + new_rx_pause = mac_stats->rx_pause; + new_tx_pause = mac_stats->tx_pause; + mac_stats->rx_bad -= (new_rx_pause - old_rx_pause); + mac_stats->tx_bad -= (new_tx_pause - old_tx_pause); + + /* Derive stats that the MAC doesn't provide directly */ + mac_stats->tx_bad_bytes = + mac_stats->tx_bytes - mac_stats->tx_good_bytes; + mac_stats->tx_packets = + mac_stats->tx_lt64 + mac_stats->tx_64 + + mac_stats->tx_65_to_127 + mac_stats->tx_128_to_255 + + mac_stats->tx_256_to_511 + mac_stats->tx_512_to_1023 + + mac_stats->tx_1024_to_15xx + mac_stats->tx_15xx_to_jumbo + + mac_stats->tx_gtjumbo; + mac_stats->tx_collision = + mac_stats->tx_single_collision + + mac_stats->tx_multiple_collision + + mac_stats->tx_excessive_collision + + mac_stats->tx_late_collision; + mac_stats->rx_bytes = + mac_stats->rx_good_bytes + mac_stats->rx_bad_bytes; + mac_stats->rx_packets = + mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64 + + mac_stats->rx_64 + mac_stats->rx_65_to_127 + + mac_stats->rx_128_to_255 + mac_stats->rx_256_to_511 + + mac_stats->rx_512_to_1023 + mac_stats->rx_1024_to_15xx + + mac_stats->rx_15xx_to_jumbo + mac_stats->rx_gtjumbo; + mac_stats->rx_good = mac_stats->rx_packets - mac_stats->rx_bad; + mac_stats->rx_lt64 = mac_stats->rx_good_lt64 + mac_stats->rx_bad_lt64; +} + +struct efx_mac_operations falcon_gmac_operations = { + .reconfigure = falcon_reconfigure_gmac, + .update_stats = falcon_update_stats_gmac, + .irq = efx_port_dummy_op_void, + .poll = efx_port_dummy_op_void, +}; diff --git a/drivers/net/sfc/falcon_hwdefs.h b/drivers/net/sfc/falcon_hwdefs.h index 5d584b0dbb517043c05ce3d7050ffd999932ce2f..bda8d5bb72e49476a26d92cb8a7692ef519814b7 100644 --- a/drivers/net/sfc/falcon_hwdefs.h +++ b/drivers/net/sfc/falcon_hwdefs.h @@ -111,12 +111,18 @@ /* NIC status register */ #define NIC_STAT_REG 0x0200 +#define EE_STRAP_EN_LBN 31 +#define EE_STRAP_EN_WIDTH 1 +#define EE_STRAP_OVR_LBN 24 +#define EE_STRAP_OVR_WIDTH 4 #define ONCHIP_SRAM_LBN 16 #define ONCHIP_SRAM_WIDTH 1 #define SF_PRST_LBN 9 #define SF_PRST_WIDTH 1 #define EE_PRST_LBN 8 #define EE_PRST_WIDTH 1 +#define STRAP_PINS_LBN 0 +#define STRAP_PINS_WIDTH 3 /* These bit definitions are extrapolated from the list of numerical * values for STRAP_PINS. */ @@ -130,6 +136,8 @@ /* GPIO control register */ #define GPIO_CTL_REG_KER 0x0210 +#define GPIO_USE_NIC_CLK_LBN (30) +#define GPIO_USE_NIC_CLK_WIDTH (1) #define GPIO_OUTPUTS_LBN (16) #define GPIO_OUTPUTS_WIDTH (4) #define GPIO_INPUTS_LBN (8) @@ -492,6 +500,107 @@ #define MAC_MCAST_HASH_REG0_KER 0xca0 #define MAC_MCAST_HASH_REG1_KER 0xcb0 +/* GMAC configuration register 1 */ +#define GM_CFG1_REG 0xe00 +#define GM_SW_RST_LBN 31 +#define GM_SW_RST_WIDTH 1 +#define GM_LOOP_LBN 8 +#define GM_LOOP_WIDTH 1 +#define GM_RX_FC_EN_LBN 5 +#define GM_RX_FC_EN_WIDTH 1 +#define GM_TX_FC_EN_LBN 4 +#define GM_TX_FC_EN_WIDTH 1 +#define GM_RX_EN_LBN 2 +#define GM_RX_EN_WIDTH 1 +#define GM_TX_EN_LBN 0 +#define GM_TX_EN_WIDTH 1 + +/* GMAC configuration register 2 */ +#define GM_CFG2_REG 0xe10 +#define GM_PAMBL_LEN_LBN 12 +#define GM_PAMBL_LEN_WIDTH 4 +#define GM_IF_MODE_LBN 8 +#define GM_IF_MODE_WIDTH 2 +#define GM_LEN_CHK_LBN 4 +#define GM_LEN_CHK_WIDTH 1 +#define GM_PAD_CRC_EN_LBN 2 +#define GM_PAD_CRC_EN_WIDTH 1 +#define GM_FD_LBN 0 +#define GM_FD_WIDTH 1 + +/* GMAC maximum frame length register */ +#define GM_MAX_FLEN_REG 0xe40 +#define GM_MAX_FLEN_LBN 0 +#define GM_MAX_FLEN_WIDTH 16 + +/* GMAC station address register 1 */ +#define GM_ADR1_REG 0xf00 +#define GM_HWADDR_5_LBN 24 +#define GM_HWADDR_5_WIDTH 8 +#define GM_HWADDR_4_LBN 16 +#define GM_HWADDR_4_WIDTH 8 +#define GM_HWADDR_3_LBN 8 +#define GM_HWADDR_3_WIDTH 8 +#define GM_HWADDR_2_LBN 0 +#define GM_HWADDR_2_WIDTH 8 + +/* GMAC station address register 2 */ +#define GM_ADR2_REG 0xf10 +#define GM_HWADDR_1_LBN 24 +#define GM_HWADDR_1_WIDTH 8 +#define GM_HWADDR_0_LBN 16 +#define GM_HWADDR_0_WIDTH 8 + +/* GMAC FIFO configuration register 0 */ +#define GMF_CFG0_REG 0xf20 +#define GMF_FTFENREQ_LBN 12 +#define GMF_FTFENREQ_WIDTH 1 +#define GMF_STFENREQ_LBN 11 +#define GMF_STFENREQ_WIDTH 1 +#define GMF_FRFENREQ_LBN 10 +#define GMF_FRFENREQ_WIDTH 1 +#define GMF_SRFENREQ_LBN 9 +#define GMF_SRFENREQ_WIDTH 1 +#define GMF_WTMENREQ_LBN 8 +#define GMF_WTMENREQ_WIDTH 1 + +/* GMAC FIFO configuration register 1 */ +#define GMF_CFG1_REG 0xf30 +#define GMF_CFGFRTH_LBN 16 +#define GMF_CFGFRTH_WIDTH 5 +#define GMF_CFGXOFFRTX_LBN 0 +#define GMF_CFGXOFFRTX_WIDTH 16 + +/* GMAC FIFO configuration register 2 */ +#define GMF_CFG2_REG 0xf40 +#define GMF_CFGHWM_LBN 16 +#define GMF_CFGHWM_WIDTH 6 +#define GMF_CFGLWM_LBN 0 +#define GMF_CFGLWM_WIDTH 6 + +/* GMAC FIFO configuration register 3 */ +#define GMF_CFG3_REG 0xf50 +#define GMF_CFGHWMFT_LBN 16 +#define GMF_CFGHWMFT_WIDTH 6 +#define GMF_CFGFTTH_LBN 0 +#define GMF_CFGFTTH_WIDTH 6 + +/* GMAC FIFO configuration register 4 */ +#define GMF_CFG4_REG 0xf60 +#define GMF_HSTFLTRFRM_PAUSE_LBN 12 +#define GMF_HSTFLTRFRM_PAUSE_WIDTH 12 + +/* GMAC FIFO configuration register 5 */ +#define GMF_CFG5_REG 0xf70 +#define GMF_CFGHDPLX_LBN 22 +#define GMF_CFGHDPLX_WIDTH 1 +#define GMF_CFGBYTMODE_LBN 19 +#define GMF_CFGBYTMODE_WIDTH 1 +#define GMF_HSTDRPLT64_LBN 18 +#define GMF_HSTDRPLT64_WIDTH 1 +#define GMF_HSTFLTRFRMDC_PAUSE_LBN 12 +#define GMF_HSTFLTRFRMDC_PAUSE_WIDTH 1 + /* XGMAC address register low */ #define XM_ADR_LO_REG 0x1200 #define XM_ADR_3_LBN 24 @@ -944,6 +1053,8 @@ #define XG_MNT_INTR_B0_WIDTH 1 #define RX_RECOVERY_A1_LBN 11 #define RX_RECOVERY_A1_WIDTH 1 +#define XFP_PHY_INTR_LBN 10 +#define XFP_PHY_INTR_WIDTH 1 #define XG_PHY_INTR_LBN 9 #define XG_PHY_INTR_WIDTH 1 #define G_PHY1_INTR_LBN 8 @@ -962,54 +1073,103 @@ ************************************************************************** * */ + #define GRxGoodOct_offset 0x0 +#define GRxGoodOct_WIDTH 48 #define GRxBadOct_offset 0x8 +#define GRxBadOct_WIDTH 48 #define GRxMissPkt_offset 0x10 +#define GRxMissPkt_WIDTH 32 #define GRxFalseCRS_offset 0x14 +#define GRxFalseCRS_WIDTH 32 #define GRxPausePkt_offset 0x18 +#define GRxPausePkt_WIDTH 32 #define GRxBadPkt_offset 0x1C +#define GRxBadPkt_WIDTH 32 #define GRxUcastPkt_offset 0x20 +#define GRxUcastPkt_WIDTH 32 #define GRxMcastPkt_offset 0x24 +#define GRxMcastPkt_WIDTH 32 #define GRxBcastPkt_offset 0x28 +#define GRxBcastPkt_WIDTH 32 #define GRxGoodLt64Pkt_offset 0x2C +#define GRxGoodLt64Pkt_WIDTH 32 #define GRxBadLt64Pkt_offset 0x30 +#define GRxBadLt64Pkt_WIDTH 32 #define GRx64Pkt_offset 0x34 +#define GRx64Pkt_WIDTH 32 #define GRx65to127Pkt_offset 0x38 +#define GRx65to127Pkt_WIDTH 32 #define GRx128to255Pkt_offset 0x3C +#define GRx128to255Pkt_WIDTH 32 #define GRx256to511Pkt_offset 0x40 +#define GRx256to511Pkt_WIDTH 32 #define GRx512to1023Pkt_offset 0x44 +#define GRx512to1023Pkt_WIDTH 32 #define GRx1024to15xxPkt_offset 0x48 +#define GRx1024to15xxPkt_WIDTH 32 #define GRx15xxtoJumboPkt_offset 0x4C +#define GRx15xxtoJumboPkt_WIDTH 32 #define GRxGtJumboPkt_offset 0x50 +#define GRxGtJumboPkt_WIDTH 32 #define GRxFcsErr64to15xxPkt_offset 0x54 +#define GRxFcsErr64to15xxPkt_WIDTH 32 #define GRxFcsErr15xxtoJumboPkt_offset 0x58 +#define GRxFcsErr15xxtoJumboPkt_WIDTH 32 #define GRxFcsErrGtJumboPkt_offset 0x5C +#define GRxFcsErrGtJumboPkt_WIDTH 32 #define GTxGoodBadOct_offset 0x80 +#define GTxGoodBadOct_WIDTH 48 #define GTxGoodOct_offset 0x88 +#define GTxGoodOct_WIDTH 48 #define GTxSglColPkt_offset 0x90 +#define GTxSglColPkt_WIDTH 32 #define GTxMultColPkt_offset 0x94 +#define GTxMultColPkt_WIDTH 32 #define GTxExColPkt_offset 0x98 +#define GTxExColPkt_WIDTH 32 #define GTxDefPkt_offset 0x9C +#define GTxDefPkt_WIDTH 32 #define GTxLateCol_offset 0xA0 +#define GTxLateCol_WIDTH 32 #define GTxExDefPkt_offset 0xA4 +#define GTxExDefPkt_WIDTH 32 #define GTxPausePkt_offset 0xA8 +#define GTxPausePkt_WIDTH 32 #define GTxBadPkt_offset 0xAC +#define GTxBadPkt_WIDTH 32 #define GTxUcastPkt_offset 0xB0 +#define GTxUcastPkt_WIDTH 32 #define GTxMcastPkt_offset 0xB4 +#define GTxMcastPkt_WIDTH 32 #define GTxBcastPkt_offset 0xB8 +#define GTxBcastPkt_WIDTH 32 #define GTxLt64Pkt_offset 0xBC +#define GTxLt64Pkt_WIDTH 32 #define GTx64Pkt_offset 0xC0 +#define GTx64Pkt_WIDTH 32 #define GTx65to127Pkt_offset 0xC4 +#define GTx65to127Pkt_WIDTH 32 #define GTx128to255Pkt_offset 0xC8 +#define GTx128to255Pkt_WIDTH 32 #define GTx256to511Pkt_offset 0xCC +#define GTx256to511Pkt_WIDTH 32 #define GTx512to1023Pkt_offset 0xD0 +#define GTx512to1023Pkt_WIDTH 32 #define GTx1024to15xxPkt_offset 0xD4 +#define GTx1024to15xxPkt_WIDTH 32 #define GTx15xxtoJumboPkt_offset 0xD8 +#define GTx15xxtoJumboPkt_WIDTH 32 #define GTxGtJumboPkt_offset 0xDC +#define GTxGtJumboPkt_WIDTH 32 #define GTxNonTcpUdpPkt_offset 0xE0 +#define GTxNonTcpUdpPkt_WIDTH 16 #define GTxMacSrcErrPkt_offset 0xE4 +#define GTxMacSrcErrPkt_WIDTH 16 #define GTxIpSrcErrPkt_offset 0xE8 +#define GTxIpSrcErrPkt_WIDTH 16 #define GDmaDone_offset 0xEC +#define GDmaDone_WIDTH 32 #define XgRxOctets_offset 0x0 #define XgRxOctets_WIDTH 48 @@ -1150,7 +1310,6 @@ struct falcon_nvconfig_board_v3 { (((type) >> EFX_LOW_BIT(field)) & EFX_MASK32(EFX_WIDTH(field))) #define NVCONFIG_OFFSET 0x300 -#define NVCONFIG_END 0x400 #define NVCONFIG_BOARD_MAGIC_NUM 0xFA1C struct falcon_nvconfig { diff --git a/drivers/net/sfc/falcon_xmac.c b/drivers/net/sfc/falcon_xmac.c index d4012314dd01f1af81c0ca7be57da7d4dc67a639..5a03713685acda98fe958ad5c1f50e7d93a8d3dc 100644 --- a/drivers/net/sfc/falcon_xmac.c +++ b/drivers/net/sfc/falcon_xmac.c @@ -15,7 +15,6 @@ #include "falcon_hwdefs.h" #include "falcon_io.h" #include "mac.h" -#include "gmii.h" #include "mdio_10g.h" #include "phy.h" #include "boards.h" @@ -26,24 +25,6 @@ * MAC operations * *************************************************************************/ -static int falcon_reset_xmac(struct efx_nic *efx) -{ - efx_oword_t reg; - int count; - - EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1); - falcon_write(efx, ®, XM_GLB_CFG_REG); - - for (count = 0; count < 10000; count++) { /* wait upto 100ms */ - falcon_read(efx, ®, XM_GLB_CFG_REG); - if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0) - return 0; - udelay(10); - } - - EFX_ERR(efx, "timed out waiting for XMAC core reset\n"); - return -ETIMEDOUT; -} /* Configure the XAUI driver that is an output from Falcon */ static void falcon_setup_xaui(struct efx_nic *efx) @@ -99,31 +80,20 @@ int falcon_reset_xaui(struct efx_nic *efx) return -ETIMEDOUT; } -static bool falcon_xgmii_status(struct efx_nic *efx) +static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) { efx_oword_t reg; - if (falcon_rev(efx) < FALCON_REV_B0) - return true; - - /* The ISR latches, so clear it and re-read */ - falcon_read(efx, ®, XM_MGT_INT_REG_B0); - falcon_read(efx, ®, XM_MGT_INT_REG_B0); - - if (EFX_OWORD_FIELD(reg, XM_LCLFLT) || - EFX_OWORD_FIELD(reg, XM_RMTFLT)) { - EFX_INFO(efx, "MGT_INT: "EFX_DWORD_FMT"\n", EFX_DWORD_VAL(reg)); - return false; - } - - return true; -} + if ((falcon_rev(efx) != FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) + return; -static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) -{ - efx_oword_t reg; + /* We expect xgmii faults if the wireside link is up */ + if (!EFX_WORKAROUND_5147(efx) || !efx->link_up) + return; - if ((falcon_rev(efx) < FALCON_REV_B0) || LOOPBACK_INTERNAL(efx)) + /* We can only use this interrupt to signal the negative edge of + * xaui_align [we have to poll the positive edge]. */ + if (!efx->mac_up) return; /* Flush the ISR */ @@ -136,35 +106,7 @@ static void falcon_mask_status_intr(struct efx_nic *efx, bool enable) falcon_write(efx, ®, XM_MGT_INT_MSK_REG_B0); } -int falcon_init_xmac(struct efx_nic *efx) -{ - int rc; - - /* Initialize the PHY first so the clock is around */ - rc = efx->phy_op->init(efx); - if (rc) - goto fail1; - - rc = falcon_reset_xaui(efx); - if (rc) - goto fail2; - - /* Wait again. Give the PHY and MAC time to come back */ - schedule_timeout_uninterruptible(HZ / 10); - - rc = falcon_reset_xmac(efx); - if (rc) - goto fail2; - - falcon_mask_status_intr(efx, true); - return 0; - - fail2: - efx->phy_op->fini(efx); - fail1: - return rc; -} - +/* Get status of XAUI link */ bool falcon_xaui_link_ok(struct efx_nic *efx) { efx_oword_t reg; @@ -188,18 +130,10 @@ bool falcon_xaui_link_ok(struct efx_nic *efx) EFX_SET_OWORD_FIELD(reg, XX_DISPERR, XX_DISPERR_RESET); falcon_write(efx, ®, XX_CORE_STAT_REG); - /* If the link is up, then check the phy side of the xaui link - * (error conditions from the wire side propoagate back through - * the phy to the xaui side). */ - if (efx->link_up && link_ok) { + /* If the link is up, then check the phy side of the xaui link */ + if (efx->link_up && link_ok) if (efx->phy_op->mmds & (1 << MDIO_MMD_PHYXS)) link_ok = mdio_clause45_phyxgxs_lane_sync(efx); - } - - /* If the PHY and XAUI links are up, then check the mac's xgmii - * fault state */ - if (efx->link_up && link_ok) - link_ok = falcon_xgmii_status(efx); return link_ok; } @@ -208,7 +142,7 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx) { unsigned int max_frame_len; efx_oword_t reg; - bool rx_fc = !!(efx->flow_control & EFX_FC_RX); + bool rx_fc = !!(efx->link_fc & EFX_FC_RX); /* Configure MAC - cut-thru mode is hard wired on */ EFX_POPULATE_DWORD_3(reg, @@ -311,70 +245,39 @@ static void falcon_reconfigure_xgxs_core(struct efx_nic *efx) /* Try and bring the Falcon side of the Falcon-Phy XAUI link fails * to come back up. Bash it until it comes back up */ -static bool falcon_check_xaui_link_up(struct efx_nic *efx) +static void falcon_check_xaui_link_up(struct efx_nic *efx, int tries) { - int max_tries, tries; - tries = EFX_WORKAROUND_5147(efx) ? 5 : 1; - max_tries = tries; + efx->mac_up = falcon_xaui_link_ok(efx); if ((efx->loopback_mode == LOOPBACK_NETWORK) || - (efx->phy_type == PHY_TYPE_NONE) || efx_phy_mode_disabled(efx->phy_mode)) - return false; - - while (tries) { - if (falcon_xaui_link_ok(efx)) - return true; + /* XAUI link is expected to be down */ + return; - EFX_LOG(efx, "%s Clobbering XAUI (%d tries left).\n", - __func__, tries); + while (!efx->mac_up && tries) { + EFX_LOG(efx, "bashing xaui\n"); falcon_reset_xaui(efx); udelay(200); - tries--; - } - EFX_LOG(efx, "Failed to bring XAUI link back up in %d tries!\n", - max_tries); - return false; + efx->mac_up = falcon_xaui_link_ok(efx); + --tries; + } } -void falcon_reconfigure_xmac(struct efx_nic *efx) +static void falcon_reconfigure_xmac(struct efx_nic *efx) { - bool xaui_link_ok; - falcon_mask_status_intr(efx, false); - falcon_deconfigure_mac_wrapper(efx); - - /* Reconfigure the PHY, disabling transmit in mac level loopback. */ - if (LOOPBACK_INTERNAL(efx)) - efx->phy_mode |= PHY_MODE_TX_DISABLED; - else - efx->phy_mode &= ~PHY_MODE_TX_DISABLED; - efx->phy_op->reconfigure(efx); - falcon_reconfigure_xgxs_core(efx); falcon_reconfigure_xmac_core(efx); falcon_reconfigure_mac_wrapper(efx); - /* Ensure XAUI link is up */ - xaui_link_ok = falcon_check_xaui_link_up(efx); - - if (xaui_link_ok && efx->link_up) - falcon_mask_status_intr(efx, true); -} - -void falcon_fini_xmac(struct efx_nic *efx) -{ - /* Isolate the MAC - PHY */ - falcon_deconfigure_mac_wrapper(efx); - - /* Potentially power down the PHY */ - efx->phy_op->fini(efx); + falcon_check_xaui_link_up(efx, 5); + falcon_mask_status_intr(efx, true); } -void falcon_update_stats_xmac(struct efx_nic *efx) +static void falcon_update_stats_xmac(struct efx_nic *efx) { struct efx_mac_stats *mac_stats = &efx->mac_stats; int rc; @@ -439,97 +342,35 @@ void falcon_update_stats_xmac(struct efx_nic *efx) mac_stats->rx_control * 64); } -int falcon_check_xmac(struct efx_nic *efx) +static void falcon_xmac_irq(struct efx_nic *efx) { - bool xaui_link_ok; - int rc; - - if ((efx->loopback_mode == LOOPBACK_NETWORK) || - efx_phy_mode_disabled(efx->phy_mode)) - return 0; - - falcon_mask_status_intr(efx, false); - xaui_link_ok = falcon_xaui_link_ok(efx); - - if (EFX_WORKAROUND_5147(efx) && !xaui_link_ok) - falcon_reset_xaui(efx); - - /* Call the PHY check_hw routine */ - rc = efx->phy_op->check_hw(efx); - - /* Unmask interrupt if everything was (and still is) ok */ - if (xaui_link_ok && efx->link_up) - falcon_mask_status_intr(efx, true); - - return rc; -} - -/* Simulate a PHY event */ -void falcon_xmac_sim_phy_event(struct efx_nic *efx) -{ - efx_qword_t phy_event; - - EFX_POPULATE_QWORD_2(phy_event, - EV_CODE, GLOBAL_EV_DECODE, - XG_PHY_INTR, 1); - falcon_generate_event(&efx->channel[0], &phy_event); + /* The XGMII link has a transient fault, which indicates either: + * - there's a transient xgmii fault + * - falcon's end of the xaui link may need a kick + * - the wire-side link may have gone down, but the lasi/poll() + * hasn't noticed yet. + * + * We only want to even bother polling XAUI if we're confident it's + * not (1) or (3). In both cases, the only reliable way to spot this + * is to wait a bit. We do this here by forcing the mac link state + * to down, and waiting for the mac poll to come round and check + */ + efx->mac_up = false; } -int falcon_xmac_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +static void falcon_poll_xmac(struct efx_nic *efx) { - mdio_clause45_get_settings(efx, ecmd); - ecmd->transceiver = XCVR_INTERNAL; - ecmd->phy_address = efx->mii.phy_id; - ecmd->autoneg = AUTONEG_DISABLE; - ecmd->duplex = DUPLEX_FULL; - return 0; -} + if (!EFX_WORKAROUND_5147(efx) || !efx->link_up || efx->mac_up) + return; -int falcon_xmac_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) -{ - if (ecmd->transceiver != XCVR_INTERNAL) - return -EINVAL; - if (ecmd->autoneg != AUTONEG_DISABLE) - return -EINVAL; - if (ecmd->duplex != DUPLEX_FULL) - return -EINVAL; - - return mdio_clause45_set_settings(efx, ecmd); + falcon_mask_status_intr(efx, false); + falcon_check_xaui_link_up(efx, 1); + falcon_mask_status_intr(efx, true); } - -int falcon_xmac_set_pause(struct efx_nic *efx, enum efx_fc_type flow_control) -{ - bool reset; - - if (flow_control & EFX_FC_AUTO) { - EFX_LOG(efx, "10G does not support flow control " - "autonegotiation\n"); - return -EINVAL; - } - - if ((flow_control & EFX_FC_TX) && !(flow_control & EFX_FC_RX)) - return -EINVAL; - - /* TX flow control may automatically turn itself off if the - * link partner (intermittently) stops responding to pause - * frames. There isn't any indication that this has happened, - * so the best we do is leave it up to the user to spot this - * and fix it be cycling transmit flow control on this end. */ - reset = ((flow_control & EFX_FC_TX) && - !(efx->flow_control & EFX_FC_TX)); - if (EFX_WORKAROUND_11482(efx) && reset) { - if (falcon_rev(efx) >= FALCON_REV_B0) { - /* Recover by resetting the EM block */ - if (efx->link_up) - falcon_drain_tx_fifo(efx); - } else { - /* Schedule a reset to recover */ - efx_schedule_reset(efx, RESET_TYPE_INVISIBLE); - } - } - - efx->flow_control = flow_control; - - return 0; -} +struct efx_mac_operations falcon_xmac_operations = { + .reconfigure = falcon_reconfigure_xmac, + .update_stats = falcon_update_stats_xmac, + .irq = falcon_xmac_irq, + .poll = falcon_poll_xmac, +}; diff --git a/drivers/net/sfc/gmii.h b/drivers/net/sfc/gmii.h index d25bbd1297f40a240025d812fa8de8af8fa8ca1f..dfccaa7b573ef414bec46f36f068cd69326b1117 100644 --- a/drivers/net/sfc/gmii.h +++ b/drivers/net/sfc/gmii.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006 Solarflare Communications Inc. + * Copyright 2006-2008 Solarflare Communications 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 @@ -57,139 +57,4 @@ #define ISR_POLARITY_CHG 0x0002 /* Bit 1 - polarity changed */ #define ISR_JABBER 0x0001 /* Bit 0 - jabber */ -/* Logically extended advertisement register */ -#define GM_ADVERTISE_SLCT ADVERTISE_SLCT -#define GM_ADVERTISE_CSMA ADVERTISE_CSMA -#define GM_ADVERTISE_10HALF ADVERTISE_10HALF -#define GM_ADVERTISE_1000XFULL ADVERTISE_1000XFULL -#define GM_ADVERTISE_10FULL ADVERTISE_10FULL -#define GM_ADVERTISE_1000XHALF ADVERTISE_1000XHALF -#define GM_ADVERTISE_100HALF ADVERTISE_100HALF -#define GM_ADVERTISE_1000XPAUSE ADVERTISE_1000XPAUSE -#define GM_ADVERTISE_100FULL ADVERTISE_100FULL -#define GM_ADVERTISE_1000XPSE_ASYM ADVERTISE_1000XPSE_ASYM -#define GM_ADVERTISE_100BASE4 ADVERTISE_100BASE4 -#define GM_ADVERTISE_PAUSE_CAP ADVERTISE_PAUSE_CAP -#define GM_ADVERTISE_PAUSE_ASYM ADVERTISE_PAUSE_ASYM -#define GM_ADVERTISE_RESV ADVERTISE_RESV -#define GM_ADVERTISE_RFAULT ADVERTISE_RFAULT -#define GM_ADVERTISE_LPACK ADVERTISE_LPACK -#define GM_ADVERTISE_NPAGE ADVERTISE_NPAGE -#define GM_ADVERTISE_1000FULL (ADVERTISE_1000FULL << 8) -#define GM_ADVERTISE_1000HALF (ADVERTISE_1000HALF << 8) -#define GM_ADVERTISE_1000 (GM_ADVERTISE_1000FULL | \ - GM_ADVERTISE_1000HALF) -#define GM_ADVERTISE_FULL (GM_ADVERTISE_1000FULL | \ - ADVERTISE_FULL) -#define GM_ADVERTISE_ALL (GM_ADVERTISE_1000FULL | \ - GM_ADVERTISE_1000HALF | \ - ADVERTISE_ALL) - -/* Logically extended link partner ability register */ -#define GM_LPA_SLCT LPA_SLCT -#define GM_LPA_10HALF LPA_10HALF -#define GM_LPA_1000XFULL LPA_1000XFULL -#define GM_LPA_10FULL LPA_10FULL -#define GM_LPA_1000XHALF LPA_1000XHALF -#define GM_LPA_100HALF LPA_100HALF -#define GM_LPA_1000XPAUSE LPA_1000XPAUSE -#define GM_LPA_100FULL LPA_100FULL -#define GM_LPA_1000XPAUSE_ASYM LPA_1000XPAUSE_ASYM -#define GM_LPA_100BASE4 LPA_100BASE4 -#define GM_LPA_PAUSE_CAP LPA_PAUSE_CAP -#define GM_LPA_PAUSE_ASYM LPA_PAUSE_ASYM -#define GM_LPA_RESV LPA_RESV -#define GM_LPA_RFAULT LPA_RFAULT -#define GM_LPA_LPACK LPA_LPACK -#define GM_LPA_NPAGE LPA_NPAGE -#define GM_LPA_1000FULL (LPA_1000FULL << 6) -#define GM_LPA_1000HALF (LPA_1000HALF << 6) -#define GM_LPA_10000FULL 0x00040000 -#define GM_LPA_10000HALF 0x00080000 -#define GM_LPA_DUPLEX (GM_LPA_1000FULL | GM_LPA_10000FULL \ - | LPA_DUPLEX) -#define GM_LPA_10 (LPA_10FULL | LPA_10HALF) -#define GM_LPA_100 LPA_100 -#define GM_LPA_1000 (GM_LPA_1000FULL | GM_LPA_1000HALF) -#define GM_LPA_10000 (GM_LPA_10000FULL | GM_LPA_10000HALF) - -/* Retrieve GMII autonegotiation advertised abilities - * - * The MII advertisment register (MII_ADVERTISE) is logically extended - * to include advertisement bits ADVERTISE_1000FULL and - * ADVERTISE_1000HALF from MII_CTRL1000. The result can be tested - * against the GM_ADVERTISE_xxx constants. - */ -static inline unsigned int gmii_advertised(struct mii_if_info *gmii) -{ - unsigned int advertise; - unsigned int ctrl1000; - - advertise = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_ADVERTISE); - ctrl1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_CTRL1000); - return (((ctrl1000 << 8) & GM_ADVERTISE_1000) | advertise); -} - -/* Retrieve GMII autonegotiation link partner abilities - * - * The MII link partner ability register (MII_LPA) is logically - * extended by adding bits LPA_1000HALF and LPA_1000FULL from - * MII_STAT1000. The result can be tested against the GM_LPA_xxx - * constants. - */ -static inline unsigned int gmii_lpa(struct mii_if_info *gmii) -{ - unsigned int lpa; - unsigned int stat1000; - - lpa = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_LPA); - stat1000 = gmii->mdio_read(gmii->dev, gmii->phy_id, MII_STAT1000); - return (((stat1000 << 6) & GM_LPA_1000) | lpa); -} - -/* Calculate GMII autonegotiated link technology - * - * "negotiated" should be the result of gmii_advertised() logically - * ANDed with the result of gmii_lpa(). - * - * "tech" will be negotiated with the unused bits masked out. For - * example, if both ends of the link are capable of both - * GM_LPA_1000FULL and GM_LPA_100FULL, GM_LPA_100FULL will be masked - * out. - */ -static inline unsigned int gmii_nway_result(unsigned int negotiated) -{ - unsigned int other_bits; - - /* Mask out the speed and duplexity bits */ - other_bits = negotiated & ~(GM_LPA_10 | GM_LPA_100 | GM_LPA_1000); - - if (negotiated & GM_LPA_1000FULL) - return (other_bits | GM_LPA_1000FULL); - else if (negotiated & GM_LPA_1000HALF) - return (other_bits | GM_LPA_1000HALF); - else - return (other_bits | mii_nway_result(negotiated)); -} - -/* Calculate GMII non-autonegotiated link technology - * - * This provides an equivalent to gmii_nway_result for the case when - * autonegotiation is disabled. - */ -static inline unsigned int gmii_forced_result(unsigned int bmcr) -{ - unsigned int result; - int full_duplex; - - full_duplex = bmcr & BMCR_FULLDPLX; - if (bmcr & BMCR_SPEED1000) - result = full_duplex ? GM_LPA_1000FULL : GM_LPA_1000HALF; - else if (bmcr & BMCR_SPEED100) - result = full_duplex ? GM_LPA_100FULL : GM_LPA_100HALF; - else - result = full_duplex ? GM_LPA_10FULL : GM_LPA_10HALF; - return result; -} - #endif /* EFX_GMII_H */ diff --git a/drivers/net/sfc/mac.h b/drivers/net/sfc/mac.h index a31571c6913780095181070d3b6675ac0674973e..4e7074278fe1f7b4fde0c619d6b1160502139efd 100644 --- a/drivers/net/sfc/mac.h +++ b/drivers/net/sfc/mac.h @@ -1,7 +1,7 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards * Copyright 2005-2006 Fen Systems Ltd. - * Copyright 2006-2007 Solarflare Communications Inc. + * Copyright 2006-2008 Solarflare Communications 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 @@ -13,17 +13,7 @@ #include "net_driver.h" -extern int falcon_init_xmac(struct efx_nic *efx); -extern void falcon_reconfigure_xmac(struct efx_nic *efx); -extern void falcon_update_stats_xmac(struct efx_nic *efx); -extern void falcon_fini_xmac(struct efx_nic *efx); -extern int falcon_check_xmac(struct efx_nic *efx); -extern void falcon_xmac_sim_phy_event(struct efx_nic *efx); -extern int falcon_xmac_get_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd); -extern int falcon_xmac_set_settings(struct efx_nic *efx, - struct ethtool_cmd *ecmd); -extern int falcon_xmac_set_pause(struct efx_nic *efx, - enum efx_fc_type pause_params); +extern struct efx_mac_operations falcon_gmac_operations; +extern struct efx_mac_operations falcon_xmac_operations; #endif diff --git a/drivers/net/sfc/mdio_10g.c b/drivers/net/sfc/mdio_10g.c index 003e48dcb2f3f67ea28f94d3731f3a7cbd9f7e88..f6a16428113dd3d61b0376a9ccd84df84c0262e4 100644 --- a/drivers/net/sfc/mdio_10g.c +++ b/drivers/net/sfc/mdio_10g.c @@ -47,13 +47,16 @@ static int mdio_clause45_check_mmd(struct efx_nic *efx, int mmd, if (LOOPBACK_INTERNAL(efx)) return 0; - /* Read MMD STATUS2 to check it is responding. */ - status = mdio_clause45_read(efx, phy_id, mmd, MDIO_MMDREG_STAT2); - if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & - ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != - MDIO_MMDREG_STAT2_PRESENT_VAL) { - EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); - return -EIO; + if (mmd != MDIO_MMD_AN) { + /* Read MMD STATUS2 to check it is responding. */ + status = mdio_clause45_read(efx, phy_id, mmd, + MDIO_MMDREG_STAT2); + if (((status >> MDIO_MMDREG_STAT2_PRESENT_LBN) & + ((1 << MDIO_MMDREG_STAT2_PRESENT_WIDTH) - 1)) != + MDIO_MMDREG_STAT2_PRESENT_VAL) { + EFX_ERR(efx, "PHY MMD %d not responding.\n", mmd); + return -EIO; + } } /* Read MMD STATUS 1 to check for fault. */ @@ -121,16 +124,18 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, int mdio_clause45_check_mmds(struct efx_nic *efx, unsigned int mmd_mask, unsigned int fatal_mask) { - int devices, mmd = 0; - int probe_mmd; + u32 devices; + int mmd = 0, probe_mmd; /* Historically we have probed the PHYXS to find out what devices are * present,but that doesn't work so well if the PHYXS isn't expected * to exist, if so just find the first item in the list supplied. */ - probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS0_PHYXS) ? MDIO_MMD_PHYXS : + probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS_PHYXS) ? MDIO_MMD_PHYXS : __ffs(mmd_mask); - devices = mdio_clause45_read(efx, efx->mii.phy_id, - probe_mmd, MDIO_MMDREG_DEVS0); + devices = (mdio_clause45_read(efx, efx->mii.phy_id, + probe_mmd, MDIO_MMDREG_DEVS0) | + mdio_clause45_read(efx, efx->mii.phy_id, + probe_mmd, MDIO_MMDREG_DEVS1) << 16); /* Check all the expected MMDs are present */ if (devices < 0) { @@ -162,7 +167,7 @@ int mdio_clause45_check_mmds(struct efx_nic *efx, bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) { int phy_id = efx->mii.phy_id; - int status; + u32 reg; bool ok = true; int mmd = 0; @@ -174,26 +179,33 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) return false; else if (efx_phy_mode_disabled(efx->phy_mode)) return false; - else if (efx->loopback_mode == LOOPBACK_PHYXS) - mmd_mask &= ~(MDIO_MMDREG_DEVS0_PHYXS | - MDIO_MMDREG_DEVS0_PCS | - MDIO_MMDREG_DEVS0_PMAPMD); - else if (efx->loopback_mode == LOOPBACK_PCS) - mmd_mask &= ~(MDIO_MMDREG_DEVS0_PCS | - MDIO_MMDREG_DEVS0_PMAPMD); + else if (efx->loopback_mode == LOOPBACK_PHYXS) { + mmd_mask &= ~(MDIO_MMDREG_DEVS_PHYXS | + MDIO_MMDREG_DEVS_PCS | + MDIO_MMDREG_DEVS_PMAPMD | + MDIO_MMDREG_DEVS_AN); + if (!mmd_mask) { + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, + MDIO_PHYXS_STATUS2); + return !(reg & (1 << MDIO_PHYXS_STATUS2_RX_FAULT_LBN)); + } + } else if (efx->loopback_mode == LOOPBACK_PCS) + mmd_mask &= ~(MDIO_MMDREG_DEVS_PCS | + MDIO_MMDREG_DEVS_PMAPMD | + MDIO_MMDREG_DEVS_AN); else if (efx->loopback_mode == LOOPBACK_PMAPMD) - mmd_mask &= ~MDIO_MMDREG_DEVS0_PMAPMD; + mmd_mask &= ~(MDIO_MMDREG_DEVS_PMAPMD | + MDIO_MMDREG_DEVS_AN); while (mmd_mask) { if (mmd_mask & 1) { /* Double reads because link state is latched, and a * read moves the current state into the register */ - status = mdio_clause45_read(efx, phy_id, - mmd, MDIO_MMDREG_STAT1); - status = mdio_clause45_read(efx, phy_id, - mmd, MDIO_MMDREG_STAT1); - - ok = ok && (status & (1 << MDIO_MMDREG_STAT1_LINK_LBN)); + reg = mdio_clause45_read(efx, phy_id, + mmd, MDIO_MMDREG_STAT1); + reg = mdio_clause45_read(efx, phy_id, + mmd, MDIO_MMDREG_STAT1); + ok = ok && (reg & (1 << MDIO_MMDREG_STAT1_LINK_LBN)); } mmd_mask = (mmd_mask >> 1); mmd++; @@ -203,61 +215,73 @@ bool mdio_clause45_links_ok(struct efx_nic *efx, unsigned int mmd_mask) void mdio_clause45_transmit_disable(struct efx_nic *efx) { - int phy_id = efx->mii.phy_id; - int ctrl1, ctrl2; - - ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_TXDIS); - if (efx->phy_mode & PHY_MODE_TX_DISABLED) - ctrl2 |= (1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); - else - ctrl1 &= ~(1 << MDIO_MMDREG_TXDIS_GLOBAL_LBN); - if (ctrl1 != ctrl2) - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_TXDIS, ctrl2); + mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_TXDIS, MDIO_MMDREG_TXDIS_GLOBAL_LBN, + efx->phy_mode & PHY_MODE_TX_DISABLED); } void mdio_clause45_phy_reconfigure(struct efx_nic *efx) { int phy_id = efx->mii.phy_id; - int ctrl1, ctrl2; - /* Handle (with debouncing) PMA/PMD loopback */ - ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1); - - if (efx->loopback_mode == LOOPBACK_PMAPMD) - ctrl2 |= (1 << MDIO_PMAPMD_CTRL1_LBACK_LBN); - else - ctrl2 &= ~(1 << MDIO_PMAPMD_CTRL1_LBACK_LBN); + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_CTRL1, MDIO_PMAPMD_CTRL1_LBACK_LBN, + efx->loopback_mode == LOOPBACK_PMAPMD); + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PCS, + MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN, + efx->loopback_mode == LOOPBACK_PCS); + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS, + MDIO_MMDREG_CTRL1, MDIO_MMDREG_CTRL1_LBACK_LBN, + efx->loopback_mode == LOOPBACK_NETWORK); +} - if (ctrl1 != ctrl2) - mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, - MDIO_MMDREG_CTRL1, ctrl2); +static void mdio_clause45_set_mmd_lpower(struct efx_nic *efx, + int lpower, int mmd) +{ + int phy = efx->mii.phy_id; + int stat = mdio_clause45_read(efx, phy, mmd, MDIO_MMDREG_STAT1); - /* Handle (with debouncing) PCS loopback */ - ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, - MDIO_MMDREG_CTRL1); - if (efx->loopback_mode == LOOPBACK_PCS) - ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN); - else - ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN); + EFX_TRACE(efx, "Setting low power mode for MMD %d to %d\n", + mmd, lpower); - if (ctrl1 != ctrl2) - mdio_clause45_write(efx, phy_id, MDIO_MMD_PCS, - MDIO_MMDREG_CTRL1, ctrl2); + if (stat & (1 << MDIO_MMDREG_STAT1_LPABLE_LBN)) { + mdio_clause45_set_flag(efx, phy, mmd, MDIO_MMDREG_CTRL1, + MDIO_MMDREG_CTRL1_LPOWER_LBN, lpower); + } +} - /* Handle (with debouncing) PHYXS network loopback */ - ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, - MDIO_MMDREG_CTRL1); - if (efx->loopback_mode == LOOPBACK_NETWORK) - ctrl2 |= (1 << MDIO_MMDREG_CTRL1_LBACK_LBN); - else - ctrl2 &= ~(1 << MDIO_MMDREG_CTRL1_LBACK_LBN); +void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, + int low_power, unsigned int mmd_mask) +{ + int mmd = 0; + mmd_mask &= ~MDIO_MMDREG_DEVS_AN; + while (mmd_mask) { + if (mmd_mask & 1) + mdio_clause45_set_mmd_lpower(efx, low_power, mmd); + mmd_mask = (mmd_mask >> 1); + mmd++; + } +} - if (ctrl1 != ctrl2) - mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS, - MDIO_MMDREG_CTRL1, ctrl2); +static u32 mdio_clause45_get_an(struct efx_nic *efx, u16 addr, u32 xnp) +{ + int phy_id = efx->mii.phy_id; + u32 result = 0; + int reg; + + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, addr); + if (reg & ADVERTISE_10HALF) + result |= ADVERTISED_10baseT_Half; + if (reg & ADVERTISE_10FULL) + result |= ADVERTISED_10baseT_Full; + if (reg & ADVERTISE_100HALF) + result |= ADVERTISED_100baseT_Half; + if (reg & ADVERTISE_100FULL) + result |= ADVERTISED_100baseT_Full; + if (reg & LPA_RESV) + result |= xnp; + + return result; } /** @@ -266,95 +290,290 @@ void mdio_clause45_phy_reconfigure(struct efx_nic *efx) * @ecmd: Buffer for settings * * On return the 'port', 'speed', 'supported' and 'advertising' fields of - * ecmd have been filled out based on the PMA type. + * ecmd have been filled out. */ void mdio_clause45_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - int pma_type; + mdio_clause45_get_settings_ext(efx, ecmd, 0, 0); +} - /* If no PMA is present we are presumably talking something XAUI-ish - * like CX4. Which we report as FIBRE (see below) */ - if ((efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_PMAPMD)) == 0) { - ecmd->speed = SPEED_10000; - ecmd->port = PORT_FIBRE; - ecmd->supported = SUPPORTED_FIBRE; - ecmd->advertising = ADVERTISED_FIBRE; - return; - } +/** + * mdio_clause45_get_settings_ext - Read (some of) the PHY settings over MDIO. + * @efx: Efx NIC + * @ecmd: Buffer for settings + * @xnp: Advertised Extended Next Page state + * @xnp_lpa: Link Partner's advertised XNP state + * + * On return the 'port', 'speed', 'supported' and 'advertising' fields of + * ecmd have been filled out. + */ +void mdio_clause45_get_settings_ext(struct efx_nic *efx, + struct ethtool_cmd *ecmd, + u32 xnp, u32 xnp_lpa) +{ + int phy_id = efx->mii.phy_id; + int reg; - pma_type = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL2); - pma_type &= MDIO_PMAPMD_CTRL2_TYPE_MASK; + ecmd->transceiver = XCVR_INTERNAL; + ecmd->phy_address = phy_id; - switch (pma_type) { - /* We represent CX4 as fibre in the absence of anything - better. */ - case MDIO_PMAPMD_CTRL2_10G_CX4: - ecmd->speed = SPEED_10000; - ecmd->port = PORT_FIBRE; - ecmd->supported = SUPPORTED_FIBRE; - ecmd->advertising = ADVERTISED_FIBRE; - break; - /* 10G Base-T */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_CTRL2); + switch (reg & MDIO_PMAPMD_CTRL2_TYPE_MASK) { case MDIO_PMAPMD_CTRL2_10G_BT: - ecmd->speed = SPEED_10000; - ecmd->port = PORT_TP; - ecmd->supported = SUPPORTED_TP | SUPPORTED_10000baseT_Full; - ecmd->advertising = (ADVERTISED_FIBRE - | ADVERTISED_10000baseT_Full); - break; case MDIO_PMAPMD_CTRL2_1G_BT: - ecmd->speed = SPEED_1000; - ecmd->port = PORT_TP; - ecmd->supported = SUPPORTED_TP | SUPPORTED_1000baseT_Full; - ecmd->advertising = (ADVERTISED_FIBRE - | ADVERTISED_1000baseT_Full); - break; case MDIO_PMAPMD_CTRL2_100_BT: - ecmd->speed = SPEED_100; - ecmd->port = PORT_TP; - ecmd->supported = SUPPORTED_TP | SUPPORTED_100baseT_Full; - ecmd->advertising = (ADVERTISED_FIBRE - | ADVERTISED_100baseT_Full); - break; case MDIO_PMAPMD_CTRL2_10_BT: - ecmd->speed = SPEED_10; ecmd->port = PORT_TP; - ecmd->supported = SUPPORTED_TP | SUPPORTED_10baseT_Full; - ecmd->advertising = ADVERTISED_FIBRE | ADVERTISED_10baseT_Full; + ecmd->supported = SUPPORTED_TP; + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_SPEED); + if (reg & (1 << MDIO_MMDREG_SPEED_10G_LBN)) + ecmd->supported |= SUPPORTED_10000baseT_Full; + if (reg & (1 << MDIO_MMDREG_SPEED_1000M_LBN)) + ecmd->supported |= (SUPPORTED_1000baseT_Full | + SUPPORTED_1000baseT_Half); + if (reg & (1 << MDIO_MMDREG_SPEED_100M_LBN)) + ecmd->supported |= (SUPPORTED_100baseT_Full | + SUPPORTED_100baseT_Half); + if (reg & (1 << MDIO_MMDREG_SPEED_10M_LBN)) + ecmd->supported |= (SUPPORTED_10baseT_Full | + SUPPORTED_10baseT_Half); + ecmd->advertising = ADVERTISED_TP; break; - /* All the other defined modes are flavours of - * 10G optical */ + + /* We represent CX4 as fibre in the absence of anything better */ + case MDIO_PMAPMD_CTRL2_10G_CX4: + /* All the other defined modes are flavours of optical */ default: - ecmd->speed = SPEED_10000; ecmd->port = PORT_FIBRE; ecmd->supported = SUPPORTED_FIBRE; ecmd->advertising = ADVERTISED_FIBRE; break; } + + if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { + ecmd->supported |= SUPPORTED_Autoneg; + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_CTRL1); + if (reg & BMCR_ANENABLE) { + ecmd->autoneg = AUTONEG_ENABLE; + ecmd->advertising |= + ADVERTISED_Autoneg | + mdio_clause45_get_an(efx, + MDIO_AN_ADVERTISE, xnp); + } else + ecmd->autoneg = AUTONEG_DISABLE; + } else + ecmd->autoneg = AUTONEG_DISABLE; + + if (ecmd->autoneg) { + /* If AN is complete, report best common mode, + * otherwise report best advertised mode. */ + u32 common = ecmd->advertising; + if (mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_STAT1) & + (1 << MDIO_AN_STATUS_AN_DONE_LBN)) { + common &= mdio_clause45_get_an(efx, MDIO_AN_LPA, + xnp_lpa); + } + if (common & ADVERTISED_10000baseT_Full) { + ecmd->speed = SPEED_10000; + ecmd->duplex = DUPLEX_FULL; + } else if (common & (ADVERTISED_1000baseT_Full | + ADVERTISED_1000baseT_Half)) { + ecmd->speed = SPEED_1000; + ecmd->duplex = !!(common & ADVERTISED_1000baseT_Full); + } else if (common & (ADVERTISED_100baseT_Full | + ADVERTISED_100baseT_Half)) { + ecmd->speed = SPEED_100; + ecmd->duplex = !!(common & ADVERTISED_100baseT_Full); + } else { + ecmd->speed = SPEED_10; + ecmd->duplex = !!(common & ADVERTISED_10baseT_Full); + } + } else { + /* Report forced settings */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_CTRL1); + ecmd->speed = (((reg & BMCR_SPEED1000) ? 100 : 1) * + ((reg & BMCR_SPEED100) ? 100 : 10)); + ecmd->duplex = (reg & BMCR_FULLDPLX || + ecmd->speed == SPEED_10000); + } } /** * mdio_clause45_set_settings - Set (some of) the PHY settings over MDIO. * @efx: Efx NIC * @ecmd: New settings - * - * Currently this just enforces that we are _not_ changing the - * 'port', 'speed', 'supported' or 'advertising' settings as these - * cannot be changed on any currently supported PHY. */ int mdio_clause45_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) { - struct ethtool_cmd tmpcmd; - mdio_clause45_get_settings(efx, &tmpcmd); - /* None of the current PHYs support more than one mode - * of operation (and only 10GBT ever will), so keep things - * simple for now */ - if ((ecmd->speed == tmpcmd.speed) && (ecmd->port == tmpcmd.port) && - (ecmd->supported == tmpcmd.supported) && - (ecmd->advertising == tmpcmd.advertising)) + int phy_id = efx->mii.phy_id; + struct ethtool_cmd prev; + u32 required; + int ctrl1_bits, reg; + + efx->phy_op->get_settings(efx, &prev); + + if (ecmd->advertising == prev.advertising && + ecmd->speed == prev.speed && + ecmd->duplex == prev.duplex && + ecmd->port == prev.port && + ecmd->autoneg == prev.autoneg) return 0; - return -EOPNOTSUPP; + + /* We can only change these settings for -T PHYs */ + if (prev.port != PORT_TP || ecmd->port != PORT_TP) + return -EINVAL; + + /* Check that PHY supports these settings and work out the + * basic control bits */ + if (ecmd->duplex) { + switch (ecmd->speed) { + case SPEED_10: + ctrl1_bits = BMCR_FULLDPLX; + required = SUPPORTED_10baseT_Full; + break; + case SPEED_100: + ctrl1_bits = BMCR_SPEED100 | BMCR_FULLDPLX; + required = SUPPORTED_100baseT_Full; + break; + case SPEED_1000: + ctrl1_bits = BMCR_SPEED1000 | BMCR_FULLDPLX; + required = SUPPORTED_1000baseT_Full; + break; + case SPEED_10000: + ctrl1_bits = (BMCR_SPEED1000 | BMCR_SPEED100 | + BMCR_FULLDPLX); + required = SUPPORTED_10000baseT_Full; + break; + default: + return -EINVAL; + } + } else { + switch (ecmd->speed) { + case SPEED_10: + ctrl1_bits = 0; + required = SUPPORTED_10baseT_Half; + break; + case SPEED_100: + ctrl1_bits = BMCR_SPEED100; + required = SUPPORTED_100baseT_Half; + break; + case SPEED_1000: + ctrl1_bits = BMCR_SPEED1000; + required = SUPPORTED_1000baseT_Half; + break; + default: + return -EINVAL; + } + } + if (ecmd->autoneg) + required |= SUPPORTED_Autoneg; + required |= ecmd->advertising; + if (required & ~prev.supported) + return -EINVAL; + + /* Set the basic control bits */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + MDIO_MMDREG_CTRL1); + reg &= ~(BMCR_SPEED1000 | BMCR_SPEED100 | BMCR_FULLDPLX | 0x003c); + reg |= ctrl1_bits; + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, MDIO_MMDREG_CTRL1, + reg); + + /* Set the AN registers */ + if (ecmd->autoneg != prev.autoneg || + ecmd->advertising != prev.advertising) { + bool xnp = false; + + if (efx->phy_op->set_xnp_advertise) + xnp = efx->phy_op->set_xnp_advertise(efx, + ecmd->advertising); + + if (ecmd->autoneg) { + reg = 0; + if (ecmd->advertising & ADVERTISED_10baseT_Half) + reg |= ADVERTISE_10HALF; + if (ecmd->advertising & ADVERTISED_10baseT_Full) + reg |= ADVERTISE_10FULL; + if (ecmd->advertising & ADVERTISED_100baseT_Half) + reg |= ADVERTISE_100HALF; + if (ecmd->advertising & ADVERTISED_100baseT_Full) + reg |= ADVERTISE_100FULL; + if (xnp) + reg |= ADVERTISE_RESV; + mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_ADVERTISE, reg); + } + + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_CTRL1); + if (ecmd->autoneg) + reg |= BMCR_ANENABLE | BMCR_ANRESTART; + else + reg &= ~BMCR_ANENABLE; + if (xnp) + reg |= 1 << MDIO_AN_CTRL_XNP_LBN; + else + reg &= ~(1 << MDIO_AN_CTRL_XNP_LBN); + mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_CTRL1, reg); + } + + return 0; +} + +void mdio_clause45_set_pause(struct efx_nic *efx) +{ + int phy_id = efx->mii.phy_id; + int reg; + + if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) { + /* Set pause capability advertising */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_ADVERTISE); + reg &= ~(ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM); + reg |= efx_fc_advertise(efx->wanted_fc); + mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_ADVERTISE, reg); + + /* Restart auto-negotiation */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_CTRL1); + if (reg & BMCR_ANENABLE) { + reg |= BMCR_ANRESTART; + mdio_clause45_write(efx, phy_id, MDIO_MMD_AN, + MDIO_MMDREG_CTRL1, reg); + } + } +} + +enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx) +{ + int phy_id = efx->mii.phy_id; + int lpa; + + if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN))) + return efx->wanted_fc; + lpa = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, MDIO_AN_LPA); + return efx_fc_resolve(efx->wanted_fc, lpa); +} + +void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, + u16 addr, int bit, bool sense) +{ + int old_val = mdio_clause45_read(efx, prt, dev, addr); + int new_val; + + if (sense) + new_val = old_val | (1 << bit); + else + new_val = old_val & ~(1 << bit); + if (old_val != new_val) + mdio_clause45_write(efx, prt, dev, addr, new_val); } diff --git a/drivers/net/sfc/mdio_10g.h b/drivers/net/sfc/mdio_10g.h index 19c42eaf7fb47d714087c62efed01f3242b802c3..09bf801d0569a2199c79d89007bc7518e0163cdc 100644 --- a/drivers/net/sfc/mdio_10g.h +++ b/drivers/net/sfc/mdio_10g.h @@ -33,6 +33,8 @@ #define MDIO_MMD_TC (6) /* Auto negotiation */ #define MDIO_MMD_AN (7) +/* Clause 22 extension */ +#define MDIO_MMD_C22EXT 29 /* Generic register locations */ #define MDIO_MMDREG_CTRL1 (0) @@ -54,6 +56,9 @@ /* Loopback bit for WIS, PCS, PHYSX and DTEXS */ #define MDIO_MMDREG_CTRL1_LBACK_LBN (14) #define MDIO_MMDREG_CTRL1_LBACK_WIDTH (1) +/* Low power */ +#define MDIO_MMDREG_CTRL1_LPOWER_LBN (11) +#define MDIO_MMDREG_CTRL1_LPOWER_WIDTH (1) /* Bits in MMDREG_STAT1 */ #define MDIO_MMDREG_STAT1_FAULT_LBN (7) @@ -70,14 +75,26 @@ #define MDIO_ID_MODEL(_id32) ((_id32 >> 4) & 0x3f) #define MDIO_ID_OUI(_id32) (_id32 >> 10) -/* Bits in MMDREG_DEVS0. Someone thoughtfully layed things out +/* Bits in MMDREG_DEVS0/1. Someone thoughtfully layed things out * so the 'bit present' bit number of an MMD is the number of * that MMD */ #define DEV_PRESENT_BIT(_b) (1 << _b) -#define MDIO_MMDREG_DEVS0_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS) -#define MDIO_MMDREG_DEVS0_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS) -#define MDIO_MMDREG_DEVS0_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD) +#define MDIO_MMDREG_DEVS_PHYXS DEV_PRESENT_BIT(MDIO_MMD_PHYXS) +#define MDIO_MMDREG_DEVS_PCS DEV_PRESENT_BIT(MDIO_MMD_PCS) +#define MDIO_MMDREG_DEVS_PMAPMD DEV_PRESENT_BIT(MDIO_MMD_PMAPMD) +#define MDIO_MMDREG_DEVS_AN DEV_PRESENT_BIT(MDIO_MMD_AN) +#define MDIO_MMDREG_DEVS_C22EXT DEV_PRESENT_BIT(MDIO_MMD_C22EXT) + +/* Bits in MMDREG_SPEED */ +#define MDIO_MMDREG_SPEED_10G_LBN 0 +#define MDIO_MMDREG_SPEED_10G_WIDTH 1 +#define MDIO_MMDREG_SPEED_1000M_LBN 4 +#define MDIO_MMDREG_SPEED_1000M_WIDTH 1 +#define MDIO_MMDREG_SPEED_100M_LBN 5 +#define MDIO_MMDREG_SPEED_100M_WIDTH 1 +#define MDIO_MMDREG_SPEED_10M_LBN 6 +#define MDIO_MMDREG_SPEED_10M_WIDTH 1 /* Bits in MMDREG_STAT2 */ #define MDIO_MMDREG_STAT2_PRESENT_VAL (2) @@ -111,17 +128,34 @@ #define MDIO_PMAPMD_CTRL2_10_BT (0xf) #define MDIO_PMAPMD_CTRL2_TYPE_MASK (0xf) +/* PMA 10GBT registers */ +#define MDIO_PMAPMD_10GBT_TXPWR (131) +#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN (0) +#define MDIO_PMAPMD_10GBT_TXPWR_SHORT_WIDTH (1) + +/* PHY XGXS Status 2 */ +#define MDIO_PHYXS_STATUS2 (8) +#define MDIO_PHYXS_STATUS2_RX_FAULT_LBN 10 + /* PHY XGXS lane state */ #define MDIO_PHYXS_LANE_STATE (0x18) #define MDIO_PHYXS_LANE_ALIGNED_LBN (12) /* AN registers */ +#define MDIO_AN_CTRL_XNP_LBN 13 #define MDIO_AN_STATUS (1) #define MDIO_AN_STATUS_XNP_LBN (7) #define MDIO_AN_STATUS_PAGE_LBN (6) #define MDIO_AN_STATUS_AN_DONE_LBN (5) #define MDIO_AN_STATUS_LP_AN_CAP_LBN (0) +#define MDIO_AN_ADVERTISE 16 +#define MDIO_AN_ADVERTISE_XNP_LBN 12 +#define MDIO_AN_LPA 19 +#define MDIO_AN_XNP 22 +#define MDIO_AN_LPA_XNP 25 + +#define MDIO_AN_10GBT_ADVERTISE 32 #define MDIO_AN_10GBT_STATUS (33) #define MDIO_AN_10GBT_STATUS_MS_FLT_LBN (15) /* MASTER/SLAVE config fault */ #define MDIO_AN_10GBT_STATUS_MS_LBN (14) /* MASTER/SLAVE config */ @@ -240,16 +274,37 @@ extern void mdio_clause45_transmit_disable(struct efx_nic *efx); /* Generic part of reconfigure: set/clear loopback bits */ extern void mdio_clause45_phy_reconfigure(struct efx_nic *efx); +/* Set the power state of the specified MMDs */ +extern void mdio_clause45_set_mmds_lpower(struct efx_nic *efx, + int low_power, unsigned int mmd_mask); + /* Read (some of) the PHY settings over MDIO */ extern void mdio_clause45_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); +/* Read (some of) the PHY settings over MDIO */ +extern void +mdio_clause45_get_settings_ext(struct efx_nic *efx, struct ethtool_cmd *ecmd, + u32 xnp, u32 xnp_lpa); + /* Set (some of) the PHY settings over MDIO */ extern int mdio_clause45_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd); +/* Set pause parameters to be advertised through AN (if available) */ +extern void mdio_clause45_set_pause(struct efx_nic *efx); + +/* Get pause parameters from AN if available (otherwise return + * requested pause parameters) + */ +enum efx_fc_type mdio_clause45_get_pause(struct efx_nic *efx); + /* Wait for specified MMDs to exit reset within a timeout */ extern int mdio_clause45_wait_reset_mmds(struct efx_nic *efx, unsigned int mmd_mask); +/* Set or clear flag, debouncing */ +extern void mdio_clause45_set_flag(struct efx_nic *efx, u8 prt, u8 dev, + u16 addr, int bit, bool sense); + #endif /* EFX_MDIO_10G_H */ diff --git a/drivers/net/sfc/mtd.c b/drivers/net/sfc/mtd.c new file mode 100644 index 0000000000000000000000000000000000000000..665cafb88d6a087a190b0391497a681442109018 --- /dev/null +++ b/drivers/net/sfc/mtd.c @@ -0,0 +1,268 @@ +/**************************************************************************** + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2005-2006 Fen Systems Ltd. + * Copyright 2006-2008 Solarflare Communications 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, incorporated herein by reference. + */ + +#include +#include +#include + +#define EFX_DRIVER_NAME "sfc_mtd" +#include "net_driver.h" +#include "spi.h" + +#define EFX_SPI_VERIFY_BUF_LEN 16 + +struct efx_mtd { + const struct efx_spi_device *spi; + struct mtd_info mtd; + char name[IFNAMSIZ + 20]; +}; + +/* SPI utilities */ + +static int efx_spi_slow_wait(struct efx_mtd *efx_mtd, bool uninterruptible) +{ + const struct efx_spi_device *spi = efx_mtd->spi; + struct efx_nic *efx = spi->efx; + u8 status; + int rc, i; + + /* Wait up to 4s for flash/EEPROM to finish a slow operation. */ + for (i = 0; i < 40; i++) { + __set_current_state(uninterruptible ? + TASK_UNINTERRUPTIBLE : TASK_INTERRUPTIBLE); + schedule_timeout(HZ / 10); + rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, + &status, sizeof(status)); + if (rc) + return rc; + if (!(status & SPI_STATUS_NRDY)) + return 0; + if (signal_pending(current)) + return -EINTR; + } + EFX_ERR(efx, "timed out waiting for %s\n", efx_mtd->name); + return -ETIMEDOUT; +} + +static int efx_spi_unlock(const struct efx_spi_device *spi) +{ + const u8 unlock_mask = (SPI_STATUS_BP2 | SPI_STATUS_BP1 | + SPI_STATUS_BP0); + u8 status; + int rc; + + rc = falcon_spi_cmd(spi, SPI_RDSR, -1, NULL, &status, sizeof(status)); + if (rc) + return rc; + + if (!(status & unlock_mask)) + return 0; /* already unlocked */ + + rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); + if (rc) + return rc; + rc = falcon_spi_cmd(spi, SPI_SST_EWSR, -1, NULL, NULL, 0); + if (rc) + return rc; + + status &= ~unlock_mask; + rc = falcon_spi_cmd(spi, SPI_WRSR, -1, &status, NULL, sizeof(status)); + if (rc) + return rc; + rc = falcon_spi_wait_write(spi); + if (rc) + return rc; + + return 0; +} + +static int efx_spi_erase(struct efx_mtd *efx_mtd, loff_t start, size_t len) +{ + const struct efx_spi_device *spi = efx_mtd->spi; + unsigned pos, block_len; + u8 empty[EFX_SPI_VERIFY_BUF_LEN]; + u8 buffer[EFX_SPI_VERIFY_BUF_LEN]; + int rc; + + if (len != spi->erase_size) + return -EINVAL; + + if (spi->erase_command == 0) + return -EOPNOTSUPP; + + rc = efx_spi_unlock(spi); + if (rc) + return rc; + rc = falcon_spi_cmd(spi, SPI_WREN, -1, NULL, NULL, 0); + if (rc) + return rc; + rc = falcon_spi_cmd(spi, spi->erase_command, start, NULL, NULL, 0); + if (rc) + return rc; + rc = efx_spi_slow_wait(efx_mtd, false); + + /* Verify the entire region has been wiped */ + memset(empty, 0xff, sizeof(empty)); + for (pos = 0; pos < len; pos += block_len) { + block_len = min(len - pos, sizeof(buffer)); + rc = falcon_spi_read(spi, start + pos, block_len, NULL, buffer); + if (rc) + return rc; + if (memcmp(empty, buffer, block_len)) + return -EIO; + + /* Avoid locking up the system */ + cond_resched(); + if (signal_pending(current)) + return -EINTR; + } + + return rc; +} + +/* MTD interface */ + +static int efx_mtd_read(struct mtd_info *mtd, loff_t start, size_t len, + size_t *retlen, u8 *buffer) +{ + struct efx_mtd *efx_mtd = mtd->priv; + const struct efx_spi_device *spi = efx_mtd->spi; + struct efx_nic *efx = spi->efx; + int rc; + + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; + rc = falcon_spi_read(spi, FALCON_FLASH_BOOTCODE_START + start, + len, retlen, buffer); + mutex_unlock(&efx->spi_lock); + return rc; +} + +static int efx_mtd_erase(struct mtd_info *mtd, struct erase_info *erase) +{ + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->spi->efx; + int rc; + + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; + rc = efx_spi_erase(efx_mtd, FALCON_FLASH_BOOTCODE_START + erase->addr, + erase->len); + mutex_unlock(&efx->spi_lock); + + if (rc == 0) { + erase->state = MTD_ERASE_DONE; + } else { + erase->state = MTD_ERASE_FAILED; + erase->fail_addr = 0xffffffff; + } + mtd_erase_callback(erase); + return rc; +} + +static int efx_mtd_write(struct mtd_info *mtd, loff_t start, + size_t len, size_t *retlen, const u8 *buffer) +{ + struct efx_mtd *efx_mtd = mtd->priv; + const struct efx_spi_device *spi = efx_mtd->spi; + struct efx_nic *efx = spi->efx; + int rc; + + rc = mutex_lock_interruptible(&efx->spi_lock); + if (rc) + return rc; + rc = falcon_spi_write(spi, FALCON_FLASH_BOOTCODE_START + start, + len, retlen, buffer); + mutex_unlock(&efx->spi_lock); + return rc; +} + +static void efx_mtd_sync(struct mtd_info *mtd) +{ + struct efx_mtd *efx_mtd = mtd->priv; + struct efx_nic *efx = efx_mtd->spi->efx; + int rc; + + mutex_lock(&efx->spi_lock); + rc = efx_spi_slow_wait(efx_mtd, true); + mutex_unlock(&efx->spi_lock); + + if (rc) + EFX_ERR(efx, "%s sync failed (%d)\n", efx_mtd->name, rc); + return; +} + +void efx_mtd_remove(struct efx_nic *efx) +{ + if (efx->spi_flash && efx->spi_flash->mtd) { + struct efx_mtd *efx_mtd = efx->spi_flash->mtd; + int rc; + + for (;;) { + rc = del_mtd_device(&efx_mtd->mtd); + if (rc != -EBUSY) + break; + ssleep(1); + } + WARN_ON(rc); + kfree(efx_mtd); + } +} + +void efx_mtd_rename(struct efx_nic *efx) +{ + if (efx->spi_flash && efx->spi_flash->mtd) { + struct efx_mtd *efx_mtd = efx->spi_flash->mtd; + snprintf(efx_mtd->name, sizeof(efx_mtd->name), + "%s sfc_flash_bootrom", efx->name); + } +} + +int efx_mtd_probe(struct efx_nic *efx) +{ + struct efx_spi_device *spi = efx->spi_flash; + struct efx_mtd *efx_mtd; + + if (!spi || spi->size <= FALCON_FLASH_BOOTCODE_START) + return -ENODEV; + + efx_mtd = kzalloc(sizeof(*efx_mtd), GFP_KERNEL); + if (!efx_mtd) + return -ENOMEM; + + efx_mtd->spi = spi; + spi->mtd = efx_mtd; + + efx_mtd->mtd.type = MTD_NORFLASH; + efx_mtd->mtd.flags = MTD_CAP_NORFLASH; + efx_mtd->mtd.size = spi->size - FALCON_FLASH_BOOTCODE_START; + efx_mtd->mtd.erasesize = spi->erase_size; + efx_mtd->mtd.writesize = 1; + efx_mtd_rename(efx); + + efx_mtd->mtd.owner = THIS_MODULE; + efx_mtd->mtd.priv = efx_mtd; + efx_mtd->mtd.name = efx_mtd->name; + efx_mtd->mtd.erase = efx_mtd_erase; + efx_mtd->mtd.read = efx_mtd_read; + efx_mtd->mtd.write = efx_mtd_write; + efx_mtd->mtd.sync = efx_mtd_sync; + + if (add_mtd_device(&efx_mtd->mtd)) { + kfree(efx_mtd); + spi->mtd = NULL; + /* add_mtd_device() returns 1 if the MTD table is full */ + return -ENOMEM; + } + + return 0; +} diff --git a/drivers/net/sfc/net_driver.h b/drivers/net/sfc/net_driver.h index cdb11fad6050b0b7700ff8ca64ac8f4afcd68579..5f255f75754e526f6df041d8665908c59fba6e53 100644 --- a/drivers/net/sfc/net_driver.h +++ b/drivers/net/sfc/net_driver.h @@ -42,7 +42,7 @@ #ifndef EFX_DRIVER_NAME #define EFX_DRIVER_NAME "sfc" #endif -#define EFX_DRIVER_VERSION "2.2" +#define EFX_DRIVER_VERSION "2.3" #ifdef EFX_ENABLE_DEBUG #define EFX_BUG_ON_PARANOID(x) BUG_ON(x) @@ -327,6 +327,7 @@ enum efx_rx_alloc_method { * * @efx: Associated Efx NIC * @channel: Channel instance number + * @name: Name for channel and IRQ * @used_flags: Channel is used by net driver * @enabled: Channel enabled indicator * @irq: IRQ number (MSI and MSI-X only) @@ -357,6 +358,7 @@ enum efx_rx_alloc_method { struct efx_channel { struct efx_nic *efx; int channel; + char name[IFNAMSIZ + 6]; int used_flags; bool enabled; int irq; @@ -414,6 +416,7 @@ struct efx_blinker { * @init_leds: Sets up board LEDs * @set_fault_led: Turns the fault LED on or off * @blink: Starts/stops blinking + * @monitor: Board-specific health check function * @fini: Cleanup function * @blinker: used to blink LEDs in software * @hwmon_client: I2C client for hardware monitor @@ -428,6 +431,7 @@ struct efx_board { * have a separate init callback that happens later than * board init. */ int (*init_leds)(struct efx_nic *efx); + int (*monitor) (struct efx_nic *nic); void (*set_fault_led) (struct efx_nic *efx, bool state); void (*blink) (struct efx_nic *efx, bool start); void (*fini) (struct efx_nic *nic); @@ -449,16 +453,20 @@ enum efx_int_mode { enum phy_type { PHY_TYPE_NONE = 0, - PHY_TYPE_CX4_RTMR = 1, - PHY_TYPE_1G_ALASKA = 2, - PHY_TYPE_10XPRESS = 3, - PHY_TYPE_XFP = 4, + PHY_TYPE_TXC43128 = 1, + PHY_TYPE_88E1111 = 2, + PHY_TYPE_SFX7101 = 3, + PHY_TYPE_QT2022C2 = 4, PHY_TYPE_PM8358 = 6, + PHY_TYPE_SFT9001A = 8, + PHY_TYPE_SFT9001B = 10, PHY_TYPE_MAX /* Insert any new items before this */ }; #define PHY_ADDR_INVALID 0xff +#define EFX_IS10G(efx) ((efx)->link_speed == 10000) + enum nic_state { STATE_INIT = 0, STATE_RUNNING = 1, @@ -499,6 +507,55 @@ enum efx_fc_type { EFX_FC_AUTO = 4, }; +/* Supported MAC bit-mask */ +enum efx_mac_type { + EFX_GMAC = 1, + EFX_XMAC = 2, +}; + +static inline unsigned int efx_fc_advertise(enum efx_fc_type wanted_fc) +{ + unsigned int adv = 0; + if (wanted_fc & EFX_FC_RX) + adv = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; + if (wanted_fc & EFX_FC_TX) + adv ^= ADVERTISE_PAUSE_ASYM; + return adv; +} + +static inline enum efx_fc_type efx_fc_resolve(enum efx_fc_type wanted_fc, + unsigned int lpa) +{ + unsigned int adv = efx_fc_advertise(wanted_fc); + + if (!(wanted_fc & EFX_FC_AUTO)) + return wanted_fc; + + if (adv & lpa & ADVERTISE_PAUSE_CAP) + return EFX_FC_RX | EFX_FC_TX; + if (adv & lpa & ADVERTISE_PAUSE_ASYM) { + if (adv & ADVERTISE_PAUSE_CAP) + return EFX_FC_RX; + if (lpa & ADVERTISE_PAUSE_CAP) + return EFX_FC_TX; + } + return 0; +} + +/** + * struct efx_mac_operations - Efx MAC operations table + * @reconfigure: Reconfigure MAC. Serialised by the mac_lock + * @update_stats: Update statistics + * @irq: Hardware MAC event callback. Serialised by the mac_lock + * @poll: Poll for hardware state. Serialised by the mac_lock + */ +struct efx_mac_operations { + void (*reconfigure) (struct efx_nic *efx); + void (*update_stats) (struct efx_nic *efx); + void (*irq) (struct efx_nic *efx); + void (*poll) (struct efx_nic *efx); +}; + /** * struct efx_phy_operations - Efx PHY operations table * @init: Initialise PHY @@ -506,17 +563,33 @@ enum efx_fc_type { * @reconfigure: Reconfigure PHY (e.g. for new link parameters) * @clear_interrupt: Clear down interrupt * @blink: Blink LEDs - * @check_hw: Check hardware + * @poll: Poll for hardware state. Serialised by the mac_lock. + * @get_settings: Get ethtool settings. Serialised by the mac_lock. + * @set_settings: Set ethtool settings. Serialised by the mac_lock. + * @set_xnp_advertise: Set abilities advertised in Extended Next Page + * (only needed where AN bit is set in mmds) + * @num_tests: Number of PHY-specific tests/results + * @test_names: Names of the tests/results + * @run_tests: Run tests and record results as appropriate. + * Flags are the ethtool tests flags. * @mmds: MMD presence mask * @loopbacks: Supported loopback modes mask */ struct efx_phy_operations { + enum efx_mac_type macs; int (*init) (struct efx_nic *efx); void (*fini) (struct efx_nic *efx); void (*reconfigure) (struct efx_nic *efx); void (*clear_interrupt) (struct efx_nic *efx); - int (*check_hw) (struct efx_nic *efx); - int (*test) (struct efx_nic *efx); + void (*poll) (struct efx_nic *efx); + void (*get_settings) (struct efx_nic *efx, + struct ethtool_cmd *ecmd); + int (*set_settings) (struct efx_nic *efx, + struct ethtool_cmd *ecmd); + bool (*set_xnp_advertise) (struct efx_nic *efx, u32); + u32 num_tests; + const char *const *test_names; + int (*run_tests) (struct efx_nic *efx, int *results, unsigned flags); int mmds; unsigned loopbacks; }; @@ -525,11 +598,15 @@ struct efx_phy_operations { * @enum efx_phy_mode - PHY operating mode flags * @PHY_MODE_NORMAL: on and should pass traffic * @PHY_MODE_TX_DISABLED: on with TX disabled + * @PHY_MODE_LOW_POWER: set to low power through MDIO + * @PHY_MODE_OFF: switched off through external control * @PHY_MODE_SPECIAL: on but will not pass traffic */ enum efx_phy_mode { PHY_MODE_NORMAL = 0, PHY_MODE_TX_DISABLED = 1, + PHY_MODE_LOW_POWER = 2, + PHY_MODE_OFF = 4, PHY_MODE_SPECIAL = 8, }; @@ -629,7 +706,7 @@ union efx_multicast_hash { * @legacy_irq: IRQ number * @workqueue: Workqueue for port reconfigures and the HW monitor. * Work items do not hold and must not acquire RTNL. - * @reset_workqueue: Workqueue for resets. Work item will acquire RTNL. + * @workqueue_name: Name of workqueue * @reset_work: Scheduled reset workitem * @monitor_work: Hardware monitor workitem * @membase_phys: Memory BAR value as physical address @@ -644,6 +721,7 @@ union efx_multicast_hash { * @rx_queue: RX DMA queues * @channel: Channels * @n_rx_queues: Number of RX queues + * @n_channels: Number of channels in use * @rx_buffer_len: RX buffer length * @rx_buffer_order: Order (log2) of number of pages for each RX buffer * @irq_status: Interrupt status buffer @@ -655,15 +733,16 @@ union efx_multicast_hash { * This field will be %NULL if no flash device is present. * @spi_eeprom: SPI EEPROM device * This field will be %NULL if no EEPROM device is present. + * @spi_lock: SPI bus lock * @n_rx_nodesc_drop_cnt: RX no descriptor drop count * @nic_data: Hardware dependant state * @mac_lock: MAC access lock. Protects @port_enabled, @phy_mode, * @port_inhibited, efx_monitor() and efx_reconfigure_port() * @port_enabled: Port enabled indicator. - * Serialises efx_stop_all(), efx_start_all() and efx_monitor() and - * efx_reconfigure_work with kernel interfaces. Safe to read under any - * one of the rtnl_lock, mac_lock, or netif_tx_lock, but all three must - * be held to modify it. + * Serialises efx_stop_all(), efx_start_all(), efx_monitor(), + * efx_phy_work(), and efx_mac_work() with kernel interfaces. Safe to read + * under any one of the rtnl_lock, mac_lock, or netif_tx_lock, but all + * three must be held to modify it. * @port_inhibited: If set, the netif_carrier is always off. Hold the mac_lock * @port_initialized: Port initialized? * @net_dev: Operating system network device. Consider holding the rtnl lock @@ -677,6 +756,7 @@ union efx_multicast_hash { * @stats_lock: Statistics update lock. Serialises statistics fetches * @stats_enabled: Temporarily disable statistics fetches. * Serialised by @stats_lock + * @mac_op: MAC interface * @mac_address: Permanent MAC address * @phy_type: PHY type * @phy_lock: PHY access lock @@ -684,13 +764,17 @@ union efx_multicast_hash { * @phy_data: PHY private data (including PHY-specific stats) * @mii: PHY interface * @phy_mode: PHY operating mode. Serialised by @mac_lock. + * @mac_up: MAC link state * @link_up: Link status - * @link_options: Link options (MII/GMII format) + * @link_fd: Link is full duplex + * @link_fc: Actualy flow control flags + * @link_speed: Link speed (Mbps) * @n_link_state_changes: Number of times the link has changed state * @promiscuous: Promiscuous flag. Protected by netif_tx_lock. * @multicast_hash: Multicast hash table - * @flow_control: Flow control flags - separate RX/TX so can't use link_options - * @reconfigure_work: work item for dealing with PHY events + * @wanted_fc: Wanted flow control flags + * @phy_work: work item for dealing with PHY events + * @mac_work: work item for dealing with MAC events * @loopback_mode: Loopback status * @loopback_modes: Supported loopback mode bitmask * @loopback_selftest: Offline self-test private state @@ -704,7 +788,7 @@ struct efx_nic { const struct efx_nic_type *type; int legacy_irq; struct workqueue_struct *workqueue; - struct workqueue_struct *reset_workqueue; + char workqueue_name[16]; struct work_struct reset_work; struct delayed_work monitor_work; resource_size_t membase_phys; @@ -723,6 +807,7 @@ struct efx_nic { struct efx_channel channel[EFX_MAX_CHANNELS]; int n_rx_queues; + int n_channels; unsigned int rx_buffer_len; unsigned int rx_buffer_order; @@ -731,12 +816,14 @@ struct efx_nic { struct efx_spi_device *spi_flash; struct efx_spi_device *spi_eeprom; + struct mutex spi_lock; unsigned n_rx_nodesc_drop_cnt; struct falcon_nic_data *nic_data; struct mutex mac_lock; + struct work_struct mac_work; bool port_enabled; bool port_inhibited; @@ -752,23 +839,27 @@ struct efx_nic { spinlock_t stats_lock; bool stats_enabled; + struct efx_mac_operations *mac_op; unsigned char mac_address[ETH_ALEN]; enum phy_type phy_type; spinlock_t phy_lock; + struct work_struct phy_work; struct efx_phy_operations *phy_op; void *phy_data; struct mii_if_info mii; enum efx_phy_mode phy_mode; + bool mac_up; bool link_up; - unsigned int link_options; + bool link_fd; + enum efx_fc_type link_fc; + unsigned int link_speed; unsigned int n_link_state_changes; bool promiscuous; union efx_multicast_hash multicast_hash; - enum efx_fc_type flow_control; - struct work_struct reconfigure_work; + enum efx_fc_type wanted_fc; atomic_t rx_reset; enum efx_loopback_mode loopback_mode; diff --git a/drivers/net/sfc/phy.h b/drivers/net/sfc/phy.h index f746536f4ffaebab288537973eb85cb33294be71..58c493ef81bb09f5aa5d5120c4bf417a28ab8246 100644 --- a/drivers/net/sfc/phy.h +++ b/drivers/net/sfc/phy.h @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007 Solarflare Communications Inc. + * Copyright 2007-2008 Solarflare Communications 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 @@ -11,9 +11,10 @@ #define EFX_PHY_H /**************************************************************************** - * 10Xpress (SFX7101) PHY + * 10Xpress (SFX7101 and SFT9001) PHYs */ -extern struct efx_phy_operations falcon_tenxpress_phy_ops; +extern struct efx_phy_operations falcon_sfx7101_phy_ops; +extern struct efx_phy_operations falcon_sft9001_phy_ops; extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink); extern void tenxpress_crc_err(struct efx_nic *efx); diff --git a/drivers/net/sfc/rx.c b/drivers/net/sfc/rx.c index 0f805da4ce55e9c09abd9f6102eb741dbe7f71be..b8ba4bbad8897f384f6eb6f6168cce13df95132a 100644 --- a/drivers/net/sfc/rx.c +++ b/drivers/net/sfc/rx.c @@ -752,7 +752,7 @@ void __efx_rx_packet(struct efx_channel *channel, channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB; done: - efx->net_dev->last_rx = jiffies; + ; } void efx_rx_strategy(struct efx_channel *channel) diff --git a/drivers/net/sfc/selftest.c b/drivers/net/sfc/selftest.c index 362956e3fe172ef1b0daaa2c5e10ac276b42f4b9..dba0d64d50cd07aeffe70c7b6af614d755d43989 100644 --- a/drivers/net/sfc/selftest.c +++ b/drivers/net/sfc/selftest.c @@ -26,7 +26,6 @@ #include "selftest.h" #include "boards.h" #include "workarounds.h" -#include "mac.h" #include "spi.h" #include "falcon_io.h" #include "mdio_10g.h" @@ -105,9 +104,11 @@ static int efx_test_mii(struct efx_nic *efx, struct efx_self_tests *tests) goto out; } - rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); - if (rc) - goto out; + if (EFX_IS10G(efx)) { + rc = mdio_clause45_check_mmds(efx, efx->phy_op->mmds, 0); + if (rc) + goto out; + } out: mutex_unlock(&efx->mac_lock); @@ -246,17 +247,20 @@ static int efx_test_eventq_irq(struct efx_channel *channel, return 0; } -static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests) +static int efx_test_phy(struct efx_nic *efx, struct efx_self_tests *tests, + unsigned flags) { int rc; - if (!efx->phy_op->test) + if (!efx->phy_op->run_tests) return 0; + EFX_BUG_ON_PARANOID(efx->phy_op->num_tests == 0 || + efx->phy_op->num_tests > EFX_MAX_PHY_TESTS); + mutex_lock(&efx->mac_lock); - rc = efx->phy_op->test(efx); + rc = efx->phy_op->run_tests(efx, tests->phy, flags); mutex_unlock(&efx->mac_lock); - tests->phy = rc ? -1 : 1; return rc; } @@ -563,8 +567,7 @@ efx_test_loopback(struct efx_tx_queue *tx_queue, return 0; } -static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, - struct efx_self_tests *tests, +static int efx_test_loopbacks(struct efx_nic *efx, struct efx_self_tests *tests, unsigned int loopback_modes) { enum efx_loopback_mode mode; @@ -593,12 +596,14 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, efx->loopback_mode = mode; efx_reconfigure_port(efx); - /* Wait for the PHY to signal the link is up */ + /* Wait for the PHY to signal the link is up. Interrupts + * are enabled for PHY's using LASI, otherwise we poll() + * quickly */ count = 0; do { struct efx_channel *channel = &efx->channel[0]; - falcon_check_xmac(efx); + efx->phy_op->poll(efx); schedule_timeout_uninterruptible(HZ / 10); if (channel->work_pending) efx_process_channel_now(channel); @@ -606,13 +611,12 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, flush_workqueue(efx->workqueue); rmb(); - /* efx->link_up can be 1 even if the XAUI link is down, - * (bug5762). Usually, it's not worth bothering with the - * difference, but for selftests, we need that extra - * guarantee that the link is really, really, up. - */ + /* We need both the phy and xaui links to be ok. + * rather than relying on the falcon_xmac irq/poll + * regime, just poll xaui directly */ link_up = efx->link_up; - if (!falcon_xaui_link_ok(efx)) + if (link_up && EFX_IS10G(efx) && + !falcon_xaui_link_ok(efx)) link_up = false; } while ((++count < 20) && !link_up); @@ -652,47 +656,48 @@ static int efx_test_loopbacks(struct efx_nic *efx, struct ethtool_cmd ecmd, /************************************************************************** * - * Entry points + * Entry point * *************************************************************************/ -/* Online (i.e. non-disruptive) testing - * This checks interrupt generation, event delivery and PHY presence. */ -int efx_online_test(struct efx_nic *efx, struct efx_self_tests *tests) +int efx_selftest(struct efx_nic *efx, struct efx_self_tests *tests, + unsigned flags) { + enum efx_loopback_mode loopback_mode = efx->loopback_mode; + int phy_mode = efx->phy_mode; + struct ethtool_cmd ecmd; struct efx_channel *channel; - int rc, rc2 = 0; + int rc_test = 0, rc_reset = 0, rc; + + /* Online (i.e. non-disruptive) testing + * This checks interrupt generation, event delivery and PHY presence. */ rc = efx_test_mii(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; rc = efx_test_nvram(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; rc = efx_test_interrupts(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; efx_for_each_channel(channel, efx) { rc = efx_test_eventq_irq(channel, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; } - return rc2; -} + if (rc_test) + return rc_test; -/* Offline (i.e. disruptive) testing - * This checks MAC and PHY loopback on the specified port. */ -int efx_offline_test(struct efx_nic *efx, - struct efx_self_tests *tests, unsigned int loopback_modes) -{ - enum efx_loopback_mode loopback_mode = efx->loopback_mode; - int phy_mode = efx->phy_mode; - struct ethtool_cmd ecmd, ecmd_test; - int rc, rc2 = 0; + if (!(flags & ETH_TEST_FL_OFFLINE)) + return efx_test_phy(efx, tests, flags); + + /* Offline (i.e. disruptive) testing + * This checks MAC and PHY loopback on the specified port. */ /* force the carrier state off so the kernel doesn't transmit during * the loopback test, and the watchdog timeout doesn't fire. Also put @@ -700,8 +705,15 @@ int efx_offline_test(struct efx_nic *efx, */ mutex_lock(&efx->mac_lock); efx->port_inhibited = true; - if (efx->loopback_modes) - efx->loopback_mode = __ffs(efx->loopback_modes); + if (efx->loopback_modes) { + /* We need the 312 clock from the PHY to test the XMAC + * registers, so move into XGMII loopback if available */ + if (efx->loopback_modes & (1 << LOOPBACK_XGMII)) + efx->loopback_mode = LOOPBACK_XGMII; + else + efx->loopback_mode = __ffs(efx->loopback_modes); + } + __efx_reconfigure_port(efx); mutex_unlock(&efx->mac_lock); @@ -709,39 +721,34 @@ int efx_offline_test(struct efx_nic *efx, efx_reset_down(efx, &ecmd); rc = efx_test_chip(efx, tests); - if (rc && !rc2) - rc2 = rc; + if (rc && !rc_test) + rc_test = rc; /* reset the chip to recover from the register test */ - rc = falcon_reset_hw(efx, RESET_TYPE_ALL); - - /* Modify the saved ecmd so that when efx_reset_up() restores the phy - * state, AN is disabled, and the phy is powered, and out of loopback */ - memcpy(&ecmd_test, &ecmd, sizeof(ecmd_test)); - if (ecmd_test.autoneg == AUTONEG_ENABLE) { - ecmd_test.autoneg = AUTONEG_DISABLE; - ecmd_test.duplex = DUPLEX_FULL; - ecmd_test.speed = SPEED_10000; - } + rc_reset = falcon_reset_hw(efx, RESET_TYPE_ALL); + + /* Ensure that the phy is powered and out of loopback + * for the bist and loopback tests */ + efx->phy_mode &= ~PHY_MODE_LOW_POWER; efx->loopback_mode = LOOPBACK_NONE; - rc = efx_reset_up(efx, &ecmd_test, rc == 0); - if (rc) { + rc = efx_reset_up(efx, &ecmd, rc_reset == 0); + if (rc && !rc_reset) + rc_reset = rc; + + if (rc_reset) { EFX_ERR(efx, "Unable to recover from chip test\n"); efx_schedule_reset(efx, RESET_TYPE_DISABLE); - return rc; + return rc_reset; } - tests->loopback_speed = ecmd_test.speed; - tests->loopback_full_duplex = ecmd_test.duplex; - - rc = efx_test_phy(efx, tests); - if (rc && !rc2) - rc2 = rc; + rc = efx_test_phy(efx, tests, flags); + if (rc && !rc_test) + rc_test = rc; - rc = efx_test_loopbacks(efx, ecmd_test, tests, loopback_modes); - if (rc && !rc2) - rc2 = rc; + rc = efx_test_loopbacks(efx, tests, efx->loopback_modes); + if (rc && !rc_test) + rc_test = rc; /* restore the PHY to the previous state */ efx->loopback_mode = loopback_mode; @@ -749,6 +756,6 @@ int efx_offline_test(struct efx_nic *efx, efx->port_inhibited = false; efx_ethtool_set_settings(efx->net_dev, &ecmd); - return rc2; + return rc_test; } diff --git a/drivers/net/sfc/selftest.h b/drivers/net/sfc/selftest.h index fc15df15d76645c08b318988eadced248c5483cf..39451cf938cfe7bd1448553fa9b0fb13e8b33f89 100644 --- a/drivers/net/sfc/selftest.h +++ b/drivers/net/sfc/selftest.h @@ -24,6 +24,8 @@ struct efx_loopback_self_tests { int rx_bad; }; +#define EFX_MAX_PHY_TESTS 20 + /* Efx self test results * For fields which are not counters, 1 indicates success and -1 * indicates failure. @@ -38,18 +40,14 @@ struct efx_self_tests { int eventq_poll[EFX_MAX_CHANNELS]; /* offline tests */ int registers; - int phy; - int loopback_speed; - int loopback_full_duplex; + int phy[EFX_MAX_PHY_TESTS]; struct efx_loopback_self_tests loopback[LOOPBACK_TEST_MAX + 1]; }; extern void efx_loopback_rx_packet(struct efx_nic *efx, const char *buf_ptr, int pkt_len); -extern int efx_online_test(struct efx_nic *efx, - struct efx_self_tests *tests); -extern int efx_offline_test(struct efx_nic *efx, - struct efx_self_tests *tests, - unsigned int loopback_modes); +extern int efx_selftest(struct efx_nic *efx, + struct efx_self_tests *tests, + unsigned flags); #endif /* EFX_SELFTEST_H */ diff --git a/drivers/net/sfc/sfe4001.c b/drivers/net/sfc/sfe4001.c index fe4e3fd223307877ce616020f5a7dd672f734b32..16b80acb999204f9ce81f110e3fac11e39b2e4c6 100644 --- a/drivers/net/sfc/sfe4001.c +++ b/drivers/net/sfc/sfe4001.c @@ -1,6 +1,6 @@ /**************************************************************************** * Driver for Solarflare Solarstorm network controllers and boards - * Copyright 2007 Solarflare Communications Inc. + * Copyright 2007-2008 Solarflare Communications 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 @@ -8,10 +8,21 @@ */ /***************************************************************************** - * Support for the SFE4001 NIC: driver code for the PCA9539 I/O expander that - * controls the PHY power rails, and for the MAX6647 temp. sensor used to check - * the PHY + * Support for the SFE4001 and SFN4111T NICs. + * + * The SFE4001 does not power-up fully at reset due to its high power + * consumption. We control its power via a PCA9539 I/O expander. + * Both boards have a MAX6647 temperature monitor which we expose to + * the lm90 driver. + * + * This also provides minimal support for reflashing the PHY, which is + * initiated by resetting it with the FLASH_CFG_1 pin pulled down. + * On SFE4001 rev A2 and later this is connected to the 3V3X output of + * the IO-expander; on the SFN4111T it is connected to Falcon's GPIO3. + * We represent reflash mode as PHY_MODE_SPECIAL and make it mutually + * exclusive with the network device being open. */ + #include #include "net_driver.h" #include "efx.h" @@ -21,6 +32,7 @@ #include "falcon_hwdefs.h" #include "falcon_io.h" #include "mac.h" +#include "workarounds.h" /************************************************************************** * @@ -65,48 +77,9 @@ #define P1_SPARE_LBN 4 #define P1_SPARE_WIDTH 4 - -/************************************************************************** - * - * Temperature Sensor - * - **************************************************************************/ -#define MAX6647 0x4e - -#define RLTS 0x00 -#define RLTE 0x01 -#define RSL 0x02 -#define RCL 0x03 -#define RCRA 0x04 -#define RLHN 0x05 -#define RLLI 0x06 -#define RRHI 0x07 -#define RRLS 0x08 -#define WCRW 0x0a -#define WLHO 0x0b -#define WRHA 0x0c -#define WRLN 0x0e -#define OSHT 0x0f -#define REET 0x10 -#define RIET 0x11 -#define RWOE 0x19 -#define RWOI 0x20 -#define HYS 0x21 -#define QUEUE 0x22 -#define MFID 0xfe -#define REVID 0xff - -/* Status bits */ -#define MAX6647_BUSY (1 << 7) /* ADC is converting */ -#define MAX6647_LHIGH (1 << 6) /* Local high temp. alarm */ -#define MAX6647_LLOW (1 << 5) /* Local low temp. alarm */ -#define MAX6647_RHIGH (1 << 4) /* Remote high temp. alarm */ -#define MAX6647_RLOW (1 << 3) /* Remote low temp. alarm */ -#define MAX6647_FAULT (1 << 2) /* DXN/DXP short/open circuit */ -#define MAX6647_EOT (1 << 1) /* Remote junction overtemp. */ -#define MAX6647_IOT (1 << 0) /* Local junction overtemp. */ - -static const u8 xgphy_max_temperature = 90; +/* Temperature Sensor */ +#define MAX664X_REG_RSL 0x02 +#define MAX664X_REG_WLHO 0x0B static void sfe4001_poweroff(struct efx_nic *efx) { @@ -119,7 +92,7 @@ static void sfe4001_poweroff(struct efx_nic *efx) i2c_smbus_write_byte_data(ioexp_client, P0_CONFIG, 0xff); /* Clear any over-temperature alert */ - i2c_smbus_read_byte_data(hwmon_client, RSL); + i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); } static int sfe4001_poweron(struct efx_nic *efx) @@ -131,7 +104,7 @@ static int sfe4001_poweron(struct efx_nic *efx) u8 out; /* Clear any previous over-temperature alert */ - rc = i2c_smbus_read_byte_data(hwmon_client, RSL); + rc = i2c_smbus_read_byte_data(hwmon_client, MAX664X_REG_RSL); if (rc < 0) return rc; @@ -209,10 +182,29 @@ fail_on: return rc; } -/* On SFE4001 rev A2 and later, we can control the FLASH_CFG_1 pin - * using the 3V3X output of the IO-expander. Allow the user to set - * this when the device is stopped, and keep it stopped then. - */ +static int sfn4111t_reset(struct efx_nic *efx) +{ + efx_oword_t reg; + + /* GPIO pins are also used for I2C, so block that temporarily */ + mutex_lock(&efx->i2c_adap.bus_lock); + + falcon_read(efx, ®, GPIO_CTL_REG_KER); + EFX_SET_OWORD_FIELD(reg, GPIO2_OEN, true); + EFX_SET_OWORD_FIELD(reg, GPIO2_OUT, false); + falcon_write(efx, ®, GPIO_CTL_REG_KER); + msleep(1000); + EFX_SET_OWORD_FIELD(reg, GPIO2_OUT, true); + EFX_SET_OWORD_FIELD(reg, GPIO3_OEN, true); + EFX_SET_OWORD_FIELD(reg, GPIO3_OUT, + !(efx->phy_mode & PHY_MODE_SPECIAL)); + falcon_write(efx, ®, GPIO_CTL_REG_KER); + + mutex_unlock(&efx->i2c_adap.bus_lock); + + ssleep(1); + return 0; +} static ssize_t show_phy_flash_cfg(struct device *dev, struct device_attribute *attr, char *buf) @@ -241,7 +233,10 @@ static ssize_t set_phy_flash_cfg(struct device *dev, err = -EBUSY; } else { efx->phy_mode = new_mode; - err = sfe4001_poweron(efx); + if (efx->board_info.type == EFX_BOARD_SFE4001) + err = sfe4001_poweron(efx); + else + err = sfn4111t_reset(efx); efx_reconfigure_port(efx); } rtnl_unlock(); @@ -261,35 +256,62 @@ static void sfe4001_fini(struct efx_nic *efx) i2c_unregister_device(efx->board_info.hwmon_client); } +static int sfe4001_check_hw(struct efx_nic *efx) +{ + s32 status; + + /* If XAUI link is up then do not monitor */ + if (EFX_WORKAROUND_7884(efx) && efx->mac_up) + return 0; + + /* Check the powered status of the PHY. Lack of power implies that + * the MAX6647 has shut down power to it, probably due to a temp. + * alarm. Reading the power status rather than the MAX6647 status + * directly because the later is read-to-clear and would thus + * start to power up the PHY again when polled, causing us to blip + * the power undesirably. + * We know we can read from the IO expander because we did + * it during power-on. Assume failure now is bad news. */ + status = i2c_smbus_read_byte_data(efx->board_info.ioexp_client, P1_IN); + if (status >= 0 && + (status & ((1 << P1_AFE_PWD_LBN) | (1 << P1_DSP_PWD25_LBN))) != 0) + return 0; + + /* Use board power control, not PHY power control */ + sfe4001_poweroff(efx); + efx->phy_mode = PHY_MODE_OFF; + + return (status < 0) ? -EIO : -ERANGE; +} + +static struct i2c_board_info sfe4001_hwmon_info = { + I2C_BOARD_INFO("max6647", 0x4e), + .irq = -1, +}; + /* This board uses an I2C expander to provider power to the PHY, which needs to * be turned on before the PHY can be used. * Context: Process context, rtnl lock held */ int sfe4001_init(struct efx_nic *efx) { - struct i2c_client *hwmon_client; int rc; - hwmon_client = i2c_new_dummy(&efx->i2c_adap, MAX6647); - if (!hwmon_client) +#if defined(CONFIG_SENSORS_LM90) || defined(CONFIG_SENSORS_LM90_MODULE) + efx->board_info.hwmon_client = + i2c_new_device(&efx->i2c_adap, &sfe4001_hwmon_info); +#else + efx->board_info.hwmon_client = + i2c_new_dummy(&efx->i2c_adap, sfe4001_hwmon_info.addr); +#endif + if (!efx->board_info.hwmon_client) return -EIO; - efx->board_info.hwmon_client = hwmon_client; - /* Set DSP over-temperature alert threshold */ - EFX_INFO(efx, "DSP cut-out at %dC\n", xgphy_max_temperature); - rc = i2c_smbus_write_byte_data(hwmon_client, WLHO, - xgphy_max_temperature); + /* Raise board/PHY high limit from 85 to 90 degrees Celsius */ + rc = i2c_smbus_write_byte_data(efx->board_info.hwmon_client, + MAX664X_REG_WLHO, 90); if (rc) - goto fail_ioexp; - - /* Read it back and verify */ - rc = i2c_smbus_read_byte_data(hwmon_client, RLHN); - if (rc < 0) - goto fail_ioexp; - if (rc != xgphy_max_temperature) { - rc = -EFAULT; - goto fail_ioexp; - } + goto fail_hwmon; efx->board_info.ioexp_client = i2c_new_dummy(&efx->i2c_adap, PCA9539); if (!efx->board_info.ioexp_client) { @@ -301,6 +323,7 @@ int sfe4001_init(struct efx_nic *efx) * blink code. */ efx->board_info.blink = tenxpress_phy_blink; + efx->board_info.monitor = sfe4001_check_hw; efx->board_info.fini = sfe4001_fini; rc = sfe4001_poweron(efx); @@ -319,6 +342,64 @@ fail_on: fail_ioexp: i2c_unregister_device(efx->board_info.ioexp_client); fail_hwmon: - i2c_unregister_device(hwmon_client); + i2c_unregister_device(efx->board_info.hwmon_client); + return rc; +} + +static int sfn4111t_check_hw(struct efx_nic *efx) +{ + s32 status; + + /* If XAUI link is up then do not monitor */ + if (EFX_WORKAROUND_7884(efx) && efx->mac_up) + return 0; + + /* Test LHIGH, RHIGH, FAULT, EOT and IOT alarms */ + status = i2c_smbus_read_byte_data(efx->board_info.hwmon_client, + MAX664X_REG_RSL); + if (status < 0) + return -EIO; + if (status & 0x57) + return -ERANGE; + return 0; +} + +static void sfn4111t_fini(struct efx_nic *efx) +{ + EFX_INFO(efx, "%s\n", __func__); + + device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); + i2c_unregister_device(efx->board_info.hwmon_client); +} + +static struct i2c_board_info sfn4111t_hwmon_info = { + I2C_BOARD_INFO("max6647", 0x4e), + .irq = -1, +}; + +int sfn4111t_init(struct efx_nic *efx) +{ + int rc; + + efx->board_info.hwmon_client = + i2c_new_device(&efx->i2c_adap, &sfn4111t_hwmon_info); + if (!efx->board_info.hwmon_client) + return -EIO; + + efx->board_info.blink = tenxpress_phy_blink; + efx->board_info.monitor = sfn4111t_check_hw; + efx->board_info.fini = sfn4111t_fini; + + rc = device_create_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg); + if (rc) + goto fail_hwmon; + + if (efx->phy_mode & PHY_MODE_SPECIAL) + sfn4111t_reset(efx); + + return 0; + +fail_hwmon: + i2c_unregister_device(efx->board_info.hwmon_client); return rc; } diff --git a/drivers/net/sfc/spi.h b/drivers/net/sfc/spi.h index feef619423776889a0d275c81ad407c0a1b65465..1b1ceb41167193f13279a1d29aa17446c4886364 100644 --- a/drivers/net/sfc/spi.h +++ b/drivers/net/sfc/spi.h @@ -25,6 +25,7 @@ #define SPI_WRDI 0x04 /* Reset write enable latch */ #define SPI_RDSR 0x05 /* Read status register */ #define SPI_WREN 0x06 /* Set write enable latch */ +#define SPI_SST_EWSR 0x50 /* SST: Enable write to status register */ #define SPI_STATUS_WPEN 0x80 /* Write-protect pin enabled */ #define SPI_STATUS_BP2 0x10 /* Block protection bit 2 */ @@ -36,6 +37,7 @@ /** * struct efx_spi_device - an Efx SPI (Serial Peripheral Interface) device * @efx: The Efx controller that owns this device + * @mtd: MTD state * @device_id: Controller's id for the device * @size: Size (in bytes) * @addr_len: Number of address bytes in read/write commands @@ -44,23 +46,51 @@ * use bit 3 of the command byte as address bit A8, rather * than having a two-byte address. If this flag is set, then * commands should be munged in this way. + * @erase_command: Erase command (or 0 if sector erase not needed). + * @erase_size: Erase sector size (in bytes) + * Erase commands affect sectors with this size and alignment. + * This must be a power of two. * @block_size: Write block size (in bytes). * Write commands are limited to blocks with this size and alignment. - * @read: Read function for the device - * @write: Write function for the device */ struct efx_spi_device { struct efx_nic *efx; +#ifdef CONFIG_SFC_MTD + void *mtd; +#endif int device_id; unsigned int size; unsigned int addr_len; unsigned int munge_address:1; + u8 erase_command; + unsigned int erase_size; unsigned int block_size; }; +int falcon_spi_cmd(const struct efx_spi_device *spi, unsigned int command, + int address, const void* in, void *out, size_t len); +int falcon_spi_wait_write(const struct efx_spi_device *spi); int falcon_spi_read(const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, u8 *buffer); int falcon_spi_write(const struct efx_spi_device *spi, loff_t start, size_t len, size_t *retlen, const u8 *buffer); +/* + * SFC4000 flash is partitioned into: + * 0-0x400 chip and board config (see falcon_hwdefs.h) + * 0x400-0x8000 unused (or may contain VPD if EEPROM not present) + * 0x8000-end boot code (mapped to PCI expansion ROM) + * SFC4000 small EEPROM (size < 0x400) is used for VPD only. + * SFC4000 large EEPROM (size >= 0x400) is partitioned into: + * 0-0x400 chip and board config + * configurable VPD + * 0x800-0x1800 boot config + * Aside from the chip and board config, all of these are optional and may + * be absent or truncated depending on the devices used. + */ +#define FALCON_NVCONFIG_END 0x400U +#define FALCON_FLASH_BOOTCODE_START 0x8000U +#define EFX_EEPROM_BOOTCONFIG_START 0x800U +#define EFX_EEPROM_BOOTCONFIG_END 0x1800U + #endif /* EFX_SPI_H */ diff --git a/drivers/net/sfc/tenxpress.c b/drivers/net/sfc/tenxpress.c index d507c93d666e1130dc2cd27768f38f2c4b710221..b9768760fae7f8de80fa4109a4514d16e3c14ff7 100644 --- a/drivers/net/sfc/tenxpress.c +++ b/drivers/net/sfc/tenxpress.c @@ -1,6 +1,6 @@ /**************************************************************************** - * Driver for Solarflare 802.3an compliant PHY - * Copyright 2007 Solarflare Communications Inc. + * Driver for Solarflare Solarstorm network controllers and boards + * Copyright 2007-2008 Solarflare Communications 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 @@ -10,45 +10,76 @@ #include #include #include "efx.h" -#include "gmii.h" #include "mdio_10g.h" #include "falcon.h" #include "phy.h" #include "falcon_hwdefs.h" #include "boards.h" -#include "mac.h" +#include "workarounds.h" +#include "selftest.h" -/* We expect these MMDs to be in the package */ -/* AN not here as mdio_check_mmds() requires STAT2 support */ -#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PMAPMD | \ - MDIO_MMDREG_DEVS0_PCS | \ - MDIO_MMDREG_DEVS0_PHYXS) - -#define TENXPRESS_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ - (1 << LOOPBACK_PCS) | \ - (1 << LOOPBACK_PMAPMD) | \ - (1 << LOOPBACK_NETWORK)) +/* We expect these MMDs to be in the package. SFT9001 also has a + * clause 22 extension MMD, but since it doesn't have all the generic + * MMD registers it is pointless to include it here. + */ +#define TENXPRESS_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PMAPMD | \ + MDIO_MMDREG_DEVS_PCS | \ + MDIO_MMDREG_DEVS_PHYXS | \ + MDIO_MMDREG_DEVS_AN) + +#define SFX7101_LOOPBACKS ((1 << LOOPBACK_PHYXS) | \ + (1 << LOOPBACK_PCS) | \ + (1 << LOOPBACK_PMAPMD) | \ + (1 << LOOPBACK_NETWORK)) + +#define SFT9001_LOOPBACKS ((1 << LOOPBACK_GPHY) | \ + (1 << LOOPBACK_PHYXS) | \ + (1 << LOOPBACK_PCS) | \ + (1 << LOOPBACK_PMAPMD) | \ + (1 << LOOPBACK_NETWORK)) /* We complain if we fail to see the link partner as 10G capable this many * times in a row (must be > 1 as sampling the autoneg. registers is racy) */ #define MAX_BAD_LP_TRIES (5) +/* LASI Control */ +#define PMA_PMD_LASI_CTRL 36866 +#define PMA_PMD_LASI_STATUS 36869 +#define PMA_PMD_LS_ALARM_LBN 0 +#define PMA_PMD_LS_ALARM_WIDTH 1 +#define PMA_PMD_TX_ALARM_LBN 1 +#define PMA_PMD_TX_ALARM_WIDTH 1 +#define PMA_PMD_RX_ALARM_LBN 2 +#define PMA_PMD_RX_ALARM_WIDTH 1 +#define PMA_PMD_AN_ALARM_LBN 3 +#define PMA_PMD_AN_ALARM_WIDTH 1 + /* Extended control register */ -#define PMA_PMD_XCONTROL_REG 0xc000 -#define PMA_PMD_LNPGA_POWERDOWN_LBN 8 -#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1 +#define PMA_PMD_XCONTROL_REG 49152 +#define PMA_PMD_EXT_GMII_EN_LBN 1 +#define PMA_PMD_EXT_GMII_EN_WIDTH 1 +#define PMA_PMD_EXT_CLK_OUT_LBN 2 +#define PMA_PMD_EXT_CLK_OUT_WIDTH 1 +#define PMA_PMD_LNPGA_POWERDOWN_LBN 8 /* SFX7101 only */ +#define PMA_PMD_LNPGA_POWERDOWN_WIDTH 1 +#define PMA_PMD_EXT_CLK312_LBN 8 /* SFT9001 only */ +#define PMA_PMD_EXT_CLK312_WIDTH 1 +#define PMA_PMD_EXT_LPOWER_LBN 12 +#define PMA_PMD_EXT_LPOWER_WIDTH 1 +#define PMA_PMD_EXT_SSR_LBN 15 +#define PMA_PMD_EXT_SSR_WIDTH 1 /* extended status register */ -#define PMA_PMD_XSTATUS_REG 0xc001 +#define PMA_PMD_XSTATUS_REG 49153 #define PMA_PMD_XSTAT_FLP_LBN (12) /* LED control register */ -#define PMA_PMD_LED_CTRL_REG (0xc007) +#define PMA_PMD_LED_CTRL_REG 49159 #define PMA_PMA_LED_ACTIVITY_LBN (3) /* LED function override register */ -#define PMA_PMD_LED_OVERR_REG (0xc009) +#define PMA_PMD_LED_OVERR_REG 49161 /* Bit positions for different LEDs (there are more but not wired on SFE4001)*/ #define PMA_PMD_LED_LINK_LBN (0) #define PMA_PMD_LED_SPEED_LBN (2) @@ -59,41 +90,99 @@ #define PMA_PMD_LED_ON (1) #define PMA_PMD_LED_OFF (2) #define PMA_PMD_LED_FLASH (3) +#define PMA_PMD_LED_MASK 3 /* All LEDs under hardware control */ #define PMA_PMD_LED_FULL_AUTO (0) /* Green and Amber under hardware control, Red off */ #define PMA_PMD_LED_DEFAULT (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN) - -/* Special Software reset register */ -#define PMA_PMD_EXT_CTRL_REG 49152 -#define PMA_PMD_EXT_SSR_LBN 15 - -/* Misc register defines */ -#define PCS_CLOCK_CTRL_REG 0xd801 +#define PMA_PMD_SPEED_ENABLE_REG 49192 +#define PMA_PMD_100TX_ADV_LBN 1 +#define PMA_PMD_100TX_ADV_WIDTH 1 +#define PMA_PMD_1000T_ADV_LBN 2 +#define PMA_PMD_1000T_ADV_WIDTH 1 +#define PMA_PMD_10000T_ADV_LBN 3 +#define PMA_PMD_10000T_ADV_WIDTH 1 +#define PMA_PMD_SPEED_LBN 4 +#define PMA_PMD_SPEED_WIDTH 4 + +/* Cable diagnostics - SFT9001 only */ +#define PMA_PMD_CDIAG_CTRL_REG 49213 +#define CDIAG_CTRL_IMMED_LBN 15 +#define CDIAG_CTRL_BRK_LINK_LBN 12 +#define CDIAG_CTRL_IN_PROG_LBN 11 +#define CDIAG_CTRL_LEN_UNIT_LBN 10 +#define CDIAG_CTRL_LEN_METRES 1 +#define PMA_PMD_CDIAG_RES_REG 49174 +#define CDIAG_RES_A_LBN 12 +#define CDIAG_RES_B_LBN 8 +#define CDIAG_RES_C_LBN 4 +#define CDIAG_RES_D_LBN 0 +#define CDIAG_RES_WIDTH 4 +#define CDIAG_RES_OPEN 2 +#define CDIAG_RES_OK 1 +#define CDIAG_RES_INVALID 0 +/* Set of 4 registers for pairs A-D */ +#define PMA_PMD_CDIAG_LEN_REG 49175 + +/* Serdes control registers - SFT9001 only */ +#define PMA_PMD_CSERDES_CTRL_REG 64258 +/* Set the 156.25 MHz output to 312.5 MHz to drive Falcon's XMAC */ +#define PMA_PMD_CSERDES_DEFAULT 0x000f + +/* Misc register defines - SFX7101 only */ +#define PCS_CLOCK_CTRL_REG 55297 #define PLL312_RST_N_LBN 2 -#define PCS_SOFT_RST2_REG 0xd806 +#define PCS_SOFT_RST2_REG 55302 #define SERDES_RST_N_LBN 13 #define XGXS_RST_N_LBN 12 -#define PCS_TEST_SELECT_REG 0xd807 /* PRM 10.5.8 */ +#define PCS_TEST_SELECT_REG 55303 /* PRM 10.5.8 */ #define CLK312_EN_LBN 3 /* PHYXS registers */ +#define PHYXS_XCONTROL_REG 49152 +#define PHYXS_RESET_LBN 15 +#define PHYXS_RESET_WIDTH 1 + #define PHYXS_TEST1 (49162) #define LOOPBACK_NEAR_LBN (8) #define LOOPBACK_NEAR_WIDTH (1) +#define PCS_10GBASET_STAT1 32 +#define PCS_10GBASET_BLKLK_LBN 0 +#define PCS_10GBASET_BLKLK_WIDTH 1 + /* Boot status register */ -#define PCS_BOOT_STATUS_REG (0xd000) +#define PCS_BOOT_STATUS_REG 53248 #define PCS_BOOT_FATAL_ERR_LBN (0) #define PCS_BOOT_PROGRESS_LBN (1) #define PCS_BOOT_PROGRESS_WIDTH (2) #define PCS_BOOT_COMPLETE_LBN (3) + #define PCS_BOOT_MAX_DELAY (100) #define PCS_BOOT_POLL_DELAY (10) +/* 100M/1G PHY registers */ +#define GPHY_XCONTROL_REG 49152 +#define GPHY_ISOLATE_LBN 10 +#define GPHY_ISOLATE_WIDTH 1 +#define GPHY_DUPLEX_LBN 8 +#define GPHY_DUPLEX_WIDTH 1 +#define GPHY_LOOPBACK_NEAR_LBN 14 +#define GPHY_LOOPBACK_NEAR_WIDTH 1 + +#define C22EXT_STATUS_REG 49153 +#define C22EXT_STATUS_LINK_LBN 2 +#define C22EXT_STATUS_LINK_WIDTH 1 + +#define C22EXT_MSTSLV_REG 49162 +#define C22EXT_MSTSLV_1000_HD_LBN 10 +#define C22EXT_MSTSLV_1000_HD_WIDTH 1 +#define C22EXT_MSTSLV_1000_FD_LBN 11 +#define C22EXT_MSTSLV_1000_FD_WIDTH 1 + /* Time to wait between powering down the LNPGA and turning off the power * rails */ #define LNPGA_PDOWN_WAIT (HZ / 5) @@ -117,6 +206,38 @@ void tenxpress_crc_err(struct efx_nic *efx) atomic_inc(&phy_data->bad_crc_count); } +static ssize_t show_phy_short_reach(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + int reg; + + reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, + MDIO_PMAPMD_10GBT_TXPWR); + return sprintf(buf, "%d\n", + !!(reg & (1 << MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN))); +} + +static ssize_t set_phy_short_reach(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct efx_nic *efx = pci_get_drvdata(to_pci_dev(dev)); + + rtnl_lock(); + mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, + MDIO_PMAPMD_10GBT_TXPWR, + MDIO_PMAPMD_10GBT_TXPWR_SHORT_LBN, + count != 0 && *buf != '0'); + efx_reconfigure_port(efx); + rtnl_unlock(); + + return count; +} + +static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach, + set_phy_short_reach); + /* Check that the C166 has booted successfully */ static int tenxpress_phy_check(struct efx_nic *efx) { @@ -148,27 +269,42 @@ static int tenxpress_phy_check(struct efx_nic *efx) static int tenxpress_init(struct efx_nic *efx) { - int rc, reg; + int phy_id = efx->mii.phy_id; + int reg; + int rc; - /* Turn on the clock */ - reg = (1 << CLK312_EN_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, - MDIO_MMD_PCS, PCS_TEST_SELECT_REG, reg); + if (efx->phy_type == PHY_TYPE_SFX7101) { + /* Enable 312.5 MHz clock */ + mdio_clause45_write(efx, phy_id, + MDIO_MMD_PCS, PCS_TEST_SELECT_REG, + 1 << CLK312_EN_LBN); + } else { + /* Enable 312.5 MHz clock and GMII */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG); + reg |= ((1 << PMA_PMD_EXT_GMII_EN_LBN) | + (1 << PMA_PMD_EXT_CLK_OUT_LBN) | + (1 << PMA_PMD_EXT_CLK312_LBN)); + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG, reg); + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, + GPHY_XCONTROL_REG, GPHY_ISOLATE_LBN, + false); + } rc = tenxpress_phy_check(efx); if (rc < 0) return rc; /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */ - reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, PMA_PMD_LED_CTRL_REG); - reg |= (1 << PMA_PMA_LED_ACTIVITY_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_CTRL_REG, reg); - - reg = PMA_PMD_LED_DEFAULT; - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG, reg); + if (efx->phy_type == PHY_TYPE_SFX7101) { + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_LED_CTRL_REG, + PMA_PMA_LED_ACTIVITY_LBN, + true); + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_LED_OVERR_REG, PMA_PMD_LED_DEFAULT); + } return rc; } @@ -184,22 +320,43 @@ static int tenxpress_phy_init(struct efx_nic *efx) efx->phy_data = phy_data; phy_data->phy_mode = efx->phy_mode; - rc = mdio_clause45_wait_reset_mmds(efx, - TENXPRESS_REQUIRED_DEVS); - if (rc < 0) - goto fail; + if (!(efx->phy_mode & PHY_MODE_SPECIAL)) { + if (efx->phy_type == PHY_TYPE_SFT9001A) { + int reg; + reg = mdio_clause45_read(efx, efx->mii.phy_id, + MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG); + reg |= (1 << PMA_PMD_EXT_SSR_LBN); + mdio_clause45_write(efx, efx->mii.phy_id, + MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG, reg); + mdelay(200); + } - rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); - if (rc < 0) - goto fail; + rc = mdio_clause45_wait_reset_mmds(efx, + TENXPRESS_REQUIRED_DEVS); + if (rc < 0) + goto fail; + + rc = mdio_clause45_check_mmds(efx, TENXPRESS_REQUIRED_DEVS, 0); + if (rc < 0) + goto fail; + } rc = tenxpress_init(efx); if (rc < 0) goto fail; + if (efx->phy_type == PHY_TYPE_SFT9001B) { + rc = device_create_file(&efx->pci_dev->dev, + &dev_attr_phy_short_reach); + if (rc) + goto fail; + } + schedule_timeout_uninterruptible(HZ / 5); /* 200ms */ - /* Let XGXS and SerDes out of reset and resets 10XPress */ + /* Let XGXS and SerDes out of reset */ falcon_reset_xaui(efx); return 0; @@ -210,21 +367,24 @@ static int tenxpress_phy_init(struct efx_nic *efx) return rc; } +/* Perform a "special software reset" on the PHY. The caller is + * responsible for saving and restoring the PHY hardware registers + * properly, and masking/unmasking LASI */ static int tenxpress_special_reset(struct efx_nic *efx) { int rc, reg; /* The XGMAC clock is driven from the SFC7101/SFT9001 312MHz clock, so * a special software reset can glitch the XGMAC sufficiently for stats - * requests to fail. Since we don't ofen special_reset, just lock. */ + * requests to fail. Since we don't often special_reset, just lock. */ spin_lock(&efx->stats_lock); /* Initiate reset */ reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, PMA_PMD_EXT_CTRL_REG); + MDIO_MMD_PMAPMD, PMA_PMD_XCONTROL_REG); reg |= (1 << PMA_PMD_EXT_SSR_LBN); mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_EXT_CTRL_REG, reg); + PMA_PMD_XCONTROL_REG, reg); mdelay(200); @@ -239,174 +399,257 @@ static int tenxpress_special_reset(struct efx_nic *efx) if (rc < 0) goto unlock; + /* Wait for the XGXS state machine to churn */ + mdelay(10); unlock: spin_unlock(&efx->stats_lock); return rc; } -static void tenxpress_set_bad_lp(struct efx_nic *efx, bool bad_lp) +static void sfx7101_check_bad_lp(struct efx_nic *efx, bool link_ok) { struct tenxpress_phy_data *pd = efx->phy_data; + int phy_id = efx->mii.phy_id; + bool bad_lp; int reg; + if (link_ok) { + bad_lp = false; + } else { + /* Check that AN has started but not completed. */ + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, + MDIO_AN_STATUS); + if (!(reg & (1 << MDIO_AN_STATUS_LP_AN_CAP_LBN))) + return; /* LP status is unknown */ + bad_lp = !(reg & (1 << MDIO_AN_STATUS_AN_DONE_LBN)); + if (bad_lp) + pd->bad_lp_tries++; + } + /* Nothing to do if all is well and was previously so. */ - if (!(bad_lp || pd->bad_lp_tries)) + if (!pd->bad_lp_tries) return; - reg = mdio_clause45_read(efx, efx->mii.phy_id, - MDIO_MMD_PMAPMD, PMA_PMD_LED_OVERR_REG); + /* Use the RX (red) LED as an error indicator once we've seen AN + * failure several times in a row, and also log a message. */ + if (!bad_lp || pd->bad_lp_tries == MAX_BAD_LP_TRIES) { + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_LED_OVERR_REG); + reg &= ~(PMA_PMD_LED_MASK << PMA_PMD_LED_RX_LBN); + if (!bad_lp) { + reg |= PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN; + } else { + reg |= PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN; + EFX_ERR(efx, "appears to be plugged into a port" + " that is not 10GBASE-T capable. The PHY" + " supports 10GBASE-T ONLY, so no link can" + " be established\n"); + } + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_LED_OVERR_REG, reg); + pd->bad_lp_tries = bad_lp; + } +} - if (bad_lp) - pd->bad_lp_tries++; - else - pd->bad_lp_tries = 0; - - if (pd->bad_lp_tries == MAX_BAD_LP_TRIES) { - pd->bad_lp_tries = 0; /* Restart count */ - reg &= ~(PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN); - reg |= (PMA_PMD_LED_FLASH << PMA_PMD_LED_RX_LBN); - EFX_ERR(efx, "This NIC appears to be plugged into" - " a port that is not 10GBASE-T capable.\n" - " This PHY is 10GBASE-T ONLY, so no link can" - " be established.\n"); +static bool sfx7101_link_ok(struct efx_nic *efx) +{ + return mdio_clause45_links_ok(efx, + MDIO_MMDREG_DEVS_PMAPMD | + MDIO_MMDREG_DEVS_PCS | + MDIO_MMDREG_DEVS_PHYXS); +} + +static bool sft9001_link_ok(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + int phy_id = efx->mii.phy_id; + u32 reg; + + if (efx_phy_mode_disabled(efx->phy_mode)) + return false; + else if (efx->loopback_mode == LOOPBACK_GPHY) + return true; + else if (efx->loopback_mode) + return mdio_clause45_links_ok(efx, + MDIO_MMDREG_DEVS_PMAPMD | + MDIO_MMDREG_DEVS_PHYXS); + + /* We must use the same definition of link state as LASI, + * otherwise we can miss a link state transition + */ + if (ecmd->speed == 10000) { + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS, + PCS_10GBASET_STAT1); + return reg & (1 << PCS_10GBASET_BLKLK_LBN); } else { - reg |= (PMA_PMD_LED_OFF << PMA_PMD_LED_RX_LBN); + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, + C22EXT_STATUS_REG); + return reg & (1 << C22EXT_STATUS_LINK_LBN); } - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_LED_OVERR_REG, reg); } -/* Check link status and return a boolean OK value. If the link is NOT - * OK we have a quick rummage round to see if we appear to be plugged - * into a non-10GBT port and if so warn the user that they won't get - * link any time soon as we are 10GBT only, unless caller specified - * not to do this check (it isn't useful in loopback) */ -static bool tenxpress_link_ok(struct efx_nic *efx, bool check_lp) +static void tenxpress_ext_loopback(struct efx_nic *efx) { - bool ok = mdio_clause45_links_ok(efx, TENXPRESS_REQUIRED_DEVS); - - if (ok) { - tenxpress_set_bad_lp(efx, false); - } else if (check_lp) { - /* Are we plugged into the wrong sort of link? */ - bool bad_lp = false; - int phy_id = efx->mii.phy_id; - int an_stat = mdio_clause45_read(efx, phy_id, MDIO_MMD_AN, - MDIO_AN_STATUS); - int xphy_stat = mdio_clause45_read(efx, phy_id, - MDIO_MMD_PMAPMD, - PMA_PMD_XSTATUS_REG); - /* Are we plugged into anything that sends FLPs? If - * not we can't distinguish between not being plugged - * in and being plugged into a non-AN antique. The FLP - * bit has the advantage of not clearing when autoneg - * restarts. */ - if (!(xphy_stat & (1 << PMA_PMD_XSTAT_FLP_LBN))) { - tenxpress_set_bad_lp(efx, false); - return ok; - } + int phy_id = efx->mii.phy_id; - /* If it can do 10GBT it must be XNP capable */ - bad_lp = !(an_stat & (1 << MDIO_AN_STATUS_XNP_LBN)); - if (!bad_lp && (an_stat & (1 << MDIO_AN_STATUS_PAGE_LBN))) { - bad_lp = !(mdio_clause45_read(efx, phy_id, - MDIO_MMD_AN, MDIO_AN_10GBT_STATUS) & - (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN)); - } - tenxpress_set_bad_lp(efx, bad_lp); - } - return ok; + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PHYXS, + PHYXS_TEST1, LOOPBACK_NEAR_LBN, + efx->loopback_mode == LOOPBACK_PHYXS); + if (efx->phy_type != PHY_TYPE_SFX7101) + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, + GPHY_XCONTROL_REG, + GPHY_LOOPBACK_NEAR_LBN, + efx->loopback_mode == LOOPBACK_GPHY); } -static void tenxpress_phyxs_loopback(struct efx_nic *efx) +static void tenxpress_low_power(struct efx_nic *efx) { int phy_id = efx->mii.phy_id; - int ctrl1, ctrl2; - ctrl1 = ctrl2 = mdio_clause45_read(efx, phy_id, MDIO_MMD_PHYXS, - PHYXS_TEST1); - if (efx->loopback_mode == LOOPBACK_PHYXS) - ctrl2 |= (1 << LOOPBACK_NEAR_LBN); + if (efx->phy_type == PHY_TYPE_SFX7101) + mdio_clause45_set_mmds_lpower( + efx, !!(efx->phy_mode & PHY_MODE_LOW_POWER), + TENXPRESS_REQUIRED_DEVS); else - ctrl2 &= ~(1 << LOOPBACK_NEAR_LBN); - if (ctrl1 != ctrl2) - mdio_clause45_write(efx, phy_id, MDIO_MMD_PHYXS, - PHYXS_TEST1, ctrl2); + mdio_clause45_set_flag( + efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG, PMA_PMD_EXT_LPOWER_LBN, + !!(efx->phy_mode & PHY_MODE_LOW_POWER)); } static void tenxpress_phy_reconfigure(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; - bool loop_change = LOOPBACK_OUT_OF(phy_data, efx, - TENXPRESS_LOOPBACKS); + struct ethtool_cmd ecmd; + bool phy_mode_change, loop_reset, loop_toggle, loopback; - if (efx->phy_mode & PHY_MODE_SPECIAL) { + if (efx->phy_mode & (PHY_MODE_OFF | PHY_MODE_SPECIAL)) { phy_data->phy_mode = efx->phy_mode; return; } - /* When coming out of transmit disable, coming out of low power - * mode, or moving out of any PHY internal loopback mode, - * perform a special software reset */ - if ((efx->phy_mode == PHY_MODE_NORMAL && - phy_data->phy_mode != PHY_MODE_NORMAL) || - loop_change) { - tenxpress_special_reset(efx); - falcon_reset_xaui(efx); + tenxpress_low_power(efx); + + phy_mode_change = (efx->phy_mode == PHY_MODE_NORMAL && + phy_data->phy_mode != PHY_MODE_NORMAL); + loopback = LOOPBACK_MASK(efx) & efx->phy_op->loopbacks; + loop_toggle = LOOPBACK_CHANGED(phy_data, efx, efx->phy_op->loopbacks); + loop_reset = (LOOPBACK_OUT_OF(phy_data, efx, efx->phy_op->loopbacks) || + LOOPBACK_CHANGED(phy_data, efx, 1 << LOOPBACK_GPHY)); + + if (loop_reset || loop_toggle || loopback || phy_mode_change) { + int rc; + + efx->phy_op->get_settings(efx, &ecmd); + + if (loop_reset || phy_mode_change) { + tenxpress_special_reset(efx); + + /* Reset XAUI if we were in 10G, and are staying + * in 10G. If we're moving into and out of 10G + * then xaui will be reset anyway */ + if (EFX_IS10G(efx)) + falcon_reset_xaui(efx); + } + + if (efx->phy_type != PHY_TYPE_SFX7101) { + /* Only change autoneg once, on coming out or + * going into loopback */ + if (loop_toggle) + ecmd.autoneg = !loopback; + if (loopback) { + ecmd.duplex = DUPLEX_FULL; + if (efx->loopback_mode == LOOPBACK_GPHY) + ecmd.speed = SPEED_1000; + else + ecmd.speed = SPEED_10000; + } + } + + rc = efx->phy_op->set_settings(efx, &ecmd); + WARN_ON(rc); } mdio_clause45_transmit_disable(efx); mdio_clause45_phy_reconfigure(efx); - tenxpress_phyxs_loopback(efx); + tenxpress_ext_loopback(efx); phy_data->loopback_mode = efx->loopback_mode; phy_data->phy_mode = efx->phy_mode; - efx->link_up = tenxpress_link_ok(efx, false); - efx->link_options = GM_LPA_10000FULL; -} -static void tenxpress_phy_clear_interrupt(struct efx_nic *efx) -{ - /* Nothing done here - LASI interrupts aren't reliable so poll */ + if (efx->phy_type == PHY_TYPE_SFX7101) { + efx->link_speed = 10000; + efx->link_fd = true; + efx->link_up = sfx7101_link_ok(efx); + } else { + efx->phy_op->get_settings(efx, &ecmd); + efx->link_speed = ecmd.speed; + efx->link_fd = ecmd.duplex == DUPLEX_FULL; + efx->link_up = sft9001_link_ok(efx, &ecmd); + } + efx->link_fc = mdio_clause45_get_pause(efx); } - /* Poll PHY for interrupt */ -static int tenxpress_phy_check_hw(struct efx_nic *efx) +static void tenxpress_phy_poll(struct efx_nic *efx) { struct tenxpress_phy_data *phy_data = efx->phy_data; - bool link_ok; - - link_ok = tenxpress_link_ok(efx, true); + bool change = false, link_ok; + unsigned link_fc; + + if (efx->phy_type == PHY_TYPE_SFX7101) { + link_ok = sfx7101_link_ok(efx); + if (link_ok != efx->link_up) { + change = true; + } else { + link_fc = mdio_clause45_get_pause(efx); + if (link_fc != efx->link_fc) + change = true; + } + sfx7101_check_bad_lp(efx, link_ok); + } else if (efx->loopback_mode) { + bool link_ok = sft9001_link_ok(efx, NULL); + if (link_ok != efx->link_up) + change = true; + } else { + u32 status = mdio_clause45_read(efx, efx->mii.phy_id, + MDIO_MMD_PMAPMD, + PMA_PMD_LASI_STATUS); + if (status & (1 << PMA_PMD_LS_ALARM_LBN)) + change = true; + } - if (link_ok != efx->link_up) - falcon_xmac_sim_phy_event(efx); + if (change) + falcon_sim_phy_event(efx); if (phy_data->phy_mode != PHY_MODE_NORMAL) - return 0; + return; - if (atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) { + if (EFX_WORKAROUND_10750(efx) && + atomic_read(&phy_data->bad_crc_count) > crc_error_reset_threshold) { EFX_ERR(efx, "Resetting XAUI due to too many CRC errors\n"); falcon_reset_xaui(efx); atomic_set(&phy_data->bad_crc_count, 0); } - - return 0; } static void tenxpress_phy_fini(struct efx_nic *efx) { int reg; - /* Power down the LNPGA */ - reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); - mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, - PMA_PMD_XCONTROL_REG, reg); - - /* Waiting here ensures that the board fini, which can turn off the - * power to the PHY, won't get run until the LNPGA powerdown has been - * given long enough to complete. */ - schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */ + if (efx->phy_type == PHY_TYPE_SFT9001B) { + device_remove_file(&efx->pci_dev->dev, + &dev_attr_phy_short_reach); + } else { + /* Power down the LNPGA */ + reg = (1 << PMA_PMD_LNPGA_POWERDOWN_LBN); + mdio_clause45_write(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_XCONTROL_REG, reg); + + /* Waiting here ensures that the board fini, which can turn + * off the power to the PHY, won't get run until the LNPGA + * powerdown has been given long enough to complete. */ + schedule_timeout_uninterruptible(LNPGA_PDOWN_WAIT); /* 200 ms */ + } kfree(efx->phy_data); efx->phy_data = NULL; @@ -430,19 +673,236 @@ void tenxpress_phy_blink(struct efx_nic *efx, bool blink) PMA_PMD_LED_OVERR_REG, reg); } -static int tenxpress_phy_test(struct efx_nic *efx) +static const char *const sfx7101_test_names[] = { + "bist" +}; + +static int +sfx7101_run_tests(struct efx_nic *efx, int *results, unsigned flags) { + int rc; + + if (!(flags & ETH_TEST_FL_OFFLINE)) + return 0; + /* BIST is automatically run after a special software reset */ - return tenxpress_special_reset(efx); + rc = tenxpress_special_reset(efx); + results[0] = rc ? -1 : 1; + return rc; } -struct efx_phy_operations falcon_tenxpress_phy_ops = { +static const char *const sft9001_test_names[] = { + "bist", + "cable.pairA.status", + "cable.pairB.status", + "cable.pairC.status", + "cable.pairD.status", + "cable.pairA.length", + "cable.pairB.length", + "cable.pairC.length", + "cable.pairD.length", +}; + +static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags) +{ + struct ethtool_cmd ecmd; + int phy_id = efx->mii.phy_id; + int rc = 0, rc2, i, res_reg; + + if (!(flags & ETH_TEST_FL_OFFLINE)) + return 0; + + efx->phy_op->get_settings(efx, &ecmd); + + /* Initialise cable diagnostic results to unknown failure */ + for (i = 1; i < 9; ++i) + results[i] = -1; + + /* Run cable diagnostics; wait up to 5 seconds for them to complete. + * A cable fault is not a self-test failure, but a timeout is. */ + mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_CDIAG_CTRL_REG, + (1 << CDIAG_CTRL_IMMED_LBN) | + (1 << CDIAG_CTRL_BRK_LINK_LBN) | + (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN)); + i = 0; + while (mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_CDIAG_CTRL_REG) & + (1 << CDIAG_CTRL_IN_PROG_LBN)) { + if (++i == 50) { + rc = -ETIMEDOUT; + goto reset; + } + msleep(100); + } + res_reg = mdio_clause45_read(efx, efx->mii.phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_CDIAG_RES_REG); + for (i = 0; i < 4; i++) { + int pair_res = + (res_reg >> (CDIAG_RES_A_LBN - i * CDIAG_RES_WIDTH)) + & ((1 << CDIAG_RES_WIDTH) - 1); + int len_reg = mdio_clause45_read(efx, efx->mii.phy_id, + MDIO_MMD_PMAPMD, + PMA_PMD_CDIAG_LEN_REG + i); + if (pair_res == CDIAG_RES_OK) + results[1 + i] = 1; + else if (pair_res == CDIAG_RES_INVALID) + results[1 + i] = -1; + else + results[1 + i] = -pair_res; + if (pair_res != CDIAG_RES_INVALID && + pair_res != CDIAG_RES_OPEN && + len_reg != 0xffff) + results[5 + i] = len_reg; + } + + /* We must reset to exit cable diagnostic mode. The BIST will + * also run when we do this. */ +reset: + rc2 = tenxpress_special_reset(efx); + results[0] = rc2 ? -1 : 1; + if (!rc) + rc = rc2; + + rc2 = efx->phy_op->set_settings(efx, &ecmd); + if (!rc) + rc = rc2; + + return rc; +} + +static u32 tenxpress_get_xnp_lpa(struct efx_nic *efx) +{ + int phy = efx->mii.phy_id; + u32 lpa = 0; + int reg; + + if (efx->phy_type != PHY_TYPE_SFX7101) { + reg = mdio_clause45_read(efx, phy, MDIO_MMD_C22EXT, + C22EXT_MSTSLV_REG); + if (reg & (1 << C22EXT_MSTSLV_1000_HD_LBN)) + lpa |= ADVERTISED_1000baseT_Half; + if (reg & (1 << C22EXT_MSTSLV_1000_FD_LBN)) + lpa |= ADVERTISED_1000baseT_Full; + } + reg = mdio_clause45_read(efx, phy, MDIO_MMD_AN, MDIO_AN_10GBT_STATUS); + if (reg & (1 << MDIO_AN_10GBT_STATUS_LP_10G_LBN)) + lpa |= ADVERTISED_10000baseT_Full; + return lpa; +} + +static void sfx7101_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + mdio_clause45_get_settings_ext(efx, ecmd, ADVERTISED_10000baseT_Full, + tenxpress_get_xnp_lpa(efx)); + ecmd->supported |= SUPPORTED_10000baseT_Full; + ecmd->advertising |= ADVERTISED_10000baseT_Full; +} + +static void sft9001_get_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + int phy_id = efx->mii.phy_id; + u32 xnp_adv = 0; + int reg; + + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD, + PMA_PMD_SPEED_ENABLE_REG); + if (EFX_WORKAROUND_13204(efx) && (reg & (1 << PMA_PMD_100TX_ADV_LBN))) + xnp_adv |= ADVERTISED_100baseT_Full; + if (reg & (1 << PMA_PMD_1000T_ADV_LBN)) + xnp_adv |= ADVERTISED_1000baseT_Full; + if (reg & (1 << PMA_PMD_10000T_ADV_LBN)) + xnp_adv |= ADVERTISED_10000baseT_Full; + + mdio_clause45_get_settings_ext(efx, ecmd, xnp_adv, + tenxpress_get_xnp_lpa(efx)); + + ecmd->supported |= (SUPPORTED_100baseT_Half | + SUPPORTED_100baseT_Full | + SUPPORTED_1000baseT_Full); + + /* Use the vendor defined C22ext register for duplex settings */ + if (ecmd->speed != SPEED_10000 && !ecmd->autoneg) { + reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_C22EXT, + GPHY_XCONTROL_REG); + ecmd->duplex = (reg & (1 << GPHY_DUPLEX_LBN) ? + DUPLEX_FULL : DUPLEX_HALF); + } +} + +static int sft9001_set_settings(struct efx_nic *efx, struct ethtool_cmd *ecmd) +{ + int phy_id = efx->mii.phy_id; + int rc; + + rc = mdio_clause45_set_settings(efx, ecmd); + if (rc) + return rc; + + if (ecmd->speed != SPEED_10000 && !ecmd->autoneg) + mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_C22EXT, + GPHY_XCONTROL_REG, GPHY_DUPLEX_LBN, + ecmd->duplex == DUPLEX_FULL); + + return rc; +} + +static bool sft9001_set_xnp_advertise(struct efx_nic *efx, u32 advertising) +{ + int phy = efx->mii.phy_id; + int reg = mdio_clause45_read(efx, phy, MDIO_MMD_PMAPMD, + PMA_PMD_SPEED_ENABLE_REG); + bool enabled; + + reg &= ~((1 << 2) | (1 << 3)); + if (EFX_WORKAROUND_13204(efx) && + (advertising & ADVERTISED_100baseT_Full)) + reg |= 1 << PMA_PMD_100TX_ADV_LBN; + if (advertising & ADVERTISED_1000baseT_Full) + reg |= 1 << PMA_PMD_1000T_ADV_LBN; + if (advertising & ADVERTISED_10000baseT_Full) + reg |= 1 << PMA_PMD_10000T_ADV_LBN; + mdio_clause45_write(efx, phy, MDIO_MMD_PMAPMD, + PMA_PMD_SPEED_ENABLE_REG, reg); + + enabled = (advertising & + (ADVERTISED_1000baseT_Half | + ADVERTISED_1000baseT_Full | + ADVERTISED_10000baseT_Full)); + if (EFX_WORKAROUND_13204(efx)) + enabled |= (advertising & ADVERTISED_100baseT_Full); + return enabled; +} + +struct efx_phy_operations falcon_sfx7101_phy_ops = { + .macs = EFX_XMAC, + .init = tenxpress_phy_init, + .reconfigure = tenxpress_phy_reconfigure, + .poll = tenxpress_phy_poll, + .fini = tenxpress_phy_fini, + .clear_interrupt = efx_port_dummy_op_void, + .get_settings = sfx7101_get_settings, + .set_settings = mdio_clause45_set_settings, + .num_tests = ARRAY_SIZE(sfx7101_test_names), + .test_names = sfx7101_test_names, + .run_tests = sfx7101_run_tests, + .mmds = TENXPRESS_REQUIRED_DEVS, + .loopbacks = SFX7101_LOOPBACKS, +}; + +struct efx_phy_operations falcon_sft9001_phy_ops = { + .macs = EFX_GMAC | EFX_XMAC, .init = tenxpress_phy_init, .reconfigure = tenxpress_phy_reconfigure, - .check_hw = tenxpress_phy_check_hw, + .poll = tenxpress_phy_poll, .fini = tenxpress_phy_fini, - .clear_interrupt = tenxpress_phy_clear_interrupt, - .test = tenxpress_phy_test, + .clear_interrupt = efx_port_dummy_op_void, + .get_settings = sft9001_get_settings, + .set_settings = sft9001_set_settings, + .set_xnp_advertise = sft9001_set_xnp_advertise, + .num_tests = ARRAY_SIZE(sft9001_test_names), + .test_names = sft9001_test_names, + .run_tests = sft9001_run_tests, .mmds = TENXPRESS_REQUIRED_DEVS, - .loopbacks = TENXPRESS_LOOPBACKS, + .loopbacks = SFT9001_LOOPBACKS, }; diff --git a/drivers/net/sfc/workarounds.h b/drivers/net/sfc/workarounds.h index fa7b49d69288d3d3fe201f6cbd1aa788cf1e8e4f..82e03e1d73713ad2cc5c7dbbc110627fb21abe15 100644 --- a/drivers/net/sfc/workarounds.h +++ b/drivers/net/sfc/workarounds.h @@ -17,15 +17,20 @@ #define EFX_WORKAROUND_ALWAYS(efx) 1 #define EFX_WORKAROUND_FALCON_A(efx) (falcon_rev(efx) <= FALCON_REV_A1) +#define EFX_WORKAROUND_10G(efx) EFX_IS10G(efx) +#define EFX_WORKAROUND_SFX7101(efx) ((efx)->phy_type == PHY_TYPE_SFX7101) +#define EFX_WORKAROUND_SFT9001A(efx) ((efx)->phy_type == PHY_TYPE_SFT9001A) /* XAUI resets if link not detected */ #define EFX_WORKAROUND_5147 EFX_WORKAROUND_ALWAYS /* RX PCIe double split performance issue */ #define EFX_WORKAROUND_7575 EFX_WORKAROUND_ALWAYS +/* Bit-bashed I2C reads cause performance drop */ +#define EFX_WORKAROUND_7884 EFX_WORKAROUND_10G /* TX pkt parser problem with <= 16 byte TXes */ #define EFX_WORKAROUND_9141 EFX_WORKAROUND_ALWAYS /* Low rate CRC errors require XAUI reset */ -#define EFX_WORKAROUND_10750 EFX_WORKAROUND_ALWAYS +#define EFX_WORKAROUND_10750 EFX_WORKAROUND_SFX7101 /* TX_EV_PKT_ERR can be caused by a dangling TX descriptor * or a PCIe error (bug 11028) */ #define EFX_WORKAROUND_10727 EFX_WORKAROUND_ALWAYS @@ -49,4 +54,9 @@ /* Leak overlength packets rather than free */ #define EFX_WORKAROUND_8071 EFX_WORKAROUND_FALCON_A +/* Need to send XNP pages for 100BaseT */ +#define EFX_WORKAROUND_13204 EFX_WORKAROUND_SFT9001A +/* Need to keep AN enabled */ +#define EFX_WORKAROUND_13963 EFX_WORKAROUND_SFT9001A + #endif /* EFX_WORKAROUNDS_H */ diff --git a/drivers/net/sfc/xfp_phy.c b/drivers/net/sfc/xfp_phy.c index 276151df3a703537ba01a315c90e7842d82ce4a8..2d50b6ecf5f9e92b87330dc574f12dbf3741b560 100644 --- a/drivers/net/sfc/xfp_phy.c +++ b/drivers/net/sfc/xfp_phy.c @@ -7,22 +7,21 @@ * by the Free Software Foundation, incorporated herein by reference. */ /* - * Driver for XFP optical PHYs (plus some support specific to the Quake 2032) + * Driver for XFP optical PHYs (plus some support specific to the Quake 2022/32) * See www.amcc.com for details (search for qt2032) */ #include #include #include "efx.h" -#include "gmii.h" #include "mdio_10g.h" #include "xenpack.h" #include "phy.h" -#include "mac.h" +#include "falcon.h" -#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS0_PCS | \ - MDIO_MMDREG_DEVS0_PMAPMD | \ - MDIO_MMDREG_DEVS0_PHYXS) +#define XFP_REQUIRED_DEVS (MDIO_MMDREG_DEVS_PCS | \ + MDIO_MMDREG_DEVS_PMAPMD | \ + MDIO_MMDREG_DEVS_PHYXS) #define XFP_LOOPBACKS ((1 << LOOPBACK_PCS) | \ (1 << LOOPBACK_PMAPMD) | \ @@ -65,7 +64,7 @@ static int xfp_reset_phy(struct efx_nic *efx) /* Check that all the MMDs we expect are present and responding. We * expect faults on some if the link is down, but not on the PHY XS */ rc = mdio_clause45_check_mmds(efx, XFP_REQUIRED_DEVS, - MDIO_MMDREG_DEVS0_PHYXS); + MDIO_MMDREG_DEVS_PHYXS); if (rc < 0) goto fail; @@ -120,15 +119,12 @@ static int xfp_link_ok(struct efx_nic *efx) return mdio_clause45_links_ok(efx, XFP_REQUIRED_DEVS); } -static int xfp_phy_check_hw(struct efx_nic *efx) +static void xfp_phy_poll(struct efx_nic *efx) { - int rc = 0; int link_up = xfp_link_ok(efx); /* Simulate a PHY event if link state has changed */ if (link_up != efx->link_up) - falcon_xmac_sim_phy_event(efx); - - return rc; + falcon_sim_phy_event(efx); } static void xfp_phy_reconfigure(struct efx_nic *efx) @@ -145,7 +141,9 @@ static void xfp_phy_reconfigure(struct efx_nic *efx) phy_data->phy_mode = efx->phy_mode; efx->link_up = xfp_link_ok(efx); - efx->link_options = GM_LPA_10000FULL; + efx->link_speed = 10000; + efx->link_fd = true; + efx->link_fc = efx->wanted_fc; } @@ -160,11 +158,14 @@ static void xfp_phy_fini(struct efx_nic *efx) } struct efx_phy_operations falcon_xfp_phy_ops = { + .macs = EFX_XMAC, .init = xfp_phy_init, .reconfigure = xfp_phy_reconfigure, - .check_hw = xfp_phy_check_hw, + .poll = xfp_phy_poll, .fini = xfp_phy_fini, .clear_interrupt = xfp_phy_clear_interrupt, + .get_settings = mdio_clause45_get_settings, + .set_settings = mdio_clause45_set_settings, .mmds = XFP_REQUIRED_DEVS, .loopbacks = XFP_LOOPBACKS, }; diff --git a/drivers/net/sgiseeq.c b/drivers/net/sgiseeq.c index 6261201403cdd143ca592a880ca5052c167522d9..97d68560067dd6e6a3da4be85c48b0e7fd5eacfe 100644 --- a/drivers/net/sgiseeq.c +++ b/drivers/net/sgiseeq.c @@ -377,7 +377,6 @@ memory_squeeze: skb_put(skb, len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; } else { @@ -657,7 +656,7 @@ static void timeout(struct net_device *dev) static void sgiseeq_set_multicast(struct net_device *dev) { - struct sgiseeq_private *sp = (struct sgiseeq_private *) dev->priv; + struct sgiseeq_private *sp = netdev_priv(dev); unsigned char oldmode = sp->mode; if(dev->flags & IFF_PROMISC) @@ -719,7 +718,6 @@ static int __init sgiseeq_probe(struct platform_device *pdev) struct sgiseeq_private *sp; struct net_device *dev; int err; - DECLARE_MAC_BUF(mac); dev = alloc_etherdev(sizeof (struct sgiseeq_private)); if (!dev) { @@ -793,8 +791,7 @@ static int __init sgiseeq_probe(struct platform_device *pdev) goto err_out_free_page; } - printk(KERN_INFO "%s: %s %s\n", - dev->name, sgiseeqstr, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: %s %pM\n", dev->name, sgiseeqstr, dev->dev_addr); return 0; diff --git a/drivers/net/sh_eth.c b/drivers/net/sh_eth.c index 59f242a6771497619e36f51cc424ef9a61e2036d..7f8e514eb5e9653613383bfe515afea8240e37f0 100644 --- a/drivers/net/sh_eth.c +++ b/drivers/net/sh_eth.c @@ -540,7 +540,6 @@ static int sh_eth_rx(struct net_device *ndev) skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, ndev); netif_rx(skb); - ndev->last_rx = jiffies; mdp->stats.rx_packets++; mdp->stats.rx_bytes += pkt_len; } @@ -800,7 +799,7 @@ static int sh_eth_phy_init(struct net_device *ndev) char phy_id[BUS_ID_SIZE]; struct phy_device *phydev = NULL; - snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, + snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, mdp->mii_bus->id , mdp->phy_id); mdp->link = PHY_DOWN; diff --git a/drivers/net/sis190.c b/drivers/net/sis190.c index e6e3bf58a56939be71258819256e8386eb47bd11..83cc3c5f79464b1ff2643e565aaaadce3aab71b2 100644 --- a/drivers/net/sis190.c +++ b/drivers/net/sis190.c @@ -627,7 +627,6 @@ static int sis190_rx_interrupt(struct net_device *dev, sis190_rx_skb(skb); - dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += pkt_size; if ((status & BCAST) == MCAST) @@ -1791,7 +1790,6 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, struct net_device *dev; void __iomem *ioaddr; int rc; - DECLARE_MAC_BUF(mac); if (!printed_version) { net_drv(&debug, KERN_INFO SIS190_DRIVER_NAME " loaded.\n"); @@ -1841,10 +1839,9 @@ static int __devinit sis190_init_one(struct pci_dev *pdev, if (rc < 0) goto err_remove_mii; - net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), " - "%s\n", + net_probe(tp, KERN_INFO "%s: %s at %p (IRQ: %d), %pM\n", pci_name(pdev), sis_chip_info[ent->driver_data].name, - ioaddr, dev->irq, print_mac(mac, dev->dev_addr)); + ioaddr, dev->irq, dev->dev_addr); net_probe(tp, KERN_INFO "%s: %s mode.\n", dev->name, (tp->features & F_HAS_RGMII) ? "RGMII" : "GMII"); diff --git a/drivers/net/sis900.c b/drivers/net/sis900.c index 8e8337e8b072252d416a497f233c8aa9a6f04ae4..4acd41a093ad8a19c1259eef5650af802b942782 100644 --- a/drivers/net/sis900.c +++ b/drivers/net/sis900.c @@ -381,6 +381,21 @@ static int __devinit sis96x_get_mac_addr(struct pci_dev * pci_dev, return 0; } +static const struct net_device_ops sis900_netdev_ops = { + .ndo_open = sis900_open, + .ndo_stop = sis900_close, + .ndo_start_xmit = sis900_start_xmit, + .ndo_set_config = sis900_set_config, + .ndo_set_multicast_list = set_rx_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = mii_ioctl, + .ndo_tx_timeout = sis900_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = sis900_poll, +#endif +}; + /** * sis900_probe - Probe for sis900 device * @pci_dev: the sis900 pci device @@ -404,7 +419,6 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, int i, ret; const char *card_name = card_names[pci_id->driver_data]; const char *dev_name = pci_name(pci_dev); - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -437,7 +451,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, if (ret) goto err_out; - sis_priv = net_dev->priv; + sis_priv = netdev_priv(net_dev); net_dev->base_addr = ioaddr; net_dev->irq = pci_dev->irq; sis_priv->pci_dev = pci_dev; @@ -462,20 +476,10 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, sis_priv->rx_ring_dma = ring_dma; /* The SiS900-specific entries in the device structure. */ - net_dev->open = &sis900_open; - net_dev->hard_start_xmit = &sis900_start_xmit; - net_dev->stop = &sis900_close; - net_dev->set_config = &sis900_set_config; - net_dev->set_multicast_list = &set_rx_mode; - net_dev->do_ioctl = &mii_ioctl; - net_dev->tx_timeout = sis900_tx_timeout; + net_dev->netdev_ops = &sis900_netdev_ops; net_dev->watchdog_timeo = TX_TIMEOUT; net_dev->ethtool_ops = &sis900_ethtool_ops; -#ifdef CONFIG_NET_POLL_CONTROLLER - net_dev->poll_controller = &sis900_poll; -#endif - if (sis900_debug > 0) sis_priv->msg_enable = sis900_debug; else @@ -534,9 +538,9 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, goto err_unmap_rx; /* print some information about our NIC */ - printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %s\n", + printk(KERN_INFO "%s: %s at %#lx, IRQ %d, %pM\n", net_dev->name, card_name, ioaddr, net_dev->irq, - print_mac(mac, net_dev->dev_addr)); + net_dev->dev_addr); /* Detect Wake on Lan support */ ret = (inl(net_dev->base_addr + CFGPMC) & PMESP) >> 27; @@ -570,7 +574,7 @@ static int __devinit sis900_probe(struct pci_dev *pci_dev, static int __devinit sis900_mii_probe(struct net_device * net_dev) { - struct sis900_private * sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); const char *dev_name = pci_name(sis_priv->pci_dev); u16 poll_bit = MII_STAT_LINK, status = 0; unsigned long timeout = jiffies + 5 * HZ; @@ -698,7 +702,7 @@ static int __devinit sis900_mii_probe(struct net_device * net_dev) static u16 sis900_default_phy(struct net_device * net_dev) { - struct sis900_private * sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct mii_phy *phy = NULL, *phy_home = NULL, *default_phy = NULL, *phy_lan = NULL; u16 status; @@ -999,7 +1003,7 @@ static void sis900_poll(struct net_device *dev) static int sis900_open(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; int ret; @@ -1055,7 +1059,7 @@ sis900_open(struct net_device *net_dev) static void sis900_init_rxfilter (struct net_device * net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; u32 rfcrSave; u32 i; @@ -1093,7 +1097,7 @@ sis900_init_rxfilter (struct net_device * net_dev) static void sis900_init_tx_ring(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; int i; @@ -1127,7 +1131,7 @@ sis900_init_tx_ring(struct net_device *net_dev) static void sis900_init_rx_ring(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; int i; @@ -1198,7 +1202,7 @@ sis900_init_rx_ring(struct net_device *net_dev) static void sis630_set_eq(struct net_device *net_dev, u8 revision) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); u16 reg14h, eq_value=0, max_value=0, min_value=0; int i, maxcount=10; @@ -1271,13 +1275,13 @@ static void sis630_set_eq(struct net_device *net_dev, u8 revision) static void sis900_timer(unsigned long data) { struct net_device *net_dev = (struct net_device *)data; - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct mii_phy *mii_phy = sis_priv->mii; static const int next_tick = 5*HZ; u16 status; if (!sis_priv->autong_complete){ - int speed, duplex = 0; + int uninitialized_var(speed), duplex = 0; sis900_read_mode(net_dev, &speed, &duplex); if (duplex){ @@ -1341,7 +1345,7 @@ static void sis900_timer(unsigned long data) static void sis900_check_mode(struct net_device *net_dev, struct mii_phy *mii_phy) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; int speed, duplex; @@ -1420,7 +1424,7 @@ static void sis900_set_mode (long ioaddr, int speed, int duplex) static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); int i = 0; u32 status; @@ -1455,7 +1459,7 @@ static void sis900_auto_negotiate(struct net_device *net_dev, int phy_addr) static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct mii_phy *phy = sis_priv->mii; int phy_addr = sis_priv->cur_phy; u32 status; @@ -1510,7 +1514,7 @@ static void sis900_read_mode(struct net_device *net_dev, int *speed, int *duplex static void sis900_tx_timeout(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; unsigned long flags; int i; @@ -1569,7 +1573,7 @@ static void sis900_tx_timeout(struct net_device *net_dev) static int sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; unsigned int entry; unsigned long flags; @@ -1638,7 +1642,7 @@ sis900_start_xmit(struct sk_buff *skb, struct net_device *net_dev) static irqreturn_t sis900_interrupt(int irq, void *dev_instance) { struct net_device *net_dev = dev_instance; - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); int boguscnt = max_interrupt_work; long ioaddr = net_dev->base_addr; u32 status; @@ -1700,7 +1704,7 @@ static irqreturn_t sis900_interrupt(int irq, void *dev_instance) static int sis900_rx(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; @@ -1789,7 +1793,6 @@ static int sis900_rx(struct net_device *net_dev) /* some network statistics */ if ((rx_status & BCAST) == MCAST) net_dev->stats.multicast++; - net_dev->last_rx = jiffies; net_dev->stats.rx_bytes += rx_size; net_dev->stats.rx_packets++; sis_priv->dirty_rx++; @@ -1850,7 +1853,7 @@ refill_rx_ring: static void sis900_finish_xmit (struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); for (; sis_priv->dirty_tx != sis_priv->cur_tx; sis_priv->dirty_tx++) { struct sk_buff *skb; @@ -1919,7 +1922,7 @@ static void sis900_finish_xmit (struct net_device *net_dev) static int sis900_close(struct net_device *net_dev) { long ioaddr = net_dev->base_addr; - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct sk_buff *skb; int i; @@ -1974,7 +1977,7 @@ static int sis900_close(struct net_device *net_dev) static void sis900_get_drvinfo(struct net_device *net_dev, struct ethtool_drvinfo *info) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); strcpy (info->driver, SIS900_MODULE_NAME); strcpy (info->version, SIS900_DRV_VERSION); @@ -1983,26 +1986,26 @@ static void sis900_get_drvinfo(struct net_device *net_dev, static u32 sis900_get_msglevel(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); return sis_priv->msg_enable; } static void sis900_set_msglevel(struct net_device *net_dev, u32 value) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); sis_priv->msg_enable = value; } static u32 sis900_get_link(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); return mii_link_ok(&sis_priv->mii_info); } static int sis900_get_settings(struct net_device *net_dev, struct ethtool_cmd *cmd) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); spin_lock_irq(&sis_priv->lock); mii_ethtool_gset(&sis_priv->mii_info, cmd); spin_unlock_irq(&sis_priv->lock); @@ -2012,7 +2015,7 @@ static int sis900_get_settings(struct net_device *net_dev, static int sis900_set_settings(struct net_device *net_dev, struct ethtool_cmd *cmd) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); int rt; spin_lock_irq(&sis_priv->lock); rt = mii_ethtool_sset(&sis_priv->mii_info, cmd); @@ -2022,7 +2025,7 @@ static int sis900_set_settings(struct net_device *net_dev, static int sis900_nway_reset(struct net_device *net_dev) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); return mii_nway_restart(&sis_priv->mii_info); } @@ -2039,7 +2042,7 @@ static int sis900_nway_reset(struct net_device *net_dev) static int sis900_set_wol(struct net_device *net_dev, struct ethtool_wolinfo *wol) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long pmctrl_addr = net_dev->base_addr + pmctrl; u32 cfgpmcsr = 0, pmctrl_bits = 0; @@ -2110,7 +2113,7 @@ static const struct ethtool_ops sis900_ethtool_ops = { static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) { - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct mii_ioctl_data *data = if_mii(rq); switch(cmd) { @@ -2144,7 +2147,7 @@ static int mii_ioctl(struct net_device *net_dev, struct ifreq *rq, int cmd) static int sis900_set_config(struct net_device *dev, struct ifmap *map) { - struct sis900_private *sis_priv = dev->priv; + struct sis900_private *sis_priv = netdev_priv(dev); struct mii_phy *mii_phy = sis_priv->mii; u16 status; @@ -2267,7 +2270,7 @@ static inline u16 sis900_mcast_bitnr(u8 *addr, u8 revision) static void set_rx_mode(struct net_device *net_dev) { long ioaddr = net_dev->base_addr; - struct sis900_private * sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); u16 mc_filter[16] = {0}; /* 256/128 bits multicast hash table */ int i, table_entries; u32 rx_mode; @@ -2342,7 +2345,7 @@ static void set_rx_mode(struct net_device *net_dev) static void sis900_reset(struct net_device *net_dev) { - struct sis900_private * sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; int i = 0; u32 status = TxRCMP | RxRCMP; @@ -2375,7 +2378,7 @@ static void sis900_reset(struct net_device *net_dev) static void __devexit sis900_remove(struct pci_dev *pci_dev) { struct net_device *net_dev = pci_get_drvdata(pci_dev); - struct sis900_private * sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); struct mii_phy *phy = NULL; while (sis_priv->first_mii) { @@ -2419,7 +2422,7 @@ static int sis900_suspend(struct pci_dev *pci_dev, pm_message_t state) static int sis900_resume(struct pci_dev *pci_dev) { struct net_device *net_dev = pci_get_drvdata(pci_dev); - struct sis900_private *sis_priv = net_dev->priv; + struct sis900_private *sis_priv = netdev_priv(net_dev); long ioaddr = net_dev->base_addr; if(!netif_running(net_dev)) diff --git a/drivers/net/skfp/skfddi.c b/drivers/net/skfp/skfddi.c index a2b092bb3626b63a35ac44bec9ab6b2049242b19..607efeaf0bc5cd00949fcdb3feaf7ec7f2b03305 100644 --- a/drivers/net/skfp/skfddi.c +++ b/drivers/net/skfp/skfddi.c @@ -168,6 +168,17 @@ static int num_boards; /* total number of adapters configured */ #define PRINTK(s, args...) #endif // DRIVERDEBUG +static const struct net_device_ops skfp_netdev_ops = { + .ndo_open = skfp_open, + .ndo_stop = skfp_close, + .ndo_start_xmit = skfp_send_pkt, + .ndo_get_stats = skfp_ctl_get_stats, + .ndo_change_mtu = fddi_change_mtu, + .ndo_set_multicast_list = skfp_ctl_set_multicast_list, + .ndo_set_mac_address = skfp_ctl_set_mac_address, + .ndo_do_ioctl = skfp_ioctl, +}; + /* * ================= * = skfp_init_one = @@ -253,13 +264,7 @@ static int skfp_init_one(struct pci_dev *pdev, } dev->irq = pdev->irq; - dev->get_stats = &skfp_ctl_get_stats; - dev->open = &skfp_open; - dev->stop = &skfp_close; - dev->hard_start_xmit = &skfp_send_pkt; - dev->set_multicast_list = &skfp_ctl_set_multicast_list; - dev->set_mac_address = &skfp_ctl_set_mac_address; - dev->do_ioctl = &skfp_ioctl; + dev->netdev_ops = &skfp_netdev_ops; SET_NETDEV_DEV(dev, &pdev->dev); @@ -612,7 +617,7 @@ static int skfp_close(struct net_device *dev) * Interrupts are disabled, then reenabled at the adapter. */ -irqreturn_t skfp_interrupt(int irq, void *dev_id) +static irqreturn_t skfp_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; struct s_smc *smc; /* private board structure pointer */ @@ -679,7 +684,7 @@ irqreturn_t skfp_interrupt(int irq, void *dev_id) * independent. * */ -struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev) +static struct net_device_stats *skfp_ctl_get_stats(struct net_device *dev) { struct s_smc *bp = netdev_priv(dev); @@ -1224,7 +1229,7 @@ static void send_queued_packets(struct s_smc *smc) * Verify if the source address is set. Insert it if necessary. * ************************/ -void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr) +static void CheckSourceAddress(unsigned char *frame, unsigned char *hw_addr) { unsigned char SRBit; @@ -1680,7 +1685,6 @@ void mac_drv_rx_complete(struct s_smc *smc, volatile struct s_smt_fp_rxd *rxd, skb->protocol = fddi_type_trans(skb, bp->dev); netif_rx(skb); - bp->dev->last_rx = jiffies; HWM_RX_CHECK(smc, RX_LOW_WATERMARK); return; @@ -1939,7 +1943,6 @@ int mac_drv_rx_init(struct s_smc *smc, int len, int fc, // deliver frame to system skb->protocol = fddi_type_trans(skb, smc->os.dev); - skb->dev->last_rx = jiffies; netif_rx(skb); return (0); diff --git a/drivers/net/skge.c b/drivers/net/skge.c index 43f4c730be42546b8be59f1f97127f2d0ef06a3a..c9dbb06f8c9430cfb06779a8486544792972996a 100644 --- a/drivers/net/skge.c +++ b/drivers/net/skge.c @@ -104,6 +104,7 @@ static void yukon_get_stats(struct skge_port *skge, u64 *data); static void yukon_init(struct skge_hw *hw, int port); static void genesis_mac_init(struct skge_hw *hw, int port); static void genesis_link_up(struct skge_port *skge); +static void skge_set_multicast(struct net_device *dev); /* Avoid conditionals by using array */ static const int txqaddr[] = { Q_XA1, Q_XA2 }; @@ -149,24 +150,6 @@ static u32 wol_supported(const struct skge_hw *hw) return WAKE_MAGIC | WAKE_PHY; } -static u32 pci_wake_enabled(struct pci_dev *dev) -{ - int pm = pci_find_capability(dev, PCI_CAP_ID_PM); - u16 value; - - /* If device doesn't support PM Capabilities, but request is to disable - * wake events, it's a nop; otherwise fail */ - if (!pm) - return 0; - - pci_read_config_word(dev, pm + PCI_PM_PMC, &value); - - value &= PCI_PM_CAP_PME_MASK; - value >>= ffs(PCI_PM_CAP_PME_MASK) - 1; /* First bit of mask */ - - return value != 0; -} - static void skge_wol_init(struct skge_port *skge) { struct skge_hw *hw = skge->hw; @@ -254,10 +237,14 @@ static int skge_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) struct skge_port *skge = netdev_priv(dev); struct skge_hw *hw = skge->hw; - if (wol->wolopts & ~wol_supported(hw)) + if ((wol->wolopts & ~wol_supported(hw)) + || !device_can_wakeup(&hw->pdev->dev)) return -EOPNOTSUPP; skge->wol = wol->wolopts; + + device_set_wakeup_enable(&hw->pdev->dev, skge->wol); + return 0; } @@ -2477,7 +2464,7 @@ static void skge_phy_reset(struct skge_port *skge) } spin_unlock_bh(&hw->phy_lock); - dev->set_multicast_list(dev); + skge_set_multicast(dev); } /* Basic MII support */ @@ -3045,6 +3032,18 @@ static inline int bad_phy_status(const struct skge_hw *hw, u32 status) (status & GMR_FS_RX_OK) == 0; } +static void skge_set_multicast(struct net_device *dev) +{ + struct skge_port *skge = netdev_priv(dev); + struct skge_hw *hw = skge->hw; + + if (hw->chip_id == CHIP_ID_GENESIS) + genesis_set_multicast(dev); + else + yukon_set_multicast(dev); + +} + /* Get receive buffer from descriptor. * Handles copy of small buffers and reallocation failures @@ -3200,7 +3199,6 @@ static int skge_poll(struct napi_struct *napi, int to_do) skb = skge_rx_get(dev, e, control, rd->status, rd->csum2); if (likely(skb)) { - dev->last_rx = jiffies; netif_receive_skb(skb); ++work_done; @@ -3216,7 +3214,7 @@ static int skge_poll(struct napi_struct *napi, int to_do) unsigned long flags; spin_lock_irqsave(&hw->hw_lock, flags); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); hw->intr_mask |= napimask[skge->port]; skge_write32(hw, B0_IMSK, hw->intr_mask); skge_read32(hw, B0_IMSK); @@ -3379,7 +3377,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id) if (status & (IS_XA1_F|IS_R1_F)) { struct skge_port *skge = netdev_priv(hw->dev[0]); hw->intr_mask &= ~(IS_XA1_F|IS_R1_F); - netif_rx_schedule(hw->dev[0], &skge->napi); + netif_rx_schedule(&skge->napi); } if (status & IS_PA_TO_TX1) @@ -3399,7 +3397,7 @@ static irqreturn_t skge_intr(int irq, void *dev_id) if (status & (IS_XA2_F|IS_R2_F)) { hw->intr_mask &= ~(IS_XA2_F|IS_R2_F); - netif_rx_schedule(hw->dev[1], &skge->napi); + netif_rx_schedule(&skge->napi); } if (status & IS_PA_TO_RX2) { @@ -3730,7 +3728,7 @@ static int skge_device_event(struct notifier_block *unused, struct skge_port *skge; struct dentry *d; - if (dev->open != &skge_up || !skge_debug) + if (dev->netdev_ops->ndo_open != &skge_up || !skge_debug) goto done; skge = netdev_priv(dev); @@ -3804,6 +3802,23 @@ static __exit void skge_debug_cleanup(void) #define skge_debug_cleanup() #endif +static const struct net_device_ops skge_netdev_ops = { + .ndo_open = skge_up, + .ndo_stop = skge_down, + .ndo_start_xmit = skge_xmit_frame, + .ndo_do_ioctl = skge_ioctl, + .ndo_get_stats = skge_get_stats, + .ndo_tx_timeout = skge_tx_timeout, + .ndo_change_mtu = skge_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = skge_set_multicast, + .ndo_set_mac_address = skge_set_mac_address, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = skge_netpoll, +#endif +}; + + /* Initialize network device */ static struct net_device *skge_devinit(struct skge_hw *hw, int port, int highmem) @@ -3817,24 +3832,9 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, } SET_NETDEV_DEV(dev, &hw->pdev->dev); - dev->open = skge_up; - dev->stop = skge_down; - dev->do_ioctl = skge_ioctl; - dev->hard_start_xmit = skge_xmit_frame; - dev->get_stats = skge_get_stats; - if (hw->chip_id == CHIP_ID_GENESIS) - dev->set_multicast_list = genesis_set_multicast; - else - dev->set_multicast_list = yukon_set_multicast; - - dev->set_mac_address = skge_set_mac_address; - dev->change_mtu = skge_change_mtu; - SET_ETHTOOL_OPS(dev, &skge_ethtool_ops); - dev->tx_timeout = skge_tx_timeout; + dev->netdev_ops = &skge_netdev_ops; + dev->ethtool_ops = &skge_ethtool_ops; dev->watchdog_timeo = TX_WATCHDOG; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = skge_netpoll; -#endif dev->irq = hw->pdev->irq; if (highmem) @@ -3856,7 +3856,7 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, skge->speed = -1; skge->advertising = skge_supported_modes(hw); - if (pci_wake_enabled(hw->pdev)) + if (device_may_wakeup(&hw->pdev->dev)) skge->wol = wol_supported(hw) & WAKE_MAGIC; hw->dev[port] = dev; @@ -3885,11 +3885,10 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port, static void __devinit skge_show_addr(struct net_device *dev) { const struct skge_port *skge = netdev_priv(dev); - DECLARE_MAC_BUF(mac); if (netif_msg_probe(skge)) - printk(KERN_INFO PFX "%s: addr %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO PFX "%s: addr %pM\n", + dev->name, dev->dev_addr); } static int __devinit skge_probe(struct pci_dev *pdev, @@ -4082,8 +4081,8 @@ static int skge_suspend(struct pci_dev *pdev, pm_message_t state) } skge_write32(hw, B0_IMSK, 0); - pci_enable_wake(pdev, pci_choose_state(pdev, state), wol); - pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + pci_prepare_to_sleep(pdev); return 0; } @@ -4096,7 +4095,7 @@ static int skge_resume(struct pci_dev *pdev) if (!hw) return 0; - err = pci_set_power_state(pdev, PCI_D0); + err = pci_back_from_sleep(pdev); if (err) goto out; @@ -4104,8 +4103,6 @@ static int skge_resume(struct pci_dev *pdev) if (err) goto out; - pci_enable_wake(pdev, PCI_D0, 0); - err = skge_reset(hw); if (err) goto out; @@ -4146,8 +4143,8 @@ static void skge_shutdown(struct pci_dev *pdev) wol |= skge->wol; } - pci_enable_wake(pdev, PCI_D3hot, wol); - pci_enable_wake(pdev, PCI_D3cold, wol); + if (pci_enable_wake(pdev, PCI_D3cold, wol)) + pci_enable_wake(pdev, PCI_D3hot, wol); pci_disable_device(pdev); pci_set_power_state(pdev, PCI_D3hot); diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c index 3813d15e2df75d613392bf20f5e134f358cd26ed..3668e81e474ddbe3f83438378527e5af12cdb2d5 100644 --- a/drivers/net/sky2.c +++ b/drivers/net/sky2.c @@ -3979,7 +3979,7 @@ static int sky2_device_event(struct notifier_block *unused, struct net_device *dev = ptr; struct sky2_port *sky2 = netdev_priv(dev); - if (dev->open != sky2_up || !sky2_debug) + if (dev->netdev_ops->ndo_open != sky2_up || !sky2_debug) return NOTIFY_DONE; switch(event) { @@ -4041,6 +4041,41 @@ static __exit void sky2_debug_cleanup(void) #define sky2_debug_cleanup() #endif +/* Two copies of network device operations to handle special case of + not allowing netpoll on second port */ +static const struct net_device_ops sky2_netdev_ops[2] = { + { + .ndo_open = sky2_up, + .ndo_stop = sky2_down, + .ndo_start_xmit = sky2_xmit_frame, + .ndo_do_ioctl = sky2_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = sky2_set_mac_address, + .ndo_set_multicast_list = sky2_set_multicast, + .ndo_change_mtu = sky2_change_mtu, + .ndo_tx_timeout = sky2_tx_timeout, +#ifdef SKY2_VLAN_TAG_USED + .ndo_vlan_rx_register = sky2_vlan_rx_register, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = sky2_netpoll, +#endif + }, + { + .ndo_open = sky2_up, + .ndo_stop = sky2_down, + .ndo_start_xmit = sky2_xmit_frame, + .ndo_do_ioctl = sky2_ioctl, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = sky2_set_mac_address, + .ndo_set_multicast_list = sky2_set_multicast, + .ndo_change_mtu = sky2_change_mtu, + .ndo_tx_timeout = sky2_tx_timeout, +#ifdef SKY2_VLAN_TAG_USED + .ndo_vlan_rx_register = sky2_vlan_rx_register, +#endif + }, +}; /* Initialize network device */ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, @@ -4057,20 +4092,9 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, SET_NETDEV_DEV(dev, &hw->pdev->dev); dev->irq = hw->pdev->irq; - dev->open = sky2_up; - dev->stop = sky2_down; - dev->do_ioctl = sky2_ioctl; - dev->hard_start_xmit = sky2_xmit_frame; - dev->set_multicast_list = sky2_set_multicast; - dev->set_mac_address = sky2_set_mac_address; - dev->change_mtu = sky2_change_mtu; SET_ETHTOOL_OPS(dev, &sky2_ethtool_ops); - dev->tx_timeout = sky2_tx_timeout; dev->watchdog_timeo = TX_WATCHDOG; -#ifdef CONFIG_NET_POLL_CONTROLLER - if (port == 0) - dev->poll_controller = sky2_netpoll; -#endif + dev->netdev_ops = &sky2_netdev_ops[port]; sky2 = netdev_priv(dev); sky2->netdev = dev; @@ -4104,7 +4128,6 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, if (!(sky2->hw->chip_id == CHIP_ID_YUKON_FE_P && sky2->hw->chip_rev == CHIP_REV_YU_FE2_A0)) { dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = sky2_vlan_rx_register; } #endif @@ -4118,11 +4141,10 @@ static __devinit struct net_device *sky2_init_netdev(struct sky2_hw *hw, static void __devinit sky2_show_addr(struct net_device *dev) { const struct sky2_port *sky2 = netdev_priv(dev); - DECLARE_MAC_BUF(mac); if (netif_msg_probe(sky2)) - printk(KERN_INFO PFX "%s: addr %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO PFX "%s: addr %pM\n", + dev->name, dev->dev_addr); } /* Handle software interrupt used during MSI test */ diff --git a/drivers/net/slip.c b/drivers/net/slip.c index 1d58991d395b6ef32120e1e265c8245ab61219e3..8e1c0baf6958287365d5b2f1e634cedc33e46bb3 100644 --- a/drivers/net/slip.c +++ b/drivers/net/slip.c @@ -365,7 +365,6 @@ static void sl_bump(struct slip *sl) skb_reset_mac_header(skb); skb->protocol = htons(ETH_P_IP); netif_rx(skb); - sl->dev->last_rx = jiffies; sl->rx_packets++; } @@ -402,7 +401,7 @@ static void sl_encaps(struct slip *sl, unsigned char *icp, int len) * if we did not request it before write operation. * 14 Oct 1994 Dmitry Gorodchanin. */ - sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); actual = sl->tty->ops->write(sl->tty, sl->xbuff, count); #ifdef SL_CHECK_TRANSMIT sl->dev->trans_start = jiffies; @@ -432,7 +431,7 @@ static void slip_write_wakeup(struct tty_struct *tty) /* Now serial buffer is almost free & we can start * transmission of another packet */ sl->tx_packets++; - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); sl_unlock(sl); return; } @@ -465,7 +464,7 @@ static void sl_tx_timeout(struct net_device *dev) (tty_chars_in_buffer(sl->tty) || sl->xleft) ? "bad line quality" : "driver error"); sl->xleft = 0; - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); sl_unlock(sl); #endif } @@ -515,10 +514,9 @@ sl_close(struct net_device *dev) struct slip *sl = netdev_priv(dev); spin_lock_bh(&sl->lock); - if (sl->tty) { + if (sl->tty) /* TTY discipline is running. */ - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - } + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); netif_stop_queue(dev); sl->rcount = 0; sl->xleft = 0; diff --git a/drivers/net/smc-mca.c b/drivers/net/smc-mca.c index d6abb68e6e2f20eb8b238c85f710ccd7a75f913d..404b80e5ba11b7cea9f2c3f7ad987704b6b8c280 100644 --- a/drivers/net/smc-mca.c +++ b/drivers/net/smc-mca.c @@ -182,6 +182,22 @@ static char *smc_mca_adapter_names[] __initdata = { static int ultra_found = 0; + +static const struct net_device_ops ultramca_netdev_ops = { + .ndo_open = ultramca_open, + .ndo_stop = ultramca_close_card, + + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init ultramca_probe(struct device *gen_dev) { unsigned short ioaddr; @@ -196,7 +212,6 @@ static int __init ultramca_probe(struct device *gen_dev) int tirq = 0; int base_addr = ultra_io[ultra_found]; int irq = ultra_irq[ultra_found]; - DECLARE_MAC_BUF(mac); if (base_addr || irq) { printk(KERN_INFO "Probing for SMC MCA adapter"); @@ -334,8 +349,8 @@ static int __init ultramca_probe(struct device *gen_dev) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + 8 + i); - printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x, %s", - slot + 1, ioaddr, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "smc_mca[%d]: Parameters: %#3x, %pM", + slot + 1, ioaddr, dev->dev_addr); /* Switch from the station address to the alternate register set * and read the useful registers there. @@ -385,11 +400,7 @@ static int __init ultramca_probe(struct device *gen_dev) ei_status.priv = slot; - dev->open = &ultramca_open; - dev->stop = &ultramca_close_card; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + dev->netdev_ops = &ultramca_netdev_ops; NS8390_init(dev, 0); diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index 00d6cf1af4843a929f5856a40c8bf3af9b0b0c9b..b3866089a206a48d4ad2900de16f80b754e07be0 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -187,6 +187,21 @@ out: } #endif +static const struct net_device_ops ultra_netdev_ops = { + .ndo_open = ultra_open, + .ndo_stop = ultra_close_card, + + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init ultra_probe1(struct net_device *dev, int ioaddr) { int i, retval; @@ -198,7 +213,6 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) unsigned char num_pages, irqreg, addr, piomode; unsigned char idreg = inb(ioaddr + 7); unsigned char reg4 = inb(ioaddr + 4) & 0x7f; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, ULTRA_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -228,8 +242,8 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + 8 + i); - printk("%s: %s at %#3x, %s", dev->name, model_name, - ioaddr, print_mac(mac, dev->dev_addr)); + printk("%s: %s at %#3x, %pM", dev->name, model_name, + ioaddr, dev->dev_addr); /* Switch from the station address to the alternate register set and read the useful registers there. */ @@ -301,11 +315,8 @@ static int __init ultra_probe1(struct net_device *dev, int ioaddr) ei_status.get_8390_hdr = &ultra_get_8390_hdr; } ei_status.reset_8390 = &ultra_reset_8390; - dev->open = &ultra_open; - dev->stop = &ultra_close_card; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + + dev->netdev_ops = &ultra_netdev_ops; NS8390_init(dev, 0); retval = register_netdev(dev); diff --git a/drivers/net/smc-ultra32.c b/drivers/net/smc-ultra32.c index a5a91ace28ccec743507e38210164a67d5dc58c4..cb6c097a2e0ad78e7b31d01ac18750540cc9fb7b 100644 --- a/drivers/net/smc-ultra32.c +++ b/drivers/net/smc-ultra32.c @@ -163,7 +163,6 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr) unsigned char idreg; unsigned char reg4; const char *ifmap[] = {"UTP No Link", "", "UTP/AUI", "UTP/BNC"}; - DECLARE_MAC_BUF(mac); if (!request_region(ioaddr, ULTRA32_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -207,8 +206,8 @@ static int __init ultra32_probe1(struct net_device *dev, int ioaddr) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + 8 + i); - printk("%s: %s at 0x%X, %s", - dev->name, model_name, ioaddr, print_mac(mac, dev->dev_addr)); + printk("%s: %s at 0x%X, %pM", + dev->name, model_name, ioaddr, dev->dev_addr); /* Switch from the station address to the alternate register set and read the useful registers there. */ diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c index 9a16a79b67d0d432f1bcf629dfba358e2a7cf918..bf3aa2a1effed6fa6301fc675d01bbf33e9d72fd 100644 --- a/drivers/net/smc911x.c +++ b/drivers/net/smc911x.c @@ -439,7 +439,6 @@ static inline void smc911x_rcv(struct net_device *dev) DBG(SMC_DEBUG_PKTS, "%s: Received packet\n", dev->name); PRINT_PKT(data, ((pkt_len - 4) <= 64) ? pkt_len - 4 : 64); - dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->stats.rx_packets++; @@ -1231,7 +1230,6 @@ smc911x_rx_dma_irq(int dma, void *data) BUG_ON(skb == NULL); lp->current_rx_skb = NULL; PRINT_PKT(skb->data, skb->len); - dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; @@ -2050,9 +2048,6 @@ err_out: */ static int __devinit smc911x_drv_probe(struct platform_device *pdev) { -#ifdef SMC_DYNAMIC_BUS_CONFIG - struct smc911x_platdata *pd = pdev->dev.platform_data; -#endif struct net_device *ndev; struct resource *res; struct smc911x_local *lp; @@ -2087,11 +2082,14 @@ static int __devinit smc911x_drv_probe(struct platform_device *pdev) lp = netdev_priv(ndev); lp->netdev = ndev; #ifdef SMC_DYNAMIC_BUS_CONFIG - if (!pd) { - ret = -EINVAL; - goto release_both; + { + struct smc911x_platdata *pd = pdev->dev.platform_data; + if (!pd) { + ret = -EINVAL; + goto release_both; + } + memcpy(&lp->cfg, pd, sizeof(lp->cfg)); } - memcpy(&lp->cfg, pd, sizeof(lp->cfg)); #endif addr = ioremap(res->start, SMC911X_IO_EXTENT); diff --git a/drivers/net/smc9194.c b/drivers/net/smc9194.c index de67744c4a2a1f1cf960e80a8cd0ec309db36e58..18d653bbd4e0556dfac549ff02510fa805f41fa0 100644 --- a/drivers/net/smc9194.c +++ b/drivers/net/smc9194.c @@ -764,7 +764,7 @@ out: . interrupt, so an auto-detect routine can detect it, and find the IRQ, ------------------------------------------------------------------------ */ -int __init smc_findirq( int ioaddr ) +static int __init smc_findirq(int ioaddr) { #ifndef NO_AUTOPROBE int timeout = 20; @@ -876,8 +876,6 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) word memory_info_register; word memory_cfg_register; - DECLARE_MAC_BUF(mac); - /* Grab the region so that no one else tries to probe our ioports. */ if (!request_region(ioaddr, SMC_IO_EXTENT, DRV_NAME)) return -EBUSY; @@ -1033,10 +1031,10 @@ static int __init smc_probe(struct net_device *dev, int ioaddr) /* . Print the Ethernet address */ - printk("ADDR: %s\n", print_mac(mac, dev->dev_addr)); + printk("ADDR: %pM\n", dev->dev_addr); /* set the private data to zero by default */ - memset(dev->priv, 0, sizeof(struct smc_local)); + memset(netdev_priv(dev), 0, sizeof(struct smc_local)); /* Grab the IRQ */ retval = request_irq(dev->irq, &smc_interrupt, 0, DRV_NAME, dev); @@ -1110,7 +1108,7 @@ static int smc_open(struct net_device *dev) int i; /* used to set hw ethernet address */ /* clear out all the junk that was put here before... */ - memset(dev->priv, 0, sizeof(struct smc_local)); + memset(netdev_priv(dev), 0, sizeof(struct smc_local)); /* reset the hardware */ @@ -1166,7 +1164,7 @@ static void smc_timeout(struct net_device *dev) smc_enable( dev->base_addr ); dev->trans_start = jiffies; /* clear anything saved */ - ((struct smc_local *)dev->priv)->saved_skb = NULL; + ((struct smc_local *)netdev_priv(dev))->saved_skb = NULL; netif_wake_queue(dev); } @@ -1272,7 +1270,6 @@ static void smc_rcv(struct net_device *dev) skb->protocol = eth_type_trans(skb, dev ); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += packet_length; } else { diff --git a/drivers/net/smc91x.c b/drivers/net/smc91x.c index 35c56abf4113193490c3ca4a91f1f12077e9eb13..b215a8d85e62d5e2fc3eb54064918ae8dd90fd97 100644 --- a/drivers/net/smc91x.c +++ b/drivers/net/smc91x.c @@ -90,33 +90,6 @@ static const char version[] = #include "smc91x.h" -#ifdef CONFIG_ISA -/* - * the LAN91C111 can be at any of the following port addresses. To change, - * for a slightly different card, you can add it to the array. Keep in - * mind that the array must end in zero. - */ -static unsigned int smc_portlist[] __initdata = { - 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, - 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0 -}; - -#ifndef SMC_IOADDR -# define SMC_IOADDR -1 -#endif -static unsigned long io = SMC_IOADDR; -module_param(io, ulong, 0400); -MODULE_PARM_DESC(io, "I/O base address"); - -#ifndef SMC_IRQ -# define SMC_IRQ -1 -#endif -static int irq = SMC_IRQ; -module_param(irq, int, 0400); -MODULE_PARM_DESC(irq, "IRQ number"); - -#endif /* CONFIG_ISA */ - #ifndef SMC_NOWAIT # define SMC_NOWAIT 0 #endif @@ -518,7 +491,6 @@ static inline void smc_rcv(struct net_device *dev) PRINT_PKT(data, packet_len - 4); - dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->stats.rx_packets++; @@ -1778,7 +1750,6 @@ static int __devinit smc_probe(struct net_device *dev, void __iomem *ioaddr, int retval; unsigned int val, revision_register; const char *version_string; - DECLARE_MAC_BUF(mac); DBG(2, "%s: %s\n", CARDNAME, __func__); @@ -1972,8 +1943,8 @@ static int __devinit smc_probe(struct net_device *dev, void __iomem *ioaddr, "set using ifconfig\n", dev->name); } else { /* Print the Ethernet address */ - printk("%s: Ethernet addr: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: Ethernet addr: %pM\n", + dev->name, dev->dev_addr); } if (lp->phy_type == 0) { @@ -2316,15 +2287,6 @@ static struct platform_driver smc_driver = { static int __init smc_init(void) { -#ifdef MODULE -#ifdef CONFIG_ISA - if (io == -1) - printk(KERN_WARNING - "%s: You shouldn't use auto-probing with insmod!\n", - CARDNAME); -#endif -#endif - return platform_driver_register(&smc_driver); } diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index a07cc9351c6bfd7568fe3502f5242cb3034e9b19..3e7c6a3cbc650c8f0a39afa4bc49eb48f7aac191 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h @@ -87,49 +87,28 @@ static inline void SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define RPC_LSA_DEFAULT RPC_LED_100_10 #define RPC_LSB_DEFAULT RPC_LED_TX_RX -# if defined (CONFIG_BFIN561_EZKIT) #define SMC_CAN_USE_8BIT 0 #define SMC_CAN_USE_16BIT 1 +# if defined(CONFIG_BF561) #define SMC_CAN_USE_32BIT 1 -#define SMC_IO_SHIFT 0 -#define SMC_NOWAIT 1 -#define SMC_USE_BFIN_DMA 0 - - -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_inl(a, r) readl((a) + (r)) -#define SMC_outl(v, a, r) writel(v, (a) + (r)) -#define SMC_outsl(a, r, p, l) outsl((unsigned long *)((a) + (r)), p, l) -#define SMC_insl(a, r, p, l) insl ((unsigned long *)((a) + (r)), p, l) # else -#define SMC_CAN_USE_8BIT 0 -#define SMC_CAN_USE_16BIT 1 #define SMC_CAN_USE_32BIT 0 +# endif #define SMC_IO_SHIFT 0 #define SMC_NOWAIT 1 #define SMC_USE_BFIN_DMA 0 - -#define SMC_inw(a, r) readw((a) + (r)) -#define SMC_outw(v, a, r) writew(v, (a) + (r)) -#define SMC_outsw(a, r, p, l) outsw((unsigned long *)((a) + (r)), p, l) -#define SMC_insw(a, r, p, l) insw ((unsigned long *)((a) + (r)), p, l) +#define SMC_inw(a, r) readw((a) + (r)) +#define SMC_outw(v, a, r) writew(v, (a) + (r)) +#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l) +#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l) +# if SMC_CAN_USE_32BIT +#define SMC_inl(a, r) readl((a) + (r)) +#define SMC_outl(v, a, r) writel(v, (a) + (r)) +#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l) +#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l) # endif -/* check if the mac in reg is valid */ -#define SMC_GET_MAC_ADDR(lp, addr) \ - do { \ - unsigned int __v; \ - __v = SMC_inw(ioaddr, ADDR0_REG(lp)); \ - addr[0] = __v; addr[1] = __v >> 8; \ - __v = SMC_inw(ioaddr, ADDR1_REG(lp)); \ - addr[2] = __v; addr[3] = __v >> 8; \ - __v = SMC_inw(ioaddr, ADDR2_REG(lp)); \ - addr[4] = __v; addr[5] = __v >> 8; \ - if (*(u32 *)(&addr[0]) == 0xFFFFFFFF) { \ - random_ether_addr(addr); \ - } \ - } while (0) + #elif defined(CONFIG_REDWOOD_5) || defined(CONFIG_REDWOOD_6) /* We can only do 16-bit reads and writes in the static memory space. */ @@ -286,19 +265,6 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg) #define SMC_IRQ_FLAGS (0) -#elif defined(CONFIG_ISA) - -#define SMC_CAN_USE_8BIT 1 -#define SMC_CAN_USE_16BIT 1 -#define SMC_CAN_USE_32BIT 0 - -#define SMC_inb(a, r) inb((a) + (r)) -#define SMC_inw(a, r) inw((a) + (r)) -#define SMC_outb(v, a, r) outb(v, (a) + (r)) -#define SMC_outw(v, a, r) outw(v, (a) + (r)) -#define SMC_insw(a, r, p, l) insw((a) + (r), p, l) -#define SMC_outsw(a, r, p, l) outsw((a) + (r), p, l) - #elif defined(CONFIG_M32R) #define SMC_CAN_USE_8BIT 0 diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c new file mode 100644 index 0000000000000000000000000000000000000000..5e989d884dddc9bc13e3f14ca7bde9749332b0cf --- /dev/null +++ b/drivers/net/smsc911x.c @@ -0,0 +1,2071 @@ +/*************************************************************************** + * + * Copyright (C) 2004-2008 SMSC + * Copyright (C) 2005-2008 ARM + * + * 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. + * + *************************************************************************** + * Rewritten, heavily based on smsc911x simple driver by SMSC. + * Partly uses io macros from smc91x.c by Nicolas Pitre + * + * Supported devices: + * LAN9115, LAN9116, LAN9117, LAN9118 + * LAN9215, LAN9216, LAN9217, LAN9218 + * LAN9210, LAN9211 + * LAN9220, LAN9221 + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "smsc911x.h" + +#define SMSC_CHIPNAME "smsc911x" +#define SMSC_MDIONAME "smsc911x-mdio" +#define SMSC_DRV_VERSION "2008-10-21" + +MODULE_LICENSE("GPL"); +MODULE_VERSION(SMSC_DRV_VERSION); + +#if USE_DEBUG > 0 +static int debug = 16; +#else +static int debug = 3; +#endif + +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)"); + +struct smsc911x_data { + void __iomem *ioaddr; + + unsigned int idrev; + + /* used to decide which workarounds apply */ + unsigned int generation; + + /* device configuration (copied from platform_data during probe) */ + struct smsc911x_platform_config config; + + /* This needs to be acquired before calling any of below: + * smsc911x_mac_read(), smsc911x_mac_write() + */ + spinlock_t mac_lock; + + /* spinlock to ensure 16-bit accesses are serialised. + * unused with a 32-bit bus */ + spinlock_t dev_lock; + + struct phy_device *phy_dev; + struct mii_bus *mii_bus; + int phy_irq[PHY_MAX_ADDR]; + unsigned int using_extphy; + int last_duplex; + int last_carrier; + + u32 msg_enable; + unsigned int gpio_setting; + unsigned int gpio_orig_setting; + struct net_device *dev; + struct napi_struct napi; + + unsigned int software_irq_signal; + +#ifdef USE_PHY_WORK_AROUND +#define MIN_PACKET_SIZE (64) + char loopback_tx_pkt[MIN_PACKET_SIZE]; + char loopback_rx_pkt[MIN_PACKET_SIZE]; + unsigned int resetcount; +#endif + + /* Members for Multicast filter workaround */ + unsigned int multicast_update_pending; + unsigned int set_bits_mask; + unsigned int clear_bits_mask; + unsigned int hashhi; + unsigned int hashlo; +}; + +/* The 16-bit access functions are significantly slower, due to the locking + * necessary. If your bus hardware can be configured to do this for you + * (in response to a single 32-bit operation from software), you should use + * the 32-bit access functions instead. */ + +static inline u32 smsc911x_reg_read(struct smsc911x_data *pdata, u32 reg) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) + return readl(pdata->ioaddr + reg); + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + u32 data; + unsigned long flags; + + /* these two 16-bit reads must be performed consecutively, so + * must not be interrupted by our own ISR (which would start + * another read operation) */ + spin_lock_irqsave(&pdata->dev_lock, flags); + data = ((readw(pdata->ioaddr + reg) & 0xFFFF) | + ((readw(pdata->ioaddr + reg + 2) & 0xFFFF) << 16)); + spin_unlock_irqrestore(&pdata->dev_lock, flags); + + return data; + } + + BUG(); +} + +static inline void smsc911x_reg_write(struct smsc911x_data *pdata, u32 reg, + u32 val) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) { + writel(val, pdata->ioaddr + reg); + return; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + unsigned long flags; + + /* these two 16-bit writes must be performed consecutively, so + * must not be interrupted by our own ISR (which would start + * another read operation) */ + spin_lock_irqsave(&pdata->dev_lock, flags); + writew(val & 0xFFFF, pdata->ioaddr + reg); + writew((val >> 16) & 0xFFFF, pdata->ioaddr + reg + 2); + spin_unlock_irqrestore(&pdata->dev_lock, flags); + return; + } + + BUG(); +} + +/* Writes a packet to the TX_DATA_FIFO */ +static inline void +smsc911x_tx_writefifo(struct smsc911x_data *pdata, unsigned int *buf, + unsigned int wordcount) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) { + writesl(pdata->ioaddr + TX_DATA_FIFO, buf, wordcount); + return; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + while (wordcount--) + smsc911x_reg_write(pdata, TX_DATA_FIFO, *buf++); + return; + } + + BUG(); +} + +/* Reads a packet out of the RX_DATA_FIFO */ +static inline void +smsc911x_rx_readfifo(struct smsc911x_data *pdata, unsigned int *buf, + unsigned int wordcount) +{ + if (pdata->config.flags & SMSC911X_USE_32BIT) { + readsl(pdata->ioaddr + RX_DATA_FIFO, buf, wordcount); + return; + } + + if (pdata->config.flags & SMSC911X_USE_16BIT) { + while (wordcount--) + *buf++ = smsc911x_reg_read(pdata, RX_DATA_FIFO); + return; + } + + BUG(); +} + +/* waits for MAC not busy, with timeout. Only called by smsc911x_mac_read + * and smsc911x_mac_write, so assumes mac_lock is held */ +static int smsc911x_mac_complete(struct smsc911x_data *pdata) +{ + int i; + u32 val; + + SMSC_ASSERT_MAC_LOCK(pdata); + + for (i = 0; i < 40; i++) { + val = smsc911x_reg_read(pdata, MAC_CSR_CMD); + if (!(val & MAC_CSR_CMD_CSR_BUSY_)) + return 0; + } + SMSC_WARNING(HW, "Timed out waiting for MAC not BUSY. " + "MAC_CSR_CMD: 0x%08X", val); + return -EIO; +} + +/* Fetches a MAC register value. Assumes mac_lock is acquired */ +static u32 smsc911x_mac_read(struct smsc911x_data *pdata, unsigned int offset) +{ + unsigned int temp; + + SMSC_ASSERT_MAC_LOCK(pdata); + + temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); + if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { + SMSC_WARNING(HW, "MAC busy at entry"); + return 0xFFFFFFFF; + } + + /* Send the MAC cmd */ + smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) | + MAC_CSR_CMD_CSR_BUSY_ | MAC_CSR_CMD_R_NOT_W_)); + + /* Workaround for hardware read-after-write restriction */ + temp = smsc911x_reg_read(pdata, BYTE_TEST); + + /* Wait for the read to complete */ + if (likely(smsc911x_mac_complete(pdata) == 0)) + return smsc911x_reg_read(pdata, MAC_CSR_DATA); + + SMSC_WARNING(HW, "MAC busy after read"); + return 0xFFFFFFFF; +} + +/* Set a mac register, mac_lock must be acquired before calling */ +static void smsc911x_mac_write(struct smsc911x_data *pdata, + unsigned int offset, u32 val) +{ + unsigned int temp; + + SMSC_ASSERT_MAC_LOCK(pdata); + + temp = smsc911x_reg_read(pdata, MAC_CSR_CMD); + if (unlikely(temp & MAC_CSR_CMD_CSR_BUSY_)) { + SMSC_WARNING(HW, + "smsc911x_mac_write failed, MAC busy at entry"); + return; + } + + /* Send data to write */ + smsc911x_reg_write(pdata, MAC_CSR_DATA, val); + + /* Write the actual data */ + smsc911x_reg_write(pdata, MAC_CSR_CMD, ((offset & 0xFF) | + MAC_CSR_CMD_CSR_BUSY_)); + + /* Workaround for hardware read-after-write restriction */ + temp = smsc911x_reg_read(pdata, BYTE_TEST); + + /* Wait for the write to complete */ + if (likely(smsc911x_mac_complete(pdata) == 0)) + return; + + SMSC_WARNING(HW, + "smsc911x_mac_write failed, MAC busy after write"); +} + +/* Get a phy register */ +static int smsc911x_mii_read(struct mii_bus *bus, int phyaddr, int regidx) +{ + struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv; + unsigned long flags; + unsigned int addr; + int i, reg; + + spin_lock_irqsave(&pdata->mac_lock, flags); + + /* Confirm MII not busy */ + if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { + SMSC_WARNING(HW, + "MII is busy in smsc911x_mii_read???"); + reg = -EIO; + goto out; + } + + /* Set the address, index & direction (read from PHY) */ + addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6); + smsc911x_mac_write(pdata, MII_ACC, addr); + + /* Wait for read to complete w/ timeout */ + for (i = 0; i < 100; i++) + if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { + reg = smsc911x_mac_read(pdata, MII_DATA); + goto out; + } + + SMSC_WARNING(HW, "Timed out waiting for MII write to finish"); + reg = -EIO; + +out: + spin_unlock_irqrestore(&pdata->mac_lock, flags); + return reg; +} + +/* Set a phy register */ +static int smsc911x_mii_write(struct mii_bus *bus, int phyaddr, int regidx, + u16 val) +{ + struct smsc911x_data *pdata = (struct smsc911x_data *)bus->priv; + unsigned long flags; + unsigned int addr; + int i, reg; + + spin_lock_irqsave(&pdata->mac_lock, flags); + + /* Confirm MII not busy */ + if (unlikely(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { + SMSC_WARNING(HW, + "MII is busy in smsc911x_mii_write???"); + reg = -EIO; + goto out; + } + + /* Put the data to write in the MAC */ + smsc911x_mac_write(pdata, MII_DATA, val); + + /* Set the address, index & direction (write to PHY) */ + addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | + MII_ACC_MII_WRITE_; + smsc911x_mac_write(pdata, MII_ACC, addr); + + /* Wait for write to complete w/ timeout */ + for (i = 0; i < 100; i++) + if (!(smsc911x_mac_read(pdata, MII_ACC) & MII_ACC_MII_BUSY_)) { + reg = 0; + goto out; + } + + SMSC_WARNING(HW, "Timed out waiting for MII write to finish"); + reg = -EIO; + +out: + spin_unlock_irqrestore(&pdata->mac_lock, flags); + return reg; +} + +/* Autodetects and initialises external phy for SMSC9115 and SMSC9117 flavors. + * If something goes wrong, returns -ENODEV to revert back to internal phy. + * Performed at initialisation only, so interrupts are enabled */ +static int smsc911x_phy_initialise_external(struct smsc911x_data *pdata) +{ + unsigned int hwcfg = smsc911x_reg_read(pdata, HW_CFG); + + /* External phy is requested, supported, and detected */ + if (hwcfg & HW_CFG_EXT_PHY_DET_) { + + /* Switch to external phy. Assuming tx and rx are stopped + * because smsc911x_phy_initialise is called before + * smsc911x_rx_initialise and tx_initialise. */ + + /* Disable phy clocks to the MAC */ + hwcfg &= (~HW_CFG_PHY_CLK_SEL_); + hwcfg |= HW_CFG_PHY_CLK_SEL_CLK_DIS_; + smsc911x_reg_write(pdata, HW_CFG, hwcfg); + udelay(10); /* Enough time for clocks to stop */ + + /* Switch to external phy */ + hwcfg |= HW_CFG_EXT_PHY_EN_; + smsc911x_reg_write(pdata, HW_CFG, hwcfg); + + /* Enable phy clocks to the MAC */ + hwcfg &= (~HW_CFG_PHY_CLK_SEL_); + hwcfg |= HW_CFG_PHY_CLK_SEL_EXT_PHY_; + smsc911x_reg_write(pdata, HW_CFG, hwcfg); + udelay(10); /* Enough time for clocks to restart */ + + hwcfg |= HW_CFG_SMI_SEL_; + smsc911x_reg_write(pdata, HW_CFG, hwcfg); + + SMSC_TRACE(HW, "Successfully switched to external PHY"); + pdata->using_extphy = 1; + } else { + SMSC_WARNING(HW, "No external PHY detected, " + "Using internal PHY instead."); + /* Use internal phy */ + return -ENODEV; + } + return 0; +} + +/* Fetches a tx status out of the status fifo */ +static unsigned int smsc911x_tx_get_txstatus(struct smsc911x_data *pdata) +{ + unsigned int result = + smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TSUSED_; + + if (result != 0) + result = smsc911x_reg_read(pdata, TX_STATUS_FIFO); + + return result; +} + +/* Fetches the next rx status */ +static unsigned int smsc911x_rx_get_rxstatus(struct smsc911x_data *pdata) +{ + unsigned int result = + smsc911x_reg_read(pdata, RX_FIFO_INF) & RX_FIFO_INF_RXSUSED_; + + if (result != 0) + result = smsc911x_reg_read(pdata, RX_STATUS_FIFO); + + return result; +} + +#ifdef USE_PHY_WORK_AROUND +static int smsc911x_phy_check_loopbackpkt(struct smsc911x_data *pdata) +{ + unsigned int tries; + u32 wrsz; + u32 rdsz; + ulong bufp; + + for (tries = 0; tries < 10; tries++) { + unsigned int txcmd_a; + unsigned int txcmd_b; + unsigned int status; + unsigned int pktlength; + unsigned int i; + + /* Zero-out rx packet memory */ + memset(pdata->loopback_rx_pkt, 0, MIN_PACKET_SIZE); + + /* Write tx packet to 118 */ + txcmd_a = (u32)((ulong)pdata->loopback_tx_pkt & 0x03) << 16; + txcmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; + txcmd_a |= MIN_PACKET_SIZE; + + txcmd_b = MIN_PACKET_SIZE << 16 | MIN_PACKET_SIZE; + + smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_a); + smsc911x_reg_write(pdata, TX_DATA_FIFO, txcmd_b); + + bufp = (ulong)pdata->loopback_tx_pkt & (~0x3); + wrsz = MIN_PACKET_SIZE + 3; + wrsz += (u32)((ulong)pdata->loopback_tx_pkt & 0x3); + wrsz >>= 2; + + smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); + + /* Wait till transmit is done */ + i = 60; + do { + udelay(5); + status = smsc911x_tx_get_txstatus(pdata); + } while ((i--) && (!status)); + + if (!status) { + SMSC_WARNING(HW, "Failed to transmit " + "during loopback test"); + continue; + } + if (status & TX_STS_ES_) { + SMSC_WARNING(HW, "Transmit encountered " + "errors during loopback test"); + continue; + } + + /* Wait till receive is done */ + i = 60; + do { + udelay(5); + status = smsc911x_rx_get_rxstatus(pdata); + } while ((i--) && (!status)); + + if (!status) { + SMSC_WARNING(HW, + "Failed to receive during loopback test"); + continue; + } + if (status & RX_STS_ES_) { + SMSC_WARNING(HW, "Receive encountered " + "errors during loopback test"); + continue; + } + + pktlength = ((status & 0x3FFF0000UL) >> 16); + bufp = (ulong)pdata->loopback_rx_pkt; + rdsz = pktlength + 3; + rdsz += (u32)((ulong)pdata->loopback_rx_pkt & 0x3); + rdsz >>= 2; + + smsc911x_rx_readfifo(pdata, (unsigned int *)bufp, rdsz); + + if (pktlength != (MIN_PACKET_SIZE + 4)) { + SMSC_WARNING(HW, "Unexpected packet size " + "during loop back test, size=%d, will retry", + pktlength); + } else { + unsigned int j; + int mismatch = 0; + for (j = 0; j < MIN_PACKET_SIZE; j++) { + if (pdata->loopback_tx_pkt[j] + != pdata->loopback_rx_pkt[j]) { + mismatch = 1; + break; + } + } + if (!mismatch) { + SMSC_TRACE(HW, "Successfully verified " + "loopback packet"); + return 0; + } else { + SMSC_WARNING(HW, "Data mismatch " + "during loop back test, will retry"); + } + } + } + + return -EIO; +} + +static int smsc911x_phy_reset(struct smsc911x_data *pdata) +{ + struct phy_device *phy_dev = pdata->phy_dev; + unsigned int temp; + unsigned int i = 100000; + + BUG_ON(!phy_dev); + BUG_ON(!phy_dev->bus); + + SMSC_TRACE(HW, "Performing PHY BCR Reset"); + smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, BMCR_RESET); + do { + msleep(1); + temp = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, + MII_BMCR); + } while ((i--) && (temp & BMCR_RESET)); + + if (temp & BMCR_RESET) { + SMSC_WARNING(HW, "PHY reset failed to complete."); + return -EIO; + } + /* Extra delay required because the phy may not be completed with + * its reset when BMCR_RESET is cleared. Specs say 256 uS is + * enough delay but using 1ms here to be safe */ + msleep(1); + + return 0; +} + +static int smsc911x_phy_loopbacktest(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + struct phy_device *phy_dev = pdata->phy_dev; + int result = -EIO; + unsigned int i, val; + unsigned long flags; + + /* Initialise tx packet using broadcast destination address */ + memset(pdata->loopback_tx_pkt, 0xff, ETH_ALEN); + + /* Use incrementing source address */ + for (i = 6; i < 12; i++) + pdata->loopback_tx_pkt[i] = (char)i; + + /* Set length type field */ + pdata->loopback_tx_pkt[12] = 0x00; + pdata->loopback_tx_pkt[13] = 0x00; + + for (i = 14; i < MIN_PACKET_SIZE; i++) + pdata->loopback_tx_pkt[i] = (char)i; + + val = smsc911x_reg_read(pdata, HW_CFG); + val &= HW_CFG_TX_FIF_SZ_; + val |= HW_CFG_SF_; + smsc911x_reg_write(pdata, HW_CFG, val); + + smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_); + smsc911x_reg_write(pdata, RX_CFG, + (u32)((ulong)pdata->loopback_rx_pkt & 0x03) << 8); + + for (i = 0; i < 10; i++) { + /* Set PHY to 10/FD, no ANEG, and loopback mode */ + smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, + BMCR_LOOPBACK | BMCR_FULLDPLX); + + /* Enable MAC tx/rx, FD */ + spin_lock_irqsave(&pdata->mac_lock, flags); + smsc911x_mac_write(pdata, MAC_CR, MAC_CR_FDPX_ + | MAC_CR_TXEN_ | MAC_CR_RXEN_); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + + if (smsc911x_phy_check_loopbackpkt(pdata) == 0) { + result = 0; + break; + } + pdata->resetcount++; + + /* Disable MAC rx */ + spin_lock_irqsave(&pdata->mac_lock, flags); + smsc911x_mac_write(pdata, MAC_CR, 0); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + + smsc911x_phy_reset(pdata); + } + + /* Disable MAC */ + spin_lock_irqsave(&pdata->mac_lock, flags); + smsc911x_mac_write(pdata, MAC_CR, 0); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + + /* Cancel PHY loopback mode */ + smsc911x_mii_write(phy_dev->bus, phy_dev->addr, MII_BMCR, 0); + + smsc911x_reg_write(pdata, TX_CFG, 0); + smsc911x_reg_write(pdata, RX_CFG, 0); + + return result; +} +#endif /* USE_PHY_WORK_AROUND */ + +static void smsc911x_phy_update_flowcontrol(struct smsc911x_data *pdata) +{ + struct phy_device *phy_dev = pdata->phy_dev; + u32 afc = smsc911x_reg_read(pdata, AFC_CFG); + u32 flow; + unsigned long flags; + + if (phy_dev->duplex == DUPLEX_FULL) { + u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); + u16 rmtadv = phy_read(phy_dev, MII_LPA); + u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); + + if (cap & FLOW_CTRL_RX) + flow = 0xFFFF0002; + else + flow = 0; + + if (cap & FLOW_CTRL_TX) + afc |= 0xF; + else + afc &= ~0xF; + + SMSC_TRACE(HW, "rx pause %s, tx pause %s", + (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), + (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); + } else { + SMSC_TRACE(HW, "half duplex"); + flow = 0; + afc |= 0xF; + } + + spin_lock_irqsave(&pdata->mac_lock, flags); + smsc911x_mac_write(pdata, FLOW, flow); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + + smsc911x_reg_write(pdata, AFC_CFG, afc); +} + +/* Update link mode if anything has changed. Called periodically when the + * PHY is in polling mode, even if nothing has changed. */ +static void smsc911x_phy_adjust_link(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + struct phy_device *phy_dev = pdata->phy_dev; + unsigned long flags; + int carrier; + + if (phy_dev->duplex != pdata->last_duplex) { + unsigned int mac_cr; + SMSC_TRACE(HW, "duplex state has changed"); + + spin_lock_irqsave(&pdata->mac_lock, flags); + mac_cr = smsc911x_mac_read(pdata, MAC_CR); + if (phy_dev->duplex) { + SMSC_TRACE(HW, + "configuring for full duplex mode"); + mac_cr |= MAC_CR_FDPX_; + } else { + SMSC_TRACE(HW, + "configuring for half duplex mode"); + mac_cr &= ~MAC_CR_FDPX_; + } + smsc911x_mac_write(pdata, MAC_CR, mac_cr); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + + smsc911x_phy_update_flowcontrol(pdata); + pdata->last_duplex = phy_dev->duplex; + } + + carrier = netif_carrier_ok(dev); + if (carrier != pdata->last_carrier) { + SMSC_TRACE(HW, "carrier state has changed"); + if (carrier) { + SMSC_TRACE(HW, "configuring for carrier OK"); + if ((pdata->gpio_orig_setting & GPIO_CFG_LED1_EN_) && + (!pdata->using_extphy)) { + /* Restore orginal GPIO configuration */ + pdata->gpio_setting = pdata->gpio_orig_setting; + smsc911x_reg_write(pdata, GPIO_CFG, + pdata->gpio_setting); + } + } else { + SMSC_TRACE(HW, "configuring for no carrier"); + /* Check global setting that LED1 + * usage is 10/100 indicator */ + pdata->gpio_setting = smsc911x_reg_read(pdata, + GPIO_CFG); + if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_) + && (!pdata->using_extphy)) { + /* Force 10/100 LED off, after saving + * orginal GPIO configuration */ + pdata->gpio_orig_setting = pdata->gpio_setting; + + pdata->gpio_setting &= ~GPIO_CFG_LED1_EN_; + pdata->gpio_setting |= (GPIO_CFG_GPIOBUF0_ + | GPIO_CFG_GPIODIR0_ + | GPIO_CFG_GPIOD0_); + smsc911x_reg_write(pdata, GPIO_CFG, + pdata->gpio_setting); + } + } + pdata->last_carrier = carrier; + } +} + +static int smsc911x_mii_probe(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + struct phy_device *phydev = NULL; + int phy_addr; + + /* find the first phy */ + for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) { + if (pdata->mii_bus->phy_map[phy_addr]) { + phydev = pdata->mii_bus->phy_map[phy_addr]; + SMSC_TRACE(PROBE, "PHY %d: addr %d, phy_id 0x%08X", + phy_addr, phydev->addr, phydev->phy_id); + break; + } + } + + if (!phydev) { + pr_err("%s: no PHY found\n", dev->name); + return -ENODEV; + } + + phydev = phy_connect(dev, phydev->dev.bus_id, + &smsc911x_phy_adjust_link, 0, pdata->config.phy_interface); + + if (IS_ERR(phydev)) { + pr_err("%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); + } + + pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", + dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq); + + /* mask with MAC supported features */ + phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + phydev->advertising = phydev->supported; + + pdata->phy_dev = phydev; + pdata->last_duplex = -1; + pdata->last_carrier = -1; + +#ifdef USE_PHY_WORK_AROUND + if (smsc911x_phy_loopbacktest(dev) < 0) { + SMSC_WARNING(HW, "Failed Loop Back Test"); + return -ENODEV; + } + SMSC_TRACE(HW, "Passed Loop Back Test"); +#endif /* USE_PHY_WORK_AROUND */ + + SMSC_TRACE(HW, "phy initialised succesfully"); + return 0; +} + +static int __devinit smsc911x_mii_init(struct platform_device *pdev, + struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + int err = -ENXIO, i; + + pdata->mii_bus = mdiobus_alloc(); + if (!pdata->mii_bus) { + err = -ENOMEM; + goto err_out_1; + } + + pdata->mii_bus->name = SMSC_MDIONAME; + snprintf(pdata->mii_bus->id, MII_BUS_ID_SIZE, "%x", pdev->id); + pdata->mii_bus->priv = pdata; + pdata->mii_bus->read = smsc911x_mii_read; + pdata->mii_bus->write = smsc911x_mii_write; + pdata->mii_bus->irq = pdata->phy_irq; + for (i = 0; i < PHY_MAX_ADDR; ++i) + pdata->mii_bus->irq[i] = PHY_POLL; + + pdata->mii_bus->parent = &pdev->dev; + + pdata->using_extphy = 0; + + switch (pdata->idrev & 0xFFFF0000) { + case 0x01170000: + case 0x01150000: + case 0x117A0000: + case 0x115A0000: + /* External PHY supported, try to autodetect */ + if (smsc911x_phy_initialise_external(pdata) < 0) { + SMSC_TRACE(HW, "No external PHY detected, " + "using internal PHY"); + } + break; + default: + SMSC_TRACE(HW, "External PHY is not supported, " + "using internal PHY"); + break; + } + + if (!pdata->using_extphy) { + /* Mask all PHYs except ID 1 (internal) */ + pdata->mii_bus->phy_mask = ~(1 << 1); + } + + if (mdiobus_register(pdata->mii_bus)) { + SMSC_WARNING(PROBE, "Error registering mii bus"); + goto err_out_free_bus_2; + } + + if (smsc911x_mii_probe(dev) < 0) { + SMSC_WARNING(PROBE, "Error registering mii bus"); + goto err_out_unregister_bus_3; + } + + return 0; + +err_out_unregister_bus_3: + mdiobus_unregister(pdata->mii_bus); +err_out_free_bus_2: + mdiobus_free(pdata->mii_bus); +err_out_1: + return err; +} + +/* Gets the number of tx statuses in the fifo */ +static unsigned int smsc911x_tx_get_txstatcount(struct smsc911x_data *pdata) +{ + return (smsc911x_reg_read(pdata, TX_FIFO_INF) + & TX_FIFO_INF_TSUSED_) >> 16; +} + +/* Reads tx statuses and increments counters where necessary */ +static void smsc911x_tx_update_txcounters(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int tx_stat; + + while ((tx_stat = smsc911x_tx_get_txstatus(pdata)) != 0) { + if (unlikely(tx_stat & 0x80000000)) { + /* In this driver the packet tag is used as the packet + * length. Since a packet length can never reach the + * size of 0x8000, this bit is reserved. It is worth + * noting that the "reserved bit" in the warning above + * does not reference a hardware defined reserved bit + * but rather a driver defined one. + */ + SMSC_WARNING(HW, + "Packet tag reserved bit is high"); + } else { + if (unlikely(tx_stat & 0x00008000)) { + dev->stats.tx_errors++; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += (tx_stat >> 16); + } + if (unlikely(tx_stat & 0x00000100)) { + dev->stats.collisions += 16; + dev->stats.tx_aborted_errors += 1; + } else { + dev->stats.collisions += + ((tx_stat >> 3) & 0xF); + } + if (unlikely(tx_stat & 0x00000800)) + dev->stats.tx_carrier_errors += 1; + if (unlikely(tx_stat & 0x00000200)) { + dev->stats.collisions++; + dev->stats.tx_aborted_errors++; + } + } + } +} + +/* Increments the Rx error counters */ +static void +smsc911x_rx_counterrors(struct net_device *dev, unsigned int rxstat) +{ + int crc_err = 0; + + if (unlikely(rxstat & 0x00008000)) { + dev->stats.rx_errors++; + if (unlikely(rxstat & 0x00000002)) { + dev->stats.rx_crc_errors++; + crc_err = 1; + } + } + if (likely(!crc_err)) { + if (unlikely((rxstat & 0x00001020) == 0x00001020)) { + /* Frame type indicates length, + * and length error is set */ + dev->stats.rx_length_errors++; + } + if (rxstat & RX_STS_MCAST_) + dev->stats.multicast++; + } +} + +/* Quickly dumps bad packets */ +static void +smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes) +{ + unsigned int pktwords = (pktbytes + NET_IP_ALIGN + 3) >> 2; + + if (likely(pktwords >= 4)) { + unsigned int timeout = 500; + unsigned int val; + smsc911x_reg_write(pdata, RX_DP_CTRL, RX_DP_CTRL_RX_FFWD_); + do { + udelay(1); + val = smsc911x_reg_read(pdata, RX_DP_CTRL); + } while (timeout-- && (val & RX_DP_CTRL_RX_FFWD_)); + + if (unlikely(timeout == 0)) + SMSC_WARNING(HW, "Timed out waiting for " + "RX FFWD to finish, RX_DP_CTRL: 0x%08X", val); + } else { + unsigned int temp; + while (pktwords--) + temp = smsc911x_reg_read(pdata, RX_DATA_FIFO); + } +} + +/* NAPI poll function */ +static int smsc911x_poll(struct napi_struct *napi, int budget) +{ + struct smsc911x_data *pdata = + container_of(napi, struct smsc911x_data, napi); + struct net_device *dev = pdata->dev; + int npackets = 0; + + while (likely(netif_running(dev)) && (npackets < budget)) { + unsigned int pktlength; + unsigned int pktwords; + struct sk_buff *skb; + unsigned int rxstat = smsc911x_rx_get_rxstatus(pdata); + + if (!rxstat) { + unsigned int temp; + /* We processed all packets available. Tell NAPI it can + * stop polling then re-enable rx interrupts */ + smsc911x_reg_write(pdata, INT_STS, INT_STS_RSFL_); + netif_rx_complete(napi); + temp = smsc911x_reg_read(pdata, INT_EN); + temp |= INT_EN_RSFL_EN_; + smsc911x_reg_write(pdata, INT_EN, temp); + break; + } + + /* Count packet for NAPI scheduling, even if it has an error. + * Error packets still require cycles to discard */ + npackets++; + + pktlength = ((rxstat & 0x3FFF0000) >> 16); + pktwords = (pktlength + NET_IP_ALIGN + 3) >> 2; + smsc911x_rx_counterrors(dev, rxstat); + + if (unlikely(rxstat & RX_STS_ES_)) { + SMSC_WARNING(RX_ERR, + "Discarding packet with error bit set"); + /* Packet has an error, discard it and continue with + * the next */ + smsc911x_rx_fastforward(pdata, pktwords); + dev->stats.rx_dropped++; + continue; + } + + skb = netdev_alloc_skb(dev, pktlength + NET_IP_ALIGN); + if (unlikely(!skb)) { + SMSC_WARNING(RX_ERR, + "Unable to allocate skb for rx packet"); + /* Drop the packet and stop this polling iteration */ + smsc911x_rx_fastforward(pdata, pktwords); + dev->stats.rx_dropped++; + break; + } + + skb->data = skb->head; + skb_reset_tail_pointer(skb); + + /* Align IP on 16B boundary */ + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, pktlength - 4); + smsc911x_rx_readfifo(pdata, (unsigned int *)skb->head, + pktwords); + skb->protocol = eth_type_trans(skb, dev); + skb->ip_summed = CHECKSUM_NONE; + netif_receive_skb(skb); + + /* Update counters */ + dev->stats.rx_packets++; + dev->stats.rx_bytes += (pktlength - 4); + dev->last_rx = jiffies; + } + + /* Return total received packets */ + return npackets; +} + +/* Returns hash bit number for given MAC address + * Example: + * 01 00 5E 00 00 01 -> returns bit number 31 */ +static unsigned int smsc911x_hash(char addr[ETH_ALEN]) +{ + return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; +} + +static void smsc911x_rx_multicast_update(struct smsc911x_data *pdata) +{ + /* Performs the multicast & mac_cr update. This is called when + * safe on the current hardware, and with the mac_lock held */ + unsigned int mac_cr; + + SMSC_ASSERT_MAC_LOCK(pdata); + + mac_cr = smsc911x_mac_read(pdata, MAC_CR); + mac_cr |= pdata->set_bits_mask; + mac_cr &= ~(pdata->clear_bits_mask); + smsc911x_mac_write(pdata, MAC_CR, mac_cr); + smsc911x_mac_write(pdata, HASHH, pdata->hashhi); + smsc911x_mac_write(pdata, HASHL, pdata->hashlo); + SMSC_TRACE(HW, "maccr 0x%08X, HASHH 0x%08X, HASHL 0x%08X", + mac_cr, pdata->hashhi, pdata->hashlo); +} + +static void smsc911x_rx_multicast_update_workaround(struct smsc911x_data *pdata) +{ + unsigned int mac_cr; + + /* This function is only called for older LAN911x devices + * (revA or revB), where MAC_CR, HASHH and HASHL should not + * be modified during Rx - newer devices immediately update the + * registers. + * + * This is called from interrupt context */ + + spin_lock(&pdata->mac_lock); + + /* Check Rx has stopped */ + if (smsc911x_mac_read(pdata, MAC_CR) & MAC_CR_RXEN_) + SMSC_WARNING(DRV, "Rx not stopped"); + + /* Perform the update - safe to do now Rx has stopped */ + smsc911x_rx_multicast_update(pdata); + + /* Re-enable Rx */ + mac_cr = smsc911x_mac_read(pdata, MAC_CR); + mac_cr |= MAC_CR_RXEN_; + smsc911x_mac_write(pdata, MAC_CR, mac_cr); + + pdata->multicast_update_pending = 0; + + spin_unlock(&pdata->mac_lock); +} + +static int smsc911x_soft_reset(struct smsc911x_data *pdata) +{ + unsigned int timeout; + unsigned int temp; + + /* Reset the LAN911x */ + smsc911x_reg_write(pdata, HW_CFG, HW_CFG_SRST_); + timeout = 10; + do { + udelay(10); + temp = smsc911x_reg_read(pdata, HW_CFG); + } while ((--timeout) && (temp & HW_CFG_SRST_)); + + if (unlikely(temp & HW_CFG_SRST_)) { + SMSC_WARNING(DRV, "Failed to complete reset"); + return -EIO; + } + return 0; +} + +/* Sets the device MAC address to dev_addr, called with mac_lock held */ +static void +smsc911x_set_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6]) +{ + u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4]; + u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | + (dev_addr[1] << 8) | dev_addr[0]; + + SMSC_ASSERT_MAC_LOCK(pdata); + + smsc911x_mac_write(pdata, ADDRH, mac_high16); + smsc911x_mac_write(pdata, ADDRL, mac_low32); +} + +static int smsc911x_open(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int timeout; + unsigned int temp; + unsigned int intcfg; + + /* if the phy is not yet registered, retry later*/ + if (!pdata->phy_dev) { + SMSC_WARNING(HW, "phy_dev is NULL"); + return -EAGAIN; + } + + if (!is_valid_ether_addr(dev->dev_addr)) { + SMSC_WARNING(HW, "dev_addr is not a valid MAC address"); + return -EADDRNOTAVAIL; + } + + /* Reset the LAN911x */ + if (smsc911x_soft_reset(pdata)) { + SMSC_WARNING(HW, "soft reset failed"); + return -EIO; + } + + smsc911x_reg_write(pdata, HW_CFG, 0x00050000); + smsc911x_reg_write(pdata, AFC_CFG, 0x006E3740); + + /* Make sure EEPROM has finished loading before setting GPIO_CFG */ + timeout = 50; + while ((timeout--) && + (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_)) { + udelay(10); + } + + if (unlikely(timeout == 0)) + SMSC_WARNING(IFUP, + "Timed out waiting for EEPROM busy bit to clear"); + + smsc911x_reg_write(pdata, GPIO_CFG, 0x70070000); + + /* The soft reset above cleared the device's MAC address, + * restore it from local copy (set in probe) */ + spin_lock_irq(&pdata->mac_lock); + smsc911x_set_mac_address(pdata, dev->dev_addr); + spin_unlock_irq(&pdata->mac_lock); + + /* Initialise irqs, but leave all sources disabled */ + smsc911x_reg_write(pdata, INT_EN, 0); + smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF); + + /* Set interrupt deassertion to 100uS */ + intcfg = ((10 << 24) | INT_CFG_IRQ_EN_); + + if (pdata->config.irq_polarity) { + SMSC_TRACE(IFUP, "irq polarity: active high"); + intcfg |= INT_CFG_IRQ_POL_; + } else { + SMSC_TRACE(IFUP, "irq polarity: active low"); + } + + if (pdata->config.irq_type) { + SMSC_TRACE(IFUP, "irq type: push-pull"); + intcfg |= INT_CFG_IRQ_TYPE_; + } else { + SMSC_TRACE(IFUP, "irq type: open drain"); + } + + smsc911x_reg_write(pdata, INT_CFG, intcfg); + + SMSC_TRACE(IFUP, "Testing irq handler using IRQ %d", dev->irq); + pdata->software_irq_signal = 0; + smp_wmb(); + + temp = smsc911x_reg_read(pdata, INT_EN); + temp |= INT_EN_SW_INT_EN_; + smsc911x_reg_write(pdata, INT_EN, temp); + + timeout = 1000; + while (timeout--) { + if (pdata->software_irq_signal) + break; + msleep(1); + } + + if (!pdata->software_irq_signal) { + dev_warn(&dev->dev, "ISR failed signaling test (IRQ %d)\n", + dev->irq); + return -ENODEV; + } + SMSC_TRACE(IFUP, "IRQ handler passed test using IRQ %d", dev->irq); + + dev_info(&dev->dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n", + (unsigned long)pdata->ioaddr, dev->irq); + + /* Bring the PHY up */ + phy_start(pdata->phy_dev); + + temp = smsc911x_reg_read(pdata, HW_CFG); + /* Preserve TX FIFO size and external PHY configuration */ + temp &= (HW_CFG_TX_FIF_SZ_|0x00000FFF); + temp |= HW_CFG_SF_; + smsc911x_reg_write(pdata, HW_CFG, temp); + + temp = smsc911x_reg_read(pdata, FIFO_INT); + temp |= FIFO_INT_TX_AVAIL_LEVEL_; + temp &= ~(FIFO_INT_RX_STS_LEVEL_); + smsc911x_reg_write(pdata, FIFO_INT, temp); + + /* set RX Data offset to 2 bytes for alignment */ + smsc911x_reg_write(pdata, RX_CFG, (2 << 8)); + + /* enable NAPI polling before enabling RX interrupts */ + napi_enable(&pdata->napi); + + temp = smsc911x_reg_read(pdata, INT_EN); + temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_); + smsc911x_reg_write(pdata, INT_EN, temp); + + spin_lock_irq(&pdata->mac_lock); + temp = smsc911x_mac_read(pdata, MAC_CR); + temp |= (MAC_CR_TXEN_ | MAC_CR_RXEN_ | MAC_CR_HBDIS_); + smsc911x_mac_write(pdata, MAC_CR, temp); + spin_unlock_irq(&pdata->mac_lock); + + smsc911x_reg_write(pdata, TX_CFG, TX_CFG_TX_ON_); + + netif_start_queue(dev); + return 0; +} + +/* Entry point for stopping the interface */ +static int smsc911x_stop(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int temp; + + /* Disable all device interrupts */ + temp = smsc911x_reg_read(pdata, INT_CFG); + temp &= ~INT_CFG_IRQ_EN_; + smsc911x_reg_write(pdata, INT_CFG, temp); + + /* Stop Tx and Rx polling */ + netif_stop_queue(dev); + napi_disable(&pdata->napi); + + /* At this point all Rx and Tx activity is stopped */ + dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP); + smsc911x_tx_update_txcounters(dev); + + /* Bring the PHY down */ + if (pdata->phy_dev) + phy_stop(pdata->phy_dev); + + SMSC_TRACE(IFDOWN, "Interface stopped"); + return 0; +} + +/* Entry point for transmitting a packet */ +static int smsc911x_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int freespace; + unsigned int tx_cmd_a; + unsigned int tx_cmd_b; + unsigned int temp; + u32 wrsz; + ulong bufp; + + freespace = smsc911x_reg_read(pdata, TX_FIFO_INF) & TX_FIFO_INF_TDFREE_; + + if (unlikely(freespace < TX_FIFO_LOW_THRESHOLD)) + SMSC_WARNING(TX_ERR, + "Tx data fifo low, space available: %d", freespace); + + /* Word alignment adjustment */ + tx_cmd_a = (u32)((ulong)skb->data & 0x03) << 16; + tx_cmd_a |= TX_CMD_A_FIRST_SEG_ | TX_CMD_A_LAST_SEG_; + tx_cmd_a |= (unsigned int)skb->len; + + tx_cmd_b = ((unsigned int)skb->len) << 16; + tx_cmd_b |= (unsigned int)skb->len; + + smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_a); + smsc911x_reg_write(pdata, TX_DATA_FIFO, tx_cmd_b); + + bufp = (ulong)skb->data & (~0x3); + wrsz = (u32)skb->len + 3; + wrsz += (u32)((ulong)skb->data & 0x3); + wrsz >>= 2; + + smsc911x_tx_writefifo(pdata, (unsigned int *)bufp, wrsz); + freespace -= (skb->len + 32); + dev_kfree_skb(skb); + dev->trans_start = jiffies; + + if (unlikely(smsc911x_tx_get_txstatcount(pdata) >= 30)) + smsc911x_tx_update_txcounters(dev); + + if (freespace < TX_FIFO_LOW_THRESHOLD) { + netif_stop_queue(dev); + temp = smsc911x_reg_read(pdata, FIFO_INT); + temp &= 0x00FFFFFF; + temp |= 0x32000000; + smsc911x_reg_write(pdata, FIFO_INT, temp); + } + + return NETDEV_TX_OK; +} + +/* Entry point for getting status counters */ +static struct net_device_stats *smsc911x_get_stats(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + smsc911x_tx_update_txcounters(dev); + dev->stats.rx_dropped += smsc911x_reg_read(pdata, RX_DROP); + return &dev->stats; +} + +/* Entry point for setting addressing modes */ +static void smsc911x_set_multicast_list(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned long flags; + + if (dev->flags & IFF_PROMISC) { + /* Enabling promiscuous mode */ + pdata->set_bits_mask = MAC_CR_PRMS_; + pdata->clear_bits_mask = (MAC_CR_MCPAS_ | MAC_CR_HPFILT_); + pdata->hashhi = 0; + pdata->hashlo = 0; + } else if (dev->flags & IFF_ALLMULTI) { + /* Enabling all multicast mode */ + pdata->set_bits_mask = MAC_CR_MCPAS_; + pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_HPFILT_); + pdata->hashhi = 0; + pdata->hashlo = 0; + } else if (dev->mc_count > 0) { + /* Enabling specific multicast addresses */ + unsigned int hash_high = 0; + unsigned int hash_low = 0; + unsigned int count = 0; + struct dev_mc_list *mc_list = dev->mc_list; + + pdata->set_bits_mask = MAC_CR_HPFILT_; + pdata->clear_bits_mask = (MAC_CR_PRMS_ | MAC_CR_MCPAS_); + + while (mc_list) { + count++; + if ((mc_list->dmi_addrlen) == ETH_ALEN) { + unsigned int bitnum = + smsc911x_hash(mc_list->dmi_addr); + unsigned int mask = 0x01 << (bitnum & 0x1F); + if (bitnum & 0x20) + hash_high |= mask; + else + hash_low |= mask; + } else { + SMSC_WARNING(DRV, "dmi_addrlen != 6"); + } + mc_list = mc_list->next; + } + if (count != (unsigned int)dev->mc_count) + SMSC_WARNING(DRV, "mc_count != dev->mc_count"); + + pdata->hashhi = hash_high; + pdata->hashlo = hash_low; + } else { + /* Enabling local MAC address only */ + pdata->set_bits_mask = 0; + pdata->clear_bits_mask = + (MAC_CR_PRMS_ | MAC_CR_MCPAS_ | MAC_CR_HPFILT_); + pdata->hashhi = 0; + pdata->hashlo = 0; + } + + spin_lock_irqsave(&pdata->mac_lock, flags); + + if (pdata->generation <= 1) { + /* Older hardware revision - cannot change these flags while + * receiving data */ + if (!pdata->multicast_update_pending) { + unsigned int temp; + SMSC_TRACE(HW, "scheduling mcast update"); + pdata->multicast_update_pending = 1; + + /* Request the hardware to stop, then perform the + * update when we get an RX_STOP interrupt */ + smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_); + temp = smsc911x_reg_read(pdata, INT_EN); + temp |= INT_EN_RXSTOP_INT_EN_; + smsc911x_reg_write(pdata, INT_EN, temp); + + temp = smsc911x_mac_read(pdata, MAC_CR); + temp &= ~(MAC_CR_RXEN_); + smsc911x_mac_write(pdata, MAC_CR, temp); + } else { + /* There is another update pending, this should now + * use the newer values */ + } + } else { + /* Newer hardware revision - can write immediately */ + smsc911x_rx_multicast_update(pdata); + } + + spin_unlock_irqrestore(&pdata->mac_lock, flags); +} + +static irqreturn_t smsc911x_irqhandler(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct smsc911x_data *pdata = netdev_priv(dev); + u32 intsts = smsc911x_reg_read(pdata, INT_STS); + u32 inten = smsc911x_reg_read(pdata, INT_EN); + int serviced = IRQ_NONE; + u32 temp; + + if (unlikely(intsts & inten & INT_STS_SW_INT_)) { + temp = smsc911x_reg_read(pdata, INT_EN); + temp &= (~INT_EN_SW_INT_EN_); + smsc911x_reg_write(pdata, INT_EN, temp); + smsc911x_reg_write(pdata, INT_STS, INT_STS_SW_INT_); + pdata->software_irq_signal = 1; + smp_wmb(); + serviced = IRQ_HANDLED; + } + + if (unlikely(intsts & inten & INT_STS_RXSTOP_INT_)) { + /* Called when there is a multicast update scheduled and + * it is now safe to complete the update */ + SMSC_TRACE(INTR, "RX Stop interrupt"); + temp = smsc911x_reg_read(pdata, INT_EN); + temp &= (~INT_EN_RXSTOP_INT_EN_); + smsc911x_reg_write(pdata, INT_EN, temp); + smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_); + smsc911x_rx_multicast_update_workaround(pdata); + serviced = IRQ_HANDLED; + } + + if (intsts & inten & INT_STS_TDFA_) { + temp = smsc911x_reg_read(pdata, FIFO_INT); + temp |= FIFO_INT_TX_AVAIL_LEVEL_; + smsc911x_reg_write(pdata, FIFO_INT, temp); + smsc911x_reg_write(pdata, INT_STS, INT_STS_TDFA_); + netif_wake_queue(dev); + serviced = IRQ_HANDLED; + } + + if (unlikely(intsts & inten & INT_STS_RXE_)) { + SMSC_TRACE(INTR, "RX Error interrupt"); + smsc911x_reg_write(pdata, INT_STS, INT_STS_RXE_); + serviced = IRQ_HANDLED; + } + + if (likely(intsts & inten & INT_STS_RSFL_)) { + if (likely(netif_rx_schedule_prep(dev, &pdata->napi))) { + /* Disable Rx interrupts */ + temp = smsc911x_reg_read(pdata, INT_EN); + temp &= (~INT_EN_RSFL_EN_); + smsc911x_reg_write(pdata, INT_EN, temp); + /* Schedule a NAPI poll */ + __netif_rx_schedule(dev, &pdata->napi); + } else { + SMSC_WARNING(RX_ERR, + "netif_rx_schedule_prep failed"); + } + serviced = IRQ_HANDLED; + } + + return serviced; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void smsc911x_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + smsc911x_irqhandler(0, dev); + enable_irq(dev->irq); +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + +/* Standard ioctls for mii-tool */ +static int smsc911x_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + + if (!netif_running(dev) || !pdata->phy_dev) + return -EINVAL; + + return phy_mii_ioctl(pdata->phy_dev, if_mii(ifr), cmd); +} + +static int +smsc911x_ethtool_getsettings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + + cmd->maxtxpkt = 1; + cmd->maxrxpkt = 1; + return phy_ethtool_gset(pdata->phy_dev, cmd); +} + +static int +smsc911x_ethtool_setsettings(struct net_device *dev, struct ethtool_cmd *cmd) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + + return phy_ethtool_sset(pdata->phy_dev, cmd); +} + +static void smsc911x_ethtool_getdrvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strlcpy(info->driver, SMSC_CHIPNAME, sizeof(info->driver)); + strlcpy(info->version, SMSC_DRV_VERSION, sizeof(info->version)); + strlcpy(info->bus_info, dev->dev.parent->bus_id, + sizeof(info->bus_info)); +} + +static int smsc911x_ethtool_nwayreset(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + + return phy_start_aneg(pdata->phy_dev); +} + +static u32 smsc911x_ethtool_getmsglevel(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + return pdata->msg_enable; +} + +static void smsc911x_ethtool_setmsglevel(struct net_device *dev, u32 level) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + pdata->msg_enable = level; +} + +static int smsc911x_ethtool_getregslen(struct net_device *dev) +{ + return (((E2P_DATA - ID_REV) / 4 + 1) + (WUCSR - MAC_CR) + 1 + 32) * + sizeof(u32); +} + +static void +smsc911x_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs, + void *buf) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + struct phy_device *phy_dev = pdata->phy_dev; + unsigned long flags; + unsigned int i; + unsigned int j = 0; + u32 *data = buf; + + regs->version = pdata->idrev; + for (i = ID_REV; i <= E2P_DATA; i += (sizeof(u32))) + data[j++] = smsc911x_reg_read(pdata, i); + + for (i = MAC_CR; i <= WUCSR; i++) { + spin_lock_irqsave(&pdata->mac_lock, flags); + data[j++] = smsc911x_mac_read(pdata, i); + spin_unlock_irqrestore(&pdata->mac_lock, flags); + } + + for (i = 0; i <= 31; i++) + data[j++] = smsc911x_mii_read(phy_dev->bus, phy_dev->addr, i); +} + +static void smsc911x_eeprom_enable_access(struct smsc911x_data *pdata) +{ + unsigned int temp = smsc911x_reg_read(pdata, GPIO_CFG); + temp &= ~GPIO_CFG_EEPR_EN_; + smsc911x_reg_write(pdata, GPIO_CFG, temp); + msleep(1); +} + +static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op) +{ + int timeout = 100; + u32 e2cmd; + + SMSC_TRACE(DRV, "op 0x%08x", op); + if (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) { + SMSC_WARNING(DRV, "Busy at start"); + return -EBUSY; + } + + e2cmd = op | E2P_CMD_EPC_BUSY_; + smsc911x_reg_write(pdata, E2P_CMD, e2cmd); + + do { + msleep(1); + e2cmd = smsc911x_reg_read(pdata, E2P_CMD); + } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (timeout--)); + + if (!timeout) { + SMSC_TRACE(DRV, "TIMED OUT"); + return -EAGAIN; + } + + if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { + SMSC_TRACE(DRV, "Error occured during eeprom operation"); + return -EINVAL; + } + + return 0; +} + +static int smsc911x_eeprom_read_location(struct smsc911x_data *pdata, + u8 address, u8 *data) +{ + u32 op = E2P_CMD_EPC_CMD_READ_ | address; + int ret; + + SMSC_TRACE(DRV, "address 0x%x", address); + ret = smsc911x_eeprom_send_cmd(pdata, op); + + if (!ret) + data[address] = smsc911x_reg_read(pdata, E2P_DATA); + + return ret; +} + +static int smsc911x_eeprom_write_location(struct smsc911x_data *pdata, + u8 address, u8 data) +{ + u32 op = E2P_CMD_EPC_CMD_ERASE_ | address; + int ret; + + SMSC_TRACE(DRV, "address 0x%x, data 0x%x", address, data); + ret = smsc911x_eeprom_send_cmd(pdata, op); + + if (!ret) { + op = E2P_CMD_EPC_CMD_WRITE_ | address; + smsc911x_reg_write(pdata, E2P_DATA, (u32)data); + ret = smsc911x_eeprom_send_cmd(pdata, op); + } + + return ret; +} + +static int smsc911x_ethtool_get_eeprom_len(struct net_device *dev) +{ + return SMSC911X_EEPROM_SIZE; +} + +static int smsc911x_ethtool_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + u8 eeprom_data[SMSC911X_EEPROM_SIZE]; + int len; + int i; + + smsc911x_eeprom_enable_access(pdata); + + len = min(eeprom->len, SMSC911X_EEPROM_SIZE); + for (i = 0; i < len; i++) { + int ret = smsc911x_eeprom_read_location(pdata, i, eeprom_data); + if (ret < 0) { + eeprom->len = 0; + return ret; + } + } + + memcpy(data, &eeprom_data[eeprom->offset], len); + eeprom->len = len; + return 0; +} + +static int smsc911x_ethtool_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + int ret; + struct smsc911x_data *pdata = netdev_priv(dev); + + smsc911x_eeprom_enable_access(pdata); + smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWEN_); + ret = smsc911x_eeprom_write_location(pdata, eeprom->offset, *data); + smsc911x_eeprom_send_cmd(pdata, E2P_CMD_EPC_CMD_EWDS_); + + /* Single byte write, according to man page */ + eeprom->len = 1; + + return ret; +} + +static const struct ethtool_ops smsc911x_ethtool_ops = { + .get_settings = smsc911x_ethtool_getsettings, + .set_settings = smsc911x_ethtool_setsettings, + .get_link = ethtool_op_get_link, + .get_drvinfo = smsc911x_ethtool_getdrvinfo, + .nway_reset = smsc911x_ethtool_nwayreset, + .get_msglevel = smsc911x_ethtool_getmsglevel, + .set_msglevel = smsc911x_ethtool_setmsglevel, + .get_regs_len = smsc911x_ethtool_getregslen, + .get_regs = smsc911x_ethtool_getregs, + .get_eeprom_len = smsc911x_ethtool_get_eeprom_len, + .get_eeprom = smsc911x_ethtool_get_eeprom, + .set_eeprom = smsc911x_ethtool_set_eeprom, +}; + +static const struct net_device_ops smsc911x_netdev_ops = { + .ndo_open = smsc911x_open, + .ndo_stop = smsc911x_stop, + .ndo_start_xmit = smsc911x_hard_start_xmit, + .ndo_get_stats = smsc911x_get_stats, + .ndo_set_multicast_list = smsc911x_set_multicast_list, + .ndo_do_ioctl = smsc911x_do_ioctl, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = smsc911x_poll_controller, +#endif +}; + +/* Initializing private device structures, only called from probe */ +static int __devinit smsc911x_init(struct net_device *dev) +{ + struct smsc911x_data *pdata = netdev_priv(dev); + unsigned int byte_test; + + SMSC_TRACE(PROBE, "Driver Parameters:"); + SMSC_TRACE(PROBE, "LAN base: 0x%08lX", + (unsigned long)pdata->ioaddr); + SMSC_TRACE(PROBE, "IRQ: %d", dev->irq); + SMSC_TRACE(PROBE, "PHY will be autodetected."); + + spin_lock_init(&pdata->dev_lock); + + if (pdata->ioaddr == 0) { + SMSC_WARNING(PROBE, "pdata->ioaddr: 0x00000000"); + return -ENODEV; + } + + /* Check byte ordering */ + byte_test = smsc911x_reg_read(pdata, BYTE_TEST); + SMSC_TRACE(PROBE, "BYTE_TEST: 0x%08X", byte_test); + if (byte_test == 0x43218765) { + SMSC_TRACE(PROBE, "BYTE_TEST looks swapped, " + "applying WORD_SWAP"); + smsc911x_reg_write(pdata, WORD_SWAP, 0xffffffff); + + /* 1 dummy read of BYTE_TEST is needed after a write to + * WORD_SWAP before its contents are valid */ + byte_test = smsc911x_reg_read(pdata, BYTE_TEST); + + byte_test = smsc911x_reg_read(pdata, BYTE_TEST); + } + + if (byte_test != 0x87654321) { + SMSC_WARNING(DRV, "BYTE_TEST: 0x%08X", byte_test); + if (((byte_test >> 16) & 0xFFFF) == (byte_test & 0xFFFF)) { + SMSC_WARNING(PROBE, + "top 16 bits equal to bottom 16 bits"); + SMSC_TRACE(PROBE, "This may mean the chip is set " + "for 32 bit while the bus is reading 16 bit"); + } + return -ENODEV; + } + + /* Default generation to zero (all workarounds apply) */ + pdata->generation = 0; + + pdata->idrev = smsc911x_reg_read(pdata, ID_REV); + switch (pdata->idrev & 0xFFFF0000) { + case 0x01180000: + case 0x01170000: + case 0x01160000: + case 0x01150000: + /* LAN911[5678] family */ + pdata->generation = pdata->idrev & 0x0000FFFF; + break; + + case 0x118A0000: + case 0x117A0000: + case 0x116A0000: + case 0x115A0000: + /* LAN921[5678] family */ + pdata->generation = 3; + break; + + case 0x92100000: + case 0x92110000: + case 0x92200000: + case 0x92210000: + /* LAN9210/LAN9211/LAN9220/LAN9221 */ + pdata->generation = 4; + break; + + default: + SMSC_WARNING(PROBE, "LAN911x not identified, idrev: 0x%08X", + pdata->idrev); + return -ENODEV; + } + + SMSC_TRACE(PROBE, "LAN911x identified, idrev: 0x%08X, generation: %d", + pdata->idrev, pdata->generation); + + if (pdata->generation == 0) + SMSC_WARNING(PROBE, + "This driver is not intended for this chip revision"); + + /* Reset the LAN911x */ + if (smsc911x_soft_reset(pdata)) + return -ENODEV; + + /* Disable all interrupt sources until we bring the device up */ + smsc911x_reg_write(pdata, INT_EN, 0); + + ether_setup(dev); + dev->flags |= IFF_MULTICAST; + netif_napi_add(dev, &pdata->napi, smsc911x_poll, SMSC_NAPI_WEIGHT); + dev->netdev_ops = &smsc911x_netdev_ops; + dev->ethtool_ops = &smsc911x_ethtool_ops; + + return 0; +} + +static int __devexit smsc911x_drv_remove(struct platform_device *pdev) +{ + struct net_device *dev; + struct smsc911x_data *pdata; + struct resource *res; + + dev = platform_get_drvdata(pdev); + BUG_ON(!dev); + pdata = netdev_priv(dev); + BUG_ON(!pdata); + BUG_ON(!pdata->ioaddr); + BUG_ON(!pdata->phy_dev); + + SMSC_TRACE(IFDOWN, "Stopping driver."); + + phy_disconnect(pdata->phy_dev); + pdata->phy_dev = NULL; + mdiobus_unregister(pdata->mii_bus); + mdiobus_free(pdata->mii_bus); + + platform_set_drvdata(pdev, NULL); + unregister_netdev(dev); + free_irq(dev->irq, dev); + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "smsc911x-memory"); + if (!res) + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + + release_mem_region(res->start, res->end - res->start); + + iounmap(pdata->ioaddr); + + free_netdev(dev); + + return 0; +} + +static int __devinit smsc911x_drv_probe(struct platform_device *pdev) +{ + struct net_device *dev; + struct smsc911x_data *pdata; + struct smsc911x_platform_config *config = pdev->dev.platform_data; + struct resource *res; + unsigned int intcfg = 0; + int res_size; + int retval; + DECLARE_MAC_BUF(mac); + + pr_info("%s: Driver version %s.\n", SMSC_CHIPNAME, SMSC_DRV_VERSION); + + /* platform data specifies irq & dynamic bus configuration */ + if (!pdev->dev.platform_data) { + pr_warning("%s: platform_data not provided\n", SMSC_CHIPNAME); + retval = -ENODEV; + goto out_0; + } + + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, + "smsc911x-memory"); + if (!res) + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (!res) { + pr_warning("%s: Could not allocate resource.\n", + SMSC_CHIPNAME); + retval = -ENODEV; + goto out_0; + } + res_size = res->end - res->start; + + if (!request_mem_region(res->start, res_size, SMSC_CHIPNAME)) { + retval = -EBUSY; + goto out_0; + } + + dev = alloc_etherdev(sizeof(struct smsc911x_data)); + if (!dev) { + pr_warning("%s: Could not allocate device.\n", SMSC_CHIPNAME); + retval = -ENOMEM; + goto out_release_io_1; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + + pdata = netdev_priv(dev); + + dev->irq = platform_get_irq(pdev, 0); + pdata->ioaddr = ioremap_nocache(res->start, res_size); + + /* copy config parameters across to pdata */ + memcpy(&pdata->config, config, sizeof(pdata->config)); + + pdata->dev = dev; + pdata->msg_enable = ((1 << debug) - 1); + + if (pdata->ioaddr == NULL) { + SMSC_WARNING(PROBE, + "Error smsc911x base address invalid"); + retval = -ENOMEM; + goto out_free_netdev_2; + } + + retval = smsc911x_init(dev); + if (retval < 0) + goto out_unmap_io_3; + + /* configure irq polarity and type before connecting isr */ + if (pdata->config.irq_polarity == SMSC911X_IRQ_POLARITY_ACTIVE_HIGH) + intcfg |= INT_CFG_IRQ_POL_; + + if (pdata->config.irq_type == SMSC911X_IRQ_TYPE_PUSH_PULL) + intcfg |= INT_CFG_IRQ_TYPE_; + + smsc911x_reg_write(pdata, INT_CFG, intcfg); + + /* Ensure interrupts are globally disabled before connecting ISR */ + smsc911x_reg_write(pdata, INT_EN, 0); + smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF); + + retval = request_irq(dev->irq, smsc911x_irqhandler, IRQF_DISABLED, + SMSC_CHIPNAME, dev); + if (retval) { + SMSC_WARNING(PROBE, + "Unable to claim requested irq: %d", dev->irq); + goto out_unmap_io_3; + } + + platform_set_drvdata(pdev, dev); + + retval = register_netdev(dev); + if (retval) { + SMSC_WARNING(PROBE, + "Error %i registering device", retval); + goto out_unset_drvdata_4; + } else { + SMSC_TRACE(PROBE, "Network interface: \"%s\"", dev->name); + } + + spin_lock_init(&pdata->mac_lock); + + retval = smsc911x_mii_init(pdev, dev); + if (retval) { + SMSC_WARNING(PROBE, + "Error %i initialising mii", retval); + goto out_unregister_netdev_5; + } + + spin_lock_irq(&pdata->mac_lock); + + /* Check if mac address has been specified when bringing interface up */ + if (is_valid_ether_addr(dev->dev_addr)) { + smsc911x_set_mac_address(pdata, dev->dev_addr); + SMSC_TRACE(PROBE, "MAC Address is specified by configuration"); + } else { + /* Try reading mac address from device. if EEPROM is present + * it will already have been set */ + u32 mac_high16 = smsc911x_mac_read(pdata, ADDRH); + u32 mac_low32 = smsc911x_mac_read(pdata, ADDRL); + dev->dev_addr[0] = (u8)(mac_low32); + dev->dev_addr[1] = (u8)(mac_low32 >> 8); + dev->dev_addr[2] = (u8)(mac_low32 >> 16); + dev->dev_addr[3] = (u8)(mac_low32 >> 24); + dev->dev_addr[4] = (u8)(mac_high16); + dev->dev_addr[5] = (u8)(mac_high16 >> 8); + + if (is_valid_ether_addr(dev->dev_addr)) { + /* eeprom values are valid so use them */ + SMSC_TRACE(PROBE, + "Mac Address is read from LAN911x EEPROM"); + } else { + /* eeprom values are invalid, generate random MAC */ + random_ether_addr(dev->dev_addr); + smsc911x_set_mac_address(pdata, dev->dev_addr); + SMSC_TRACE(PROBE, + "MAC Address is set to random_ether_addr"); + } + } + + spin_unlock_irq(&pdata->mac_lock); + + dev_info(&dev->dev, "MAC Address: %s\n", + print_mac(mac, dev->dev_addr)); + + return 0; + +out_unregister_netdev_5: + unregister_netdev(dev); +out_unset_drvdata_4: + platform_set_drvdata(pdev, NULL); + free_irq(dev->irq, dev); +out_unmap_io_3: + iounmap(pdata->ioaddr); +out_free_netdev_2: + free_netdev(dev); +out_release_io_1: + release_mem_region(res->start, res->end - res->start); +out_0: + return retval; +} + +static struct platform_driver smsc911x_driver = { + .probe = smsc911x_drv_probe, + .remove = smsc911x_drv_remove, + .driver = { + .name = SMSC_CHIPNAME, + }, +}; + +/* Entry point for loading the module */ +static int __init smsc911x_init_module(void) +{ + return platform_driver_register(&smsc911x_driver); +} + +/* entry point for unloading the module */ +static void __exit smsc911x_cleanup_module(void) +{ + platform_driver_unregister(&smsc911x_driver); +} + +module_init(smsc911x_init_module); +module_exit(smsc911x_cleanup_module); diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h new file mode 100644 index 0000000000000000000000000000000000000000..2b76654bb958c665fb39fbe7a2b5bae225e61320 --- /dev/null +++ b/drivers/net/smsc911x.h @@ -0,0 +1,390 @@ +/*************************************************************************** + * + * Copyright (C) 2004-2008 SMSC + * Copyright (C) 2005-2008 ARM + * + * 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. + * + ***************************************************************************/ +#ifndef __SMSC911X_H__ +#define __SMSC911X_H__ + +#define TX_FIFO_LOW_THRESHOLD ((u32)1600) +#define SMSC911X_EEPROM_SIZE ((u32)7) +#define USE_DEBUG 0 + +/* This is the maximum number of packets to be received every + * NAPI poll */ +#define SMSC_NAPI_WEIGHT 16 + +/* implements a PHY loopback test at initialisation time, to ensure a packet + * can be succesfully looped back */ +#define USE_PHY_WORK_AROUND + +#define DPRINTK(nlevel, klevel, fmt, args...) \ + ((void)((NETIF_MSG_##nlevel & pdata->msg_enable) && \ + printk(KERN_##klevel "%s: %s: " fmt "\n", \ + pdata->dev->name, __func__, ## args))) + +#if USE_DEBUG >= 1 +#define SMSC_WARNING(nlevel, fmt, args...) \ + DPRINTK(nlevel, WARNING, fmt, ## args) +#else +#define SMSC_WARNING(nlevel, fmt, args...) \ + ({ do {} while (0); 0; }) +#endif + +#if USE_DEBUG >= 2 +#define SMSC_TRACE(nlevel, fmt, args...) \ + DPRINTK(nlevel, INFO, fmt, ## args) +#else +#define SMSC_TRACE(nlevel, fmt, args...) \ + ({ do {} while (0); 0; }) +#endif + +#ifdef CONFIG_DEBUG_SPINLOCK +#define SMSC_ASSERT_MAC_LOCK(pdata) \ + WARN_ON(!spin_is_locked(&pdata->mac_lock)) +#else +#define SMSC_ASSERT_MAC_LOCK(pdata) do {} while (0) +#endif /* CONFIG_DEBUG_SPINLOCK */ + +/* SMSC911x registers and bitfields */ +#define RX_DATA_FIFO 0x00 + +#define TX_DATA_FIFO 0x20 +#define TX_CMD_A_ON_COMP_ 0x80000000 +#define TX_CMD_A_BUF_END_ALGN_ 0x03000000 +#define TX_CMD_A_4_BYTE_ALGN_ 0x00000000 +#define TX_CMD_A_16_BYTE_ALGN_ 0x01000000 +#define TX_CMD_A_32_BYTE_ALGN_ 0x02000000 +#define TX_CMD_A_DATA_OFFSET_ 0x001F0000 +#define TX_CMD_A_FIRST_SEG_ 0x00002000 +#define TX_CMD_A_LAST_SEG_ 0x00001000 +#define TX_CMD_A_BUF_SIZE_ 0x000007FF +#define TX_CMD_B_PKT_TAG_ 0xFFFF0000 +#define TX_CMD_B_ADD_CRC_DISABLE_ 0x00002000 +#define TX_CMD_B_DISABLE_PADDING_ 0x00001000 +#define TX_CMD_B_PKT_BYTE_LENGTH_ 0x000007FF + +#define RX_STATUS_FIFO 0x40 +#define RX_STS_ES_ 0x00008000 +#define RX_STS_MCAST_ 0x00000400 + +#define RX_STATUS_FIFO_PEEK 0x44 + +#define TX_STATUS_FIFO 0x48 +#define TX_STS_ES_ 0x00008000 + +#define TX_STATUS_FIFO_PEEK 0x4C + +#define ID_REV 0x50 +#define ID_REV_CHIP_ID_ 0xFFFF0000 +#define ID_REV_REV_ID_ 0x0000FFFF + +#define INT_CFG 0x54 +#define INT_CFG_INT_DEAS_ 0xFF000000 +#define INT_CFG_INT_DEAS_CLR_ 0x00004000 +#define INT_CFG_INT_DEAS_STS_ 0x00002000 +#define INT_CFG_IRQ_INT_ 0x00001000 +#define INT_CFG_IRQ_EN_ 0x00000100 +#define INT_CFG_IRQ_POL_ 0x00000010 +#define INT_CFG_IRQ_TYPE_ 0x00000001 + +#define INT_STS 0x58 +#define INT_STS_SW_INT_ 0x80000000 +#define INT_STS_TXSTOP_INT_ 0x02000000 +#define INT_STS_RXSTOP_INT_ 0x01000000 +#define INT_STS_RXDFH_INT_ 0x00800000 +#define INT_STS_RXDF_INT_ 0x00400000 +#define INT_STS_TX_IOC_ 0x00200000 +#define INT_STS_RXD_INT_ 0x00100000 +#define INT_STS_GPT_INT_ 0x00080000 +#define INT_STS_PHY_INT_ 0x00040000 +#define INT_STS_PME_INT_ 0x00020000 +#define INT_STS_TXSO_ 0x00010000 +#define INT_STS_RWT_ 0x00008000 +#define INT_STS_RXE_ 0x00004000 +#define INT_STS_TXE_ 0x00002000 +#define INT_STS_TDFU_ 0x00000800 +#define INT_STS_TDFO_ 0x00000400 +#define INT_STS_TDFA_ 0x00000200 +#define INT_STS_TSFF_ 0x00000100 +#define INT_STS_TSFL_ 0x00000080 +#define INT_STS_RXDF_ 0x00000040 +#define INT_STS_RDFL_ 0x00000020 +#define INT_STS_RSFF_ 0x00000010 +#define INT_STS_RSFL_ 0x00000008 +#define INT_STS_GPIO2_INT_ 0x00000004 +#define INT_STS_GPIO1_INT_ 0x00000002 +#define INT_STS_GPIO0_INT_ 0x00000001 + +#define INT_EN 0x5C +#define INT_EN_SW_INT_EN_ 0x80000000 +#define INT_EN_TXSTOP_INT_EN_ 0x02000000 +#define INT_EN_RXSTOP_INT_EN_ 0x01000000 +#define INT_EN_RXDFH_INT_EN_ 0x00800000 +#define INT_EN_TIOC_INT_EN_ 0x00200000 +#define INT_EN_RXD_INT_EN_ 0x00100000 +#define INT_EN_GPT_INT_EN_ 0x00080000 +#define INT_EN_PHY_INT_EN_ 0x00040000 +#define INT_EN_PME_INT_EN_ 0x00020000 +#define INT_EN_TXSO_EN_ 0x00010000 +#define INT_EN_RWT_EN_ 0x00008000 +#define INT_EN_RXE_EN_ 0x00004000 +#define INT_EN_TXE_EN_ 0x00002000 +#define INT_EN_TDFU_EN_ 0x00000800 +#define INT_EN_TDFO_EN_ 0x00000400 +#define INT_EN_TDFA_EN_ 0x00000200 +#define INT_EN_TSFF_EN_ 0x00000100 +#define INT_EN_TSFL_EN_ 0x00000080 +#define INT_EN_RXDF_EN_ 0x00000040 +#define INT_EN_RDFL_EN_ 0x00000020 +#define INT_EN_RSFF_EN_ 0x00000010 +#define INT_EN_RSFL_EN_ 0x00000008 +#define INT_EN_GPIO2_INT_ 0x00000004 +#define INT_EN_GPIO1_INT_ 0x00000002 +#define INT_EN_GPIO0_INT_ 0x00000001 + +#define BYTE_TEST 0x64 + +#define FIFO_INT 0x68 +#define FIFO_INT_TX_AVAIL_LEVEL_ 0xFF000000 +#define FIFO_INT_TX_STS_LEVEL_ 0x00FF0000 +#define FIFO_INT_RX_AVAIL_LEVEL_ 0x0000FF00 +#define FIFO_INT_RX_STS_LEVEL_ 0x000000FF + +#define RX_CFG 0x6C +#define RX_CFG_RX_END_ALGN_ 0xC0000000 +#define RX_CFG_RX_END_ALGN4_ 0x00000000 +#define RX_CFG_RX_END_ALGN16_ 0x40000000 +#define RX_CFG_RX_END_ALGN32_ 0x80000000 +#define RX_CFG_RX_DMA_CNT_ 0x0FFF0000 +#define RX_CFG_RX_DUMP_ 0x00008000 +#define RX_CFG_RXDOFF_ 0x00001F00 + +#define TX_CFG 0x70 +#define TX_CFG_TXS_DUMP_ 0x00008000 +#define TX_CFG_TXD_DUMP_ 0x00004000 +#define TX_CFG_TXSAO_ 0x00000004 +#define TX_CFG_TX_ON_ 0x00000002 +#define TX_CFG_STOP_TX_ 0x00000001 + +#define HW_CFG 0x74 +#define HW_CFG_TTM_ 0x00200000 +#define HW_CFG_SF_ 0x00100000 +#define HW_CFG_TX_FIF_SZ_ 0x000F0000 +#define HW_CFG_TR_ 0x00003000 +#define HW_CFG_SRST_ 0x00000001 + +/* only available on 115/117 */ +#define HW_CFG_PHY_CLK_SEL_ 0x00000060 +#define HW_CFG_PHY_CLK_SEL_INT_PHY_ 0x00000000 +#define HW_CFG_PHY_CLK_SEL_EXT_PHY_ 0x00000020 +#define HW_CFG_PHY_CLK_SEL_CLK_DIS_ 0x00000040 +#define HW_CFG_SMI_SEL_ 0x00000010 +#define HW_CFG_EXT_PHY_DET_ 0x00000008 +#define HW_CFG_EXT_PHY_EN_ 0x00000004 +#define HW_CFG_SRST_TO_ 0x00000002 + +/* only available on 116/118 */ +#define HW_CFG_32_16_BIT_MODE_ 0x00000004 + +#define RX_DP_CTRL 0x78 +#define RX_DP_CTRL_RX_FFWD_ 0x80000000 + +#define RX_FIFO_INF 0x7C +#define RX_FIFO_INF_RXSUSED_ 0x00FF0000 +#define RX_FIFO_INF_RXDUSED_ 0x0000FFFF + +#define TX_FIFO_INF 0x80 +#define TX_FIFO_INF_TSUSED_ 0x00FF0000 +#define TX_FIFO_INF_TDFREE_ 0x0000FFFF + +#define PMT_CTRL 0x84 +#define PMT_CTRL_PM_MODE_ 0x00003000 +#define PMT_CTRL_PM_MODE_D0_ 0x00000000 +#define PMT_CTRL_PM_MODE_D1_ 0x00001000 +#define PMT_CTRL_PM_MODE_D2_ 0x00002000 +#define PMT_CTRL_PM_MODE_D3_ 0x00003000 +#define PMT_CTRL_PHY_RST_ 0x00000400 +#define PMT_CTRL_WOL_EN_ 0x00000200 +#define PMT_CTRL_ED_EN_ 0x00000100 +#define PMT_CTRL_PME_TYPE_ 0x00000040 +#define PMT_CTRL_WUPS_ 0x00000030 +#define PMT_CTRL_WUPS_NOWAKE_ 0x00000000 +#define PMT_CTRL_WUPS_ED_ 0x00000010 +#define PMT_CTRL_WUPS_WOL_ 0x00000020 +#define PMT_CTRL_WUPS_MULTI_ 0x00000030 +#define PMT_CTRL_PME_IND_ 0x00000008 +#define PMT_CTRL_PME_POL_ 0x00000004 +#define PMT_CTRL_PME_EN_ 0x00000002 +#define PMT_CTRL_READY_ 0x00000001 + +#define GPIO_CFG 0x88 +#define GPIO_CFG_LED3_EN_ 0x40000000 +#define GPIO_CFG_LED2_EN_ 0x20000000 +#define GPIO_CFG_LED1_EN_ 0x10000000 +#define GPIO_CFG_GPIO2_INT_POL_ 0x04000000 +#define GPIO_CFG_GPIO1_INT_POL_ 0x02000000 +#define GPIO_CFG_GPIO0_INT_POL_ 0x01000000 +#define GPIO_CFG_EEPR_EN_ 0x00700000 +#define GPIO_CFG_GPIOBUF2_ 0x00040000 +#define GPIO_CFG_GPIOBUF1_ 0x00020000 +#define GPIO_CFG_GPIOBUF0_ 0x00010000 +#define GPIO_CFG_GPIODIR2_ 0x00000400 +#define GPIO_CFG_GPIODIR1_ 0x00000200 +#define GPIO_CFG_GPIODIR0_ 0x00000100 +#define GPIO_CFG_GPIOD4_ 0x00000020 +#define GPIO_CFG_GPIOD3_ 0x00000010 +#define GPIO_CFG_GPIOD2_ 0x00000004 +#define GPIO_CFG_GPIOD1_ 0x00000002 +#define GPIO_CFG_GPIOD0_ 0x00000001 + +#define GPT_CFG 0x8C +#define GPT_CFG_TIMER_EN_ 0x20000000 +#define GPT_CFG_GPT_LOAD_ 0x0000FFFF + +#define GPT_CNT 0x90 +#define GPT_CNT_GPT_CNT_ 0x0000FFFF + +#define WORD_SWAP 0x98 + +#define FREE_RUN 0x9C + +#define RX_DROP 0xA0 + +#define MAC_CSR_CMD 0xA4 +#define MAC_CSR_CMD_CSR_BUSY_ 0x80000000 +#define MAC_CSR_CMD_R_NOT_W_ 0x40000000 +#define MAC_CSR_CMD_CSR_ADDR_ 0x000000FF + +#define MAC_CSR_DATA 0xA8 + +#define AFC_CFG 0xAC +#define AFC_CFG_AFC_HI_ 0x00FF0000 +#define AFC_CFG_AFC_LO_ 0x0000FF00 +#define AFC_CFG_BACK_DUR_ 0x000000F0 +#define AFC_CFG_FCMULT_ 0x00000008 +#define AFC_CFG_FCBRD_ 0x00000004 +#define AFC_CFG_FCADD_ 0x00000002 +#define AFC_CFG_FCANY_ 0x00000001 + +#define E2P_CMD 0xB0 +#define E2P_CMD_EPC_BUSY_ 0x80000000 +#define E2P_CMD_EPC_CMD_ 0x70000000 +#define E2P_CMD_EPC_CMD_READ_ 0x00000000 +#define E2P_CMD_EPC_CMD_EWDS_ 0x10000000 +#define E2P_CMD_EPC_CMD_EWEN_ 0x20000000 +#define E2P_CMD_EPC_CMD_WRITE_ 0x30000000 +#define E2P_CMD_EPC_CMD_WRAL_ 0x40000000 +#define E2P_CMD_EPC_CMD_ERASE_ 0x50000000 +#define E2P_CMD_EPC_CMD_ERAL_ 0x60000000 +#define E2P_CMD_EPC_CMD_RELOAD_ 0x70000000 +#define E2P_CMD_EPC_TIMEOUT_ 0x00000200 +#define E2P_CMD_MAC_ADDR_LOADED_ 0x00000100 +#define E2P_CMD_EPC_ADDR_ 0x000000FF + +#define E2P_DATA 0xB4 +#define E2P_DATA_EEPROM_DATA_ 0x000000FF +#define LAN_REGISTER_EXTENT 0x00000100 + +/* + * MAC Control and Status Register (Indirect Address) + * Offset (through the MAC_CSR CMD and DATA port) + */ +#define MAC_CR 0x01 +#define MAC_CR_RXALL_ 0x80000000 +#define MAC_CR_HBDIS_ 0x10000000 +#define MAC_CR_RCVOWN_ 0x00800000 +#define MAC_CR_LOOPBK_ 0x00200000 +#define MAC_CR_FDPX_ 0x00100000 +#define MAC_CR_MCPAS_ 0x00080000 +#define MAC_CR_PRMS_ 0x00040000 +#define MAC_CR_INVFILT_ 0x00020000 +#define MAC_CR_PASSBAD_ 0x00010000 +#define MAC_CR_HFILT_ 0x00008000 +#define MAC_CR_HPFILT_ 0x00002000 +#define MAC_CR_LCOLL_ 0x00001000 +#define MAC_CR_BCAST_ 0x00000800 +#define MAC_CR_DISRTY_ 0x00000400 +#define MAC_CR_PADSTR_ 0x00000100 +#define MAC_CR_BOLMT_MASK_ 0x000000C0 +#define MAC_CR_DFCHK_ 0x00000020 +#define MAC_CR_TXEN_ 0x00000008 +#define MAC_CR_RXEN_ 0x00000004 + +#define ADDRH 0x02 + +#define ADDRL 0x03 + +#define HASHH 0x04 + +#define HASHL 0x05 + +#define MII_ACC 0x06 +#define MII_ACC_PHY_ADDR_ 0x0000F800 +#define MII_ACC_MIIRINDA_ 0x000007C0 +#define MII_ACC_MII_WRITE_ 0x00000002 +#define MII_ACC_MII_BUSY_ 0x00000001 + +#define MII_DATA 0x07 + +#define FLOW 0x08 +#define FLOW_FCPT_ 0xFFFF0000 +#define FLOW_FCPASS_ 0x00000004 +#define FLOW_FCEN_ 0x00000002 +#define FLOW_FCBSY_ 0x00000001 + +#define VLAN1 0x09 + +#define VLAN2 0x0A + +#define WUFF 0x0B + +#define WUCSR 0x0C +#define WUCSR_GUE_ 0x00000200 +#define WUCSR_WUFR_ 0x00000040 +#define WUCSR_MPR_ 0x00000020 +#define WUCSR_WAKE_EN_ 0x00000004 +#define WUCSR_MPEN_ 0x00000002 + +/* + * Phy definitions (vendor-specific) + */ +#define LAN9118_PHY_ID 0x00C0001C + +#define MII_INTSTS 0x1D + +#define MII_INTMSK 0x1E +#define PHY_INTMSK_AN_RCV_ (1 << 1) +#define PHY_INTMSK_PDFAULT_ (1 << 2) +#define PHY_INTMSK_AN_ACK_ (1 << 3) +#define PHY_INTMSK_LNKDOWN_ (1 << 4) +#define PHY_INTMSK_RFAULT_ (1 << 5) +#define PHY_INTMSK_AN_COMP_ (1 << 6) +#define PHY_INTMSK_ENERGYON_ (1 << 7) +#define PHY_INTMSK_DEFAULT_ (PHY_INTMSK_ENERGYON_ | \ + PHY_INTMSK_AN_COMP_ | \ + PHY_INTMSK_RFAULT_ | \ + PHY_INTMSK_LNKDOWN_) + +#define ADVERTISE_PAUSE_ALL (ADVERTISE_PAUSE_CAP | \ + ADVERTISE_PAUSE_ASYM) + +#define LPA_PAUSE_ALL (LPA_PAUSE_CAP | \ + LPA_PAUSE_ASYM) + +#endif /* __SMSC911X_H__ */ diff --git a/drivers/net/smsc9420.c b/drivers/net/smsc9420.c new file mode 100644 index 0000000000000000000000000000000000000000..27e017d969667f474b4c647c23c1fffe42a19bbf --- /dev/null +++ b/drivers/net/smsc9420.c @@ -0,0 +1,1744 @@ + /*************************************************************************** + * + * Copyright (C) 2007,2008 SMSC + * + * 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. + * + *************************************************************************** + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "smsc9420.h" + +#define DRV_NAME "smsc9420" +#define PFX DRV_NAME ": " +#define DRV_MDIONAME "smsc9420-mdio" +#define DRV_DESCRIPTION "SMSC LAN9420 driver" +#define DRV_VERSION "1.01" + +MODULE_LICENSE("GPL"); +MODULE_VERSION(DRV_VERSION); + +struct smsc9420_dma_desc { + u32 status; + u32 length; + u32 buffer1; + u32 buffer2; +}; + +struct smsc9420_ring_info { + struct sk_buff *skb; + dma_addr_t mapping; +}; + +struct smsc9420_pdata { + void __iomem *base_addr; + struct pci_dev *pdev; + struct net_device *dev; + + struct smsc9420_dma_desc *rx_ring; + struct smsc9420_dma_desc *tx_ring; + struct smsc9420_ring_info *tx_buffers; + struct smsc9420_ring_info *rx_buffers; + dma_addr_t rx_dma_addr; + dma_addr_t tx_dma_addr; + int tx_ring_head, tx_ring_tail; + int rx_ring_head, rx_ring_tail; + + spinlock_t int_lock; + spinlock_t phy_lock; + + struct napi_struct napi; + + bool software_irq_signal; + bool rx_csum; + u32 msg_enable; + + struct phy_device *phy_dev; + struct mii_bus *mii_bus; + int phy_irq[PHY_MAX_ADDR]; + int last_duplex; + int last_carrier; +}; + +static const struct pci_device_id smsc9420_id_table[] = { + { PCI_VENDOR_ID_9420, PCI_DEVICE_ID_9420, PCI_ANY_ID, PCI_ANY_ID, }, + { 0, } +}; + +MODULE_DEVICE_TABLE(pci, smsc9420_id_table); + +#define SMSC_MSG_DEFAULT (NETIF_MSG_DRV | NETIF_MSG_PROBE | NETIF_MSG_LINK) + +static uint smsc_debug; +static uint debug = -1; +module_param(debug, uint, 0); +MODULE_PARM_DESC(debug, "debug level"); + +#define smsc_dbg(TYPE, f, a...) \ +do { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_DEBUG PFX f "\n", ## a); \ +} while (0) + +#define smsc_info(TYPE, f, a...) \ +do { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_INFO PFX f "\n", ## a); \ +} while (0) + +#define smsc_warn(TYPE, f, a...) \ +do { if ((pd)->msg_enable & NETIF_MSG_##TYPE) \ + printk(KERN_WARNING PFX f "\n", ## a); \ +} while (0) + +static inline u32 smsc9420_reg_read(struct smsc9420_pdata *pd, u32 offset) +{ + return ioread32(pd->base_addr + offset); +} + +static inline void +smsc9420_reg_write(struct smsc9420_pdata *pd, u32 offset, u32 value) +{ + iowrite32(value, pd->base_addr + offset); +} + +static inline void smsc9420_pci_flush_write(struct smsc9420_pdata *pd) +{ + /* to ensure PCI write completion, we must perform a PCI read */ + smsc9420_reg_read(pd, ID_REV); +} + +static int smsc9420_mii_read(struct mii_bus *bus, int phyaddr, int regidx) +{ + struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv; + unsigned long flags; + u32 addr; + int i, reg = -EIO; + + spin_lock_irqsave(&pd->phy_lock, flags); + + /* confirm MII not busy */ + if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) { + smsc_warn(DRV, "MII is busy???"); + goto out; + } + + /* set the address, index & direction (read from PHY) */ + addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | + MII_ACCESS_MII_READ_; + smsc9420_reg_write(pd, MII_ACCESS, addr); + + /* wait for read to complete with 50us timeout */ + for (i = 0; i < 5; i++) { + if (!(smsc9420_reg_read(pd, MII_ACCESS) & + MII_ACCESS_MII_BUSY_)) { + reg = (u16)smsc9420_reg_read(pd, MII_DATA); + goto out; + } + udelay(10); + } + + smsc_warn(DRV, "MII busy timeout!"); + +out: + spin_unlock_irqrestore(&pd->phy_lock, flags); + return reg; +} + +static int smsc9420_mii_write(struct mii_bus *bus, int phyaddr, int regidx, + u16 val) +{ + struct smsc9420_pdata *pd = (struct smsc9420_pdata *)bus->priv; + unsigned long flags; + u32 addr; + int i, reg = -EIO; + + spin_lock_irqsave(&pd->phy_lock, flags); + + /* confirm MII not busy */ + if ((smsc9420_reg_read(pd, MII_ACCESS) & MII_ACCESS_MII_BUSY_)) { + smsc_warn(DRV, "MII is busy???"); + goto out; + } + + /* put the data to write in the MAC */ + smsc9420_reg_write(pd, MII_DATA, (u32)val); + + /* set the address, index & direction (write to PHY) */ + addr = ((phyaddr & 0x1F) << 11) | ((regidx & 0x1F) << 6) | + MII_ACCESS_MII_WRITE_; + smsc9420_reg_write(pd, MII_ACCESS, addr); + + /* wait for write to complete with 50us timeout */ + for (i = 0; i < 5; i++) { + if (!(smsc9420_reg_read(pd, MII_ACCESS) & + MII_ACCESS_MII_BUSY_)) { + reg = 0; + goto out; + } + udelay(10); + } + + smsc_warn(DRV, "MII busy timeout!"); + +out: + spin_unlock_irqrestore(&pd->phy_lock, flags); + return reg; +} + +/* Returns hash bit number for given MAC address + * Example: + * 01 00 5E 00 00 01 -> returns bit number 31 */ +static u32 smsc9420_hash(u8 addr[ETH_ALEN]) +{ + return (ether_crc(ETH_ALEN, addr) >> 26) & 0x3f; +} + +static int smsc9420_eeprom_reload(struct smsc9420_pdata *pd) +{ + int timeout = 100000; + + BUG_ON(!pd); + + if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) { + smsc_dbg(DRV, "smsc9420_eeprom_reload: Eeprom busy"); + return -EIO; + } + + smsc9420_reg_write(pd, E2P_CMD, + (E2P_CMD_EPC_BUSY_ | E2P_CMD_EPC_CMD_RELOAD_)); + + do { + udelay(10); + if (!(smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_)) + return 0; + } while (timeout--); + + smsc_warn(DRV, "smsc9420_eeprom_reload: Eeprom timed out"); + return -EIO; +} + +/* Standard ioctls for mii-tool */ +static int smsc9420_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + + if (!netif_running(dev) || !pd->phy_dev) + return -EINVAL; + + return phy_mii_ioctl(pd->phy_dev, if_mii(ifr), cmd); +} + +static int smsc9420_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + + cmd->maxtxpkt = 1; + cmd->maxrxpkt = 1; + return phy_ethtool_gset(pd->phy_dev, cmd); +} + +static int smsc9420_ethtool_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + + return phy_ethtool_sset(pd->phy_dev, cmd); +} + +static void smsc9420_ethtool_get_drvinfo(struct net_device *netdev, + struct ethtool_drvinfo *drvinfo) +{ + struct smsc9420_pdata *pd = netdev_priv(netdev); + + strcpy(drvinfo->driver, DRV_NAME); + strcpy(drvinfo->bus_info, pci_name(pd->pdev)); + strcpy(drvinfo->version, DRV_VERSION); +} + +static u32 smsc9420_ethtool_get_msglevel(struct net_device *netdev) +{ + struct smsc9420_pdata *pd = netdev_priv(netdev); + return pd->msg_enable; +} + +static void smsc9420_ethtool_set_msglevel(struct net_device *netdev, u32 data) +{ + struct smsc9420_pdata *pd = netdev_priv(netdev); + pd->msg_enable = data; +} + +static int smsc9420_ethtool_nway_reset(struct net_device *netdev) +{ + struct smsc9420_pdata *pd = netdev_priv(netdev); + return phy_start_aneg(pd->phy_dev); +} + +static int smsc9420_ethtool_getregslen(struct net_device *dev) +{ + /* all smsc9420 registers plus all phy registers */ + return 0x100 + (32 * sizeof(u32)); +} + +static void +smsc9420_ethtool_getregs(struct net_device *dev, struct ethtool_regs *regs, + void *buf) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + struct phy_device *phy_dev = pd->phy_dev; + unsigned int i, j = 0; + u32 *data = buf; + + regs->version = smsc9420_reg_read(pd, ID_REV); + for (i = 0; i < 0x100; i += (sizeof(u32))) + data[j++] = smsc9420_reg_read(pd, i); + + for (i = 0; i <= 31; i++) + data[j++] = smsc9420_mii_read(phy_dev->bus, phy_dev->addr, i); +} + +static void smsc9420_eeprom_enable_access(struct smsc9420_pdata *pd) +{ + unsigned int temp = smsc9420_reg_read(pd, GPIO_CFG); + temp &= ~GPIO_CFG_EEPR_EN_; + smsc9420_reg_write(pd, GPIO_CFG, temp); + msleep(1); +} + +static int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op) +{ + int timeout = 100; + u32 e2cmd; + + smsc_dbg(HW, "op 0x%08x", op); + if (smsc9420_reg_read(pd, E2P_CMD) & E2P_CMD_EPC_BUSY_) { + smsc_warn(HW, "Busy at start"); + return -EBUSY; + } + + e2cmd = op | E2P_CMD_EPC_BUSY_; + smsc9420_reg_write(pd, E2P_CMD, e2cmd); + + do { + msleep(1); + e2cmd = smsc9420_reg_read(pd, E2P_CMD); + } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (timeout--)); + + if (!timeout) { + smsc_info(HW, "TIMED OUT"); + return -EAGAIN; + } + + if (e2cmd & E2P_CMD_EPC_TIMEOUT_) { + smsc_info(HW, "Error occured during eeprom operation"); + return -EINVAL; + } + + return 0; +} + +static int smsc9420_eeprom_read_location(struct smsc9420_pdata *pd, + u8 address, u8 *data) +{ + u32 op = E2P_CMD_EPC_CMD_READ_ | address; + int ret; + + smsc_dbg(HW, "address 0x%x", address); + ret = smsc9420_eeprom_send_cmd(pd, op); + + if (!ret) + data[address] = smsc9420_reg_read(pd, E2P_DATA); + + return ret; +} + +static int smsc9420_eeprom_write_location(struct smsc9420_pdata *pd, + u8 address, u8 data) +{ + u32 op = E2P_CMD_EPC_CMD_ERASE_ | address; + int ret; + + smsc_dbg(HW, "address 0x%x, data 0x%x", address, data); + ret = smsc9420_eeprom_send_cmd(pd, op); + + if (!ret) { + op = E2P_CMD_EPC_CMD_WRITE_ | address; + smsc9420_reg_write(pd, E2P_DATA, (u32)data); + ret = smsc9420_eeprom_send_cmd(pd, op); + } + + return ret; +} + +static int smsc9420_ethtool_get_eeprom_len(struct net_device *dev) +{ + return SMSC9420_EEPROM_SIZE; +} + +static int smsc9420_ethtool_get_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + u8 eeprom_data[SMSC9420_EEPROM_SIZE]; + int len, i; + + smsc9420_eeprom_enable_access(pd); + + len = min(eeprom->len, SMSC9420_EEPROM_SIZE); + for (i = 0; i < len; i++) { + int ret = smsc9420_eeprom_read_location(pd, i, eeprom_data); + if (ret < 0) { + eeprom->len = 0; + return ret; + } + } + + memcpy(data, &eeprom_data[eeprom->offset], len); + eeprom->len = len; + return 0; +} + +static int smsc9420_ethtool_set_eeprom(struct net_device *dev, + struct ethtool_eeprom *eeprom, u8 *data) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + int ret; + + smsc9420_eeprom_enable_access(pd); + smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWEN_); + ret = smsc9420_eeprom_write_location(pd, eeprom->offset, *data); + smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWDS_); + + /* Single byte write, according to man page */ + eeprom->len = 1; + + return ret; +} + +static const struct ethtool_ops smsc9420_ethtool_ops = { + .get_settings = smsc9420_ethtool_get_settings, + .set_settings = smsc9420_ethtool_set_settings, + .get_drvinfo = smsc9420_ethtool_get_drvinfo, + .get_msglevel = smsc9420_ethtool_get_msglevel, + .set_msglevel = smsc9420_ethtool_set_msglevel, + .nway_reset = smsc9420_ethtool_nway_reset, + .get_link = ethtool_op_get_link, + .get_eeprom_len = smsc9420_ethtool_get_eeprom_len, + .get_eeprom = smsc9420_ethtool_get_eeprom, + .set_eeprom = smsc9420_ethtool_set_eeprom, + .get_regs_len = smsc9420_ethtool_getregslen, + .get_regs = smsc9420_ethtool_getregs, +}; + +/* Sets the device MAC address to dev_addr */ +static void smsc9420_set_mac_address(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + u8 *dev_addr = dev->dev_addr; + u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4]; + u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) | + (dev_addr[1] << 8) | dev_addr[0]; + + smsc9420_reg_write(pd, ADDRH, mac_high16); + smsc9420_reg_write(pd, ADDRL, mac_low32); +} + +static void smsc9420_check_mac_address(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + + /* Check if mac address has been specified when bringing interface up */ + if (is_valid_ether_addr(dev->dev_addr)) { + smsc9420_set_mac_address(dev); + smsc_dbg(PROBE, "MAC Address is specified by configuration"); + } else { + /* Try reading mac address from device. if EEPROM is present + * it will already have been set */ + u32 mac_high16 = smsc9420_reg_read(pd, ADDRH); + u32 mac_low32 = smsc9420_reg_read(pd, ADDRL); + dev->dev_addr[0] = (u8)(mac_low32); + dev->dev_addr[1] = (u8)(mac_low32 >> 8); + dev->dev_addr[2] = (u8)(mac_low32 >> 16); + dev->dev_addr[3] = (u8)(mac_low32 >> 24); + dev->dev_addr[4] = (u8)(mac_high16); + dev->dev_addr[5] = (u8)(mac_high16 >> 8); + + if (is_valid_ether_addr(dev->dev_addr)) { + /* eeprom values are valid so use them */ + smsc_dbg(PROBE, "Mac Address is read from EEPROM"); + } else { + /* eeprom values are invalid, generate random MAC */ + random_ether_addr(dev->dev_addr); + smsc9420_set_mac_address(dev); + smsc_dbg(PROBE, + "MAC Address is set to random_ether_addr"); + } + } +} + +static void smsc9420_stop_tx(struct smsc9420_pdata *pd) +{ + u32 dmac_control, mac_cr, dma_intr_ena; + int timeOut = 1000; + + /* disable TX DMAC */ + dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); + dmac_control &= (~DMAC_CONTROL_ST_); + smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); + + /* Wait max 10ms for transmit process to stop */ + while (timeOut--) { + if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_TS_) + break; + udelay(10); + } + + if (!timeOut) + smsc_warn(IFDOWN, "TX DMAC failed to stop"); + + /* ACK Tx DMAC stop bit */ + smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_TXPS_); + + /* mask TX DMAC interrupts */ + dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); + dma_intr_ena &= ~(DMAC_INTR_ENA_TX_); + smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); + smsc9420_pci_flush_write(pd); + + /* stop MAC TX */ + mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_TXEN_); + smsc9420_reg_write(pd, MAC_CR, mac_cr); + smsc9420_pci_flush_write(pd); +} + +static void smsc9420_free_tx_ring(struct smsc9420_pdata *pd) +{ + int i; + + BUG_ON(!pd->tx_ring); + + if (!pd->tx_buffers) + return; + + for (i = 0; i < TX_RING_SIZE; i++) { + struct sk_buff *skb = pd->tx_buffers[i].skb; + + if (skb) { + BUG_ON(!pd->tx_buffers[i].mapping); + pci_unmap_single(pd->pdev, pd->tx_buffers[i].mapping, + skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + } + + pd->tx_ring[i].status = 0; + pd->tx_ring[i].length = 0; + pd->tx_ring[i].buffer1 = 0; + pd->tx_ring[i].buffer2 = 0; + } + wmb(); + + kfree(pd->tx_buffers); + pd->tx_buffers = NULL; + + pd->tx_ring_head = 0; + pd->tx_ring_tail = 0; +} + +static void smsc9420_free_rx_ring(struct smsc9420_pdata *pd) +{ + int i; + + BUG_ON(!pd->rx_ring); + + if (!pd->rx_buffers) + return; + + for (i = 0; i < RX_RING_SIZE; i++) { + if (pd->rx_buffers[i].skb) + dev_kfree_skb_any(pd->rx_buffers[i].skb); + + if (pd->rx_buffers[i].mapping) + pci_unmap_single(pd->pdev, pd->rx_buffers[i].mapping, + PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + + pd->rx_ring[i].status = 0; + pd->rx_ring[i].length = 0; + pd->rx_ring[i].buffer1 = 0; + pd->rx_ring[i].buffer2 = 0; + } + wmb(); + + kfree(pd->rx_buffers); + pd->rx_buffers = NULL; + + pd->rx_ring_head = 0; + pd->rx_ring_tail = 0; +} + +static void smsc9420_stop_rx(struct smsc9420_pdata *pd) +{ + int timeOut = 1000; + u32 mac_cr, dmac_control, dma_intr_ena; + + /* mask RX DMAC interrupts */ + dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); + dma_intr_ena &= (~DMAC_INTR_ENA_RX_); + smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); + smsc9420_pci_flush_write(pd); + + /* stop RX MAC prior to stoping DMA */ + mac_cr = smsc9420_reg_read(pd, MAC_CR) & (~MAC_CR_RXEN_); + smsc9420_reg_write(pd, MAC_CR, mac_cr); + smsc9420_pci_flush_write(pd); + + /* stop RX DMAC */ + dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); + dmac_control &= (~DMAC_CONTROL_SR_); + smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); + smsc9420_pci_flush_write(pd); + + /* wait up to 10ms for receive to stop */ + while (timeOut--) { + if (smsc9420_reg_read(pd, DMAC_STATUS) & DMAC_STS_RS_) + break; + udelay(10); + } + + if (!timeOut) + smsc_warn(IFDOWN, "RX DMAC did not stop! timeout."); + + /* ACK the Rx DMAC stop bit */ + smsc9420_reg_write(pd, DMAC_STATUS, DMAC_STS_RXPS_); +} + +static irqreturn_t smsc9420_isr(int irq, void *dev_id) +{ + struct smsc9420_pdata *pd = dev_id; + u32 int_cfg, int_sts, int_ctl; + irqreturn_t ret = IRQ_NONE; + ulong flags; + + BUG_ON(!pd); + BUG_ON(!pd->base_addr); + + int_cfg = smsc9420_reg_read(pd, INT_CFG); + + /* check if it's our interrupt */ + if ((int_cfg & (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) != + (INT_CFG_IRQ_EN_ | INT_CFG_IRQ_INT_)) + return IRQ_NONE; + + int_sts = smsc9420_reg_read(pd, INT_STAT); + + if (likely(INT_STAT_DMAC_INT_ & int_sts)) { + u32 status = smsc9420_reg_read(pd, DMAC_STATUS); + u32 ints_to_clear = 0; + + if (status & DMAC_STS_TX_) { + ints_to_clear |= (DMAC_STS_TX_ | DMAC_STS_NIS_); + netif_wake_queue(pd->dev); + } + + if (status & DMAC_STS_RX_) { + /* mask RX DMAC interrupts */ + u32 dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); + dma_intr_ena &= (~DMAC_INTR_ENA_RX_); + smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); + smsc9420_pci_flush_write(pd); + + ints_to_clear |= (DMAC_STS_RX_ | DMAC_STS_NIS_); + netif_rx_schedule(&pd->napi); + } + + if (ints_to_clear) + smsc9420_reg_write(pd, DMAC_STATUS, ints_to_clear); + + ret = IRQ_HANDLED; + } + + if (unlikely(INT_STAT_SW_INT_ & int_sts)) { + /* mask software interrupt */ + spin_lock_irqsave(&pd->int_lock, flags); + int_ctl = smsc9420_reg_read(pd, INT_CTL); + int_ctl &= (~INT_CTL_SW_INT_EN_); + smsc9420_reg_write(pd, INT_CTL, int_ctl); + spin_unlock_irqrestore(&pd->int_lock, flags); + + smsc9420_reg_write(pd, INT_STAT, INT_STAT_SW_INT_); + pd->software_irq_signal = true; + smp_wmb(); + + ret = IRQ_HANDLED; + } + + /* to ensure PCI write completion, we must perform a PCI read */ + smsc9420_pci_flush_write(pd); + + return ret; +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void smsc9420_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + smsc9420_isr(0, dev); + enable_irq(dev->irq); +} +#endif /* CONFIG_NET_POLL_CONTROLLER */ + +static void smsc9420_dmac_soft_reset(struct smsc9420_pdata *pd) +{ + smsc9420_reg_write(pd, BUS_MODE, BUS_MODE_SWR_); + smsc9420_reg_read(pd, BUS_MODE); + udelay(2); + if (smsc9420_reg_read(pd, BUS_MODE) & BUS_MODE_SWR_) + smsc_warn(DRV, "Software reset not cleared"); +} + +static int smsc9420_stop(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + u32 int_cfg; + ulong flags; + + BUG_ON(!pd); + BUG_ON(!pd->phy_dev); + + /* disable master interrupt */ + spin_lock_irqsave(&pd->int_lock, flags); + int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); + smsc9420_reg_write(pd, INT_CFG, int_cfg); + spin_unlock_irqrestore(&pd->int_lock, flags); + + netif_tx_disable(dev); + napi_disable(&pd->napi); + + smsc9420_stop_tx(pd); + smsc9420_free_tx_ring(pd); + + smsc9420_stop_rx(pd); + smsc9420_free_rx_ring(pd); + + free_irq(dev->irq, pd); + + smsc9420_dmac_soft_reset(pd); + + phy_stop(pd->phy_dev); + + phy_disconnect(pd->phy_dev); + pd->phy_dev = NULL; + mdiobus_unregister(pd->mii_bus); + mdiobus_free(pd->mii_bus); + + return 0; +} + +static void smsc9420_rx_count_stats(struct net_device *dev, u32 desc_status) +{ + if (unlikely(desc_status & RDES0_ERROR_SUMMARY_)) { + dev->stats.rx_errors++; + if (desc_status & RDES0_DESCRIPTOR_ERROR_) + dev->stats.rx_over_errors++; + else if (desc_status & (RDES0_FRAME_TOO_LONG_ | + RDES0_RUNT_FRAME_ | RDES0_COLLISION_SEEN_)) + dev->stats.rx_frame_errors++; + else if (desc_status & RDES0_CRC_ERROR_) + dev->stats.rx_crc_errors++; + } + + if (unlikely(desc_status & RDES0_LENGTH_ERROR_)) + dev->stats.rx_length_errors++; + + if (unlikely(!((desc_status & RDES0_LAST_DESCRIPTOR_) && + (desc_status & RDES0_FIRST_DESCRIPTOR_)))) + dev->stats.rx_length_errors++; + + if (desc_status & RDES0_MULTICAST_FRAME_) + dev->stats.multicast++; +} + +static void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index, + const u32 status) +{ + struct net_device *dev = pd->dev; + struct sk_buff *skb; + u16 packet_length = (status & RDES0_FRAME_LENGTH_MASK_) + >> RDES0_FRAME_LENGTH_SHFT_; + + /* remove crc from packet lendth */ + packet_length -= 4; + + if (pd->rx_csum) + packet_length -= 2; + + dev->stats.rx_packets++; + dev->stats.rx_bytes += packet_length; + + pci_unmap_single(pd->pdev, pd->rx_buffers[index].mapping, + PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + pd->rx_buffers[index].mapping = 0; + + skb = pd->rx_buffers[index].skb; + pd->rx_buffers[index].skb = NULL; + + if (pd->rx_csum) { + u16 hw_csum = get_unaligned_le16(skb_tail_pointer(skb) + + NET_IP_ALIGN + packet_length + 4); + put_unaligned_le16(cpu_to_le16(hw_csum), &skb->csum); + skb->ip_summed = CHECKSUM_COMPLETE; + } + + skb_reserve(skb, NET_IP_ALIGN); + skb_put(skb, packet_length); + + skb->protocol = eth_type_trans(skb, dev); + + netif_receive_skb(skb); + dev->last_rx = jiffies; +} + +static int smsc9420_alloc_rx_buffer(struct smsc9420_pdata *pd, int index) +{ + struct sk_buff *skb = netdev_alloc_skb(pd->dev, PKT_BUF_SZ); + dma_addr_t mapping; + + BUG_ON(pd->rx_buffers[index].skb); + BUG_ON(pd->rx_buffers[index].mapping); + + if (unlikely(!skb)) { + smsc_warn(RX_ERR, "Failed to allocate new skb!"); + return -ENOMEM; + } + + skb->dev = pd->dev; + + mapping = pci_map_single(pd->pdev, skb_tail_pointer(skb), + PKT_BUF_SZ, PCI_DMA_FROMDEVICE); + if (pci_dma_mapping_error(pd->pdev, mapping)) { + dev_kfree_skb_any(skb); + smsc_warn(RX_ERR, "pci_map_single failed!"); + return -ENOMEM; + } + + pd->rx_buffers[index].skb = skb; + pd->rx_buffers[index].mapping = mapping; + pd->rx_ring[index].buffer1 = mapping + NET_IP_ALIGN; + pd->rx_ring[index].status = RDES0_OWN_; + wmb(); + + return 0; +} + +static void smsc9420_alloc_new_rx_buffers(struct smsc9420_pdata *pd) +{ + while (pd->rx_ring_tail != pd->rx_ring_head) { + if (smsc9420_alloc_rx_buffer(pd, pd->rx_ring_tail)) + break; + + pd->rx_ring_tail = (pd->rx_ring_tail + 1) % RX_RING_SIZE; + } +} + +static int smsc9420_rx_poll(struct napi_struct *napi, int budget) +{ + struct smsc9420_pdata *pd = + container_of(napi, struct smsc9420_pdata, napi); + struct net_device *dev = pd->dev; + u32 drop_frame_cnt, dma_intr_ena, status; + int work_done; + + for (work_done = 0; work_done < budget; work_done++) { + rmb(); + status = pd->rx_ring[pd->rx_ring_head].status; + + /* stop if DMAC owns this dma descriptor */ + if (status & RDES0_OWN_) + break; + + smsc9420_rx_count_stats(dev, status); + smsc9420_rx_handoff(pd, pd->rx_ring_head, status); + pd->rx_ring_head = (pd->rx_ring_head + 1) % RX_RING_SIZE; + smsc9420_alloc_new_rx_buffers(pd); + } + + drop_frame_cnt = smsc9420_reg_read(pd, MISS_FRAME_CNTR); + dev->stats.rx_dropped += + (drop_frame_cnt & 0xFFFF) + ((drop_frame_cnt >> 17) & 0x3FF); + + /* Kick RXDMA */ + smsc9420_reg_write(pd, RX_POLL_DEMAND, 1); + smsc9420_pci_flush_write(pd); + + if (work_done < budget) { + netif_rx_complete(&pd->napi); + + /* re-enable RX DMA interrupts */ + dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); + dma_intr_ena |= (DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_); + smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); + smsc9420_pci_flush_write(pd); + } + return work_done; +} + +static void +smsc9420_tx_update_stats(struct net_device *dev, u32 status, u32 length) +{ + if (unlikely(status & TDES0_ERROR_SUMMARY_)) { + dev->stats.tx_errors++; + if (status & (TDES0_EXCESSIVE_DEFERRAL_ | + TDES0_EXCESSIVE_COLLISIONS_)) + dev->stats.tx_aborted_errors++; + + if (status & (TDES0_LOSS_OF_CARRIER_ | TDES0_NO_CARRIER_)) + dev->stats.tx_carrier_errors++; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += (length & 0x7FF); + } + + if (unlikely(status & TDES0_EXCESSIVE_COLLISIONS_)) { + dev->stats.collisions += 16; + } else { + dev->stats.collisions += + (status & TDES0_COLLISION_COUNT_MASK_) >> + TDES0_COLLISION_COUNT_SHFT_; + } + + if (unlikely(status & TDES0_HEARTBEAT_FAIL_)) + dev->stats.tx_heartbeat_errors++; +} + +/* Check for completed dma transfers, update stats and free skbs */ +static void smsc9420_complete_tx(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + + while (pd->tx_ring_tail != pd->tx_ring_head) { + int index = pd->tx_ring_tail; + u32 status, length; + + rmb(); + status = pd->tx_ring[index].status; + length = pd->tx_ring[index].length; + + /* Check if DMA still owns this descriptor */ + if (unlikely(TDES0_OWN_ & status)) + break; + + smsc9420_tx_update_stats(dev, status, length); + + BUG_ON(!pd->tx_buffers[index].skb); + BUG_ON(!pd->tx_buffers[index].mapping); + + pci_unmap_single(pd->pdev, pd->tx_buffers[index].mapping, + pd->tx_buffers[index].skb->len, PCI_DMA_TODEVICE); + pd->tx_buffers[index].mapping = 0; + + dev_kfree_skb_any(pd->tx_buffers[index].skb); + pd->tx_buffers[index].skb = NULL; + + pd->tx_ring[index].buffer1 = 0; + wmb(); + + pd->tx_ring_tail = (pd->tx_ring_tail + 1) % TX_RING_SIZE; + } +} + +static int smsc9420_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + dma_addr_t mapping; + int index = pd->tx_ring_head; + u32 tmp_desc1; + bool about_to_take_last_desc = + (((pd->tx_ring_head + 2) % TX_RING_SIZE) == pd->tx_ring_tail); + + smsc9420_complete_tx(dev); + + rmb(); + BUG_ON(pd->tx_ring[index].status & TDES0_OWN_); + BUG_ON(pd->tx_buffers[index].skb); + BUG_ON(pd->tx_buffers[index].mapping); + + mapping = pci_map_single(pd->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + if (pci_dma_mapping_error(pd->pdev, mapping)) { + smsc_warn(TX_ERR, "pci_map_single failed, dropping packet"); + return NETDEV_TX_BUSY; + } + + pd->tx_buffers[index].skb = skb; + pd->tx_buffers[index].mapping = mapping; + + tmp_desc1 = (TDES1_LS_ | ((u32)skb->len & 0x7FF)); + if (unlikely(about_to_take_last_desc)) { + tmp_desc1 |= TDES1_IC_; + netif_stop_queue(pd->dev); + } + + /* check if we are at the last descriptor and need to set EOR */ + if (unlikely(index == (TX_RING_SIZE - 1))) + tmp_desc1 |= TDES1_TER_; + + pd->tx_ring[index].buffer1 = mapping; + pd->tx_ring[index].length = tmp_desc1; + wmb(); + + /* increment head */ + pd->tx_ring_head = (pd->tx_ring_head + 1) % TX_RING_SIZE; + + /* assign ownership to DMAC */ + pd->tx_ring[index].status = TDES0_OWN_; + wmb(); + + /* kick the DMA */ + smsc9420_reg_write(pd, TX_POLL_DEMAND, 1); + smsc9420_pci_flush_write(pd); + + dev->trans_start = jiffies; + + return NETDEV_TX_OK; +} + +static struct net_device_stats *smsc9420_get_stats(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + u32 counter = smsc9420_reg_read(pd, MISS_FRAME_CNTR); + dev->stats.rx_dropped += + (counter & 0x0000FFFF) + ((counter >> 17) & 0x000003FF); + return &dev->stats; +} + +static void smsc9420_set_multicast_list(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + u32 mac_cr = smsc9420_reg_read(pd, MAC_CR); + + if (dev->flags & IFF_PROMISC) { + smsc_dbg(HW, "Promiscuous Mode Enabled"); + mac_cr |= MAC_CR_PRMS_; + mac_cr &= (~MAC_CR_MCPAS_); + mac_cr &= (~MAC_CR_HPFILT_); + } else if (dev->flags & IFF_ALLMULTI) { + smsc_dbg(HW, "Receive all Multicast Enabled"); + mac_cr &= (~MAC_CR_PRMS_); + mac_cr |= MAC_CR_MCPAS_; + mac_cr &= (~MAC_CR_HPFILT_); + } else if (dev->mc_count > 0) { + struct dev_mc_list *mc_list = dev->mc_list; + u32 hash_lo = 0, hash_hi = 0; + + smsc_dbg(HW, "Multicast filter enabled"); + while (mc_list) { + u32 bit_num = smsc9420_hash(mc_list->dmi_addr); + u32 mask = 1 << (bit_num & 0x1F); + + if (bit_num & 0x20) + hash_hi |= mask; + else + hash_lo |= mask; + + mc_list = mc_list->next; + } + smsc9420_reg_write(pd, HASHH, hash_hi); + smsc9420_reg_write(pd, HASHL, hash_lo); + + mac_cr &= (~MAC_CR_PRMS_); + mac_cr &= (~MAC_CR_MCPAS_); + mac_cr |= MAC_CR_HPFILT_; + } else { + smsc_dbg(HW, "Receive own packets only."); + smsc9420_reg_write(pd, HASHH, 0); + smsc9420_reg_write(pd, HASHL, 0); + + mac_cr &= (~MAC_CR_PRMS_); + mac_cr &= (~MAC_CR_MCPAS_); + mac_cr &= (~MAC_CR_HPFILT_); + } + + smsc9420_reg_write(pd, MAC_CR, mac_cr); + smsc9420_pci_flush_write(pd); +} + +static void smsc9420_phy_update_flowcontrol(struct smsc9420_pdata *pd) +{ + struct phy_device *phy_dev = pd->phy_dev; + u32 flow; + + if (phy_dev->duplex == DUPLEX_FULL) { + u16 lcladv = phy_read(phy_dev, MII_ADVERTISE); + u16 rmtadv = phy_read(phy_dev, MII_LPA); + u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); + + if (cap & FLOW_CTRL_RX) + flow = 0xFFFF0002; + else + flow = 0; + + smsc_info(LINK, "rx pause %s, tx pause %s", + (cap & FLOW_CTRL_RX ? "enabled" : "disabled"), + (cap & FLOW_CTRL_TX ? "enabled" : "disabled")); + } else { + smsc_info(LINK, "half duplex"); + flow = 0; + } + + smsc9420_reg_write(pd, FLOW, flow); +} + +/* Update link mode if anything has changed. Called periodically when the + * PHY is in polling mode, even if nothing has changed. */ +static void smsc9420_phy_adjust_link(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + struct phy_device *phy_dev = pd->phy_dev; + int carrier; + + if (phy_dev->duplex != pd->last_duplex) { + u32 mac_cr = smsc9420_reg_read(pd, MAC_CR); + if (phy_dev->duplex) { + smsc_dbg(LINK, "full duplex mode"); + mac_cr |= MAC_CR_FDPX_; + } else { + smsc_dbg(LINK, "half duplex mode"); + mac_cr &= ~MAC_CR_FDPX_; + } + smsc9420_reg_write(pd, MAC_CR, mac_cr); + + smsc9420_phy_update_flowcontrol(pd); + pd->last_duplex = phy_dev->duplex; + } + + carrier = netif_carrier_ok(dev); + if (carrier != pd->last_carrier) { + if (carrier) + smsc_dbg(LINK, "carrier OK"); + else + smsc_dbg(LINK, "no carrier"); + pd->last_carrier = carrier; + } +} + +static int smsc9420_mii_probe(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + struct phy_device *phydev = NULL; + + BUG_ON(pd->phy_dev); + + /* Device only supports internal PHY at address 1 */ + if (!pd->mii_bus->phy_map[1]) { + pr_err("%s: no PHY found at address 1\n", dev->name); + return -ENODEV; + } + + phydev = pd->mii_bus->phy_map[1]; + smsc_info(PROBE, "PHY addr %d, phy_id 0x%08X", phydev->addr, + phydev->phy_id); + + phydev = phy_connect(dev, phydev->dev.bus_id, + &smsc9420_phy_adjust_link, 0, PHY_INTERFACE_MODE_MII); + + if (IS_ERR(phydev)) { + pr_err("%s: Could not attach to PHY\n", dev->name); + return PTR_ERR(phydev); + } + + pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n", + dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq); + + /* mask with MAC supported features */ + phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + phydev->advertising = phydev->supported; + + pd->phy_dev = phydev; + pd->last_duplex = -1; + pd->last_carrier = -1; + + return 0; +} + +static int smsc9420_mii_init(struct net_device *dev) +{ + struct smsc9420_pdata *pd = netdev_priv(dev); + int err = -ENXIO, i; + + pd->mii_bus = mdiobus_alloc(); + if (!pd->mii_bus) { + err = -ENOMEM; + goto err_out_1; + } + pd->mii_bus->name = DRV_MDIONAME; + snprintf(pd->mii_bus->id, MII_BUS_ID_SIZE, "%x", + (pd->pdev->bus->number << 8) | pd->pdev->devfn); + pd->mii_bus->priv = pd; + pd->mii_bus->read = smsc9420_mii_read; + pd->mii_bus->write = smsc9420_mii_write; + pd->mii_bus->irq = pd->phy_irq; + for (i = 0; i < PHY_MAX_ADDR; ++i) + pd->mii_bus->irq[i] = PHY_POLL; + + /* Mask all PHYs except ID 1 (internal) */ + pd->mii_bus->phy_mask = ~(1 << 1); + + if (mdiobus_register(pd->mii_bus)) { + smsc_warn(PROBE, "Error registering mii bus"); + goto err_out_free_bus_2; + } + + if (smsc9420_mii_probe(dev) < 0) { + smsc_warn(PROBE, "Error probing mii bus"); + goto err_out_unregister_bus_3; + } + + return 0; + +err_out_unregister_bus_3: + mdiobus_unregister(pd->mii_bus); +err_out_free_bus_2: + mdiobus_free(pd->mii_bus); +err_out_1: + return err; +} + +static int smsc9420_alloc_tx_ring(struct smsc9420_pdata *pd) +{ + int i; + + BUG_ON(!pd->tx_ring); + + pd->tx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) * + TX_RING_SIZE), GFP_KERNEL); + if (!pd->tx_buffers) { + smsc_warn(IFUP, "Failed to allocated tx_buffers"); + return -ENOMEM; + } + + /* Initialize the TX Ring */ + for (i = 0; i < TX_RING_SIZE; i++) { + pd->tx_buffers[i].skb = NULL; + pd->tx_buffers[i].mapping = 0; + pd->tx_ring[i].status = 0; + pd->tx_ring[i].length = 0; + pd->tx_ring[i].buffer1 = 0; + pd->tx_ring[i].buffer2 = 0; + } + pd->tx_ring[TX_RING_SIZE - 1].length = TDES1_TER_; + wmb(); + + pd->tx_ring_head = 0; + pd->tx_ring_tail = 0; + + smsc9420_reg_write(pd, TX_BASE_ADDR, pd->tx_dma_addr); + smsc9420_pci_flush_write(pd); + + return 0; +} + +static int smsc9420_alloc_rx_ring(struct smsc9420_pdata *pd) +{ + int i; + + BUG_ON(!pd->rx_ring); + + pd->rx_buffers = kmalloc((sizeof(struct smsc9420_ring_info) * + RX_RING_SIZE), GFP_KERNEL); + if (pd->rx_buffers == NULL) { + smsc_warn(IFUP, "Failed to allocated rx_buffers"); + goto out; + } + + /* initialize the rx ring */ + for (i = 0; i < RX_RING_SIZE; i++) { + pd->rx_ring[i].status = 0; + pd->rx_ring[i].length = PKT_BUF_SZ; + pd->rx_ring[i].buffer2 = 0; + pd->rx_buffers[i].skb = NULL; + pd->rx_buffers[i].mapping = 0; + } + pd->rx_ring[RX_RING_SIZE - 1].length = (PKT_BUF_SZ | RDES1_RER_); + + /* now allocate the entire ring of skbs */ + for (i = 0; i < RX_RING_SIZE; i++) { + if (smsc9420_alloc_rx_buffer(pd, i)) { + smsc_warn(IFUP, "failed to allocate rx skb %d", i); + goto out_free_rx_skbs; + } + } + + pd->rx_ring_head = 0; + pd->rx_ring_tail = 0; + + smsc9420_reg_write(pd, VLAN1, ETH_P_8021Q); + smsc_dbg(IFUP, "VLAN1 = 0x%08x", smsc9420_reg_read(pd, VLAN1)); + + if (pd->rx_csum) { + /* Enable RX COE */ + u32 coe = smsc9420_reg_read(pd, COE_CR) | RX_COE_EN; + smsc9420_reg_write(pd, COE_CR, coe); + smsc_dbg(IFUP, "COE_CR = 0x%08x", coe); + } + + smsc9420_reg_write(pd, RX_BASE_ADDR, pd->rx_dma_addr); + smsc9420_pci_flush_write(pd); + + return 0; + +out_free_rx_skbs: + smsc9420_free_rx_ring(pd); +out: + return -ENOMEM; +} + +static int smsc9420_open(struct net_device *dev) +{ + struct smsc9420_pdata *pd; + u32 bus_mode, mac_cr, dmac_control, int_cfg, dma_intr_ena, int_ctl; + unsigned long flags; + int result = 0, timeout; + + BUG_ON(!dev); + pd = netdev_priv(dev); + BUG_ON(!pd); + + if (!is_valid_ether_addr(dev->dev_addr)) { + smsc_warn(IFUP, "dev_addr is not a valid MAC address"); + result = -EADDRNOTAVAIL; + goto out_0; + } + + netif_carrier_off(dev); + + /* disable, mask and acknowlege all interrupts */ + spin_lock_irqsave(&pd->int_lock, flags); + int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); + smsc9420_reg_write(pd, INT_CFG, int_cfg); + smsc9420_reg_write(pd, INT_CTL, 0); + spin_unlock_irqrestore(&pd->int_lock, flags); + smsc9420_reg_write(pd, DMAC_INTR_ENA, 0); + smsc9420_reg_write(pd, INT_STAT, 0xFFFFFFFF); + smsc9420_pci_flush_write(pd); + + if (request_irq(dev->irq, smsc9420_isr, IRQF_SHARED | IRQF_DISABLED, + DRV_NAME, pd)) { + smsc_warn(IFUP, "Unable to use IRQ = %d", dev->irq); + result = -ENODEV; + goto out_0; + } + + smsc9420_dmac_soft_reset(pd); + + /* make sure MAC_CR is sane */ + smsc9420_reg_write(pd, MAC_CR, 0); + + smsc9420_set_mac_address(dev); + + /* Configure GPIO pins to drive LEDs */ + smsc9420_reg_write(pd, GPIO_CFG, + (GPIO_CFG_LED_3_ | GPIO_CFG_LED_2_ | GPIO_CFG_LED_1_)); + + bus_mode = BUS_MODE_DMA_BURST_LENGTH_16; + +#ifdef __BIG_ENDIAN + bus_mode |= BUS_MODE_DBO_; +#endif + + smsc9420_reg_write(pd, BUS_MODE, bus_mode); + + smsc9420_pci_flush_write(pd); + + /* set bus master bridge arbitration priority for Rx and TX DMA */ + smsc9420_reg_write(pd, BUS_CFG, BUS_CFG_RXTXWEIGHT_4_1); + + smsc9420_reg_write(pd, DMAC_CONTROL, + (DMAC_CONTROL_SF_ | DMAC_CONTROL_OSF_)); + + smsc9420_pci_flush_write(pd); + + /* test the IRQ connection to the ISR */ + smsc_dbg(IFUP, "Testing ISR using IRQ %d", dev->irq); + + spin_lock_irqsave(&pd->int_lock, flags); + /* configure interrupt deassertion timer and enable interrupts */ + int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_; + int_cfg &= ~(INT_CFG_INT_DEAS_MASK); + int_cfg |= (INT_DEAS_TIME & INT_CFG_INT_DEAS_MASK); + smsc9420_reg_write(pd, INT_CFG, int_cfg); + + /* unmask software interrupt */ + int_ctl = smsc9420_reg_read(pd, INT_CTL) | INT_CTL_SW_INT_EN_; + smsc9420_reg_write(pd, INT_CTL, int_ctl); + spin_unlock_irqrestore(&pd->int_lock, flags); + smsc9420_pci_flush_write(pd); + + timeout = 1000; + pd->software_irq_signal = false; + smp_wmb(); + while (timeout--) { + if (pd->software_irq_signal) + break; + msleep(1); + } + + /* disable interrupts */ + spin_lock_irqsave(&pd->int_lock, flags); + int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); + smsc9420_reg_write(pd, INT_CFG, int_cfg); + spin_unlock_irqrestore(&pd->int_lock, flags); + + if (!pd->software_irq_signal) { + smsc_warn(IFUP, "ISR failed signaling test"); + result = -ENODEV; + goto out_free_irq_1; + } + + smsc_dbg(IFUP, "ISR passed test using IRQ %d", dev->irq); + + result = smsc9420_alloc_tx_ring(pd); + if (result) { + smsc_warn(IFUP, "Failed to Initialize tx dma ring"); + result = -ENOMEM; + goto out_free_irq_1; + } + + result = smsc9420_alloc_rx_ring(pd); + if (result) { + smsc_warn(IFUP, "Failed to Initialize rx dma ring"); + result = -ENOMEM; + goto out_free_tx_ring_2; + } + + result = smsc9420_mii_init(dev); + if (result) { + smsc_warn(IFUP, "Failed to initialize Phy"); + result = -ENODEV; + goto out_free_rx_ring_3; + } + + /* Bring the PHY up */ + phy_start(pd->phy_dev); + + napi_enable(&pd->napi); + + /* start tx and rx */ + mac_cr = smsc9420_reg_read(pd, MAC_CR) | MAC_CR_TXEN_ | MAC_CR_RXEN_; + smsc9420_reg_write(pd, MAC_CR, mac_cr); + + dmac_control = smsc9420_reg_read(pd, DMAC_CONTROL); + dmac_control |= DMAC_CONTROL_ST_ | DMAC_CONTROL_SR_; + smsc9420_reg_write(pd, DMAC_CONTROL, dmac_control); + smsc9420_pci_flush_write(pd); + + dma_intr_ena = smsc9420_reg_read(pd, DMAC_INTR_ENA); + dma_intr_ena |= + (DMAC_INTR_ENA_TX_ | DMAC_INTR_ENA_RX_ | DMAC_INTR_ENA_NIS_); + smsc9420_reg_write(pd, DMAC_INTR_ENA, dma_intr_ena); + smsc9420_pci_flush_write(pd); + + netif_wake_queue(dev); + + smsc9420_reg_write(pd, RX_POLL_DEMAND, 1); + + /* enable interrupts */ + spin_lock_irqsave(&pd->int_lock, flags); + int_cfg = smsc9420_reg_read(pd, INT_CFG) | INT_CFG_IRQ_EN_; + smsc9420_reg_write(pd, INT_CFG, int_cfg); + spin_unlock_irqrestore(&pd->int_lock, flags); + + return 0; + +out_free_rx_ring_3: + smsc9420_free_rx_ring(pd); +out_free_tx_ring_2: + smsc9420_free_tx_ring(pd); +out_free_irq_1: + free_irq(dev->irq, pd); +out_0: + return result; +} + +#ifdef CONFIG_PM + +static int smsc9420_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct smsc9420_pdata *pd = netdev_priv(dev); + u32 int_cfg; + ulong flags; + + /* disable interrupts */ + spin_lock_irqsave(&pd->int_lock, flags); + int_cfg = smsc9420_reg_read(pd, INT_CFG) & (~INT_CFG_IRQ_EN_); + smsc9420_reg_write(pd, INT_CFG, int_cfg); + spin_unlock_irqrestore(&pd->int_lock, flags); + + if (netif_running(dev)) { + netif_tx_disable(dev); + smsc9420_stop_tx(pd); + smsc9420_free_tx_ring(pd); + + napi_disable(&pd->napi); + smsc9420_stop_rx(pd); + smsc9420_free_rx_ring(pd); + + free_irq(dev->irq, pd); + + netif_device_detach(dev); + } + + pci_save_state(pdev); + pci_enable_wake(pdev, pci_choose_state(pdev, state), 0); + pci_disable_device(pdev); + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int smsc9420_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct smsc9420_pdata *pd = netdev_priv(dev); + int err; + + pci_set_power_state(pdev, PCI_D0); + pci_restore_state(pdev); + + err = pci_enable_device(pdev); + if (err) + return err; + + pci_set_master(pdev); + + err = pci_enable_wake(pdev, 0, 0); + if (err) + smsc_warn(IFUP, "pci_enable_wake failed: %d", err); + + if (netif_running(dev)) { + err = smsc9420_open(dev); + netif_device_attach(dev); + } + return err; +} + +#endif /* CONFIG_PM */ + +static const struct net_device_ops smsc9420_netdev_ops = { + .ndo_open = smsc9420_open, + .ndo_stop = smsc9420_stop, + .ndo_start_xmit = smsc9420_hard_start_xmit, + .ndo_get_stats = smsc9420_get_stats, + .ndo_set_multicast_list = smsc9420_set_multicast_list, + .ndo_do_ioctl = smsc9420_do_ioctl, + .ndo_validate_addr = eth_validate_addr, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = smsc9420_poll_controller, +#endif /* CONFIG_NET_POLL_CONTROLLER */ +}; + +static int __devinit +smsc9420_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct net_device *dev; + struct smsc9420_pdata *pd; + void __iomem *virt_addr; + int result = 0; + u32 id_rev; + + printk(KERN_INFO DRV_DESCRIPTION " version " DRV_VERSION "\n"); + + /* First do the PCI initialisation */ + result = pci_enable_device(pdev); + if (unlikely(result)) { + printk(KERN_ERR "Cannot enable smsc9420\n"); + goto out_0; + } + + pci_set_master(pdev); + + dev = alloc_etherdev(sizeof(*pd)); + if (!dev) { + printk(KERN_ERR "ether device alloc failed\n"); + goto out_disable_pci_device_1; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + + if (!(pci_resource_flags(pdev, SMSC_BAR) & IORESOURCE_MEM)) { + printk(KERN_ERR "Cannot find PCI device base address\n"); + goto out_free_netdev_2; + } + + if ((pci_request_regions(pdev, DRV_NAME))) { + printk(KERN_ERR "Cannot obtain PCI resources, aborting.\n"); + goto out_free_netdev_2; + } + + if (pci_set_dma_mask(pdev, DMA_32BIT_MASK)) { + printk(KERN_ERR "No usable DMA configuration, aborting.\n"); + goto out_free_regions_3; + } + + virt_addr = ioremap(pci_resource_start(pdev, SMSC_BAR), + pci_resource_len(pdev, SMSC_BAR)); + if (!virt_addr) { + printk(KERN_ERR "Cannot map device registers, aborting.\n"); + goto out_free_regions_3; + } + + /* registers are double mapped with 0 offset for LE and 0x200 for BE */ + virt_addr += LAN9420_CPSR_ENDIAN_OFFSET; + + dev->base_addr = (ulong)virt_addr; + + pd = netdev_priv(dev); + + /* pci descriptors are created in the PCI consistent area */ + pd->rx_ring = pci_alloc_consistent(pdev, + sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE + + sizeof(struct smsc9420_dma_desc) * TX_RING_SIZE, + &pd->rx_dma_addr); + + if (!pd->rx_ring) + goto out_free_io_4; + + /* descriptors are aligned due to the nature of pci_alloc_consistent */ + pd->tx_ring = (struct smsc9420_dma_desc *) + (pd->rx_ring + RX_RING_SIZE); + pd->tx_dma_addr = pd->rx_dma_addr + + sizeof(struct smsc9420_dma_desc) * RX_RING_SIZE; + + pd->pdev = pdev; + pd->dev = dev; + pd->base_addr = virt_addr; + pd->msg_enable = smsc_debug; + pd->rx_csum = true; + + smsc_dbg(PROBE, "lan_base=0x%08lx", (ulong)virt_addr); + + id_rev = smsc9420_reg_read(pd, ID_REV); + switch (id_rev & 0xFFFF0000) { + case 0x94200000: + smsc_info(PROBE, "LAN9420 identified, ID_REV=0x%08X", id_rev); + break; + default: + smsc_warn(PROBE, "LAN9420 NOT identified"); + smsc_warn(PROBE, "ID_REV=0x%08X", id_rev); + goto out_free_dmadesc_5; + } + + smsc9420_dmac_soft_reset(pd); + smsc9420_eeprom_reload(pd); + smsc9420_check_mac_address(dev); + + dev->netdev_ops = &smsc9420_netdev_ops; + dev->ethtool_ops = &smsc9420_ethtool_ops; + dev->irq = pdev->irq; + + netif_napi_add(dev, &pd->napi, smsc9420_rx_poll, NAPI_WEIGHT); + + result = register_netdev(dev); + if (result) { + smsc_warn(PROBE, "error %i registering device", result); + goto out_free_dmadesc_5; + } + + pci_set_drvdata(pdev, dev); + + spin_lock_init(&pd->int_lock); + spin_lock_init(&pd->phy_lock); + + dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr); + + return 0; + +out_free_dmadesc_5: + pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) * + (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr); +out_free_io_4: + iounmap(virt_addr - LAN9420_CPSR_ENDIAN_OFFSET); +out_free_regions_3: + pci_release_regions(pdev); +out_free_netdev_2: + free_netdev(dev); +out_disable_pci_device_1: + pci_disable_device(pdev); +out_0: + return -ENODEV; +} + +static void __devexit smsc9420_remove(struct pci_dev *pdev) +{ + struct net_device *dev; + struct smsc9420_pdata *pd; + + dev = pci_get_drvdata(pdev); + if (!dev) + return; + + pci_set_drvdata(pdev, NULL); + + pd = netdev_priv(dev); + unregister_netdev(dev); + + /* tx_buffers and rx_buffers are freed in stop */ + BUG_ON(pd->tx_buffers); + BUG_ON(pd->rx_buffers); + + BUG_ON(!pd->tx_ring); + BUG_ON(!pd->rx_ring); + + pci_free_consistent(pdev, sizeof(struct smsc9420_dma_desc) * + (RX_RING_SIZE + TX_RING_SIZE), pd->rx_ring, pd->rx_dma_addr); + + iounmap(pd->base_addr - LAN9420_CPSR_ENDIAN_OFFSET); + pci_release_regions(pdev); + free_netdev(dev); + pci_disable_device(pdev); +} + +static struct pci_driver smsc9420_driver = { + .name = DRV_NAME, + .id_table = smsc9420_id_table, + .probe = smsc9420_probe, + .remove = __devexit_p(smsc9420_remove), +#ifdef CONFIG_PM + .suspend = smsc9420_suspend, + .resume = smsc9420_resume, +#endif /* CONFIG_PM */ +}; + +static int __init smsc9420_init_module(void) +{ + smsc_debug = netif_msg_init(debug, SMSC_MSG_DEFAULT); + + return pci_register_driver(&smsc9420_driver); +} + +static void __exit smsc9420_exit_module(void) +{ + pci_unregister_driver(&smsc9420_driver); +} + +module_init(smsc9420_init_module); +module_exit(smsc9420_exit_module); diff --git a/drivers/net/smsc9420.h b/drivers/net/smsc9420.h new file mode 100644 index 0000000000000000000000000000000000000000..69c351f93f86cd3c531121411215ca692061c8b2 --- /dev/null +++ b/drivers/net/smsc9420.h @@ -0,0 +1,275 @@ + /*************************************************************************** + * + * Copyright (C) 2007,2008 SMSC + * + * 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. + * + *************************************************************************** + */ + +#ifndef _SMSC9420_H +#define _SMSC9420_H + +#define TX_RING_SIZE (32) +#define RX_RING_SIZE (128) + +/* interrupt deassertion in multiples of 10us */ +#define INT_DEAS_TIME (50) + +#define NAPI_WEIGHT (64) +#define SMSC_BAR (3) + +#ifdef __BIG_ENDIAN +/* Register set is duplicated for BE at an offset of 0x200 */ +#define LAN9420_CPSR_ENDIAN_OFFSET (0x200) +#else +#define LAN9420_CPSR_ENDIAN_OFFSET (0) +#endif + +#define PCI_VENDOR_ID_9420 (0x1055) +#define PCI_DEVICE_ID_9420 (0xE420) + +#define LAN_REGISTER_EXTENT (0x400) + +#define SMSC9420_EEPROM_SIZE ((u32)11) + +#define PKT_BUF_SZ (VLAN_ETH_FRAME_LEN + NET_IP_ALIGN + 4) + +/***********************************************/ +/* DMA Controller Control and Status Registers */ +/***********************************************/ +#define BUS_MODE (0x00) +#define BUS_MODE_SWR_ (BIT(0)) +#define BUS_MODE_DMA_BURST_LENGTH_1 (BIT(8)) +#define BUS_MODE_DMA_BURST_LENGTH_2 (BIT(9)) +#define BUS_MODE_DMA_BURST_LENGTH_4 (BIT(10)) +#define BUS_MODE_DMA_BURST_LENGTH_8 (BIT(11)) +#define BUS_MODE_DMA_BURST_LENGTH_16 (BIT(12)) +#define BUS_MODE_DMA_BURST_LENGTH_32 (BIT(13)) +#define BUS_MODE_DBO_ (BIT(20)) + +#define TX_POLL_DEMAND (0x04) + +#define RX_POLL_DEMAND (0x08) + +#define RX_BASE_ADDR (0x0C) + +#define TX_BASE_ADDR (0x10) + +#define DMAC_STATUS (0x14) +#define DMAC_STS_TS_ (7 << 20) +#define DMAC_STS_RS_ (7 << 17) +#define DMAC_STS_NIS_ (BIT(16)) +#define DMAC_STS_AIS_ (BIT(15)) +#define DMAC_STS_RWT_ (BIT(9)) +#define DMAC_STS_RXPS_ (BIT(8)) +#define DMAC_STS_RXBU_ (BIT(7)) +#define DMAC_STS_RX_ (BIT(6)) +#define DMAC_STS_TXUNF_ (BIT(5)) +#define DMAC_STS_TXBU_ (BIT(2)) +#define DMAC_STS_TXPS_ (BIT(1)) +#define DMAC_STS_TX_ (BIT(0)) + +#define DMAC_CONTROL (0x18) +#define DMAC_CONTROL_TTM_ (BIT(22)) +#define DMAC_CONTROL_SF_ (BIT(21)) +#define DMAC_CONTROL_ST_ (BIT(13)) +#define DMAC_CONTROL_OSF_ (BIT(2)) +#define DMAC_CONTROL_SR_ (BIT(1)) + +#define DMAC_INTR_ENA (0x1C) +#define DMAC_INTR_ENA_NIS_ (BIT(16)) +#define DMAC_INTR_ENA_AIS_ (BIT(15)) +#define DMAC_INTR_ENA_RWT_ (BIT(9)) +#define DMAC_INTR_ENA_RXPS_ (BIT(8)) +#define DMAC_INTR_ENA_RXBU_ (BIT(7)) +#define DMAC_INTR_ENA_RX_ (BIT(6)) +#define DMAC_INTR_ENA_TXBU_ (BIT(2)) +#define DMAC_INTR_ENA_TXPS_ (BIT(1)) +#define DMAC_INTR_ENA_TX_ (BIT(0)) + +#define MISS_FRAME_CNTR (0x20) + +#define TX_BUFF_ADDR (0x50) + +#define RX_BUFF_ADDR (0x54) + +/* Transmit Descriptor Bit Defs */ +#define TDES0_OWN_ (0x80000000) +#define TDES0_ERROR_SUMMARY_ (0x00008000) +#define TDES0_LOSS_OF_CARRIER_ (0x00000800) +#define TDES0_NO_CARRIER_ (0x00000400) +#define TDES0_LATE_COLLISION_ (0x00000200) +#define TDES0_EXCESSIVE_COLLISIONS_ (0x00000100) +#define TDES0_HEARTBEAT_FAIL_ (0x00000080) +#define TDES0_COLLISION_COUNT_MASK_ (0x00000078) +#define TDES0_COLLISION_COUNT_SHFT_ (3) +#define TDES0_EXCESSIVE_DEFERRAL_ (0x00000004) +#define TDES0_DEFERRED_ (0x00000001) + +#define TDES1_IC_ 0x80000000 +#define TDES1_LS_ 0x40000000 +#define TDES1_FS_ 0x20000000 +#define TDES1_TXCSEN_ 0x08000000 +#define TDES1_TER_ (BIT(25)) +#define TDES1_TCH_ 0x01000000 + +/* Receive Descriptor 0 Bit Defs */ +#define RDES0_OWN_ (0x80000000) +#define RDES0_FRAME_LENGTH_MASK_ (0x07FF0000) +#define RDES0_FRAME_LENGTH_SHFT_ (16) +#define RDES0_ERROR_SUMMARY_ (0x00008000) +#define RDES0_DESCRIPTOR_ERROR_ (0x00004000) +#define RDES0_LENGTH_ERROR_ (0x00001000) +#define RDES0_RUNT_FRAME_ (0x00000800) +#define RDES0_MULTICAST_FRAME_ (0x00000400) +#define RDES0_FIRST_DESCRIPTOR_ (0x00000200) +#define RDES0_LAST_DESCRIPTOR_ (0x00000100) +#define RDES0_FRAME_TOO_LONG_ (0x00000080) +#define RDES0_COLLISION_SEEN_ (0x00000040) +#define RDES0_FRAME_TYPE_ (0x00000020) +#define RDES0_WATCHDOG_TIMEOUT_ (0x00000010) +#define RDES0_MII_ERROR_ (0x00000008) +#define RDES0_DRIBBLING_BIT_ (0x00000004) +#define RDES0_CRC_ERROR_ (0x00000002) + +/* Receive Descriptor 1 Bit Defs */ +#define RDES1_RER_ (0x02000000) + +/***********************************************/ +/* MAC Control and Status Registers */ +/***********************************************/ +#define MAC_CR (0x80) +#define MAC_CR_RXALL_ (0x80000000) +#define MAC_CR_DIS_RXOWN_ (0x00800000) +#define MAC_CR_LOOPBK_ (0x00200000) +#define MAC_CR_FDPX_ (0x00100000) +#define MAC_CR_MCPAS_ (0x00080000) +#define MAC_CR_PRMS_ (0x00040000) +#define MAC_CR_INVFILT_ (0x00020000) +#define MAC_CR_PASSBAD_ (0x00010000) +#define MAC_CR_HFILT_ (0x00008000) +#define MAC_CR_HPFILT_ (0x00002000) +#define MAC_CR_LCOLL_ (0x00001000) +#define MAC_CR_DIS_BCAST_ (0x00000800) +#define MAC_CR_DIS_RTRY_ (0x00000400) +#define MAC_CR_PADSTR_ (0x00000100) +#define MAC_CR_BOLMT_MSK (0x000000C0) +#define MAC_CR_MFCHK_ (0x00000020) +#define MAC_CR_TXEN_ (0x00000008) +#define MAC_CR_RXEN_ (0x00000004) + +#define ADDRH (0x84) + +#define ADDRL (0x88) + +#define HASHH (0x8C) + +#define HASHL (0x90) + +#define MII_ACCESS (0x94) +#define MII_ACCESS_MII_BUSY_ (0x00000001) +#define MII_ACCESS_MII_WRITE_ (0x00000002) +#define MII_ACCESS_MII_READ_ (0x00000000) +#define MII_ACCESS_INDX_MSK_ (0x000007C0) +#define MII_ACCESS_PHYADDR_MSK_ (0x0000F8C0) +#define MII_ACCESS_INDX_SHFT_CNT (6) +#define MII_ACCESS_PHYADDR_SHFT_CNT (11) + +#define MII_DATA (0x98) + +#define FLOW (0x9C) + +#define VLAN1 (0xA0) + +#define VLAN2 (0xA4) + +#define WUFF (0xA8) + +#define WUCSR (0xAC) + +#define COE_CR (0xB0) +#define TX_COE_EN (0x00010000) +#define RX_COE_MODE (0x00000002) +#define RX_COE_EN (0x00000001) + +/***********************************************/ +/* System Control and Status Registers */ +/***********************************************/ +#define ID_REV (0xC0) + +#define INT_CTL (0xC4) +#define INT_CTL_SW_INT_EN_ (0x00008000) +#define INT_CTL_SBERR_INT_EN_ (1 << 12) +#define INT_CTL_MBERR_INT_EN_ (1 << 13) +#define INT_CTL_GPT_INT_EN_ (0x00000008) +#define INT_CTL_PHY_INT_EN_ (0x00000004) +#define INT_CTL_WAKE_INT_EN_ (0x00000002) + +#define INT_STAT (0xC8) +#define INT_STAT_SW_INT_ (1 << 15) +#define INT_STAT_MBERR_INT_ (1 << 13) +#define INT_STAT_SBERR_INT_ (1 << 12) +#define INT_STAT_GPT_INT_ (1 << 3) +#define INT_STAT_PHY_INT_ (0x00000004) +#define INT_STAT_WAKE_INT_ (0x00000002) +#define INT_STAT_DMAC_INT_ (0x00000001) + +#define INT_CFG (0xCC) +#define INT_CFG_IRQ_INT_ (0x00080000) +#define INT_CFG_IRQ_EN_ (0x00040000) +#define INT_CFG_INT_DEAS_CLR_ (0x00000200) +#define INT_CFG_INT_DEAS_MASK (0x000000FF) + +#define GPIO_CFG (0xD0) +#define GPIO_CFG_LED_3_ (0x40000000) +#define GPIO_CFG_LED_2_ (0x20000000) +#define GPIO_CFG_LED_1_ (0x10000000) +#define GPIO_CFG_EEPR_EN_ (0x00700000) + +#define GPT_CFG (0xD4) +#define GPT_CFG_TIMER_EN_ (0x20000000) + +#define GPT_CNT (0xD8) + +#define BUS_CFG (0xDC) +#define BUS_CFG_RXTXWEIGHT_1_1 (0 << 25) +#define BUS_CFG_RXTXWEIGHT_2_1 (1 << 25) +#define BUS_CFG_RXTXWEIGHT_3_1 (2 << 25) +#define BUS_CFG_RXTXWEIGHT_4_1 (3 << 25) + +#define PMT_CTRL (0xE0) + +#define FREE_RUN (0xF4) + +#define E2P_CMD (0xF8) +#define E2P_CMD_EPC_BUSY_ (0x80000000) +#define E2P_CMD_EPC_CMD_ (0x70000000) +#define E2P_CMD_EPC_CMD_READ_ (0x00000000) +#define E2P_CMD_EPC_CMD_EWDS_ (0x10000000) +#define E2P_CMD_EPC_CMD_EWEN_ (0x20000000) +#define E2P_CMD_EPC_CMD_WRITE_ (0x30000000) +#define E2P_CMD_EPC_CMD_WRAL_ (0x40000000) +#define E2P_CMD_EPC_CMD_ERASE_ (0x50000000) +#define E2P_CMD_EPC_CMD_ERAL_ (0x60000000) +#define E2P_CMD_EPC_CMD_RELOAD_ (0x70000000) +#define E2P_CMD_EPC_TIMEOUT_ (0x00000200) +#define E2P_CMD_MAC_ADDR_LOADED_ (0x00000100) +#define E2P_CMD_EPC_ADDR_ (0x000000FF) + +#define E2P_DATA (0xFC) +#define E2P_DATA_EEPROM_DATA_ (0x000000FF) + +#endif /* _SMSC9420_H */ diff --git a/drivers/net/sonic.c b/drivers/net/sonic.c index 8069f3e32d83db988a33277073c1cd5d706b601a..211e805c122350a2707e90858321d8a8fd4a5a60 100644 --- a/drivers/net/sonic.c +++ b/drivers/net/sonic.c @@ -450,7 +450,6 @@ static void sonic_rx(struct net_device *dev) skb_trim(used_skb, pkt_len); used_skb->protocol = eth_type_trans(used_skb, dev); netif_rx(used_skb); - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; diff --git a/drivers/net/sonic.h b/drivers/net/sonic.h index 7db13e4a7ea55c70c8b31c9cd0c93dbbb6012d1f..07091dd27e5df2969592a3faa54f30fdad4a4844 100644 --- a/drivers/net/sonic.h +++ b/drivers/net/sonic.h @@ -371,7 +371,7 @@ static inline __u16 sonic_buf_get(void* base, int bitmode, static inline void sonic_cda_put(struct net_device* dev, int entry, int offset, __u16 val) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); sonic_buf_put(lp->cda, lp->dma_bitmode, (entry * SIZEOF_SONIC_CD) + offset, val); } @@ -379,27 +379,27 @@ static inline void sonic_cda_put(struct net_device* dev, int entry, static inline __u16 sonic_cda_get(struct net_device* dev, int entry, int offset) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); return sonic_buf_get(lp->cda, lp->dma_bitmode, (entry * SIZEOF_SONIC_CD) + offset); } static inline void sonic_set_cam_enable(struct net_device* dev, __u16 val) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); sonic_buf_put(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE, val); } static inline __u16 sonic_get_cam_enable(struct net_device* dev) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); return sonic_buf_get(lp->cda, lp->dma_bitmode, SONIC_CDA_CAM_ENABLE); } static inline void sonic_tda_put(struct net_device* dev, int entry, int offset, __u16 val) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); sonic_buf_put(lp->tda, lp->dma_bitmode, (entry * SIZEOF_SONIC_TD) + offset, val); } @@ -407,7 +407,7 @@ static inline void sonic_tda_put(struct net_device* dev, int entry, static inline __u16 sonic_tda_get(struct net_device* dev, int entry, int offset) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); return sonic_buf_get(lp->tda, lp->dma_bitmode, (entry * SIZEOF_SONIC_TD) + offset); } @@ -415,7 +415,7 @@ static inline __u16 sonic_tda_get(struct net_device* dev, int entry, static inline void sonic_rda_put(struct net_device* dev, int entry, int offset, __u16 val) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); sonic_buf_put(lp->rda, lp->dma_bitmode, (entry * SIZEOF_SONIC_RD) + offset, val); } @@ -423,7 +423,7 @@ static inline void sonic_rda_put(struct net_device* dev, int entry, static inline __u16 sonic_rda_get(struct net_device* dev, int entry, int offset) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); return sonic_buf_get(lp->rda, lp->dma_bitmode, (entry * SIZEOF_SONIC_RD) + offset); } @@ -431,7 +431,7 @@ static inline __u16 sonic_rda_get(struct net_device* dev, int entry, static inline void sonic_rra_put(struct net_device* dev, int entry, int offset, __u16 val) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); sonic_buf_put(lp->rra, lp->dma_bitmode, (entry * SIZEOF_SONIC_RR) + offset, val); } @@ -439,7 +439,7 @@ static inline void sonic_rra_put(struct net_device* dev, int entry, static inline __u16 sonic_rra_get(struct net_device* dev, int entry, int offset) { - struct sonic_local* lp = (struct sonic_local *) dev->priv; + struct sonic_local *lp = netdev_priv(dev); return sonic_buf_get(lp->rra, lp->dma_bitmode, (entry * SIZEOF_SONIC_RR) + offset); } diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 07599b492359f16bc348f4271eb32793a3a362e0..c5c123d3af57f00b5930d7cf318f1a3444f5dcd5 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c @@ -789,7 +789,7 @@ spider_net_set_low_watermark(struct spider_net_card *card) * spider_net_release_tx_chain releases the tx descriptors that spider has * finished with (if non-brutal) or simply release tx descriptors (if brutal). * If some other context is calling this function, we return 1 so that we're - * scheduled again (if we were scheduled) and will not loose initiative. + * scheduled again (if we were scheduled) and will not lose initiative. */ static int spider_net_release_tx_chain(struct spider_net_card *card, int brutal) @@ -1302,7 +1302,7 @@ static int spider_net_poll(struct napi_struct *napi, int budget) /* if all packets are in the stack, enable interrupts and return 0 */ /* if not, return 1 */ if (packets_done < budget) { - netif_rx_complete(netdev, napi); + netif_rx_complete(napi); spider_net_rx_irq_on(card); card->ignore_rx_ramfull = 0; } @@ -1529,8 +1529,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg, spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev, - &card->napi); + netif_rx_schedule(&card->napi); } show_error = 0; break; @@ -1550,8 +1549,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg, spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev, - &card->napi); + netif_rx_schedule(&card->napi); show_error = 0; break; @@ -1565,8 +1563,7 @@ spider_net_handle_error_irq(struct spider_net_card *card, u32 status_reg, spider_net_refill_rx_chain(card); spider_net_enable_rxdmac(card); card->num_rx_ints ++; - netif_rx_schedule(card->netdev, - &card->napi); + netif_rx_schedule(&card->napi); show_error = 0; break; @@ -1660,11 +1657,11 @@ spider_net_interrupt(int irq, void *ptr) if (status_reg & SPIDER_NET_RXINT ) { spider_net_rx_irq_off(card); - netif_rx_schedule(netdev, &card->napi); + netif_rx_schedule(&card->napi); card->num_rx_ints ++; } if (status_reg & SPIDER_NET_TXINT) - netif_rx_schedule(netdev, &card->napi); + netif_rx_schedule(&card->napi); if (status_reg & SPIDER_NET_LINKINT) spider_net_link_reset(netdev); diff --git a/drivers/net/spider_net_ethtool.c b/drivers/net/spider_net_ethtool.c index 85691d2a0be26a454e65550d867d4e59a0713119..5bae728c3820a01b00ace7672d1422fecc9d8aee 100644 --- a/drivers/net/spider_net_ethtool.c +++ b/drivers/net/spider_net_ethtool.c @@ -118,7 +118,7 @@ spider_net_ethtool_nway_reset(struct net_device *netdev) static u32 spider_net_ethtool_get_rx_csum(struct net_device *netdev) { - struct spider_net_card *card = netdev->priv; + struct spider_net_card *card = netdev_priv(netdev); return card->options.rx_csum; } @@ -126,7 +126,7 @@ spider_net_ethtool_get_rx_csum(struct net_device *netdev) static int spider_net_ethtool_set_rx_csum(struct net_device *netdev, u32 n) { - struct spider_net_card *card = netdev->priv; + struct spider_net_card *card = netdev_priv(netdev); card->options.rx_csum = n; return 0; @@ -137,7 +137,7 @@ static void spider_net_ethtool_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ering) { - struct spider_net_card *card = netdev->priv; + struct spider_net_card *card = netdev_priv(netdev); ering->tx_max_pending = SPIDER_NET_TX_DESCRIPTORS_MAX; ering->tx_pending = card->tx_chain.num_desc; @@ -158,7 +158,7 @@ static int spider_net_get_sset_count(struct net_device *netdev, int sset) static void spider_net_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { - struct spider_net_card *card = netdev->priv; + struct spider_net_card *card = netdev_priv(netdev); data[0] = netdev->stats.tx_packets; data[1] = netdev->stats.tx_bytes; diff --git a/drivers/net/starfire.c b/drivers/net/starfire.c index 5a40f2d78beb1a9114478ac9e0385556c29d30bf..f54ac2389da29dd444395853582c5153a55309e9 100644 --- a/drivers/net/starfire.c +++ b/drivers/net/starfire.c @@ -653,7 +653,6 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, void __iomem *base; int drv_flags, io_size; int boguscnt; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -823,9 +822,9 @@ static int __devinit starfire_init_one(struct pci_dev *pdev, if (register_netdev(dev)) goto err_out_cleardev; - printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", dev->name, netdrv_tbl[chip_idx].name, base, - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); if (drv_flags & CanHaveMII) { int phy, phy_idx = 0; @@ -881,9 +880,9 @@ static int mdio_read(struct net_device *dev, int phy_id, int location) void __iomem *mdio_addr = np->base + MIICtrl + (phy_id<<7) + (location<<2); int result, boguscnt=1000; /* ??? Should we add a busy-wait here? */ - do + do { result = readl(mdio_addr); - while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0); + } while ((result & 0xC0000000) != 0x80000000 && --boguscnt > 0); if (boguscnt == 0) return 0; if ((result & 0xffff) == 0xffff) @@ -1291,8 +1290,8 @@ static irqreturn_t intr_handler(int irq, void *dev_instance) if (intr_status & (IntrRxDone | IntrRxEmpty)) { u32 enable; - if (likely(netif_rx_schedule_prep(dev, &np->napi))) { - __netif_rx_schedule(dev, &np->napi); + if (likely(netif_rx_schedule_prep(&np->napi))) { + __netif_rx_schedule(&np->napi); enable = readl(ioaddr + IntrEnable); enable &= ~(IntrRxDone | IntrRxEmpty); writel(enable, ioaddr + IntrEnable); @@ -1452,12 +1451,8 @@ static int __netdev_rx(struct net_device *dev, int *quota) #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ if (debug > 5) { - printk(KERN_DEBUG " Rx data " MAC_FMT " " MAC_FMT - " %2.2x%2.2x.\n", - skb->data[0], skb->data[1], skb->data[2], - skb->data[3], skb->data[4], skb->data[5], - skb->data[6], skb->data[7], skb->data[8], - skb->data[9], skb->data[10], skb->data[11], + printk(KERN_DEBUG " Rx data %pM %pM %2.2x%2.2x.\n", + skb->data, skb->data + 6, skb->data[12], skb->data[13]); } #endif @@ -1501,7 +1496,6 @@ static int __netdev_rx(struct net_device *dev, int *quota) } else #endif /* VLAN_SUPPORT */ netif_receive_skb(skb); - dev->last_rx = jiffies; np->stats.rx_packets++; next_rx: @@ -1541,7 +1535,7 @@ static int netdev_poll(struct napi_struct *napi, int budget) intr_status = readl(ioaddr + IntrStatus); } while (intr_status & (IntrRxDone | IntrRxEmpty)); - netif_rx_complete(dev, napi); + netif_rx_complete(napi); intr_status = readl(ioaddr + IntrEnable); intr_status |= IntrRxDone | IntrRxEmpty; writel(intr_status, ioaddr + IntrEnable); diff --git a/drivers/net/stnic.c b/drivers/net/stnic.c index 2ed0bd5968157620a2179757875fe25cafaa3d6a..87a6b8eabc672355fd9ee12ae6aa738c8e8d3c0c 100644 --- a/drivers/net/stnic.c +++ b/drivers/net/stnic.c @@ -60,8 +60,6 @@ static byte stnic_eadr[6] = static struct net_device *stnic_dev; -static int stnic_open (struct net_device *dev); -static int stnic_close (struct net_device *dev); static void stnic_reset (struct net_device *dev); static void stnic_get_hdr (struct net_device *dev, struct e8390_pkt_hdr *hdr, int ring_page); @@ -122,11 +120,7 @@ static int __init stnic_probe(void) /* Set the base address to point to the NIC, not the "real" base! */ dev->base_addr = 0x1000; dev->irq = IRQ_STNIC; - dev->open = &stnic_open; - dev->stop = &stnic_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + dev->netdev_ops = &ei_netdev_ops; /* Snarf the interrupt now. There's no point in waiting since we cannot share and the board will usually be enabled. */ @@ -168,23 +162,6 @@ static int __init stnic_probe(void) return 0; } -static int -stnic_open (struct net_device *dev) -{ -#if 0 - printk (KERN_DEBUG "stnic open\n"); -#endif - ei_open (dev); - return 0; -} - -static int -stnic_close (struct net_device *dev) -{ - ei_close (dev); - return 0; -} - static void stnic_reset (struct net_device *dev) { diff --git a/drivers/net/sun3_82586.c b/drivers/net/sun3_82586.c index e531302d95f5078680e1065bda74550346574055..e0d84772771ca6bf61a32f9019104b500680114b 100644 --- a/drivers/net/sun3_82586.c +++ b/drivers/net/sun3_82586.c @@ -209,7 +209,7 @@ static int sun3_82586_open(struct net_device *dev) static int check586(struct net_device *dev,char *where,unsigned size) { struct priv pb; - struct priv *p = /* (struct priv *) dev->priv*/ &pb; + struct priv *p = &pb; char *iscp_addr; int i; @@ -247,7 +247,7 @@ static int check586(struct net_device *dev,char *where,unsigned size) */ static void alloc586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); sun3_reset586(); DELAY(1); @@ -363,17 +363,21 @@ static int __init sun3_82586_probe1(struct net_device *dev,int ioaddr) goto out; } - ((struct priv *) (dev->priv))->memtop = (char *)dvma_btov(dev->mem_start); - ((struct priv *) (dev->priv))->base = (unsigned long) dvma_btov(0); + ((struct priv *)netdev_priv(dev))->memtop = + (char *)dvma_btov(dev->mem_start); + ((struct priv *)netdev_priv(dev))->base = (unsigned long) dvma_btov(0); alloc586(dev); /* set number of receive-buffs according to memsize */ if(size == 0x2000) - ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_8; + ((struct priv *)netdev_priv(dev))->num_recv_buffs = + NUM_RECV_BUFFS_8; else if(size == 0x4000) - ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_16; + ((struct priv *)netdev_priv(dev))->num_recv_buffs = + NUM_RECV_BUFFS_16; else - ((struct priv *) dev->priv)->num_recv_buffs = NUM_RECV_BUFFS_32; + ((struct priv *)netdev_priv(dev))->num_recv_buffs = + NUM_RECV_BUFFS_32; printk("Memaddr: 0x%lx, Memsize: %d, IRQ %d\n",dev->mem_start,size, dev->irq); @@ -397,7 +401,7 @@ static int init586(struct net_device *dev) { void *ptr; int i,result=0; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); volatile struct configure_cmd_struct *cfg_cmd; volatile struct iasetup_cmd_struct *ias_cmd; volatile struct tdr_cmd_struct *tdr_cmd; @@ -631,7 +635,7 @@ static void *alloc_rfa(struct net_device *dev,void *ptr) volatile struct rfd_struct *rfd = (struct rfd_struct *)ptr; volatile struct rbd_struct *rbd; int i; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); memset((char *) rfd,0,sizeof(struct rfd_struct)*(p->num_recv_buffs+rfdadd)); p->rfd_first = rfd; @@ -683,7 +687,7 @@ static irqreturn_t sun3_82586_interrupt(int irq,void *dev_id) printk ("sun3_82586-interrupt: irq %d for unknown device.\n",irq); return IRQ_NONE; } - p = (struct priv *) dev->priv; + p = netdev_priv(dev); if(debuglevel > 1) printk("I"); @@ -753,7 +757,7 @@ static void sun3_82586_rcv_int(struct net_device *dev) unsigned short totlen; struct sk_buff *skb; struct rbd_struct *rbd; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); if(debuglevel > 0) printk("R"); @@ -871,7 +875,7 @@ static void sun3_82586_rcv_int(struct net_device *dev) static void sun3_82586_rnr_int(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); p->stats.rx_errors++; @@ -895,7 +899,7 @@ static void sun3_82586_rnr_int(struct net_device *dev) static void sun3_82586_xmt_int(struct net_device *dev) { int status; - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); if(debuglevel > 0) printk("X"); @@ -945,7 +949,7 @@ static void sun3_82586_xmt_int(struct net_device *dev) static void startrecv586(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); WAIT_4_SCB_CMD(); WAIT_4_SCB_CMD_RUC(); @@ -957,7 +961,7 @@ static void startrecv586(struct net_device *dev) static void sun3_82586_timeout(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); #ifndef NO_NOPCOMMANDS if(p->scb->cus & CU_ACTIVE) /* COMMAND-UNIT active? */ { @@ -999,7 +1003,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) #ifndef NO_NOPCOMMANDS int next_nop; #endif - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); if(skb->len > XMIT_BUFF_SIZE) { @@ -1108,7 +1112,7 @@ static int sun3_82586_send_packet(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *sun3_82586_get_stats(struct net_device *dev) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); unsigned short crc,aln,rsc,ovrn; crc = swab16(p->scb->crc_errs); /* get error-statistic from the ni82586 */ @@ -1171,7 +1175,7 @@ void cleanup_module(void) */ void sun3_82586_dump(struct net_device *dev,void *ptr) { - struct priv *p = (struct priv *) dev->priv; + struct priv *p = netdev_priv(dev); struct dump_cmd_struct *dump_cmd = (struct dump_cmd_struct *) ptr; int i; diff --git a/drivers/net/sun3lance.c b/drivers/net/sun3lance.c index 359452a06c67d7160e444ee3ab893afec2747f6d..4bb8f72c65cceb3f4e20d20229c299ebca33abf0 100644 --- a/drivers/net/sun3lance.c +++ b/drivers/net/sun3lance.c @@ -303,7 +303,6 @@ static int __init lance_probe( struct net_device *dev) static int did_version; volatile unsigned short *ioaddr_probe; unsigned short tmp1, tmp2; - DECLARE_MAC_BUF(mac); #ifdef CONFIG_SUN3 ioaddr = (unsigned long)ioremap(LANCE_OBIO, PAGE_SIZE); @@ -379,7 +378,7 @@ static int __init lance_probe( struct net_device *dev) MEM->init.hwaddr[4] = dev->dev_addr[5]; MEM->init.hwaddr[5] = dev->dev_addr[4]; - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); MEM->init.mode = 0x0000; MEM->init.filter[0] = 0x00000000; @@ -824,12 +823,10 @@ static int lance_rx( struct net_device *dev ) #if 0 if (lance_debug >= 3) { u_char *data = PKTBUF_ADDR(head); - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2) printk("%s: RX pkt %d type 0x%04x" - " from %s to %s", + " from %pM to %pM", dev->name, lp->new_tx, ((u_short *)data)[6], - print_mac(mac, &data[6]), print_mac(mac2, data)); + &data[6], data); printk(" data %02x %02x %02x %02x %02x %02x %02x %02x " "len %d at %08x\n", @@ -852,7 +849,6 @@ static int lance_rx( struct net_device *dev ) skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/sunbmac.c b/drivers/net/sunbmac.c index 018d0fca9422bc2760c835b6f9a9de46670da7e1..7f69c7f176c457f7d6d46f58fda37ab7363c4b3a 100644 --- a/drivers/net/sunbmac.c +++ b/drivers/net/sunbmac.c @@ -878,7 +878,6 @@ static void bigmac_rx(struct bigmac *bp) /* No checksums done by the BigMAC ;-( */ skb->protocol = eth_type_trans(skb, bp->dev); netif_rx(skb); - bp->dev->last_rx = jiffies; bp->enet_stats.rx_packets++; bp->enet_stats.rx_bytes += len; next: @@ -917,7 +916,7 @@ static irqreturn_t bigmac_interrupt(int irq, void *dev_id) static int bigmac_open(struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); int ret; ret = request_irq(dev->irq, &bigmac_interrupt, IRQF_SHARED, dev->name, bp); @@ -934,7 +933,7 @@ static int bigmac_open(struct net_device *dev) static int bigmac_close(struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); del_timer(&bp->bigmac_timer); bp->timer_state = asleep; @@ -948,7 +947,7 @@ static int bigmac_close(struct net_device *dev) static void bigmac_tx_timeout(struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); bigmac_init_hw(bp, 0); netif_wake_queue(dev); @@ -957,7 +956,7 @@ static void bigmac_tx_timeout(struct net_device *dev) /* Put a packet on the wire. */ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); int len, entry; u32 mapping; @@ -990,7 +989,7 @@ static int bigmac_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *bigmac_get_stats(struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); bigmac_get_counters(bp, bp->bregs); return &bp->enet_stats; @@ -998,7 +997,7 @@ static struct net_device_stats *bigmac_get_stats(struct net_device *dev) static void bigmac_set_multicast(struct net_device *dev) { - struct bigmac *bp = (struct bigmac *) dev->priv; + struct bigmac *bp = netdev_priv(dev); void __iomem *bregs = bp->bregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; @@ -1061,7 +1060,7 @@ static void bigmac_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *i static u32 bigmac_get_link(struct net_device *dev) { - struct bigmac *bp = dev->priv; + struct bigmac *bp = netdev_priv(dev); spin_lock_irq(&bp->lock); bp->sw_bmsr = bigmac_tcvr_read(bp, bp->tregs, BIGMAC_BMSR); @@ -1081,7 +1080,6 @@ static int __devinit bigmac_ether_init(struct of_device *op, static int version_printed; struct net_device *dev; u8 bsizes, bsizes_more; - DECLARE_MAC_BUF(mac); struct bigmac *bp; int i; @@ -1212,8 +1210,8 @@ static int __devinit bigmac_ether_init(struct of_device *op, dev_set_drvdata(&bp->bigmac_op->dev, bp); - printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: BigMAC 100baseT Ethernet %pM\n", + dev->name, dev->dev_addr); return 0; @@ -1235,7 +1233,7 @@ fail_and_cleanup: bp->bmac_block, bp->bblock_dvma); - /* This also frees the co-located 'dev->priv' */ + /* This also frees the co-located private data */ free_netdev(dev); return -ENODEV; } diff --git a/drivers/net/sundance.c b/drivers/net/sundance.c index f860ea150395871357639e4f457834fbf67408c1..698893b92003d0f5022a86ba43f12f3a0fa064ce 100644 --- a/drivers/net/sundance.c +++ b/drivers/net/sundance.c @@ -468,7 +468,6 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, int bar = 1; #endif int phy, phy_end, phy_idx = 0; - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -547,9 +546,9 @@ static int __devinit sundance_probe1 (struct pci_dev *pdev, if (i) goto err_out_unmap_rx; - printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", dev->name, pci_id_tbl[chip_idx].name, ioaddr, - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); np->phys[0] = 1; /* Default setting */ np->mii_preamble_required++; @@ -1351,7 +1350,6 @@ static void rx_poll(unsigned long data) skb->protocol = eth_type_trans(skb, dev); /* Note: checksum -> skb->ip_summed = CHECKSUM_UNNECESSARY; */ netif_rx(skb); - dev->last_rx = jiffies; } entry = (entry + 1) % RX_RING_SIZE; received++; diff --git a/drivers/net/sungem.c b/drivers/net/sungem.c index fed7eba65ead6268e292eddc66c73905d8e263c7..8a7460412482d5165f24f74c3a13a1c7d4df333a 100644 --- a/drivers/net/sungem.c +++ b/drivers/net/sungem.c @@ -164,7 +164,7 @@ static u16 __phy_read(struct gem *gp, int phy_addr, int reg) static inline int _phy_read(struct net_device *dev, int mii_id, int reg) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); return __phy_read(gp, mii_id, reg); } @@ -197,7 +197,7 @@ static void __phy_write(struct gem *gp, int phy_addr, int reg, u16 val) static inline void _phy_write(struct net_device *dev, int mii_id, int reg, int val) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); __phy_write(gp, mii_id, reg, val & 0xffff); } @@ -863,7 +863,6 @@ static int gem_rx(struct gem *gp, int work_to_do) gp->net_stats.rx_packets++; gp->net_stats.rx_bytes += len; - gp->dev->last_rx = jiffies; next: entry = NEXT_RX(entry); @@ -922,7 +921,7 @@ static int gem_poll(struct napi_struct *napi, int budget) gp->status = readl(gp->regs + GREG_STAT); } while (gp->status & GREG_STAT_NAPI); - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); gem_enable_ints(gp); spin_unlock_irqrestore(&gp->lock, flags); @@ -933,7 +932,7 @@ static int gem_poll(struct napi_struct *napi, int budget) static irqreturn_t gem_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned long flags; /* Swallow interrupts when shutting the chip down, though @@ -945,7 +944,7 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id) spin_lock_irqsave(&gp->lock, flags); - if (netif_rx_schedule_prep(dev, &gp->napi)) { + if (netif_rx_schedule_prep(&gp->napi)) { u32 gem_status = readl(gp->regs + GREG_STAT); if (gem_status == 0) { @@ -955,7 +954,7 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id) } gp->status = gem_status; gem_disable_ints(gp); - __netif_rx_schedule(dev, &gp->napi); + __netif_rx_schedule(&gp->napi); } spin_unlock_irqrestore(&gp->lock, flags); @@ -979,7 +978,7 @@ static void gem_poll_controller(struct net_device *dev) static void gem_tx_timeout(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); printk(KERN_ERR "%s: transmit timed out, resetting\n", dev->name); if (!gp->running) { @@ -1018,7 +1017,7 @@ static __inline__ int gem_intme(int entry) static int gem_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); int entry; u64 ctrl; unsigned long flags; @@ -2208,7 +2207,7 @@ static void gem_stop_phy(struct gem *gp, int wol) static int gem_do_start(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&gp->lock, flags); @@ -2255,7 +2254,7 @@ static int gem_do_start(struct net_device *dev) static void gem_do_stop(struct net_device *dev, int wol) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned long flags; spin_lock_irqsave(&gp->lock, flags); @@ -2330,7 +2329,7 @@ static void gem_reset_task(struct work_struct *work) static int gem_open(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); int rc = 0; mutex_lock(&gp->pm_mutex); @@ -2349,7 +2348,7 @@ static int gem_open(struct net_device *dev) static int gem_close(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); mutex_lock(&gp->pm_mutex); @@ -2368,7 +2367,7 @@ static int gem_close(struct net_device *dev) static int gem_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned long flags; mutex_lock(&gp->pm_mutex); @@ -2432,7 +2431,7 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state) static int gem_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned long flags; printk(KERN_INFO "%s: resuming\n", dev->name); @@ -2506,7 +2505,7 @@ static int gem_resume(struct pci_dev *pdev) static struct net_device_stats *gem_get_stats(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); struct net_device_stats *stats = &gp->net_stats; spin_lock_irq(&gp->lock); @@ -2542,7 +2541,7 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) static int gem_set_mac_address(struct net_device *dev, void *addr) { struct sockaddr *macaddr = (struct sockaddr *) addr; - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unsigned char *e = &dev->dev_addr[0]; if (!is_valid_ether_addr(macaddr->sa_data)) @@ -2570,7 +2569,7 @@ static int gem_set_mac_address(struct net_device *dev, void *addr) static void gem_set_multicast(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); u32 rxcfg, rxcfg_new; int limit = 10000; @@ -2619,7 +2618,7 @@ static void gem_set_multicast(struct net_device *dev) static int gem_change_mtu(struct net_device *dev, int new_mtu) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU) return -EINVAL; @@ -2650,7 +2649,7 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu) static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); strcpy(info->driver, DRV_NAME); strcpy(info->version, DRV_VERSION); @@ -2659,7 +2658,7 @@ static void gem_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) { @@ -2720,7 +2719,7 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); /* Verify the settings we care about. */ if (cmd->autoneg != AUTONEG_ENABLE && @@ -2751,7 +2750,7 @@ static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int gem_nway_reset(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); if (!gp->want_autoneg) return -EINVAL; @@ -2768,13 +2767,13 @@ static int gem_nway_reset(struct net_device *dev) static u32 gem_get_msglevel(struct net_device *dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); return gp->msg_enable; } static void gem_set_msglevel(struct net_device *dev, u32 value) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); gp->msg_enable = value; } @@ -2786,7 +2785,7 @@ static void gem_set_msglevel(struct net_device *dev, u32 value) static void gem_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); /* Add more when I understand how to program the chip */ if (gp->has_wol) { @@ -2800,7 +2799,7 @@ static void gem_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) static int gem_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); if (!gp->has_wol) return -EOPNOTSUPP; @@ -2822,7 +2821,7 @@ static const struct ethtool_ops gem_ethtool_ops = { static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); struct mii_ioctl_data *data = if_mii(ifr); int rc = -EOPNOTSUPP; unsigned long flags; @@ -2954,7 +2953,7 @@ static void gem_remove_one(struct pci_dev *pdev) struct net_device *dev = pci_get_drvdata(pdev); if (dev) { - struct gem *gp = dev->priv; + struct gem *gp = netdev_priv(dev); unregister_netdev(dev); @@ -2998,7 +2997,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev, struct net_device *dev; struct gem *gp; int err, pci_using_dac; - DECLARE_MAC_BUF(mac); if (gem_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -3058,7 +3056,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, } SET_NETDEV_DEV(dev, &pdev->dev); - gp = dev->priv; + gp = netdev_priv(dev); err = pci_request_regions(pdev, DRV_NAME); if (err) { @@ -3182,9 +3180,8 @@ static int __devinit gem_init_one(struct pci_dev *pdev, goto err_out_free_consistent; } - printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet " - "%s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Sun GEM (PCI) 10/100/1000BaseT Ethernet %pM\n", + dev->name, dev->dev_addr); if (gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) diff --git a/drivers/net/sunhme.c b/drivers/net/sunhme.c index f1ebeb5f65b2f56d6ba3a6ee9da9eb579cfb16d1..b22d3355fb45f7157328824390315fcf9013d372 100644 --- a/drivers/net/sunhme.c +++ b/drivers/net/sunhme.c @@ -2072,7 +2072,6 @@ static void happy_meal_rx(struct happy_meal *hp, struct net_device *dev) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; hp->net_stats.rx_packets++; hp->net_stats.rx_bytes += len; next: @@ -2131,7 +2130,7 @@ static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie) for (i = 0; i < 4; i++) { struct net_device *dev = qp->happy_meals[i]; - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); u32 happy_status = hme_read32(hp, hp->gregs + GREG_STAT); HMD(("quattro_interrupt: status=%08x ", happy_status)); @@ -2176,7 +2175,7 @@ static irqreturn_t quattro_sbus_interrupt(int irq, void *cookie) static int happy_meal_open(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); int res; HMD(("happy_meal_open: ")); @@ -2208,7 +2207,7 @@ static int happy_meal_open(struct net_device *dev) static int happy_meal_close(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); spin_lock_irq(&hp->happy_lock); happy_meal_stop(hp, hp->gregs); @@ -2237,7 +2236,7 @@ static int happy_meal_close(struct net_device *dev) static void happy_meal_tx_timeout(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); printk (KERN_ERR "%s: transmit timed out, resetting\n", dev->name); tx_dump_log(); @@ -2255,7 +2254,7 @@ static void happy_meal_tx_timeout(struct net_device *dev) static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); int entry; u32 tx_flags; @@ -2344,7 +2343,7 @@ static int happy_meal_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *happy_meal_get_stats(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); spin_lock_irq(&hp->happy_lock); happy_meal_get_counters(hp, hp->bigmacregs); @@ -2355,7 +2354,7 @@ static struct net_device_stats *happy_meal_get_stats(struct net_device *dev) static void happy_meal_set_multicast(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); void __iomem *bregs = hp->bigmacregs; struct dev_mc_list *dmi = dev->mc_list; char *addrs; @@ -2401,7 +2400,7 @@ static void happy_meal_set_multicast(struct net_device *dev) /* Ethtool support... */ static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); cmd->supported = (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | @@ -2446,7 +2445,7 @@ static int hme_get_settings(struct net_device *dev, struct ethtool_cmd *cmd) static int hme_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); /* Verify the settings we care about. */ if (cmd->autoneg != AUTONEG_ENABLE && @@ -2470,7 +2469,7 @@ static int hme_set_settings(struct net_device *dev, struct ethtool_cmd *cmd) static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); strcpy(info->driver, "sunhme"); strcpy(info->version, "2.02"); @@ -2492,7 +2491,7 @@ static void hme_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info static u32 hme_get_link(struct net_device *dev) { - struct happy_meal *hp = dev->priv; + struct happy_meal *hp = netdev_priv(dev); spin_lock_irq(&hp->happy_lock); hp->sw_bmcr = happy_meal_tcvr_read(hp, hp->tcvregs, MII_BMCR); @@ -2617,7 +2616,6 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) struct net_device *dev; int i, qfe_slot = -1; int err = -ENODEV; - DECLARE_MAC_BUF(mac); if (is_qfe) { qp = quattro_sbus_find(op); @@ -2797,7 +2795,7 @@ static int __devinit happy_meal_sbus_probe_one(struct of_device *op, int is_qfe) printk(KERN_INFO "%s: HAPPY MEAL (SBUS) 10/100baseT Ethernet ", dev->name); - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); return 0; @@ -2932,7 +2930,6 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, int i, qfe_slot = -1; char prom_name[64]; int err; - DECLARE_MAC_BUF(mac); /* Now make sure pci_dev cookie is there. */ #ifdef CONFIG_SPARC @@ -2973,7 +2970,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, dev->base_addr = (long) pdev; - hp = (struct happy_meal *)dev->priv; + hp = netdev_priv(dev); memset(hp, 0, sizeof(*hp)); hp->happy_dev = pdev; @@ -3141,7 +3138,7 @@ static int __devinit happy_meal_pci_probe(struct pci_dev *pdev, printk(KERN_INFO "%s: HAPPY MEAL (PCI/CheerIO) 10/100BaseT Ethernet ", dev->name); - printk("%s\n", print_mac(mac, dev->dev_addr)); + printk("%pM\n", dev->dev_addr); return 0; diff --git a/drivers/net/sunlance.c b/drivers/net/sunlance.c index 704301a5a7ffed417655912cbc0a61552d55bf71..281373281756e381d24125eb841f903eda0a8286 100644 --- a/drivers/net/sunlance.c +++ b/drivers/net/sunlance.c @@ -555,7 +555,6 @@ static void lance_rx_dvma(struct net_device *dev) len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } @@ -726,7 +725,6 @@ static void lance_rx_pio(struct net_device *dev) lance_piocopy_to_skb(skb, &(ib->rx_buf[entry][0]), len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; } @@ -1321,7 +1319,6 @@ static int __devinit sparc_lance_probe_one(struct of_device *op, static unsigned version_printed; struct lance_private *lp; struct net_device *dev; - DECLARE_MAC_BUF(mac); int i; dev = alloc_etherdev(sizeof(struct lance_private) + 8); @@ -1491,8 +1488,8 @@ no_link_test: dev_set_drvdata(&op->dev, lp); - printk(KERN_INFO "%s: LANCE %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: LANCE %pM\n", + dev->name, dev->dev_addr); return 0; diff --git a/drivers/net/sunqe.c b/drivers/net/sunqe.c index f63644744ff9dafafb56eb746d3acf5018b3733f..6e8f377355fe8a6e98ab28676c0fa09671bc501a 100644 --- a/drivers/net/sunqe.c +++ b/drivers/net/sunqe.c @@ -446,7 +446,6 @@ static void qe_rx(struct sunqe *qep) len); skb->protocol = eth_type_trans(skb, qep->dev); netif_rx(skb); - qep->dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += len; } @@ -513,7 +512,7 @@ static irqreturn_t qec_interrupt(int irq, void *dev_id) static int qe_open(struct net_device *dev) { - struct sunqe *qep = (struct sunqe *) dev->priv; + struct sunqe *qep = netdev_priv(dev); qep->mconfig = (MREGS_MCONFIG_TXENAB | MREGS_MCONFIG_RXENAB | @@ -523,7 +522,7 @@ static int qe_open(struct net_device *dev) static int qe_close(struct net_device *dev) { - struct sunqe *qep = (struct sunqe *) dev->priv; + struct sunqe *qep = netdev_priv(dev); qe_stop(qep); return 0; @@ -549,7 +548,7 @@ static void qe_tx_reclaim(struct sunqe *qep) static void qe_tx_timeout(struct net_device *dev) { - struct sunqe *qep = (struct sunqe *) dev->priv; + struct sunqe *qep = netdev_priv(dev); int tx_full; spin_lock_irq(&qep->lock); @@ -575,7 +574,7 @@ out: /* Get a packet queued to go onto the wire. */ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct sunqe *qep = (struct sunqe *) dev->priv; + struct sunqe *qep = netdev_priv(dev); struct sunqe_buffers *qbufs = qep->buffers; __u32 txbuf_dvma, qbufs_dvma = qep->buffers_dvma; unsigned char *txbuf; @@ -627,7 +626,7 @@ static int qe_start_xmit(struct sk_buff *skb, struct net_device *dev) static void qe_set_multicast(struct net_device *dev) { - struct sunqe *qep = (struct sunqe *) dev->priv; + struct sunqe *qep = netdev_priv(dev); struct dev_mc_list *dmi = dev->mc_list; u8 new_mconfig = qep->mconfig; char *addrs; @@ -693,7 +692,7 @@ static void qe_set_multicast(struct net_device *dev) static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { const struct linux_prom_registers *regs; - struct sunqe *qep = dev->priv; + struct sunqe *qep = netdev_priv(dev); struct of_device *op; strcpy(info->driver, "sunqe"); @@ -708,7 +707,7 @@ static void qe_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) static u32 qe_get_link(struct net_device *dev) { - struct sunqe *qep = dev->priv; + struct sunqe *qep = netdev_priv(dev); void __iomem *mregs = qep->mregs; u8 phyconfig; diff --git a/drivers/net/sunvnet.c b/drivers/net/sunvnet.c index a720065553df48645f121c86b11bcf8bf5c61e52..233f1cda36e52b425e952ba823a02bfe11c1ab81 100644 --- a/drivers/net/sunvnet.c +++ b/drivers/net/sunvnet.c @@ -1149,7 +1149,6 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev, struct vnet *vp; const u64 *rmac; int len, i, err, switch_port; - DECLARE_MAC_BUF(mac); print_version(); @@ -1214,8 +1213,8 @@ static int __devinit vnet_port_probe(struct vio_dev *vdev, dev_set_drvdata(&vdev->dev, port); - printk(KERN_INFO "%s: PORT ( remote-mac %s%s )\n", - vp->dev->name, print_mac(mac, port->raddr), + printk(KERN_INFO "%s: PORT ( remote-mac %pM%s )\n", + vp->dev->name, port->raddr, switch_port ? " switch-port" : ""); vio_port_up(&port->vio); diff --git a/drivers/net/tc35815.c b/drivers/net/tc35815.c index df20cafff7dd3a5da1926740e5cb14193f5b81f9..bcd0e60cbda98984c9383f55cc4df671510d33a1 100644 --- a/drivers/net/tc35815.c +++ b/drivers/net/tc35815.c @@ -37,6 +37,7 @@ static const char *version = "tc35815.c:v" DRV_VERSION "\n"; #include #include #include +#include #include #include #include @@ -236,7 +237,7 @@ struct tc35815_regs { #define Rx_Halted 0x00008000 /* Rx Halted */ #define Rx_Good 0x00004000 /* Rx Good */ #define Rx_RxPar 0x00002000 /* Rx Parity Error */ - /* 0x00001000 not use */ +#define Rx_TypePkt 0x00001000 /* Rx Type Packet */ #define Rx_LongErr 0x00000800 /* Rx Long Error */ #define Rx_Over 0x00000400 /* Rx Overflow */ #define Rx_CRCErr 0x00000200 /* Rx CRC Error */ @@ -244,8 +245,9 @@ struct tc35815_regs { #define Rx_10Stat 0x00000080 /* Rx 10Mbps Status */ #define Rx_IntRx 0x00000040 /* Rx Interrupt */ #define Rx_CtlRecd 0x00000020 /* Rx Control Receive */ +#define Rx_InLenErr 0x00000010 /* Rx In Range Frame Length Error */ -#define Rx_Stat_Mask 0x0000EFC0 /* Rx All Status Mask */ +#define Rx_Stat_Mask 0x0000FFF0 /* Rx All Status Mask */ /* Int_En bit asign -------------------------------------------------------- */ #define Int_NRAbtEn 0x00000800 /* 1:Non-recoverable Abort Enable */ @@ -340,7 +342,7 @@ struct BDesc { Tx_En) /* maybe 0x7b01 */ #endif #define RX_CTL_CMD (Rx_EnGood | Rx_EnRxPar | Rx_EnLongErr | Rx_EnOver \ - | Rx_EnCRCErr | Rx_EnAlign | Rx_RxEn) /* maybe 0x6f01 */ + | Rx_EnCRCErr | Rx_EnAlign | Rx_StripCRC | Rx_RxEn) /* maybe 0x6f11 */ #define INT_EN_CMD (Int_NRAbtEn | \ Int_DmParErrEn | Int_DParDEn | Int_DParErrEn | \ Int_SSysErrEn | Int_RMasAbtEn | Int_RTargAbtEn | \ @@ -372,9 +374,11 @@ struct BDesc { #if RX_CTL_CMD & Rx_LongEn #define RX_BUF_SIZE PAGE_SIZE #elif RX_CTL_CMD & Rx_StripCRC -#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 4 + 2, 32) /* +2: reserve */ +#define RX_BUF_SIZE \ + L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + NET_IP_ALIGN) #else -#define RX_BUF_SIZE ALIGN(ETH_FRAME_LEN + 2, 32) /* +2: reserve */ +#define RX_BUF_SIZE \ + L1_CACHE_ALIGN(ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN + NET_IP_ALIGN) #endif #endif /* TC35815_USE_PACKEDBUFFER */ #define RX_FD_RESERVE (2 / 2) /* max 2 BD per RxFD */ @@ -865,7 +869,6 @@ static int __devinit tc35815_init_one(struct pci_dev *pdev, struct net_device *dev; struct tc35815_local *lp; int rc; - DECLARE_MAC_BUF(mac); static int printed_version; if (!printed_version++) { @@ -942,11 +945,11 @@ static int __devinit tc35815_init_one(struct pci_dev *pdev, goto err_out; memcpy(dev->perm_addr, dev->dev_addr, dev->addr_len); - printk(KERN_INFO "%s: %s at 0x%lx, %s, IRQ %d\n", + printk(KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n", dev->name, chip_info[ent->driver_data].name, dev->base_addr, - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); rc = tc_mii_init(dev); @@ -1288,12 +1291,9 @@ panic_queues(struct net_device *dev) static void print_eth(const u8 *add) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "print_eth(%p)\n", add); - printk(KERN_DEBUG " %s =>", print_mac(mac, add + 6)); - printk(KERN_CONT " %s : %02x%02x\n", - print_mac(mac, add), add[12], add[13]); + printk(KERN_DEBUG " %pM => %pM : %02x%02x\n", + add + 6, add, add[12], add[13]); } static int tc35815_tx_full(struct net_device *dev) @@ -1609,8 +1609,8 @@ static irqreturn_t tc35815_interrupt(int irq, void *dev_id) if (!(dmactl & DMA_IntMask)) { /* disable interrupts */ tc_writel(dmactl | DMA_IntMask, &tr->DMA_Ctl); - if (netif_rx_schedule_prep(dev, &lp->napi)) - __netif_rx_schedule(dev, &lp->napi); + if (netif_rx_schedule_prep(&lp->napi)) + __netif_rx_schedule(&lp->napi); else { printk(KERN_ERR "%s: interrupt taken in poll\n", dev->name); @@ -1669,7 +1669,7 @@ tc35815_rx(struct net_device *dev) struct RxFD *next_rfd; #endif #if (RX_CTL_CMD & Rx_StripCRC) == 0 - pkt_len -= 4; + pkt_len -= ETH_FCS_LEN; #endif if (netif_msg_rx_status(lp)) @@ -1688,14 +1688,14 @@ tc35815_rx(struct net_device *dev) #endif #ifdef TC35815_USE_PACKEDBUFFER BUG_ON(bd_count > 2); - skb = dev_alloc_skb(pkt_len + 2); /* +2: for reserve */ + skb = dev_alloc_skb(pkt_len + NET_IP_ALIGN); if (skb == NULL) { printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name); dev->stats.rx_dropped++; break; } - skb_reserve(skb, 2); /* 16 bit alignment */ + skb_reserve(skb, NET_IP_ALIGN); data = skb_put(skb, pkt_len); @@ -1747,8 +1747,9 @@ tc35815_rx(struct net_device *dev) pci_unmap_single(lp->pci_dev, lp->rx_skbs[cur_bd].skb_dma, RX_BUF_SIZE, PCI_DMA_FROMDEVICE); - if (!HAVE_DMA_RXALIGN(lp)) - memmove(skb->data, skb->data - 2, pkt_len); + if (!HAVE_DMA_RXALIGN(lp) && NET_IP_ALIGN) + memmove(skb->data, skb->data - NET_IP_ALIGN, + pkt_len); data = skb_put(skb, pkt_len); #endif /* TC35815_USE_PACKEDBUFFER */ if (netif_msg_pktdata(lp)) @@ -1760,7 +1761,6 @@ tc35815_rx(struct net_device *dev) #else netif_rx(skb); #endif - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } else { @@ -1919,7 +1919,7 @@ static int tc35815_poll(struct napi_struct *napi, int budget) spin_unlock(&lp->lock); if (received < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); /* enable interrupts */ tc_writel(tc_readl(&tr->DMA_Ctl) & ~DMA_IntMask, &tr->DMA_Ctl); } @@ -2153,13 +2153,12 @@ static void tc35815_set_cam_entry(struct net_device *dev, int index, unsigned ch int cam_index = index * 6; u32 cam_data; u32 saved_addr; - DECLARE_MAC_BUF(mac); saved_addr = tc_readl(&tr->CAM_Adr); if (netif_msg_hw(lp)) - printk(KERN_DEBUG "%s: CAM %d: %s\n", - dev->name, index, print_mac(mac, addr)); + printk(KERN_DEBUG "%s: CAM %d: %pM\n", + dev->name, index, addr); if (index & 1) { /* read modify write */ tc_writel(cam_index - 2, &tr->CAM_Adr); diff --git a/drivers/net/tehuti.c b/drivers/net/tehuti.c index 91f9054a1d9522b5f60f0347d6264beeba8d4c60..a10a83a11d9fb07a02d10d2f8b1fad1f13c26a71 100644 --- a/drivers/net/tehuti.c +++ b/drivers/net/tehuti.c @@ -251,7 +251,7 @@ static void bdx_isr_extra(struct bdx_priv *priv, u32 isr) static irqreturn_t bdx_isr_napi(int irq, void *dev) { struct net_device *ndev = dev; - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); u32 isr; ENTER; @@ -265,8 +265,8 @@ static irqreturn_t bdx_isr_napi(int irq, void *dev) bdx_isr_extra(priv, isr); if (isr & (IR_RX_DESC_0 | IR_TX_FREE_0)) { - if (likely(netif_rx_schedule_prep(ndev, &priv->napi))) { - __netif_rx_schedule(ndev, &priv->napi); + if (likely(netif_rx_schedule_prep(&priv->napi))) { + __netif_rx_schedule(&priv->napi); RET(IRQ_HANDLED); } else { /* NOTE: we get here if intr has slipped into window @@ -289,7 +289,6 @@ static irqreturn_t bdx_isr_napi(int irq, void *dev) static int bdx_poll(struct napi_struct *napi, int budget) { struct bdx_priv *priv = container_of(napi, struct bdx_priv, napi); - struct net_device *dev = priv->ndev; int work_done; ENTER; @@ -303,7 +302,7 @@ static int bdx_poll(struct napi_struct *napi, int budget) * device lock and allow waiting tasks (eg rmmod) to advance) */ priv->napi_stop = 0; - netif_rx_complete(dev, napi); + netif_rx_complete(napi); bdx_enable_interrupts(priv); } return work_done; @@ -559,7 +558,7 @@ static int bdx_close(struct net_device *ndev) struct bdx_priv *priv = NULL; ENTER; - priv = ndev->priv; + priv = netdev_priv(ndev); napi_disable(&priv->napi); @@ -588,7 +587,7 @@ static int bdx_open(struct net_device *ndev) int rc; ENTER; - priv = ndev->priv; + priv = netdev_priv(ndev); bdx_reset(priv); if (netif_running(ndev)) netif_stop_queue(priv->ndev); @@ -633,7 +632,7 @@ static int bdx_range_check(struct bdx_priv *priv, u32 offset) static int bdx_ioctl_priv(struct net_device *ndev, struct ifreq *ifr, int cmd) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); u32 data[3]; int error; @@ -698,7 +697,7 @@ static int bdx_ioctl(struct net_device *ndev, struct ifreq *ifr, int cmd) */ static void __bdx_vlan_rx_vid(struct net_device *ndev, uint16_t vid, int enable) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); u32 reg, bit, val; ENTER; @@ -748,7 +747,7 @@ static void bdx_vlan_rx_kill_vid(struct net_device *ndev, unsigned short vid) static void bdx_vlan_rx_register(struct net_device *ndev, struct vlan_group *grp) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); ENTER; DBG("device='%s', group='%p'\n", ndev->name, grp); @@ -787,7 +786,7 @@ static int bdx_change_mtu(struct net_device *ndev, int new_mtu) static void bdx_setmulti(struct net_device *ndev) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); u32 rxf_val = GMAC_RX_FILTER_AM | GMAC_RX_FILTER_AB | GMAC_RX_FILTER_OSEN; @@ -847,7 +846,7 @@ static void bdx_setmulti(struct net_device *ndev) static int bdx_set_mac(struct net_device *ndev, void *p) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); struct sockaddr *addr = p; ENTER; @@ -929,7 +928,7 @@ static void bdx_update_stats(struct bdx_priv *priv) static struct net_device_stats *bdx_get_stats(struct net_device *ndev) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); struct net_device_stats *net_stat = &priv->net_stats; return net_stat; } @@ -1237,7 +1236,6 @@ static int bdx_rx_receive(struct bdx_priv *priv, struct rxd_fifo *f, int budget) ENTER; max_done = budget; - priv->ndev->last_rx = jiffies; f->m.wptr = READ_REG(priv, f->m.reg_WPTR) & TXF_WPTR_WR_PTR; size = f->m.wptr - f->m.rptr; @@ -1624,7 +1622,7 @@ static inline int bdx_tx_space(struct bdx_priv *priv) */ static int bdx_tx_transmit(struct sk_buff *skb, struct net_device *ndev) { - struct bdx_priv *priv = ndev->priv; + struct bdx_priv *priv = netdev_priv(ndev); struct txd_fifo *f = &priv->txd_fifo0; int txd_checksum = 7; /* full checksum */ int txd_lgsnd = 0; @@ -1886,6 +1884,21 @@ static void bdx_tx_push_desc_safe(struct bdx_priv *priv, void *data, int size) RET(); } +static const struct net_device_ops bdx_netdev_ops = { + .ndo_open = bdx_open, + .ndo_stop = bdx_close, + .ndo_start_xmit = bdx_tx_transmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = bdx_ioctl, + .ndo_set_multicast_list = bdx_setmulti, + .ndo_get_stats = bdx_get_stats, + .ndo_change_mtu = bdx_change_mtu, + .ndo_set_mac_address = bdx_set_mac, + .ndo_vlan_rx_register = bdx_vlan_rx_register, + .ndo_vlan_rx_add_vid = bdx_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = bdx_vlan_rx_kill_vid, +}; + /** * bdx_probe - Device Initialization Routine * @pdev: PCI device information struct @@ -1995,18 +2008,8 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) goto err_out_iomap; } - ndev->open = bdx_open; - ndev->stop = bdx_close; - ndev->hard_start_xmit = bdx_tx_transmit; - ndev->do_ioctl = bdx_ioctl; - ndev->set_multicast_list = bdx_setmulti; - ndev->get_stats = bdx_get_stats; - ndev->change_mtu = bdx_change_mtu; - ndev->set_mac_address = bdx_set_mac; + ndev->netdev_ops = &bdx_netdev_ops; ndev->tx_queue_len = BDX_NDEV_TXQ_LEN; - ndev->vlan_rx_register = bdx_vlan_rx_register; - ndev->vlan_rx_add_vid = bdx_vlan_rx_add_vid; - ndev->vlan_rx_kill_vid = bdx_vlan_rx_kill_vid; bdx_ethtool_ops(ndev); /* ethtool interface */ @@ -2027,7 +2030,7 @@ bdx_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ndev->features |= NETIF_F_HIGHDMA; /************** priv ****************/ - priv = nic->priv[port] = ndev->priv; + priv = nic->priv[port] = netdev_priv(ndev); memset(priv, 0, sizeof(struct bdx_priv)); priv->pBdxRegs = nic->regs + port * 0x8000; @@ -2150,7 +2153,7 @@ static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) { u32 rdintcm; u32 tdintcm; - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); rdintcm = priv->rdintcm; tdintcm = priv->tdintcm; @@ -2181,7 +2184,7 @@ static int bdx_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd) static void bdx_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo) { - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); strlcat(drvinfo->driver, BDX_DRV_NAME, sizeof(drvinfo->driver)); strlcat(drvinfo->version, BDX_DRV_VERSION, sizeof(drvinfo->version)); @@ -2223,7 +2226,7 @@ bdx_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal) { u32 rdintcm; u32 tdintcm; - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); rdintcm = priv->rdintcm; tdintcm = priv->tdintcm; @@ -2252,7 +2255,7 @@ bdx_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *ecoal) { u32 rdintcm; u32 tdintcm; - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); int rx_coal; int tx_coal; int rx_max_coal; @@ -2310,7 +2313,7 @@ static inline int bdx_tx_fifo_size_to_packets(int tx_size) static void bdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); /*max_pending - the maximum-sized FIFO we allow */ ring->rx_max_pending = bdx_rx_fifo_size_to_packets(3); @@ -2327,7 +2330,7 @@ bdx_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) static int bdx_set_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring) { - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); int rx_size = 0; int tx_size = 0; @@ -2388,7 +2391,7 @@ static void bdx_get_strings(struct net_device *netdev, u32 stringset, u8 *data) */ static int bdx_get_stats_count(struct net_device *netdev) { - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); BDX_ASSERT(ARRAY_SIZE(bdx_stat_names) != sizeof(struct bdx_stats) / sizeof(u64)); return ((priv->stats_flag) ? ARRAY_SIZE(bdx_stat_names) : 0); @@ -2403,7 +2406,7 @@ static int bdx_get_stats_count(struct net_device *netdev) static void bdx_get_ethtool_stats(struct net_device *netdev, struct ethtool_stats *stats, u64 *data) { - struct bdx_priv *priv = netdev->priv; + struct bdx_priv *priv = netdev_priv(netdev); if (priv->stats_flag) { diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index eb9f8f3638e1923bf664f55bdbf4de9e32621a47..04ae1e86aeaa4c8b05ad6de192034f43e439420d 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -54,20 +54,21 @@ #include #endif +#define BAR_0 0 +#define BAR_2 2 + #if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE) #define TG3_VLAN_TAG_USED 1 #else #define TG3_VLAN_TAG_USED 0 #endif -#define TG3_TSO_SUPPORT 1 - #include "tg3.h" #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "3.94" -#define DRV_MODULE_RELDATE "August 14, 2008" +#define DRV_MODULE_VERSION "3.97" +#define DRV_MODULE_RELDATE "December 10, 2008" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -129,6 +130,8 @@ /* minimum number of free TX descriptors required to wake up TX process */ #define TG3_TX_WAKEUP_THRESH(tp) ((tp)->tx_pending / 4) +#define TG3_RAW_IP_ALIGN 2 + /* number of ETHTOOL_GSTATS u64's */ #define TG3_NUM_STATS (sizeof(struct tg3_ethtool_stats)/sizeof(u64)) @@ -205,7 +208,13 @@ static struct pci_device_id tg3_pci_tbl[] = { {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5723)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5761E)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761S)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_5761SE)}, {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5785)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57780)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57760)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57790)}, + {PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, TG3PCI_DEVICE_TIGON3_57720)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9DXX)}, {PCI_DEVICE(PCI_VENDOR_ID_SYSKONNECT, PCI_DEVICE_ID_SYSKONNECT_9MXX)}, {PCI_DEVICE(PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000)}, @@ -872,13 +881,48 @@ static int tg3_mdio_reset(struct mii_bus *bp) return 0; } -static void tg3_mdio_config(struct tg3 *tp) +static void tg3_mdio_config_5785(struct tg3 *tp) { u32 val; + struct phy_device *phydev; - if (tp->mdio_bus->phy_map[PHY_ADDR]->interface != - PHY_INTERFACE_MODE_RGMII) + phydev = tp->mdio_bus->phy_map[PHY_ADDR]; + switch (phydev->drv->phy_id & phydev->drv->phy_id_mask) { + case TG3_PHY_ID_BCM50610: + val = MAC_PHYCFG2_50610_LED_MODES; + break; + case TG3_PHY_ID_BCMAC131: + val = MAC_PHYCFG2_AC131_LED_MODES; + break; + case TG3_PHY_ID_RTL8211C: + val = MAC_PHYCFG2_RTL8211C_LED_MODES; + break; + case TG3_PHY_ID_RTL8201E: + val = MAC_PHYCFG2_RTL8201E_LED_MODES; + break; + default: return; + } + + if (phydev->interface != PHY_INTERFACE_MODE_RGMII) { + tw32(MAC_PHYCFG2, val); + + val = tr32(MAC_PHYCFG1); + val &= ~MAC_PHYCFG1_RGMII_INT; + tw32(MAC_PHYCFG1, val); + + return; + } + + if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) + val |= MAC_PHYCFG2_EMODE_MASK_MASK | + MAC_PHYCFG2_FMODE_MASK_MASK | + MAC_PHYCFG2_GMODE_MASK_MASK | + MAC_PHYCFG2_ACT_MASK_MASK | + MAC_PHYCFG2_QUAL_MASK_MASK | + MAC_PHYCFG2_INBAND_ENABLE; + + tw32(MAC_PHYCFG2, val); val = tr32(MAC_PHYCFG1) & ~(MAC_PHYCFG1_RGMII_EXT_RX_DEC | MAC_PHYCFG1_RGMII_SND_STAT_EN); @@ -890,11 +934,6 @@ static void tg3_mdio_config(struct tg3 *tp) } tw32(MAC_PHYCFG1, val | MAC_PHYCFG1_RGMII_INT | MAC_PHYCFG1_TXC_DRV); - val = tr32(MAC_PHYCFG2) & ~(MAC_PHYCFG2_INBAND_ENABLE); - if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) - val |= MAC_PHYCFG2_INBAND_ENABLE; - tw32(MAC_PHYCFG2, val); - val = tr32(MAC_EXT_RGMII_MODE); val &= ~(MAC_RGMII_MODE_RX_INT_B | MAC_RGMII_MODE_RX_QUALITY | @@ -903,7 +942,7 @@ static void tg3_mdio_config(struct tg3 *tp) MAC_RGMII_MODE_TX_ENABLE | MAC_RGMII_MODE_TX_LOWPWR | MAC_RGMII_MODE_TX_RESET); - if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) { + if (!(tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE)) { if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) val |= MAC_RGMII_MODE_RX_INT_B | MAC_RGMII_MODE_RX_QUALITY | @@ -929,8 +968,9 @@ static void tg3_mdio_start(struct tg3 *tp) tw32_f(MAC_MI_MODE, tp->mi_mode); udelay(80); - if (tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) - tg3_mdio_config(tp); + if ((tp->tg3_flags3 & TG3_FLG3_MDIOBUS_INITED) && + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tg3_mdio_config_5785(tp); } static void tg3_mdio_stop(struct tg3 *tp) @@ -984,29 +1024,44 @@ static int tg3_mdio_init(struct tg3 *tp) if (i) { printk(KERN_WARNING "%s: mdiobus_reg failed (0x%x)\n", tp->dev->name, i); + mdiobus_free(tp->mdio_bus); return i; } - tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; - phydev = tp->mdio_bus->phy_map[PHY_ADDR]; - switch (phydev->phy_id) { + if (!phydev || !phydev->drv) { + printk(KERN_WARNING "%s: No PHY devices\n", tp->dev->name); + mdiobus_unregister(tp->mdio_bus); + mdiobus_free(tp->mdio_bus); + return -ENODEV; + } + + switch (phydev->drv->phy_id & phydev->drv->phy_id_mask) { + case TG3_PHY_ID_BCM57780: + phydev->interface = PHY_INTERFACE_MODE_GMII; + break; case TG3_PHY_ID_BCM50610: - phydev->interface = PHY_INTERFACE_MODE_RGMII; if (tp->tg3_flags3 & TG3_FLG3_RGMII_STD_IBND_DISABLE) phydev->dev_flags |= PHY_BRCM_STD_IBND_DISABLE; if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_RX_EN) phydev->dev_flags |= PHY_BRCM_EXT_IBND_RX_ENABLE; if (tp->tg3_flags3 & TG3_FLG3_RGMII_EXT_IBND_TX_EN) phydev->dev_flags |= PHY_BRCM_EXT_IBND_TX_ENABLE; + /* fallthru */ + case TG3_PHY_ID_RTL8211C: + phydev->interface = PHY_INTERFACE_MODE_RGMII; break; + case TG3_PHY_ID_RTL8201E: case TG3_PHY_ID_BCMAC131: phydev->interface = PHY_INTERFACE_MODE_MII; break; } - tg3_mdio_config(tp); + tp->tg3_flags3 |= TG3_FLG3_MDIOBUS_INITED; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + tg3_mdio_config_5785(tp); return 0; } @@ -1130,9 +1185,9 @@ static void tg3_link_report(struct tg3 *tp) printk(KERN_INFO PFX "%s: Flow control is %s for TX and %s for RX.\n", tp->dev->name, - (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) ? + (tp->link_config.active_flowctrl & FLOW_CTRL_TX) ? "on" : "off", - (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) ? + (tp->link_config.active_flowctrl & FLOW_CTRL_RX) ? "on" : "off"); tg3_ump_link_report(tp); } @@ -1142,11 +1197,11 @@ static u16 tg3_advert_flowctrl_1000T(u8 flow_ctrl) { u16 miireg; - if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + if ((flow_ctrl & FLOW_CTRL_TX) && (flow_ctrl & FLOW_CTRL_RX)) miireg = ADVERTISE_PAUSE_CAP; - else if (flow_ctrl & TG3_FLOW_CTRL_TX) + else if (flow_ctrl & FLOW_CTRL_TX) miireg = ADVERTISE_PAUSE_ASYM; - else if (flow_ctrl & TG3_FLOW_CTRL_RX) + else if (flow_ctrl & FLOW_CTRL_RX) miireg = ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM; else miireg = 0; @@ -1158,11 +1213,11 @@ static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) { u16 miireg; - if ((flow_ctrl & TG3_FLOW_CTRL_TX) && (flow_ctrl & TG3_FLOW_CTRL_RX)) + if ((flow_ctrl & FLOW_CTRL_TX) && (flow_ctrl & FLOW_CTRL_RX)) miireg = ADVERTISE_1000XPAUSE; - else if (flow_ctrl & TG3_FLOW_CTRL_TX) + else if (flow_ctrl & FLOW_CTRL_TX) miireg = ADVERTISE_1000XPSE_ASYM; - else if (flow_ctrl & TG3_FLOW_CTRL_RX) + else if (flow_ctrl & FLOW_CTRL_RX) miireg = ADVERTISE_1000XPAUSE | ADVERTISE_1000XPSE_ASYM; else miireg = 0; @@ -1170,28 +1225,6 @@ static u16 tg3_advert_flowctrl_1000X(u8 flow_ctrl) return miireg; } -static u8 tg3_resolve_flowctrl_1000T(u16 lcladv, u16 rmtadv) -{ - u8 cap = 0; - - if (lcladv & ADVERTISE_PAUSE_CAP) { - if (lcladv & ADVERTISE_PAUSE_ASYM) { - if (rmtadv & LPA_PAUSE_CAP) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - else if (rmtadv & LPA_PAUSE_ASYM) - cap = TG3_FLOW_CTRL_RX; - } else { - if (rmtadv & LPA_PAUSE_CAP) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; - } - } else if (lcladv & ADVERTISE_PAUSE_ASYM) { - if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) - cap = TG3_FLOW_CTRL_TX; - } - - return cap; -} - static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) { u8 cap = 0; @@ -1199,16 +1232,16 @@ static u8 tg3_resolve_flowctrl_1000X(u16 lcladv, u16 rmtadv) if (lcladv & ADVERTISE_1000XPAUSE) { if (lcladv & ADVERTISE_1000XPSE_ASYM) { if (rmtadv & LPA_1000XPAUSE) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + cap = FLOW_CTRL_TX | FLOW_CTRL_RX; else if (rmtadv & LPA_1000XPAUSE_ASYM) - cap = TG3_FLOW_CTRL_RX; + cap = FLOW_CTRL_RX; } else { if (rmtadv & LPA_1000XPAUSE) - cap = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + cap = FLOW_CTRL_TX | FLOW_CTRL_RX; } } else if (lcladv & ADVERTISE_1000XPSE_ASYM) { if ((rmtadv & LPA_1000XPAUSE) && (rmtadv & LPA_1000XPAUSE_ASYM)) - cap = TG3_FLOW_CTRL_TX; + cap = FLOW_CTRL_TX; } return cap; @@ -1231,13 +1264,13 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) flowctrl = tg3_resolve_flowctrl_1000X(lcladv, rmtadv); else - flowctrl = tg3_resolve_flowctrl_1000T(lcladv, rmtadv); + flowctrl = mii_resolve_flowctrl_fdx(lcladv, rmtadv); } else flowctrl = tp->link_config.flowctrl; tp->link_config.active_flowctrl = flowctrl; - if (flowctrl & TG3_FLOW_CTRL_RX) + if (flowctrl & FLOW_CTRL_RX) tp->rx_mode |= RX_MODE_FLOW_CTRL_ENABLE; else tp->rx_mode &= ~RX_MODE_FLOW_CTRL_ENABLE; @@ -1245,7 +1278,7 @@ static void tg3_setup_flow_control(struct tg3 *tp, u32 lcladv, u32 rmtadv) if (old_rx_mode != tp->rx_mode) tw32_f(MAC_RX_MODE, tp->rx_mode); - if (flowctrl & TG3_FLOW_CTRL_TX) + if (flowctrl & FLOW_CTRL_TX) tp->tx_mode |= TX_MODE_FLOW_CTRL_ENABLE; else tp->tx_mode &= ~TX_MODE_FLOW_CTRL_ENABLE; @@ -1299,6 +1332,15 @@ static void tg3_adjust_link(struct net_device *dev) udelay(40); } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + if (phydev->speed == SPEED_10) + tw32(MAC_MI_STAT, + MAC_MI_STAT_10MBPS_MODE | + MAC_MI_STAT_LNKSTAT_ATTN_ENAB); + else + tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); + } + if (phydev->speed == SPEED_1000 && phydev->duplex == DUPLEX_HALF) tw32(MAC_TX_LENGTHS, ((2 << TX_LENGTHS_IPG_CRS_SHIFT) | @@ -1339,25 +1381,37 @@ static int tg3_phy_init(struct tg3 *tp) phydev = tp->mdio_bus->phy_map[PHY_ADDR]; /* Attach the MAC to the PHY. */ - phydev = phy_connect(tp->dev, phydev->dev.bus_id, tg3_adjust_link, + phydev = phy_connect(tp->dev, dev_name(&phydev->dev), tg3_adjust_link, phydev->dev_flags, phydev->interface); if (IS_ERR(phydev)) { printk(KERN_ERR "%s: Could not attach to PHY\n", tp->dev->name); return PTR_ERR(phydev); } - tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED; - /* Mask with MAC supported features. */ - phydev->supported &= (PHY_GBIT_FEATURES | - SUPPORTED_Pause | - SUPPORTED_Asym_Pause); + switch (phydev->interface) { + case PHY_INTERFACE_MODE_GMII: + case PHY_INTERFACE_MODE_RGMII: + if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY)) { + phydev->supported &= (PHY_GBIT_FEATURES | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + } + /* fallthru */ + case PHY_INTERFACE_MODE_MII: + phydev->supported &= (PHY_BASIC_FEATURES | + SUPPORTED_Pause | + SUPPORTED_Asym_Pause); + break; + default: + phy_disconnect(tp->mdio_bus->phy_map[PHY_ADDR]); + return -EINVAL; + } - phydev->advertising = phydev->supported; + tp->tg3_flags3 |= TG3_FLG3_PHY_CONNECTED; - printk(KERN_INFO - "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n", - tp->dev->name, phydev->drv->name, phydev->dev.bus_id); + phydev->advertising = phydev->supported; return 0; } @@ -1406,6 +1460,34 @@ static void tg3_phydsp_write(struct tg3 *tp, u32 reg, u32 val) tg3_writephy(tp, MII_TG3_DSP_RW_PORT, val); } +static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable) +{ + u32 reg; + + if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS)) + return; + + reg = MII_TG3_MISC_SHDW_WREN | + MII_TG3_MISC_SHDW_SCR5_SEL | + MII_TG3_MISC_SHDW_SCR5_LPED | + MII_TG3_MISC_SHDW_SCR5_DLPTLM | + MII_TG3_MISC_SHDW_SCR5_SDTL | + MII_TG3_MISC_SHDW_SCR5_C125OE; + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 || !enable) + reg |= MII_TG3_MISC_SHDW_SCR5_DLLAPD; + + tg3_writephy(tp, MII_TG3_MISC_SHDW, reg); + + + reg = MII_TG3_MISC_SHDW_WREN | + MII_TG3_MISC_SHDW_APD_SEL | + MII_TG3_MISC_SHDW_APD_WKTM_84MS; + if (enable) + reg |= MII_TG3_MISC_SHDW_APD_ENABLE; + + tg3_writephy(tp, MII_TG3_MISC_SHDW, reg); +} + static void tg3_phy_toggle_automdix(struct tg3 *tp, int enable) { u32 phy; @@ -1737,7 +1819,8 @@ static int tg3_phy_reset(struct tg3 *tp) tw32(TG3_CPMU_CTRL, cpmuctrl); } - if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) { + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX || + GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) { u32 val; val = tr32(TG3_CPMU_LSPD_1000MB_CLK); @@ -1747,16 +1830,15 @@ static int tg3_phy_reset(struct tg3 *tp) udelay(40); tw32_f(TG3_CPMU_LSPD_1000MB_CLK, val); } - - /* Disable GPHY autopowerdown. */ - tg3_writephy(tp, MII_TG3_MISC_SHDW, - MII_TG3_MISC_SHDW_WREN | - MII_TG3_MISC_SHDW_APD_SEL | - MII_TG3_MISC_SHDW_APD_WKTM_84MS); } tg3_phy_apply_otp(tp); + if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD) + tg3_phy_toggle_apd(tp, true); + else + tg3_phy_toggle_apd(tp, false); + out: if (tp->tg3_flags2 & TG3_FLG2_PHY_ADC_BUG) { tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); @@ -1961,7 +2043,7 @@ static int tg3_halt_cpu(struct tg3 *, u32); static int tg3_nvram_lock(struct tg3 *); static void tg3_nvram_unlock(struct tg3 *); -static void tg3_power_down_phy(struct tg3 *tp) +static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power) { u32 val; @@ -1984,10 +2066,15 @@ static void tg3_power_down_phy(struct tg3 *tp) tw32_f(GRC_MISC_CFG, val | GRC_MISC_CFG_EPHY_IDDQ); udelay(40); return; - } else if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { + } else if (do_low_power) { tg3_writephy(tp, MII_TG3_EXT_CTRL, MII_TG3_EXT_CTRL_FORCE_LED_OFF); - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x01b2); + + tg3_writephy(tp, MII_TG3_AUX_CTRL, + MII_TG3_AUXCTL_SHDWSEL_PWRCTL | + MII_TG3_AUXCTL_PCTL_100TX_LPWR | + MII_TG3_AUXCTL_PCTL_SPR_ISOLATE | + MII_TG3_AUXCTL_PCTL_VREG_11V); } /* The PHY should not be powered down on some chips because @@ -1999,7 +2086,8 @@ static void tg3_power_down_phy(struct tg3 *tp) (tp->tg3_flags2 & TG3_FLG2_MII_SERDES))) return; - if (tp->tg3_flags3 & TG3_FLG3_5761_5784_AX_FIXES) { + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX || + GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5761_AX) { val = tr32(TG3_CPMU_LSPD_1000MB_CLK); val &= ~CPMU_LSPD_1000MB_MACCLK_MASK; val |= CPMU_LSPD_1000MB_MACCLK_12_5; @@ -2009,9 +2097,47 @@ static void tg3_power_down_phy(struct tg3 *tp) tg3_writephy(tp, MII_BMCR, BMCR_PDOWN); } +/* tp->lock is held. */ +static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1) +{ + u32 addr_high, addr_low; + int i; + + addr_high = ((tp->dev->dev_addr[0] << 8) | + tp->dev->dev_addr[1]); + addr_low = ((tp->dev->dev_addr[2] << 24) | + (tp->dev->dev_addr[3] << 16) | + (tp->dev->dev_addr[4] << 8) | + (tp->dev->dev_addr[5] << 0)); + for (i = 0; i < 4; i++) { + if (i == 1 && skip_mac_1) + continue; + tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high); + tw32(MAC_ADDR_0_LOW + (i * 8), addr_low); + } + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { + for (i = 0; i < 12; i++) { + tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high); + tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low); + } + } + + addr_high = (tp->dev->dev_addr[0] + + tp->dev->dev_addr[1] + + tp->dev->dev_addr[2] + + tp->dev->dev_addr[3] + + tp->dev->dev_addr[4] + + tp->dev->dev_addr[5]) & + TX_BACKOFF_SEED_MASK; + tw32(MAC_TX_BACKOFF_SEED, addr_high); +} + static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) { u32 misc_host_ctrl; + bool device_should_wake, do_low_power; /* Make sure register accesses (indirect or otherwise) * will function correctly. @@ -2041,15 +2167,34 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tp->dev->name, state); return -EINVAL; } + + /* Restore the CLKREQ setting. */ + if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) { + u16 lnkctl; + + pci_read_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_LNKCTL, + &lnkctl); + lnkctl |= PCI_EXP_LNKCTL_CLKREQ_EN; + pci_write_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_LNKCTL, + lnkctl); + } + misc_host_ctrl = tr32(TG3PCI_MISC_HOST_CTRL); tw32(TG3PCI_MISC_HOST_CTRL, misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT); + device_should_wake = pci_pme_capable(tp->pdev, state) && + device_may_wakeup(&tp->pdev->dev) && + (tp->tg3_flags & TG3_FLAG_WOL_ENABLE); + if (tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB) { + do_low_power = false; if ((tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) && !tp->link_config.phy_is_low_power) { struct phy_device *phydev; - u32 advertising; + u32 phyid, advertising; phydev = tp->mdio_bus->phy_map[PHY_ADDR]; @@ -2066,7 +2211,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) ADVERTISED_10baseT_Half; if ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || - (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) { + device_should_wake) { if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) advertising |= ADVERTISED_100baseT_Half | @@ -2079,8 +2224,19 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) phydev->advertising = advertising; phy_start_aneg(phydev); + + phyid = phydev->drv->phy_id & phydev->drv->phy_id_mask; + if (phyid != TG3_PHY_ID_BCMAC131) { + phyid &= TG3_PHY_OUI_MASK; + if (phyid == TG3_PHY_OUI_1 && + phyid == TG3_PHY_OUI_2 && + phyid == TG3_PHY_OUI_3) + do_low_power = true; + } } } else { + do_low_power = true; + if (tp->link_config.phy_is_low_power == 0) { tp->link_config.phy_is_low_power = 1; tp->link_config.orig_speed = tp->link_config.speed; @@ -2096,6 +2252,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } } + __tg3_set_mac_addr(tp, 0); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { u32 val; @@ -2118,11 +2276,11 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) WOL_DRV_WOL | WOL_SET_MAGIC_PKT); - if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) { + if (device_should_wake) { u32 mac_mode; if (!(tp->tg3_flags2 & TG3_FLG2_PHY_SERDES)) { - if (!(tp->tg3_flags3 & TG3_FLG3_USE_PHYLIB)) { + if (do_low_power) { tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); udelay(40); } @@ -2150,9 +2308,12 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) if (!(tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) tw32(MAC_LED_CTRL, tp->led_ctrl); - if (pci_pme_capable(tp->pdev, state) && - (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) - mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; + mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; + if (((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + !(tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) && + ((tp->tg3_flags & TG3_FLAG_ENABLE_ASF) || + (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))) + mac_mode |= MAC_MODE_KEEP_FRAME_IN_WOL; if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { mac_mode |= tp->mac_mode & @@ -2224,10 +2385,9 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) } } - if (!(tp->tg3_flags & TG3_FLAG_WOL_ENABLE) && - !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) && - !(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)) - tg3_power_down_phy(tp); + if (!(device_should_wake) && + !(tp->tg3_flags & TG3_FLAG_ENABLE_ASF)) + tg3_power_down_phy(tp, do_low_power); tg3_frob_aux_power(tp); @@ -2250,7 +2410,7 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state) tg3_write_sig_post_reset(tp, RESET_KIND_SHUTDOWN); - if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) + if (device_should_wake) pci_enable_wake(tp->pdev, state, true); /* Finally, set the new power state. */ @@ -2789,6 +2949,24 @@ relink: NIC_SRAM_FIRMWARE_MBOX_MAGIC2); } + /* Prevent send BD corruption. */ + if (tp->tg3_flags3 & TG3_FLG3_CLKREQ_BUG) { + u16 oldlnkctl, newlnkctl; + + pci_read_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_LNKCTL, + &oldlnkctl); + if (tp->link_config.active_speed == SPEED_100 || + tp->link_config.active_speed == SPEED_10) + newlnkctl = oldlnkctl & ~PCI_EXP_LNKCTL_CLKREQ_EN; + else + newlnkctl = oldlnkctl | PCI_EXP_LNKCTL_CLKREQ_EN; + if (newlnkctl != oldlnkctl) + pci_write_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_LNKCTL, + newlnkctl); + } + if (current_link_up != netif_carrier_ok(tp->dev)) { if (current_link_up) netif_carrier_on(tp->dev); @@ -3765,8 +3943,7 @@ static int tg3_setup_phy(struct tg3 *tp, int force_reset) err = tg3_setup_copper_phy(tp, force_reset); } - if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5784_A1) { + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) { u32 val, scale; val = tr32(TG3_CPMU_CLCK_STAT) & CPMU_CLCK_STAT_MAC_CLCK_MASK; @@ -4100,12 +4277,15 @@ static int tg3_rx(struct tg3 *tp, int budget) goto next_pkt; } - len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - 4; /* omit crc */ + len = ((desc->idx_len & RXD_LEN_MASK) >> RXD_LEN_SHIFT) - + ETH_FCS_LEN; if (len > RX_COPY_THRESHOLD - && tp->rx_offset == 2 - /* rx_offset != 2 iff this is a 5701 card running - * in PCI-X mode [see tg3_get_invariants()] */ + && tp->rx_offset == NET_IP_ALIGN + /* rx_offset will likely not equal NET_IP_ALIGN + * if this is a 5701 card running in PCI-X mode + * [see tg3_get_invariants()] + */ ) { int skb_size; @@ -4125,11 +4305,12 @@ static int tg3_rx(struct tg3 *tp, int budget) tg3_recycle_rx(tp, opaque_key, desc_idx, *post_ptr); - copy_skb = netdev_alloc_skb(tp->dev, len + 2); + copy_skb = netdev_alloc_skb(tp->dev, + len + TG3_RAW_IP_ALIGN); if (copy_skb == NULL) goto drop_it_no_recycle; - skb_reserve(copy_skb, 2); + skb_reserve(copy_skb, TG3_RAW_IP_ALIGN); skb_put(copy_skb, len); pci_dma_sync_single_for_cpu(tp->pdev, dma_addr, len, PCI_DMA_FROMDEVICE); skb_copy_from_linear_data(skb, copy_skb->data, len); @@ -4157,7 +4338,6 @@ static int tg3_rx(struct tg3 *tp, int budget) #endif netif_receive_skb(skb); - tp->dev->last_rx = jiffies; received++; budget--; @@ -4271,7 +4451,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) sblk->status &= ~SD_STATUS_UPDATED; if (likely(!tg3_has_work(tp))) { - netif_rx_complete(tp->dev, napi); + netif_rx_complete(napi); tg3_restart_ints(tp); break; } @@ -4281,7 +4461,7 @@ static int tg3_poll(struct napi_struct *napi, int budget) tx_recovery: /* work_done is guaranteed to be less than budget. */ - netif_rx_complete(tp->dev, napi); + netif_rx_complete(napi); schedule_work(&tp->reset_task); return work_done; } @@ -4330,7 +4510,7 @@ static irqreturn_t tg3_msi_1shot(int irq, void *dev_id) prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); if (likely(!tg3_irq_sync(tp))) - netif_rx_schedule(dev, &tp->napi); + netif_rx_schedule(&tp->napi); return IRQ_HANDLED; } @@ -4355,7 +4535,7 @@ static irqreturn_t tg3_msi(int irq, void *dev_id) */ tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (likely(!tg3_irq_sync(tp))) - netif_rx_schedule(dev, &tp->napi); + netif_rx_schedule(&tp->napi); return IRQ_RETVAL(1); } @@ -4397,7 +4577,7 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) sblk->status &= ~SD_STATUS_UPDATED; if (likely(tg3_has_work(tp))) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); - netif_rx_schedule(dev, &tp->napi); + netif_rx_schedule(&tp->napi); } else { /* No work, shared interrupt perhaps? re-enable * interrupts, and flush that PCI write @@ -4443,7 +4623,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); if (tg3_irq_sync(tp)) goto out; - if (netif_rx_schedule_prep(dev, &tp->napi)) { + if (netif_rx_schedule_prep(&tp->napi)) { prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]); /* Update last_tag to mark that this status has been * seen. Because interrupt may be shared, we may be @@ -4451,7 +4631,7 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) * if tg3_poll() is not scheduled. */ tp->last_tag = sblk->status_tag; - __netif_rx_schedule(dev, &tp->napi); + __netif_rx_schedule(&tp->napi); } out: return IRQ_RETVAL(handled); @@ -5557,6 +5737,13 @@ static void tg3_ape_driver_state_change(struct tg3 *tp, int kind) event = APE_EVENT_STATUS_STATE_START; break; case RESET_KIND_SHUTDOWN: + /* With the interface we are currently using, + * APE does not track driver state. Wiping + * out the HOST SEGMENT SIGNATURE forces + * the APE to assume OS absent status. + */ + tg3_ape_write32(tp, TG3_APE_HOST_SEG_SIG, 0x0); + event = APE_EVENT_STATUS_STATE_UNLOAD; break; case RESET_KIND_SUSPEND: @@ -5721,17 +5908,19 @@ static void tg3_restore_pci_state(struct tg3 *tp) pci_write_config_word(tp->pdev, PCI_COMMAND, tp->pci_cmd); - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) - pcie_set_readrq(tp->pdev, 4096); - else { - pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, - tp->pci_cacheline_sz); - pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER, - tp->pci_lat_timer); + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) { + if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) + pcie_set_readrq(tp->pdev, 4096); + else { + pci_write_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, + tp->pci_cacheline_sz); + pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER, + tp->pci_lat_timer); + } } /* Make sure PCI-X relaxed ordering bit is clear. */ - if (tp->pcix_cap) { + if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { u16 pcix_cmd; pci_read_config_word(tp->pdev, tp->pcix_cap + PCI_X_CMD, @@ -5788,11 +5977,7 @@ static int tg3_chip_reset(struct tg3 *tp) tg3_save_pci_state(tp); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + (tp->tg3_flags3 & TG3_FLG3_5755_PLUS)) tw32(GRC_FASTBOOT_PC, 0); /* @@ -5871,7 +6056,7 @@ static int tg3_chip_reset(struct tg3 *tp) udelay(120); - if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { + if ((tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) && tp->pcie_cap) { if (tp->pci_chip_rev_id == CHIPREV_ID_5750_A0) { int i; u32 cfg_val; @@ -5884,8 +6069,23 @@ static int tg3_chip_reset(struct tg3 *tp) pci_write_config_dword(tp->pdev, 0xc4, cfg_val | (1 << 15)); } - /* Set PCIE max payload size and clear error status. */ - pci_write_config_dword(tp->pdev, 0xd8, 0xf5000); + + /* Set PCIE max payload size to 128 bytes and + * clear the "no snoop" and "relaxed ordering" bits. + */ + pci_write_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_DEVCTL, + 0); + + pcie_set_readrq(tp->pdev, 4096); + + /* Clear error status */ + pci_write_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_DEVSTA, + PCI_EXP_DEVSTA_CED | + PCI_EXP_DEVSTA_NFED | + PCI_EXP_DEVSTA_FED | + PCI_EXP_DEVSTA_URD); } tg3_restore_pci_state(tp); @@ -6883,43 +7083,6 @@ static int tg3_load_tso_firmware(struct tg3 *tp) } -/* tp->lock is held. */ -static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1) -{ - u32 addr_high, addr_low; - int i; - - addr_high = ((tp->dev->dev_addr[0] << 8) | - tp->dev->dev_addr[1]); - addr_low = ((tp->dev->dev_addr[2] << 24) | - (tp->dev->dev_addr[3] << 16) | - (tp->dev->dev_addr[4] << 8) | - (tp->dev->dev_addr[5] << 0)); - for (i = 0; i < 4; i++) { - if (i == 1 && skip_mac_1) - continue; - tw32(MAC_ADDR_0_HIGH + (i * 8), addr_high); - tw32(MAC_ADDR_0_LOW + (i * 8), addr_low); - } - - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { - for (i = 0; i < 12; i++) { - tw32(MAC_EXTADDR_0_HIGH + (i * 8), addr_high); - tw32(MAC_EXTADDR_0_LOW + (i * 8), addr_low); - } - } - - addr_high = (tp->dev->dev_addr[0] + - tp->dev->dev_addr[1] + - tp->dev->dev_addr[2] + - tp->dev->dev_addr[3] + - tp->dev->dev_addr[4] + - tp->dev->dev_addr[5]) & - TX_BACKOFF_SEED_MASK; - tw32(MAC_TX_BACKOFF_SEED, addr_high); -} - static int tg3_set_mac_addr(struct net_device *dev, void *p) { struct tg3 *tp = netdev_priv(dev); @@ -7024,8 +7187,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) tg3_write_sig_legacy(tp, RESET_KIND_INIT); - if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5784_A1) { + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5784_AX) { val = tr32(TG3_CPMU_CTRL); val &= ~(CPMU_CTRL_LINK_AWARE_MODE | CPMU_CTRL_LINK_IDLE_MODE); tw32(TG3_CPMU_CTRL, val); @@ -7091,8 +7253,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) return err; if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) { + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) { /* This value is determined during the probe time DMA * engine test, tg3_test_dma. */ @@ -7332,7 +7493,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) RDMAC_MODE_LNGREAD_ENAB); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) rdmac_mode |= RDMAC_MODE_BD_SBD_CRPT_ENAB | RDMAC_MODE_MBUF_RBD_CRPT_ENAB | RDMAC_MODE_MBUF_SBD_CRPT_ENAB; @@ -7354,7 +7516,11 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) rdmac_mode |= RDMAC_MODE_FIFO_LONG_BURST; if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) - rdmac_mode |= (1 << 27); + rdmac_mode |= RDMAC_MODE_IPV4_LSO_EN; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + rdmac_mode |= RDMAC_MODE_IPV6_LSO_EN; /* Receive/send statistics. */ if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { @@ -7501,11 +7667,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) } /* Enable host coalescing bug fix */ - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761) || - (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785)) + if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) val |= WDMAC_MODE_STATUS_TAG_FIX; tw32_f(WDMAC_MODE, val); @@ -7566,10 +7728,7 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) udelay(100); tp->rx_mode = RX_MODE_ENABLE; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) tp->rx_mode |= RX_MODE_IPV6_CSUM_ENABLE; tw32_f(MAC_RX_MODE, tp->rx_mode); @@ -9066,7 +9225,8 @@ static void tg3_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) else wol->supported = 0; wol->wolopts = 0; - if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) + if ((tp->tg3_flags & TG3_FLAG_WOL_ENABLE) && + device_can_wakeup(&tp->pdev->dev)) wol->wolopts = WAKE_MAGIC; memset(&wol->sopass, 0, sizeof(wol->sopass)); } @@ -9116,14 +9276,15 @@ static int tg3_set_tso(struct net_device *dev, u32 value) return -EINVAL; return 0; } - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) { + if ((dev->features & NETIF_F_IPV6_CSUM) && + (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2)) { if (value) { dev->features |= NETIF_F_TSO6; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) dev->features |= NETIF_F_TSO_ECN; } else dev->features &= ~(NETIF_F_TSO6 | NETIF_F_TSO_ECN); @@ -9238,12 +9399,12 @@ static void tg3_get_pauseparam(struct net_device *dev, struct ethtool_pauseparam epause->autoneg = (tp->tg3_flags & TG3_FLAG_PAUSE_AUTONEG) != 0; - if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_RX) + if (tp->link_config.active_flowctrl & FLOW_CTRL_RX) epause->rx_pause = 1; else epause->rx_pause = 0; - if (tp->link_config.active_flowctrl & TG3_FLOW_CTRL_TX) + if (tp->link_config.active_flowctrl & FLOW_CTRL_TX) epause->tx_pause = 1; else epause->tx_pause = 0; @@ -9294,14 +9455,14 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam } } else { if (epause->rx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; + tp->link_config.flowctrl |= FLOW_CTRL_RX; else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; + tp->link_config.flowctrl &= ~FLOW_CTRL_RX; if (epause->tx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; + tp->link_config.flowctrl |= FLOW_CTRL_TX; else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; + tp->link_config.flowctrl &= ~FLOW_CTRL_TX; if (netif_running(dev)) tg3_setup_flow_control(tp, 0, 0); @@ -9321,13 +9482,13 @@ static int tg3_set_pauseparam(struct net_device *dev, struct ethtool_pauseparam else tp->tg3_flags &= ~TG3_FLAG_PAUSE_AUTONEG; if (epause->rx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_RX; + tp->link_config.flowctrl |= FLOW_CTRL_RX; else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_RX; + tp->link_config.flowctrl &= ~FLOW_CTRL_RX; if (epause->tx_pause) - tp->link_config.flowctrl |= TG3_FLOW_CTRL_TX; + tp->link_config.flowctrl |= FLOW_CTRL_TX; else - tp->link_config.flowctrl &= ~TG3_FLOW_CTRL_TX; + tp->link_config.flowctrl &= ~FLOW_CTRL_TX; if (netif_running(dev)) { tg3_halt(tp, RESET_KIND_SHUTDOWN, 1); @@ -9378,11 +9539,7 @@ static int tg3_set_tx_csum(struct net_device *dev, u32 data) return 0; } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) ethtool_op_set_tx_ipv6_csum(dev, data); else ethtool_op_set_tx_csum(dev, data); @@ -9899,18 +10056,13 @@ static int tg3_test_memory(struct tg3 *tp) int err = 0; int i; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) - mem_tbl = mem_tbl_5755; - else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) - mem_tbl = mem_tbl_5906; - else - mem_tbl = mem_tbl_5705; - } else + if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + mem_tbl = mem_tbl_5755; + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + mem_tbl = mem_tbl_5906; + else if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) + mem_tbl = mem_tbl_5705; + else mem_tbl = mem_tbl_570x; for (i = 0; mem_tbl[i].offset != 0xffffffff; i++) { @@ -10110,9 +10262,11 @@ static int tg3_test_loopback(struct tg3 *tp) if (err) return TG3_LOOPBACK_FAILED; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + /* Turn off gphy autopowerdown. */ + if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD) + tg3_phy_toggle_apd(tp, false); + + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { int i; u32 status; @@ -10139,9 +10293,7 @@ static int tg3_test_loopback(struct tg3 *tp) if (tg3_run_loopback(tp, TG3_MAC_LOOPBACK)) err |= TG3_MAC_LOOPBACK_FAILED; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + if (tp->tg3_flags & TG3_FLAG_CPMU_PRESENT) { tw32(TG3_CPMU_CTRL, cpmuctrl); /* Release the mutex */ @@ -10154,6 +10306,10 @@ static int tg3_test_loopback(struct tg3 *tp) err |= TG3_PHY_LOOPBACK_FAILED; } + /* Re-enable gphy autopowerdown. */ + if (tp->tg3_flags3 & TG3_FLG3_PHY_ENABLE_APD) + tg3_phy_toggle_apd(tp, true); + return err; } @@ -10756,6 +10912,102 @@ static void __devinit tg3_get_5906_nvram_info(struct tg3 *tp) tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; } +static void __devinit tg3_get_57780_nvram_info(struct tg3 *tp) +{ + u32 nvcfg1; + + nvcfg1 = tr32(NVRAM_CFG1); + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5787VENDOR_ATMEL_EEPROM_376KHZ: + case FLASH_5787VENDOR_MICRO_EEPROM_376KHZ: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->nvram_pagesize = ATMEL_AT24C512_CHIP_SIZE; + + nvcfg1 &= ~NVRAM_CFG1_COMPAT_BYPASS; + tw32(NVRAM_CFG1, nvcfg1); + return; + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: + case FLASH_57780VENDOR_ATMEL_AT45DB011D: + case FLASH_57780VENDOR_ATMEL_AT45DB011B: + case FLASH_57780VENDOR_ATMEL_AT45DB021D: + case FLASH_57780VENDOR_ATMEL_AT45DB021B: + case FLASH_57780VENDOR_ATMEL_AT45DB041D: + case FLASH_57780VENDOR_ATMEL_AT45DB041B: + tp->nvram_jedecnum = JEDEC_ATMEL; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5752VENDOR_ATMEL_FLASH_BUFFERED: + case FLASH_57780VENDOR_ATMEL_AT45DB011D: + case FLASH_57780VENDOR_ATMEL_AT45DB011B: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + case FLASH_57780VENDOR_ATMEL_AT45DB021D: + case FLASH_57780VENDOR_ATMEL_AT45DB021B: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + case FLASH_57780VENDOR_ATMEL_AT45DB041D: + case FLASH_57780VENDOR_ATMEL_AT45DB041B: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + } + break; + case FLASH_5752VENDOR_ST_M45PE10: + case FLASH_5752VENDOR_ST_M45PE20: + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_jedecnum = JEDEC_ST; + tp->tg3_flags |= TG3_FLAG_NVRAM_BUFFERED; + tp->tg3_flags2 |= TG3_FLG2_FLASH; + + switch (nvcfg1 & NVRAM_CFG1_5752VENDOR_MASK) { + case FLASH_5752VENDOR_ST_M45PE10: + tp->nvram_size = TG3_NVRAM_SIZE_128KB; + break; + case FLASH_5752VENDOR_ST_M45PE20: + tp->nvram_size = TG3_NVRAM_SIZE_256KB; + break; + case FLASH_5752VENDOR_ST_M45PE40: + tp->nvram_size = TG3_NVRAM_SIZE_512KB; + break; + } + break; + default: + return; + } + + switch (nvcfg1 & NVRAM_CFG1_5752PAGE_SIZE_MASK) { + case FLASH_5752PAGE_SIZE_256: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 256; + break; + case FLASH_5752PAGE_SIZE_512: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 512; + break; + case FLASH_5752PAGE_SIZE_1K: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 1024; + break; + case FLASH_5752PAGE_SIZE_2K: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 2048; + break; + case FLASH_5752PAGE_SIZE_4K: + tp->tg3_flags3 |= TG3_FLG3_NO_NVRAM_ADDR_TRANS; + tp->nvram_pagesize = 4096; + break; + case FLASH_5752PAGE_SIZE_264: + tp->nvram_pagesize = 264; + break; + case FLASH_5752PAGE_SIZE_528: + tp->nvram_pagesize = 528; + break; + } +} + /* Chips other than 5700/5701 use the NVRAM for fetching info. */ static void __devinit tg3_nvram_init(struct tg3 *tp) { @@ -10796,6 +11048,8 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) tg3_get_5761_nvram_info(tp); else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tg3_get_5906_nvram_info(tp); + else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + tg3_get_57780_nvram_info(tp); else tg3_get_nvram_info(tp); @@ -11116,12 +11370,8 @@ static int tg3_nvram_write_block_buffered(struct tg3 *tp, u32 offset, u32 len, if (i == (len - 4)) nvram_cmd |= NVRAM_CMD_LAST; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5755) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5787) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5784) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5761) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) && + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5752 && + !(tp->tg3_flags3 & TG3_FLG3_5755_PLUS) && (tp->nvram_jedecnum == JEDEC_ST) && (nvram_cmd & NVRAM_CMD_FIRST)) { @@ -11296,10 +11546,9 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (val & VCPU_CFGSHDW_ASPM_DBNC) tp->tg3_flags |= TG3_FLAG_ASPM_WORKAROUND; if ((val & VCPU_CFGSHDW_WOL_ENABLE) && - (val & VCPU_CFGSHDW_WOL_MAGPKT) && - device_may_wakeup(&tp->pdev->dev)) + (val & VCPU_CFGSHDW_WOL_MAGPKT)) tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; - return; + goto done; } tg3_read_mem(tp, NIC_SRAM_DATA_SIG, &val); @@ -11421,15 +11670,17 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) tp->tg3_flags2 |= TG3_FLG2_ASF_NEW_HANDSHAKE; } - if (nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) + + if ((nic_cfg & NIC_SRAM_DATA_CFG_APE_ENABLE) && + (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) tp->tg3_flags3 |= TG3_FLG3_ENABLE_APE; + if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES && !(nic_cfg & NIC_SRAM_DATA_CFG_FIBER_WOL)) tp->tg3_flags &= ~TG3_FLAG_WOL_CAP; if ((tp->tg3_flags & TG3_FLAG_WOL_CAP) && - (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE) && - device_may_wakeup(&tp->pdev->dev)) + (nic_cfg & NIC_SRAM_DATA_CFG_WOL_ENABLE)) tp->tg3_flags |= TG3_FLAG_WOL_ENABLE; if (cfg2 & (1 << 17)) @@ -11440,6 +11691,11 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (cfg2 & (1 << 18)) tp->tg3_flags2 |= TG3_FLG2_SERDES_PREEMPHASIS; + if (((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && + GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX)) && + (cfg2 & NIC_SRAM_DATA_CFG_2_APD_EN)) + tp->tg3_flags3 |= TG3_FLG3_PHY_ENABLE_APD; + if (tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS) { u32 cfg3; @@ -11455,6 +11711,10 @@ static void __devinit tg3_get_eeprom_hw_cfg(struct tg3 *tp) if (cfg4 & NIC_SRAM_RGMII_EXT_IBND_TX_EN) tp->tg3_flags3 |= TG3_FLG3_RGMII_EXT_IBND_TX_EN; } +done: + device_init_wakeup(&tp->pdev->dev, tp->tg3_flags & TG3_FLAG_WOL_CAP); + device_set_wakeup_enable(&tp->pdev->dev, + tp->tg3_flags & TG3_FLAG_WOL_ENABLE); } static int __devinit tg3_issue_otp_command(struct tg3 *tp, u32 cmd) @@ -11751,6 +12011,51 @@ static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset) return 1; } +static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val) +{ + u32 offset, major, minor, build; + + tp->fw_ver[0] = 's'; + tp->fw_ver[1] = 'b'; + tp->fw_ver[2] = '\0'; + + if ((val & TG3_EEPROM_SB_FORMAT_MASK) != TG3_EEPROM_SB_FORMAT_1) + return; + + switch (val & TG3_EEPROM_SB_REVISION_MASK) { + case TG3_EEPROM_SB_REVISION_0: + offset = TG3_EEPROM_SB_F1R0_EDH_OFF; + break; + case TG3_EEPROM_SB_REVISION_2: + offset = TG3_EEPROM_SB_F1R2_EDH_OFF; + break; + case TG3_EEPROM_SB_REVISION_3: + offset = TG3_EEPROM_SB_F1R3_EDH_OFF; + break; + default: + return; + } + + if (tg3_nvram_read_swab(tp, offset, &val)) + return; + + build = (val & TG3_EEPROM_SB_EDH_BLD_MASK) >> + TG3_EEPROM_SB_EDH_BLD_SHFT; + major = (val & TG3_EEPROM_SB_EDH_MAJ_MASK) >> + TG3_EEPROM_SB_EDH_MAJ_SHFT; + minor = val & TG3_EEPROM_SB_EDH_MIN_MASK; + + if (minor > 99 || build > 26) + return; + + snprintf(&tp->fw_ver[2], 30, " v%d.%02d", major, minor); + + if (build > 0) { + tp->fw_ver[8] = 'a' + build - 1; + tp->fw_ver[9] = '\0'; + } +} + static void __devinit tg3_read_fw_ver(struct tg3 *tp) { u32 val, offset, start; @@ -11760,8 +12065,12 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp) if (tg3_nvram_read_swab(tp, 0, &val)) return; - if (val != TG3_EEPROM_MAGIC) + if (val != TG3_EEPROM_MAGIC) { + if ((val & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW) + tg3_read_sb_ver(tp, val); + return; + } if (tg3_nvram_read_swab(tp, 0xc, &offset) || tg3_nvram_read_swab(tp, 0x4, &start)) @@ -11849,11 +12158,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) { }, }; u32 misc_ctrl_reg; - u32 cacheline_sz_reg; u32 pci_state_reg, grc_misc_cfg; u32 val; u16 pci_cmd; - int err, pcie_cap; + int err; /* Force memory write invalidate off. If we leave it on, * then on 5700_BX chips we have to enable a workaround. @@ -11882,7 +12190,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_read_config_dword(tp->pdev, TG3PCI_PRODID_ASICREV, &prod_id_asic_rev); - tp->pci_chip_rev_id = prod_id_asic_rev & PROD_ID_ASIC_REV_MASK; + tp->pci_chip_rev_id = prod_id_asic_rev; } /* Wrong chip ID in 5752 A0. This code can be removed later @@ -12019,26 +12327,23 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl); - pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ, - &cacheline_sz_reg); - - tp->pci_cacheline_sz = (cacheline_sz_reg >> 0) & 0xff; - tp->pci_lat_timer = (cacheline_sz_reg >> 8) & 0xff; - tp->pci_hdr_type = (cacheline_sz_reg >> 16) & 0xff; - tp->pci_bist = (cacheline_sz_reg >> 24) & 0xff; - if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5714)) tp->pdev_peer = tg3_find_peer(tp); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + /* Intentionally exclude ASIC_REV_5906 */ + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + tp->tg3_flags3 |= TG3_FLG3_5755_PLUS; + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5750 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906 || + (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_5750_PLUS; @@ -12046,6 +12351,18 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->tg3_flags2 & TG3_FLG2_5750_PLUS)) tp->tg3_flags2 |= TG3_FLG2_5705_PLUS; + /* 5700 B0 chips do not support checksumming correctly due + * to hardware bugs. + */ + if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) + tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; + else { + tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; + tp->dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; + if (tp->tg3_flags3 & TG3_FLG3_5755_PLUS) + tp->dev->features |= NETIF_F_IPV6_CSUM; + } + if (tp->tg3_flags2 & TG3_FLG2_5750_PLUS) { tp->tg3_flags |= TG3_FLAG_SUPPORT_MSI; if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5750_AX || @@ -12055,11 +12372,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->pdev_peer == tp->pdev)) tp->tg3_flags &= ~TG3_FLAG_SUPPORT_MSI; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { tp->tg3_flags2 |= TG3_FLG2_HW_TSO_2; tp->tg3_flags2 |= TG3_FLG2_1SHOT_MSI; @@ -12076,21 +12389,41 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) tp->tg3_flags2 |= TG3_FLG2_JUMBO_CAPABLE; - pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP); - if (pcie_cap != 0) { + pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, + &pci_state_reg); + + tp->pcie_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_EXP); + if (tp->pcie_cap != 0) { + u16 lnkctl; + tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; pcie_set_readrq(tp->pdev, 4096); - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) { - u16 lnkctl; - - pci_read_config_word(tp->pdev, - pcie_cap + PCI_EXP_LNKCTL, - &lnkctl); - if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) + pci_read_config_word(tp->pdev, + tp->pcie_cap + PCI_EXP_LNKCTL, + &lnkctl); + if (lnkctl & PCI_EXP_LNKCTL_CLKREQ_EN) { + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->tg3_flags2 &= ~TG3_FLG2_HW_TSO_2; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) + tp->tg3_flags3 |= TG3_FLG3_CLKREQ_BUG; } + } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + tp->tg3_flags2 |= TG3_FLG2_PCI_EXPRESS; + } else if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || + (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { + tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX); + if (!tp->pcix_cap) { + printk(KERN_ERR PFX "Cannot find PCI-X " + "capability, aborting.\n"); + return -EIO; + } + + if (!(pci_state_reg & PCISTATE_CONV_PCI_MODE)) + tp->tg3_flags |= TG3_FLAG_PCIX_MODE; } /* If we have an AMD 762 or VIA K8T800 chipset, write @@ -12103,42 +12436,29 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) !(tp->tg3_flags2 & TG3_FLG2_PCI_EXPRESS)) tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER; + pci_read_config_byte(tp->pdev, PCI_CACHE_LINE_SIZE, + &tp->pci_cacheline_sz); + pci_read_config_byte(tp->pdev, PCI_LATENCY_TIMER, + &tp->pci_lat_timer); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703 && tp->pci_lat_timer < 64) { tp->pci_lat_timer = 64; - - cacheline_sz_reg = ((tp->pci_cacheline_sz & 0xff) << 0); - cacheline_sz_reg |= ((tp->pci_lat_timer & 0xff) << 8); - cacheline_sz_reg |= ((tp->pci_hdr_type & 0xff) << 16); - cacheline_sz_reg |= ((tp->pci_bist & 0xff) << 24); - - pci_write_config_dword(tp->pdev, TG3PCI_CACHELINESZ, - cacheline_sz_reg); - } - - if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) || - (tp->tg3_flags2 & TG3_FLG2_5780_CLASS)) { - tp->pcix_cap = pci_find_capability(tp->pdev, PCI_CAP_ID_PCIX); - if (!tp->pcix_cap) { - printk(KERN_ERR PFX "Cannot find PCI-X " - "capability, aborting.\n"); - return -EIO; - } + pci_write_config_byte(tp->pdev, PCI_LATENCY_TIMER, + tp->pci_lat_timer); } - pci_read_config_dword(tp->pdev, TG3PCI_PCISTATE, - &pci_state_reg); - - if (tp->pcix_cap && (pci_state_reg & PCISTATE_CONV_PCI_MODE) == 0) { - tp->tg3_flags |= TG3_FLAG_PCIX_MODE; + if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) { + /* 5700 BX chips need to have their TX producer index + * mailboxes written twice to workaround a bug. + */ + tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG; - /* If this is a 5700 BX chipset, and we are in PCI-X - * mode, enable register write workaround. + /* If we are in PCI-X mode, enable register write workaround. * * The workaround is to use indirect register accesses * for all chip writes not to mailbox registers. */ - if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) { + if (tp->tg3_flags & TG3_FLAG_PCIX_MODE) { u32 pm_reg; tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; @@ -12163,12 +12483,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) } } - /* 5700 BX chips need to have their TX producer index mailboxes - * written twice to workaround a bug. - */ - if (GET_CHIP_REV(tp->pci_chip_rev_id) == CHIPREV_5700_BX) - tp->tg3_flags |= TG3_FLAG_TXD_MBOX_HWBUG; - if ((pci_state_reg & PCISTATE_BUS_SPEED_HIGH) != 0) tp->tg3_flags |= TG3_FLAG_PCI_HIGH_SPEED; if ((pci_state_reg & PCISTATE_BUS_32BIT) != 0) @@ -12263,16 +12577,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) { + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tp->tg3_flags |= TG3_FLAG_CPMU_PRESENT; - if (tp->pci_chip_rev_id == CHIPREV_ID_5784_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5784_A1 || - tp->pci_chip_rev_id == CHIPREV_ID_5761_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5761_A1) - tp->tg3_flags3 |= TG3_FLG3_5761_5784_AX_FIXES; - } - /* Set up tp->grc_local_ctrl before calling tg3_set_power_state(). * GPIO1 driven high will bring 5700's external PHY out of reset. * It is also used as eeprom write protect on LOMs. @@ -12288,7 +12596,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5752) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_OE3; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tp->grc_local_ctrl |= GRC_LCLCTRL_GPIO_UART_SEL; if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5761) { @@ -12308,12 +12617,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) return err; } - /* 5700 B0 chips do not support checksumming correctly due - * to hardware bugs. - */ - if (tp->pci_chip_rev_id == CHIPREV_ID_5700_B0) - tp->tg3_flags |= TG3_FLAG_BROKEN_CHECKSUMS; - /* Derive initial jumbo mode from MTU assigned in * ether_setup() via the alloc_etherdev() call */ @@ -12346,7 +12649,10 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) tp->tg3_flags2 |= TG3_FLG2_PHY_5704_A0_BUG; - if (tp->tg3_flags2 & TG3_FLG2_5705_PLUS) { + if ((tp->tg3_flags2 & TG3_FLG2_5705_PLUS) && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785 && + GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_57780) { if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || @@ -12356,8 +12662,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) tp->tg3_flags2 |= TG3_FLG2_PHY_JITTER_BUG; if (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5755M) tp->tg3_flags2 |= TG3_FLG2_PHY_ADJUST_TRIM; - } else if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906 && - GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5785) + } else tp->tg3_flags2 |= TG3_FLG2_PHY_BER_BUG; } @@ -12378,7 +12683,8 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) tp->coalesce_mode |= HOSTCC_MODE_32BYTE; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) tp->tg3_flags3 |= TG3_FLG3_USE_PHYLIB; err = tg3_mdio_init(tp); @@ -12463,6 +12769,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->pdev->device == PCI_DEVICE_ID_TIGON3_5751F || tp->pdev->device == PCI_DEVICE_ID_TIGON3_5753F || tp->pdev->device == PCI_DEVICE_ID_TIGON3_5787F)) || + tp->pdev->device == TG3PCI_DEVICE_TIGON3_57790 || GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) tp->tg3_flags |= TG3_FLAG_10_100_ONLY; @@ -12512,20 +12819,7 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) else tp->tg3_flags &= ~TG3_FLAG_POLL_SERDES; - /* All chips before 5787 can get confused if TX buffers - * straddle the 4GB address boundary in some cases. - */ - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) - tp->dev->hard_start_xmit = tg3_start_xmit; - else - tp->dev->hard_start_xmit = tg3_start_xmit_dma_bug; - - tp->rx_offset = 2; + tp->rx_offset = NET_IP_ALIGN; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701 && (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) tp->rx_offset = 0; @@ -13241,18 +13535,53 @@ static void __devinit tg3_init_coal(struct tg3 *tp) } } +static const struct net_device_ops tg3_netdev_ops = { + .ndo_open = tg3_open, + .ndo_stop = tg3_close, + .ndo_start_xmit = tg3_start_xmit, + .ndo_get_stats = tg3_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = tg3_set_rx_mode, + .ndo_set_mac_address = tg3_set_mac_addr, + .ndo_do_ioctl = tg3_ioctl, + .ndo_tx_timeout = tg3_tx_timeout, + .ndo_change_mtu = tg3_change_mtu, +#if TG3_VLAN_TAG_USED + .ndo_vlan_rx_register = tg3_vlan_rx_register, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = tg3_poll_controller, +#endif +}; + +static const struct net_device_ops tg3_netdev_ops_dma_bug = { + .ndo_open = tg3_open, + .ndo_stop = tg3_close, + .ndo_start_xmit = tg3_start_xmit_dma_bug, + .ndo_get_stats = tg3_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = tg3_set_rx_mode, + .ndo_set_mac_address = tg3_set_mac_addr, + .ndo_do_ioctl = tg3_ioctl, + .ndo_tx_timeout = tg3_tx_timeout, + .ndo_change_mtu = tg3_change_mtu, +#if TG3_VLAN_TAG_USED + .ndo_vlan_rx_register = tg3_vlan_rx_register, +#endif +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = tg3_poll_controller, +#endif +}; + static int __devinit tg3_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { static int tg3_version_printed = 0; - resource_size_t tg3reg_base; - unsigned long tg3reg_len; struct net_device *dev; struct tg3 *tp; int err, pm_cap; char str[40]; u64 dma_mask, persist_dma_mask; - DECLARE_MAC_BUF(mac); if (tg3_version_printed++ == 0) printk(KERN_INFO "%s", version); @@ -13264,13 +13593,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, return err; } - if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { - printk(KERN_ERR PFX "Cannot find proper PCI device " - "base address, aborting.\n"); - err = -ENODEV; - goto err_out_disable_pdev; - } - err = pci_request_regions(pdev, DRV_MODULE_NAME); if (err) { printk(KERN_ERR PFX "Cannot obtain PCI resources, " @@ -13289,9 +13611,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_free_res; } - tg3reg_base = pci_resource_start(pdev, 0); - tg3reg_len = pci_resource_len(pdev, 0); - dev = alloc_etherdev(sizeof(*tp)); if (!dev) { printk(KERN_ERR PFX "Etherdev alloc failed, aborting.\n"); @@ -13303,7 +13622,6 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, #if TG3_VLAN_TAG_USED dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX; - dev->vlan_rx_register = tg3_vlan_rx_register; #endif tp = netdev_priv(dev); @@ -13343,7 +13661,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, spin_lock_init(&tp->indirect_lock); INIT_WORK(&tp->reset_task, tg3_reset_task); - tp->regs = ioremap_nocache(tg3reg_base, tg3reg_len); + tp->regs = pci_ioremap_bar(pdev, BAR_0); if (!tp->regs) { printk(KERN_ERR PFX "Cannot map device registers, " "aborting.\n"); @@ -13357,21 +13675,10 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, tp->rx_jumbo_pending = TG3_DEF_RX_JUMBO_RING_PENDING; tp->tx_pending = TG3_DEF_TX_RING_PENDING; - dev->open = tg3_open; - dev->stop = tg3_close; - dev->get_stats = tg3_get_stats; - dev->set_multicast_list = tg3_set_rx_mode; - dev->set_mac_address = tg3_set_mac_addr; - dev->do_ioctl = tg3_ioctl; - dev->tx_timeout = tg3_tx_timeout; netif_napi_add(dev, &tp->napi, tg3_poll, 64); dev->ethtool_ops = &tg3_ethtool_ops; dev->watchdog_timeo = TG3_TX_TIMEOUT; - dev->change_mtu = tg3_change_mtu; dev->irq = pdev->irq; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = tg3_poll_controller; -#endif err = tg3_get_invariants(tp); if (err) { @@ -13380,6 +13687,13 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_iounmap; } + if ((tp->tg3_flags3 & TG3_FLG3_5755_PLUS) || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906) + dev->netdev_ops = &tg3_netdev_ops; + else + dev->netdev_ops = &tg3_netdev_ops_dma_bug; + + /* The EPB bridge inside 5714, 5715, and 5780 and any * device behind the EPB cannot support DMA addresses > 40-bit. * On 64-bit systems with IOMMU, use 40-bit dma_mask. @@ -13439,14 +13753,16 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, * is off by default, but can be enabled using ethtool. */ if (tp->tg3_flags2 & TG3_FLG2_HW_TSO) { - dev->features |= NETIF_F_TSO; - if ((tp->tg3_flags2 & TG3_FLG2_HW_TSO_2) && - (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5906)) + if (dev->features & NETIF_F_IP_CSUM) + dev->features |= NETIF_F_TSO; + if ((dev->features & NETIF_F_IPV6_CSUM) && + (tp->tg3_flags2 & TG3_FLG2_HW_TSO_2)) dev->features |= NETIF_F_TSO6; if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 && GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5784_AX) || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57780) dev->features |= NETIF_F_TSO_ECN; } @@ -13466,17 +13782,7 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, } if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) { - if (!(pci_resource_flags(pdev, 2) & IORESOURCE_MEM)) { - printk(KERN_ERR PFX "Cannot find proper PCI device " - "base address for APE, aborting.\n"); - err = -ENODEV; - goto err_out_iounmap; - } - - tg3reg_base = pci_resource_start(pdev, 2); - tg3reg_len = pci_resource_len(pdev, 2); - - tp->aperegs = ioremap_nocache(tg3reg_base, tg3reg_len); + tp->aperegs = pci_ioremap_bar(pdev, BAR_2); if (!tp->aperegs) { printk(KERN_ERR PFX "Cannot map APE registers, " "aborting.\n"); @@ -13504,25 +13810,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_apeunmap; } - /* Tigon3 can do ipv4 only... and some chips have buggy - * checksumming. - */ - if ((tp->tg3_flags & TG3_FLAG_BROKEN_CHECKSUMS) == 0) { - dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG; - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5755 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5787 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5784 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5761 || - GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5785) - dev->features |= NETIF_F_IPV6_CSUM; - - tp->tg3_flags |= TG3_FLAG_RX_CHECKSUMS; - } else - tp->tg3_flags &= ~TG3_FLAG_RX_CHECKSUMS; - /* flow control autonegotiation is default behavior */ tp->tg3_flags |= TG3_FLAG_PAUSE_AUTONEG; - tp->link_config.flowctrl = TG3_FLOW_CTRL_TX | TG3_FLOW_CTRL_RX; + tp->link_config.flowctrl = FLOW_CTRL_TX | FLOW_CTRL_RX; tg3_init_coal(tp); @@ -13535,26 +13825,34 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, goto err_out_apeunmap; } - printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x PHY(%s)] " - "(%s) %s Ethernet %s\n", + printk(KERN_INFO "%s: Tigon3 [partno(%s) rev %04x] (%s) MAC address %pM\n", dev->name, tp->board_part_number, tp->pci_chip_rev_id, - tg3_phy_string(tp), tg3_bus_string(tp, str), - ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" : - ((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" : - "10/100/1000Base-T")), - print_mac(mac, dev->dev_addr)); + dev->dev_addr); - printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] " - "MIirq[%d] ASF[%d] WireSpeed[%d] TSOcap[%d]\n", + if (tp->tg3_flags3 & TG3_FLG3_PHY_CONNECTED) + printk(KERN_INFO + "%s: attached PHY driver [%s] (mii_bus:phy_addr=%s)\n", + tp->dev->name, + tp->mdio_bus->phy_map[PHY_ADDR]->drv->name, + dev_name(&tp->mdio_bus->phy_map[PHY_ADDR]->dev)); + else + printk(KERN_INFO + "%s: attached PHY is %s (%s Ethernet) (WireSpeed[%d])\n", + tp->dev->name, tg3_phy_string(tp), + ((tp->tg3_flags & TG3_FLAG_10_100_ONLY) ? "10/100Base-TX" : + ((tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) ? "1000Base-SX" : + "10/100/1000Base-T")), + (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0); + + printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] MIirq[%d] ASF[%d] TSOcap[%d]\n", dev->name, (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0, (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0, (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0, (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0, - (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0, (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0); printk(KERN_INFO "%s: dma_rwctrl[%08x] dma_mask[%d-bit]\n", dev->name, tp->dma_rwctrl, diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index be252abe8985faf0fb2d7c75bec2d10095ef4f7c..8936edfb0438c992c6cf7ceeb8d6880aa0fa98fe 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -38,26 +38,13 @@ #define TG3PCI_DEVICE_TIGON3_2 0x1645 /* BCM5701 */ #define TG3PCI_DEVICE_TIGON3_3 0x1646 /* BCM5702 */ #define TG3PCI_DEVICE_TIGON3_4 0x1647 /* BCM5703 */ -#define TG3PCI_COMMAND 0x00000004 -#define TG3PCI_STATUS 0x00000006 -#define TG3PCI_CCREVID 0x00000008 -#define TG3PCI_CACHELINESZ 0x0000000c -#define TG3PCI_LATTIMER 0x0000000d -#define TG3PCI_HEADERTYPE 0x0000000e -#define TG3PCI_BIST 0x0000000f -#define TG3PCI_BASE0_LOW 0x00000010 -#define TG3PCI_BASE0_HIGH 0x00000014 -/* 0x18 --> 0x2c unused */ -#define TG3PCI_SUBSYSVENID 0x0000002c -#define TG3PCI_SUBSYSID 0x0000002e -#define TG3PCI_ROMADDR 0x00000030 -#define TG3PCI_CAPLIST 0x00000034 -/* 0x35 --> 0x3c unused */ -#define TG3PCI_IRQ_LINE 0x0000003c -#define TG3PCI_IRQ_PIN 0x0000003d -#define TG3PCI_MIN_GNT 0x0000003e -#define TG3PCI_MAX_LAT 0x0000003f -/* 0x40 --> 0x64 unused */ +#define TG3PCI_DEVICE_TIGON3_5761S 0x1688 +#define TG3PCI_DEVICE_TIGON3_5761SE 0x1689 +#define TG3PCI_DEVICE_TIGON3_57780 0x1692 +#define TG3PCI_DEVICE_TIGON3_57760 0x1690 +#define TG3PCI_DEVICE_TIGON3_57790 0x1694 +#define TG3PCI_DEVICE_TIGON3_57720 0x168c +/* 0x04 --> 0x64 unused */ #define TG3PCI_MSI_DATA 0x00000064 /* 0x66 --> 0x68 unused */ #define TG3PCI_MISC_HOST_CTRL 0x00000068 @@ -108,10 +95,6 @@ #define CHIPREV_ID_5752_A1 0x6001 #define CHIPREV_ID_5714_A2 0x9002 #define CHIPREV_ID_5906_A1 0xc001 -#define CHIPREV_ID_5784_A0 0x5784000 -#define CHIPREV_ID_5784_A1 0x5784001 -#define CHIPREV_ID_5761_A0 0x5761000 -#define CHIPREV_ID_5761_A1 0x5761001 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 @@ -129,6 +112,7 @@ #define ASIC_REV_5784 0x5784 #define ASIC_REV_5761 0x5761 #define ASIC_REV_5785 0x5785 +#define ASIC_REV_57780 0x57780 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -325,6 +309,7 @@ #define MAC_MODE_TDE_ENABLE 0x00200000 #define MAC_MODE_RDE_ENABLE 0x00400000 #define MAC_MODE_FHDE_ENABLE 0x00800000 +#define MAC_MODE_KEEP_FRAME_IN_WOL 0x01000000 #define MAC_MODE_APE_RX_EN 0x08000000 #define MAC_MODE_APE_TX_EN 0x10000000 #define MAC_STATUS 0x00000404 @@ -414,6 +399,7 @@ #define MI_COM_DATA_MASK 0x0000ffff #define MAC_MI_STAT 0x00000450 #define MAC_MI_STAT_LNKSTAT_ATTN_ENAB 0x00000001 +#define MAC_MI_STAT_10MBPS_MODE 0x00000002 #define MAC_MI_MODE 0x00000454 #define MAC_MI_MODE_CLK_10MHZ 0x00000001 #define MAC_MI_MODE_SHORT_PREAMBLE 0x00000002 @@ -539,6 +525,100 @@ #define MAC_PHYCFG1_TXC_DRV 0x20000000 #define MAC_PHYCFG2 0x000005a4 #define MAC_PHYCFG2_INBAND_ENABLE 0x00000001 +#define MAC_PHYCFG2_EMODE_MASK_MASK 0x000001c0 +#define MAC_PHYCFG2_EMODE_MASK_AC131 0x000000c0 +#define MAC_PHYCFG2_EMODE_MASK_50610 0x00000100 +#define MAC_PHYCFG2_EMODE_MASK_RT8211 0x00000000 +#define MAC_PHYCFG2_EMODE_MASK_RT8201 0x000001c0 +#define MAC_PHYCFG2_EMODE_COMP_MASK 0x00000e00 +#define MAC_PHYCFG2_EMODE_COMP_AC131 0x00000600 +#define MAC_PHYCFG2_EMODE_COMP_50610 0x00000400 +#define MAC_PHYCFG2_EMODE_COMP_RT8211 0x00000800 +#define MAC_PHYCFG2_EMODE_COMP_RT8201 0x00000000 +#define MAC_PHYCFG2_FMODE_MASK_MASK 0x00007000 +#define MAC_PHYCFG2_FMODE_MASK_AC131 0x00006000 +#define MAC_PHYCFG2_FMODE_MASK_50610 0x00004000 +#define MAC_PHYCFG2_FMODE_MASK_RT8211 0x00000000 +#define MAC_PHYCFG2_FMODE_MASK_RT8201 0x00007000 +#define MAC_PHYCFG2_FMODE_COMP_MASK 0x00038000 +#define MAC_PHYCFG2_FMODE_COMP_AC131 0x00030000 +#define MAC_PHYCFG2_FMODE_COMP_50610 0x00008000 +#define MAC_PHYCFG2_FMODE_COMP_RT8211 0x00038000 +#define MAC_PHYCFG2_FMODE_COMP_RT8201 0x00000000 +#define MAC_PHYCFG2_GMODE_MASK_MASK 0x001c0000 +#define MAC_PHYCFG2_GMODE_MASK_AC131 0x001c0000 +#define MAC_PHYCFG2_GMODE_MASK_50610 0x00100000 +#define MAC_PHYCFG2_GMODE_MASK_RT8211 0x00000000 +#define MAC_PHYCFG2_GMODE_MASK_RT8201 0x001c0000 +#define MAC_PHYCFG2_GMODE_COMP_MASK 0x00e00000 +#define MAC_PHYCFG2_GMODE_COMP_AC131 0x00e00000 +#define MAC_PHYCFG2_GMODE_COMP_50610 0x00000000 +#define MAC_PHYCFG2_GMODE_COMP_RT8211 0x00200000 +#define MAC_PHYCFG2_GMODE_COMP_RT8201 0x00000000 +#define MAC_PHYCFG2_ACT_MASK_MASK 0x03000000 +#define MAC_PHYCFG2_ACT_MASK_AC131 0x03000000 +#define MAC_PHYCFG2_ACT_MASK_50610 0x01000000 +#define MAC_PHYCFG2_ACT_MASK_RT8211 0x03000000 +#define MAC_PHYCFG2_ACT_MASK_RT8201 0x01000000 +#define MAC_PHYCFG2_ACT_COMP_MASK 0x0c000000 +#define MAC_PHYCFG2_ACT_COMP_AC131 0x00000000 +#define MAC_PHYCFG2_ACT_COMP_50610 0x00000000 +#define MAC_PHYCFG2_ACT_COMP_RT8211 0x00000000 +#define MAC_PHYCFG2_ACT_COMP_RT8201 0x08000000 +#define MAC_PHYCFG2_QUAL_MASK_MASK 0x30000000 +#define MAC_PHYCFG2_QUAL_MASK_AC131 0x30000000 +#define MAC_PHYCFG2_QUAL_MASK_50610 0x30000000 +#define MAC_PHYCFG2_QUAL_MASK_RT8211 0x30000000 +#define MAC_PHYCFG2_QUAL_MASK_RT8201 0x30000000 +#define MAC_PHYCFG2_QUAL_COMP_MASK 0xc0000000 +#define MAC_PHYCFG2_QUAL_COMP_AC131 0x00000000 +#define MAC_PHYCFG2_QUAL_COMP_50610 0x00000000 +#define MAC_PHYCFG2_QUAL_COMP_RT8211 0x00000000 +#define MAC_PHYCFG2_QUAL_COMP_RT8201 0x00000000 +#define MAC_PHYCFG2_50610_LED_MODES \ + (MAC_PHYCFG2_EMODE_MASK_50610 | \ + MAC_PHYCFG2_EMODE_COMP_50610 | \ + MAC_PHYCFG2_FMODE_MASK_50610 | \ + MAC_PHYCFG2_FMODE_COMP_50610 | \ + MAC_PHYCFG2_GMODE_MASK_50610 | \ + MAC_PHYCFG2_GMODE_COMP_50610 | \ + MAC_PHYCFG2_ACT_MASK_50610 | \ + MAC_PHYCFG2_ACT_COMP_50610 | \ + MAC_PHYCFG2_QUAL_MASK_50610 | \ + MAC_PHYCFG2_QUAL_COMP_50610) +#define MAC_PHYCFG2_AC131_LED_MODES \ + (MAC_PHYCFG2_EMODE_MASK_AC131 | \ + MAC_PHYCFG2_EMODE_COMP_AC131 | \ + MAC_PHYCFG2_FMODE_MASK_AC131 | \ + MAC_PHYCFG2_FMODE_COMP_AC131 | \ + MAC_PHYCFG2_GMODE_MASK_AC131 | \ + MAC_PHYCFG2_GMODE_COMP_AC131 | \ + MAC_PHYCFG2_ACT_MASK_AC131 | \ + MAC_PHYCFG2_ACT_COMP_AC131 | \ + MAC_PHYCFG2_QUAL_MASK_AC131 | \ + MAC_PHYCFG2_QUAL_COMP_AC131) +#define MAC_PHYCFG2_RTL8211C_LED_MODES \ + (MAC_PHYCFG2_EMODE_MASK_RT8211 | \ + MAC_PHYCFG2_EMODE_COMP_RT8211 | \ + MAC_PHYCFG2_FMODE_MASK_RT8211 | \ + MAC_PHYCFG2_FMODE_COMP_RT8211 | \ + MAC_PHYCFG2_GMODE_MASK_RT8211 | \ + MAC_PHYCFG2_GMODE_COMP_RT8211 | \ + MAC_PHYCFG2_ACT_MASK_RT8211 | \ + MAC_PHYCFG2_ACT_COMP_RT8211 | \ + MAC_PHYCFG2_QUAL_MASK_RT8211 | \ + MAC_PHYCFG2_QUAL_COMP_RT8211) +#define MAC_PHYCFG2_RTL8201E_LED_MODES \ + (MAC_PHYCFG2_EMODE_MASK_RT8201 | \ + MAC_PHYCFG2_EMODE_COMP_RT8201 | \ + MAC_PHYCFG2_FMODE_MASK_RT8201 | \ + MAC_PHYCFG2_FMODE_COMP_RT8201 | \ + MAC_PHYCFG2_GMODE_MASK_RT8201 | \ + MAC_PHYCFG2_GMODE_COMP_RT8201 | \ + MAC_PHYCFG2_ACT_MASK_RT8201 | \ + MAC_PHYCFG2_ACT_COMP_RT8201 | \ + MAC_PHYCFG2_QUAL_MASK_RT8201 | \ + MAC_PHYCFG2_QUAL_COMP_RT8201) #define MAC_EXT_RGMII_MODE 0x000005a8 #define MAC_RGMII_MODE_TX_ENABLE 0x00000001 #define MAC_RGMII_MODE_TX_LOWPWR 0x00000002 @@ -1104,6 +1184,8 @@ #define RDMAC_MODE_MBUF_SBD_CRPT_ENAB 0x00002000 #define RDMAC_MODE_FIFO_SIZE_128 0x00020000 #define RDMAC_MODE_FIFO_LONG_BURST 0x00030000 +#define RDMAC_MODE_IPV4_LSO_EN 0x08000000 +#define RDMAC_MODE_IPV6_LSO_EN 0x10000000 #define RDMAC_STATUS 0x00004804 #define RDMAC_STATUS_TGTABORT 0x00000004 #define RDMAC_STATUS_MSTABORT 0x00000008 @@ -1550,6 +1632,12 @@ #define FLASH_5761VENDOR_ST_A_M45PE40 0x02000000 #define FLASH_5761VENDOR_ST_A_M45PE80 0x02000002 #define FLASH_5761VENDOR_ST_A_M45PE16 0x02000003 +#define FLASH_57780VENDOR_ATMEL_AT45DB011D 0x00400000 +#define FLASH_57780VENDOR_ATMEL_AT45DB011B 0x03400000 +#define FLASH_57780VENDOR_ATMEL_AT45DB021D 0x00400002 +#define FLASH_57780VENDOR_ATMEL_AT45DB021B 0x03400002 +#define FLASH_57780VENDOR_ATMEL_AT45DB041D 0x00400001 +#define FLASH_57780VENDOR_ATMEL_AT45DB041B 0x03400001 #define NVRAM_CFG1_5752PAGE_SIZE_MASK 0x70000000 #define FLASH_5752PAGE_SIZE_256 0x00000000 #define FLASH_5752PAGE_SIZE_512 0x10000000 @@ -1557,6 +1645,7 @@ #define FLASH_5752PAGE_SIZE_2K 0x30000000 #define FLASH_5752PAGE_SIZE_4K 0x40000000 #define FLASH_5752PAGE_SIZE_264 0x50000000 +#define FLASH_5752PAGE_SIZE_528 0x60000000 #define NVRAM_CFG2 0x00007018 #define NVRAM_CFG3 0x0000701c #define NVRAM_SWARB 0x00007020 @@ -1649,6 +1738,17 @@ #define TG3_NVM_DIRTYPE_SHIFT 24 #define TG3_NVM_DIRTYPE_ASFINI 1 +#define TG3_EEPROM_SB_F1R0_EDH_OFF 0x10 +#define TG3_EEPROM_SB_F1R2_EDH_OFF 0x14 +#define TG3_EEPROM_SB_F1R2_MBA_OFF 0x10 +#define TG3_EEPROM_SB_F1R3_EDH_OFF 0x18 +#define TG3_EEPROM_SB_EDH_MAJ_MASK 0x00000700 +#define TG3_EEPROM_SB_EDH_MAJ_SHFT 8 +#define TG3_EEPROM_SB_EDH_MIN_MASK 0x000000ff +#define TG3_EEPROM_SB_EDH_BLD_MASK 0x0000f800 +#define TG3_EEPROM_SB_EDH_BLD_SHFT 11 + + /* 32K Window into NIC internal memory */ #define NIC_SRAM_WIN_BASE 0x00008000 @@ -1724,6 +1824,7 @@ #define NIC_SRAM_DATA_CFG_2 0x00000d38 +#define NIC_SRAM_DATA_CFG_2_APD_EN 0x00000400 #define SHASTA_EXT_LED_MODE_MASK 0x00018000 #define SHASTA_EXT_LED_LEGACY 0x00000000 #define SHASTA_EXT_LED_SHARED 0x00008000 @@ -1792,6 +1893,11 @@ #define MII_TG3_AUX_CTRL 0x18 /* auxilliary control register */ +#define MII_TG3_AUXCTL_PCTL_100TX_LPWR 0x0010 +#define MII_TG3_AUXCTL_PCTL_SPR_ISOLATE 0x0020 +#define MII_TG3_AUXCTL_PCTL_VREG_11V 0x0180 +#define MII_TG3_AUXCTL_SHDWSEL_PWRCTL 0x0002 + #define MII_TG3_AUXCTL_MISC_WREN 0x8000 #define MII_TG3_AUXCTL_MISC_FORCE_AMDIX 0x0200 #define MII_TG3_AUXCTL_MISC_RDSEL_MISC 0x7000 @@ -1817,12 +1923,6 @@ #define MII_TG3_ISTAT 0x1a /* IRQ status register */ #define MII_TG3_IMASK 0x1b /* IRQ mask register */ -#define MII_TG3_MISC_SHDW 0x1c -#define MII_TG3_MISC_SHDW_WREN 0x8000 -#define MII_TG3_MISC_SHDW_APD_SEL 0x2800 - -#define MII_TG3_MISC_SHDW_APD_WKTM_84MS 0x0001 - /* ISTAT/IMASK event bits */ #define MII_TG3_INT_LINKCHG 0x0002 #define MII_TG3_INT_SPEEDCHG 0x0004 @@ -1831,7 +1931,9 @@ #define MII_TG3_MISC_SHDW 0x1c #define MII_TG3_MISC_SHDW_WREN 0x8000 -#define MII_TG3_MISC_SHDW_SCR5_SEL 0x1400 + +#define MII_TG3_MISC_SHDW_APD_WKTM_84MS 0x0001 +#define MII_TG3_MISC_SHDW_APD_ENABLE 0x0020 #define MII_TG3_MISC_SHDW_APD_SEL 0x2800 #define MII_TG3_MISC_SHDW_SCR5_C125OE 0x0001 @@ -1839,9 +1941,8 @@ #define MII_TG3_MISC_SHDW_SCR5_SDTL 0x0004 #define MII_TG3_MISC_SHDW_SCR5_DLPTLM 0x0008 #define MII_TG3_MISC_SHDW_SCR5_LPED 0x0010 +#define MII_TG3_MISC_SHDW_SCR5_SEL 0x1400 -#define MII_TG3_MISC_SHDW_APD_WKTM_84MS 0x0001 -#define MII_TG3_MISC_SHDW_APD_ENABLE 0x0020 #define MII_TG3_EPHY_TEST 0x1f /* 5906 PHY register */ #define MII_TG3_EPHY_SHADOW_EN 0x80 @@ -2211,8 +2312,6 @@ struct tg3_link_config { u8 duplex; u8 autoneg; u8 flowctrl; -#define TG3_FLOW_CTRL_TX 0x01 -#define TG3_FLOW_CTRL_RX 0x02 /* Describes what we actually have. */ u8 active_flowctrl; @@ -2507,7 +2606,6 @@ struct tg3 { u32 tg3_flags3; #define TG3_FLG3_NO_NVRAM_ADDR_TRANS 0x00000001 #define TG3_FLG3_ENABLE_APE 0x00000002 -#define TG3_FLG3_5761_5784_AX_FIXES 0x00000004 #define TG3_FLG3_5701_DMA_BUG 0x00000008 #define TG3_FLG3_USE_PHYLIB 0x00000010 #define TG3_FLG3_MDIOBUS_INITED 0x00000020 @@ -2516,6 +2614,9 @@ struct tg3 { #define TG3_FLG3_RGMII_STD_IBND_DISABLE 0x00000100 #define TG3_FLG3_RGMII_EXT_IBND_RX_EN 0x00000200 #define TG3_FLG3_RGMII_EXT_IBND_TX_EN 0x00000400 +#define TG3_FLG3_CLKREQ_BUG 0x00000800 +#define TG3_FLG3_PHY_ENABLE_APD 0x00001000 +#define TG3_FLG3_5755_PLUS 0x00002000 struct timer_list timer; u16 timer_counter; @@ -2547,14 +2648,16 @@ struct tg3 { /* PCI block */ u32 pci_chip_rev_id; + u16 pci_cmd; u8 pci_cacheline_sz; u8 pci_lat_timer; - u8 pci_hdr_type; - u8 pci_bist; int pm_cap; int msi_cap; + union { int pcix_cap; + int pcie_cap; + }; struct mii_bus *mdio_bus; int mdio_irq[PHY_MAX_ADDR]; @@ -2588,11 +2691,16 @@ struct tg3 { #define PHY_REV_BCM5411_X0 0x1 /* Found on Netgear GA302T */ #define TG3_PHY_ID_BCM50610 0x143bd60 #define TG3_PHY_ID_BCMAC131 0x143bc70 - +#define TG3_PHY_ID_RTL8211C 0x001cc910 +#define TG3_PHY_ID_RTL8201E 0x00008200 +#define TG3_PHY_ID_BCM57780 0x03625d90 +#define TG3_PHY_OUI_MASK 0xfffffc00 +#define TG3_PHY_OUI_1 0x00206000 +#define TG3_PHY_OUI_2 0x0143bc00 +#define TG3_PHY_OUI_3 0x03625c00 u32 led_ctrl; u32 phy_otp; - u16 pci_cmd; char board_part_number[24]; #define TG3_VER_SIZE 32 diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index e60498232b94f83dede6c6d4ae153d8d135d7b19..85ef8b744557621f335134b2be61a119be72d09c 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c @@ -163,6 +163,11 @@ * v1.15 Apr 4, 2002 - Correct operation when aui=1 to be * 10T half duplex no loopback * Thanks to Gunnar Eikman + * + * Sakari Ailus : + * + * v1.15a Dec 15 2008 - Remove bbuf support, it doesn't work anyway. + * *******************************************************************************/ #include @@ -213,12 +218,8 @@ static int debug; module_param(debug, int, 0); MODULE_PARM_DESC(debug, "ThunderLAN debug mask"); -static int bbuf; -module_param(bbuf, int, 0); -MODULE_PARM_DESC(bbuf, "ThunderLAN use big buffer (0-1)"); - static const char TLanSignature[] = "TLAN"; -static const char tlan_banner[] = "ThunderLAN driver v1.15\n"; +static const char tlan_banner[] = "ThunderLAN driver v1.15a\n"; static int tlan_have_pci; static int tlan_have_eisa; @@ -859,13 +860,8 @@ static int TLan_Init( struct net_device *dev ) priv = netdev_priv(dev); - if ( bbuf ) { - dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) - * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE ); - } else { - dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) - * ( sizeof(TLanList) ); - } + dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) + * ( sizeof(TLanList) ); priv->dmaStorage = pci_alloc_consistent(priv->pciDev, dma_size, &priv->dmaStorageDMA); priv->dmaSize = dma_size; @@ -881,16 +877,6 @@ static int TLan_Init( struct net_device *dev ) priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; priv->txListDMA = priv->rxListDMA + sizeof(TLanList) * TLAN_NUM_RX_LISTS; - if ( bbuf ) { - priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); - priv->rxBufferDMA =priv->txListDMA - + sizeof(TLanList) * TLAN_NUM_TX_LISTS; - priv->txBuffer = priv->rxBuffer - + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); - priv->txBufferDMA = priv->rxBufferDMA - + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); - } - err = 0; for ( i = 0; i < 6 ; i++ ) err |= TLan_EeReadByte( dev, @@ -1094,9 +1080,8 @@ static void TLan_tx_timeout_work(struct work_struct *work) static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) { TLanPrivateInfo *priv = netdev_priv(dev); - TLanList *tail_list; dma_addr_t tail_list_phys; - u8 *tail_buffer; + TLanList *tail_list; unsigned long flags; unsigned int txlen; @@ -1125,15 +1110,10 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) tail_list->forward = 0; - if ( bbuf ) { - tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE ); - skb_copy_from_linear_data(skb, tail_buffer, txlen); - } else { - tail_list->buffer[0].address = pci_map_single(priv->pciDev, - skb->data, txlen, - PCI_DMA_TODEVICE); - TLan_StoreSKB(tail_list, skb); - } + tail_list->buffer[0].address = pci_map_single(priv->pciDev, + skb->data, txlen, + PCI_DMA_TODEVICE); + TLan_StoreSKB(tail_list, skb); tail_list->frameSize = (u16) txlen; tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) txlen; @@ -1163,9 +1143,6 @@ static int TLan_StartTx( struct sk_buff *skb, struct net_device *dev ) CIRC_INC( priv->txTail, TLAN_NUM_TX_LISTS ); - if ( bbuf ) - dev_kfree_skb_any(skb); - dev->trans_start = jiffies; return 0; @@ -1429,17 +1406,16 @@ static u32 TLan_HandleTxEOF( struct net_device *dev, u16 host_int ) head_list = priv->txList + priv->txHead; while (((tmpCStat = head_list->cStat ) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { + struct sk_buff *skb = TLan_GetSKB(head_list); + ack++; - if ( ! bbuf ) { - struct sk_buff *skb = TLan_GetSKB(head_list); - pci_unmap_single(priv->pciDev, head_list->buffer[0].address, - max(skb->len, - (unsigned int)TLAN_MIN_FRAME_SIZE), - PCI_DMA_TODEVICE); - dev_kfree_skb_any(skb); - head_list->buffer[8].address = 0; - head_list->buffer[9].address = 0; - } + pci_unmap_single(priv->pciDev, head_list->buffer[0].address, + max(skb->len, + (unsigned int)TLAN_MIN_FRAME_SIZE), + PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); + head_list->buffer[8].address = 0; + head_list->buffer[9].address = 0; if ( tmpCStat & TLAN_CSTAT_EOC ) eoc = 1; @@ -1549,7 +1525,6 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) TLanPrivateInfo *priv = netdev_priv(dev); u32 ack = 0; int eoc = 0; - u8 *head_buffer; TLanList *head_list; struct sk_buff *skb; TLanList *tail_list; @@ -1564,53 +1539,33 @@ static u32 TLan_HandleRxEOF( struct net_device *dev, u16 host_int ) while (((tmpCStat = head_list->cStat) & TLAN_CSTAT_FRM_CMP) && (ack < 255)) { dma_addr_t frameDma = head_list->buffer[0].address; u32 frameSize = head_list->frameSize; + struct sk_buff *new_skb; + ack++; if (tmpCStat & TLAN_CSTAT_EOC) eoc = 1; - if (bbuf) { - skb = netdev_alloc_skb(dev, frameSize + 7); - if ( !skb ) - goto drop_and_reuse; - - head_buffer = priv->rxBuffer - + (priv->rxHead * TLAN_MAX_FRAME_SIZE); - skb_reserve(skb, 2); - pci_dma_sync_single_for_cpu(priv->pciDev, - frameDma, frameSize, - PCI_DMA_FROMDEVICE); - skb_copy_from_linear_data(skb, head_buffer, frameSize); - skb_put(skb, frameSize); - dev->stats.rx_bytes += frameSize; - - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); - } else { - struct sk_buff *new_skb; - - new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); - if ( !new_skb ) - goto drop_and_reuse; - - skb = TLan_GetSKB(head_list); - pci_unmap_single(priv->pciDev, frameDma, - TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); - skb_put( skb, frameSize ); + new_skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); + if ( !new_skb ) + goto drop_and_reuse; - dev->stats.rx_bytes += frameSize; + skb = TLan_GetSKB(head_list); + pci_unmap_single(priv->pciDev, frameDma, + TLAN_MAX_FRAME_SIZE, PCI_DMA_FROMDEVICE); + skb_put( skb, frameSize ); - skb->protocol = eth_type_trans( skb, dev ); - netif_rx( skb ); + dev->stats.rx_bytes += frameSize; - skb_reserve( new_skb, NET_IP_ALIGN ); - head_list->buffer[0].address = pci_map_single(priv->pciDev, - new_skb->data, - TLAN_MAX_FRAME_SIZE, - PCI_DMA_FROMDEVICE); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); - TLan_StoreSKB(head_list, new_skb); + skb_reserve( new_skb, NET_IP_ALIGN ); + head_list->buffer[0].address = pci_map_single(priv->pciDev, + new_skb->data, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); - } + TLan_StoreSKB(head_list, new_skb); drop_and_reuse: head_list->forward = 0; head_list->cStat = 0; @@ -1653,8 +1608,6 @@ drop_and_reuse: } } - dev->last_rx = jiffies; - return ack; } /* TLan_HandleRxEOF */ @@ -1995,12 +1948,7 @@ static void TLan_ResetLists( struct net_device *dev ) for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { list = priv->txList + i; list->cStat = TLAN_CSTAT_UNUSED; - if ( bbuf ) { - list->buffer[0].address = priv->txBufferDMA - + ( i * TLAN_MAX_FRAME_SIZE ); - } else { - list->buffer[0].address = 0; - } + list->buffer[0].address = 0; list->buffer[2].count = 0; list->buffer[2].address = 0; list->buffer[8].address = 0; @@ -2015,23 +1963,18 @@ static void TLan_ResetLists( struct net_device *dev ) list->cStat = TLAN_CSTAT_READY; list->frameSize = TLAN_MAX_FRAME_SIZE; list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; - if ( bbuf ) { - list->buffer[0].address = priv->rxBufferDMA - + ( i * TLAN_MAX_FRAME_SIZE ); - } else { - skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); - if ( !skb ) { - pr_err("TLAN: out of memory for received data.\n" ); - break; - } - - skb_reserve( skb, NET_IP_ALIGN ); - list->buffer[0].address = pci_map_single(priv->pciDev, - skb->data, - TLAN_MAX_FRAME_SIZE, - PCI_DMA_FROMDEVICE); - TLan_StoreSKB(list, skb); + skb = netdev_alloc_skb(dev, TLAN_MAX_FRAME_SIZE + 7 ); + if ( !skb ) { + pr_err("TLAN: out of memory for received data.\n" ); + break; } + + skb_reserve( skb, NET_IP_ALIGN ); + list->buffer[0].address = pci_map_single(priv->pciDev, + skb->data, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); + TLan_StoreSKB(list, skb); list->buffer[1].count = 0; list->buffer[1].address = 0; list->forward = list_phys + sizeof(TLanList); @@ -2054,35 +1997,33 @@ static void TLan_FreeLists( struct net_device *dev ) TLanList *list; struct sk_buff *skb; - if ( ! bbuf ) { - for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { - list = priv->txList + i; - skb = TLan_GetSKB(list); - if ( skb ) { - pci_unmap_single( - priv->pciDev, - list->buffer[0].address, - max(skb->len, - (unsigned int)TLAN_MIN_FRAME_SIZE), - PCI_DMA_TODEVICE); - dev_kfree_skb_any( skb ); - list->buffer[8].address = 0; - list->buffer[9].address = 0; - } + for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { + list = priv->txList + i; + skb = TLan_GetSKB(list); + if ( skb ) { + pci_unmap_single( + priv->pciDev, + list->buffer[0].address, + max(skb->len, + (unsigned int)TLAN_MIN_FRAME_SIZE), + PCI_DMA_TODEVICE); + dev_kfree_skb_any( skb ); + list->buffer[8].address = 0; + list->buffer[9].address = 0; } + } - for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { - list = priv->rxList + i; - skb = TLan_GetSKB(list); - if ( skb ) { - pci_unmap_single(priv->pciDev, - list->buffer[0].address, - TLAN_MAX_FRAME_SIZE, - PCI_DMA_FROMDEVICE); - dev_kfree_skb_any( skb ); - list->buffer[8].address = 0; - list->buffer[9].address = 0; - } + for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { + list = priv->rxList + i; + skb = TLan_GetSKB(list); + if ( skb ) { + pci_unmap_single(priv->pciDev, + list->buffer[0].address, + TLAN_MAX_FRAME_SIZE, + PCI_DMA_FROMDEVICE); + dev_kfree_skb_any( skb ); + list->buffer[8].address = 0; + list->buffer[9].address = 0; } } } /* TLan_FreeLists */ diff --git a/drivers/net/tokenring/3c359.c b/drivers/net/tokenring/3c359.c index bf621328b6019e3a89bc21406ecaf4f8370218d9..43853e3b210e42977100f1c1b3828a3dfa9fe623 100644 --- a/drivers/net/tokenring/3c359.c +++ b/drivers/net/tokenring/3c359.c @@ -296,8 +296,9 @@ static int __devinit xl_probe(struct pci_dev *pdev, } ; /* - * Allowing init_trdev to allocate the dev->priv structure will align xl_private - * on a 32 bytes boundary which we need for the rx/tx descriptors + * Allowing init_trdev to allocate the private data will align + * xl_private on a 32 bytes boundary which we need for the rx/tx + * descriptors */ dev = alloc_trdev(sizeof(struct xl_private)) ; @@ -638,13 +639,13 @@ static int xl_open(struct net_device *dev) /* These MUST be on 8 byte boundaries */ xl_priv->xl_tx_ring = kzalloc((sizeof(struct xl_tx_desc) * XL_TX_RING_SIZE) + 7, GFP_DMA | GFP_KERNEL); if (xl_priv->xl_tx_ring == NULL) { - printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n", + printk(KERN_WARNING "%s: Not enough memory to allocate tx buffers.\n", dev->name); free_irq(dev->irq,dev); return -ENOMEM; } xl_priv->xl_rx_ring = kzalloc((sizeof(struct xl_rx_desc) * XL_RX_RING_SIZE) +7, GFP_DMA | GFP_KERNEL); - if (xl_priv->xl_tx_ring == NULL) { + if (xl_priv->xl_rx_ring == NULL) { printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers.\n", dev->name); free_irq(dev->irq,dev); @@ -669,6 +670,8 @@ static int xl_open(struct net_device *dev) if (i==0) { printk(KERN_WARNING "%s: Not enough memory to allocate rx buffers. Adapter disabled \n",dev->name) ; free_irq(dev->irq,dev) ; + kfree(xl_priv->xl_tx_ring); + kfree(xl_priv->xl_rx_ring); return -EIO ; } @@ -974,7 +977,6 @@ static void xl_rx(struct net_device *dev) netif_rx(skb2) ; } /* if multiple buffers */ - dev->last_rx = jiffies ; } /* while packet to do */ /* Clear the updComplete interrupt */ @@ -1571,7 +1573,6 @@ static void xl_arb_cmd(struct net_device *dev) * anyway. */ - dev->last_rx = jiffies ; /* Acknowledge interrupt, this tells nic we are done with the arb */ writel(ACK_INTERRUPT | ARBCACK | LATCH_ACK, xl_mmio + MMIO_COMMAND) ; diff --git a/drivers/net/tokenring/Kconfig b/drivers/net/tokenring/Kconfig index e6b2e06493e79b4c0fe05dbd5397bf48224b36d8..c4137b0f808e6bd443967f4f3f49c8d44d823daa 100644 --- a/drivers/net/tokenring/Kconfig +++ b/drivers/net/tokenring/Kconfig @@ -4,7 +4,7 @@ # So far, we only have PCI, ISA, and MCA token ring devices menuconfig TR - bool "Token Ring driver support" + tristate "Token Ring driver support" depends on NETDEVICES && !UML depends on (PCI || ISA || MCA || CCW) select LLC diff --git a/drivers/net/tokenring/abyss.c b/drivers/net/tokenring/abyss.c index 7a7de0469eae098412036df35e8b9b636e291622..b566d6d79ecdbe7ce0a5f58f7546f50e77600ec5 100644 --- a/drivers/net/tokenring/abyss.c +++ b/drivers/net/tokenring/abyss.c @@ -99,7 +99,6 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ struct net_local *tp; int ret, pci_irq_line; unsigned long pci_ioaddr; - DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -147,8 +146,7 @@ static int __devinit abyss_attach(struct pci_dev *pdev, const struct pci_device_ abyss_read_eeprom(dev); - printk("%s: Ring Station Address: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: Ring Station Address: %pM\n", dev->name, dev->dev_addr); tp = netdev_priv(dev); tp->setnselout = abyss_setnselout_pins; diff --git a/drivers/net/tokenring/ibmtr.c b/drivers/net/tokenring/ibmtr.c index e494c63bfbd9643088c0c30680fdc956becf8b60..fa7bce6e0c6dc56019d18197b2076ddfd3e6a3d8 100644 --- a/drivers/net/tokenring/ibmtr.c +++ b/drivers/net/tokenring/ibmtr.c @@ -389,7 +389,6 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) unsigned long timeout; static int version_printed; #endif - DECLARE_MAC_BUF(mac); /* Query the adapter PIO base port which will return * indication of where MMIO was placed. We also have a @@ -703,8 +702,7 @@ static int __devinit ibmtr_probe1(struct net_device *dev, int PIOaddr) channel_def[cardpresent - 1], adapter_def(ti->adapter_type)); DPRINTK("using irq %d, PIOaddr %hx, %dK shared RAM.\n", irq, PIOaddr, ti->mapped_ram_size / 2); - DPRINTK("Hardware address : %s\n", - print_mac(mac, dev->dev_addr)); + DPRINTK("Hardware address : %pM\n", dev->dev_addr); if (ti->page_mask) DPRINTK("Shared RAM paging enabled. " "Page size: %uK Shared Ram size %dK\n", @@ -1741,8 +1739,6 @@ static void tr_rx(struct net_device *dev) void __iomem *trhhdr = rbuf + offsetof(struct rec_buf, data); u8 saddr[6]; u8 daddr[6]; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); int i; for (i = 0 ; i < 6 ; i++) saddr[i] = readb(trhhdr + SADDR_OFST + i); @@ -1750,9 +1746,9 @@ static void tr_rx(struct net_device *dev) daddr[i] = readb(trhhdr + DADDR_OFST + i); DPRINTK("Probably non-IP frame received.\n"); DPRINTK("ssap: %02X dsap: %02X " - "saddr: %s daddr: %$s\n", + "saddr: %pM daddr: %pM\n", readb(llc + SSAP_OFST), readb(llc + DSAP_OFST), - print_mac(mac, saddr), print_mac(mac2, daddr)); + saddr, daddr); } #endif @@ -1826,7 +1822,6 @@ static void tr_rx(struct net_device *dev) skb->ip_summed = CHECKSUM_COMPLETE; } netif_rx(skb); - dev->last_rx = jiffies; } /*tr_rx */ /*****************************************************************************/ @@ -1842,8 +1837,8 @@ static void ibmtr_reset_timer(struct timer_list *tmr, struct net_device *dev) /*****************************************************************************/ -void tok_rerun(unsigned long dev_addr){ - +static void tok_rerun(unsigned long dev_addr) +{ struct net_device *dev = (struct net_device *)dev_addr; struct tok_info *ti = netdev_priv(dev); diff --git a/drivers/net/tokenring/lanstreamer.c b/drivers/net/tokenring/lanstreamer.c index 59d1673f9387febe69304c48e1c6a17a6e19e538..239c75217b120624d7ae500ce919552a869507b5 100644 --- a/drivers/net/tokenring/lanstreamer.c +++ b/drivers/net/tokenring/lanstreamer.c @@ -446,9 +446,6 @@ static int streamer_reset(struct net_device *dev) unsigned int uaa_addr; struct sk_buff *skb = NULL; __u16 misr; -#if STREAMER_DEBUG - DECLARE_MAC_BUF(mac); -#endif streamer_priv = netdev_priv(dev); streamer_mmio = streamer_priv->streamer_mmio; @@ -577,8 +574,7 @@ static int streamer_reset(struct net_device *dev) dev->dev_addr[i+1]= addr & 0xff; } #if STREAMER_DEBUG - printk("Adapter address: %s\n", - print_mac(mac, dev->dev_addr)); + printk("Adapter address: %pM\n", dev->dev_addr); #endif } return 0; @@ -1013,7 +1009,6 @@ static void streamer_rx(struct net_device *dev) /* send up to the protocol */ netif_rx(skb); } - dev->last_rx = jiffies; streamer_priv->streamer_stats.rx_packets++; streamer_priv->streamer_stats.rx_bytes += length; } /* if skb == null */ @@ -1538,7 +1533,6 @@ static void streamer_arb_cmd(struct net_device *dev) #if STREAMER_NETWORK_MONITOR struct trh_hdr *mac_hdr; - DECLARE_MAC_BUF(mac); #endif writew(streamer_priv->arb, streamer_mmio + LAPA); @@ -1611,11 +1605,11 @@ static void streamer_arb_cmd(struct net_device *dev) dev->name); mac_hdr = tr_hdr(mac_frame); printk(KERN_WARNING - "%s: MAC Frame Dest. Addr: %s\n", - dev->name, print_mac(mac, mac_hdr->daddr)); + "%s: MAC Frame Dest. Addr: %pM\n", + dev->name, mac_hdr->daddr); printk(KERN_WARNING - "%s: MAC Frame Srce. Addr: %s\n", - dev->name, DEV->ADDR6(mac_hdr->saddr)); + "%s: MAC Frame Srce. Addr: %pM\n", + dev->name, mac_hdr->saddr); #endif netif_rx(mac_frame); @@ -1850,8 +1844,6 @@ static int sprintf_info(char *buffer, struct net_device *dev) struct streamer_parameters_table spt; int size = 0; int i; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); writew(streamer_priv->streamer_addr_table_addr, streamer_mmio + LAPA); for (i = 0; i < 14; i += 2) { @@ -1873,9 +1865,8 @@ static int sprintf_info(char *buffer, struct net_device *dev) size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name); size += sprintf(buffer + size, - "%6s: %s : %s : %02x:%02x:%02x:%02x\n", - dev->name, print_mac(mac, dev->dev_addr), - print_mac(mac2, sat.node_addr), + "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n", + dev->name, dev->dev_addr, sat.node_addr, sat.func_addr[0], sat.func_addr[1], sat.func_addr[2], sat.func_addr[3]); @@ -1884,19 +1875,18 @@ static int sprintf_info(char *buffer, struct net_device *dev) size += sprintf(buffer + size, "%6s: Physical Addr : Up Node Address : Poll Address : AccPri : Auth Src : Att Code :\n", dev->name); size += sprintf(buffer + size, - "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n", + "%6s: %02x:%02x:%02x:%02x : %pM : %pM : %04x : %04x : %04x :\n", dev->name, spt.phys_addr[0], spt.phys_addr[1], spt.phys_addr[2], spt.phys_addr[3], - print_mac(mac, spt.up_node_addr), - print_mac(mac2, spt.poll_addr), + spt.up_node_addr, spt.poll_addr, ntohs(spt.acc_priority), ntohs(spt.auth_source_class), ntohs(spt.att_code)); size += sprintf(buffer + size, "%6s: Source Address : Bcn T : Maj. V : Lan St : Lcl Rg : Mon Err : Frame Correl : \n", dev->name); size += sprintf(buffer + size, - "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n", - dev->name, print_mac(mac, spt.source_addr), + "%6s: %pM : %04x : %04x : %04x : %04x : %04x : %04x : \n", + dev->name, spt.source_addr, ntohs(spt.beacon_type), ntohs(spt.major_vector), ntohs(spt.lan_status), ntohs(spt.local_ring), ntohs(spt.mon_error), ntohs(spt.frame_correl)); @@ -1905,10 +1895,10 @@ static int sprintf_info(char *buffer, struct net_device *dev) dev->name); size += sprintf(buffer + size, - "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n", + "%6s: : %02x : %02x : %pM : %02x:%02x:%02x:%02x : \n", dev->name, ntohs(spt.beacon_transmit), ntohs(spt.beacon_receive), - print_mac(mac, spt.beacon_naun), + spt.beacon_naun, spt.beacon_phys[0], spt.beacon_phys[1], spt.beacon_phys[2], spt.beacon_phys[3]); return size; diff --git a/drivers/net/tokenring/madgemc.c b/drivers/net/tokenring/madgemc.c index c9c5a2b1ed9e9ea6a49d8e5f2af22e9799adb403..917b4d201e099da1aa3ed3a7b64f78ea4a5aceed 100644 --- a/drivers/net/tokenring/madgemc.c +++ b/drivers/net/tokenring/madgemc.c @@ -152,7 +152,6 @@ static int __devinit madgemc_probe(struct device *device) struct card_info *card; struct mca_device *mdev = to_mca_device(device); int ret = 0; - DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -323,8 +322,8 @@ static int __devinit madgemc_probe(struct device *device) mca_device_set_name(mdev, (card->cardtype == 0x08)?MADGEMC16_CARDNAME:MADGEMC32_CARDNAME); mca_set_adapter_procfn(mdev->slot, madgemc_mcaproc, dev); - printk("%s: Ring Station Address: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: Ring Station Address: %pM\n", + dev->name, dev->dev_addr); if (tmsdev_init(dev, device)) { printk("%s: unable to get memory for dev->priv.\n", @@ -467,7 +466,7 @@ static irqreturn_t madgemc_interrupt(int irq, void *dev_id) * zero to leave the TMS NSELOUT bits unaffected. * */ -unsigned short madgemc_setnselout_pins(struct net_device *dev) +static unsigned short madgemc_setnselout_pins(struct net_device *dev) { unsigned char reg1; struct net_local *tp = netdev_priv(dev); @@ -690,7 +689,6 @@ static int madgemc_mcaproc(char *buf, int slot, void *d) struct net_local *tp = netdev_priv(dev); struct card_info *curcard = tp->tmspriv; int len = 0; - DECLARE_MAC_BUF(mac); len += sprintf(buf+len, "-------\n"); if (curcard) { @@ -714,8 +712,8 @@ static int madgemc_mcaproc(char *buf, int slot, void *d) } len += sprintf(buf+len, " (%s)\n", (curcard->fairness)?"Unfair":"Fair"); - len += sprintf(buf+len, "Ring Station Address: %s\n", - print_mac(mac, dev->dev_addr)); + len += sprintf(buf+len, "Ring Station Address: %pM\n", + dev->dev_addr); } else len += sprintf(buf+len, "Card not configured\n"); diff --git a/drivers/net/tokenring/olympic.c b/drivers/net/tokenring/olympic.c index 0ab51a0f35fc9cc5ae811610bc776759ff49c453..ecb5c7c969105ff6d79622f17f50a47c6ea3bd3e 100644 --- a/drivers/net/tokenring/olympic.c +++ b/drivers/net/tokenring/olympic.c @@ -421,10 +421,7 @@ static int olympic_init(struct net_device *dev) memcpy_fromio(&dev->dev_addr[0], adapter_addr,6); #if OLYMPIC_DEBUG - { - DECLARE_MAC_BUF(mac); - printk("adapter address: %s\n", print_mac(mac, dev->dev_addr)); - } + printk("adapter address: %pM\n", dev->dev_addr); #endif olympic_priv->olympic_addr_table_addr = swab16(readw(init_srb + 12)); @@ -441,7 +438,6 @@ static int olympic_open(struct net_device *dev) unsigned long flags, t; int i, open_finished = 1 ; u8 resp, err; - DECLARE_MAC_BUF(mac); DECLARE_WAITQUEUE(wait,current) ; @@ -569,8 +565,8 @@ static int olympic_open(struct net_device *dev) goto out; case 0x32: - printk(KERN_WARNING "%s: Invalid LAA: %s\n", - dev->name, print_mac(mac, olympic_priv->olympic_laa)); + printk(KERN_WARNING "%s: Invalid LAA: %pM\n", + dev->name, olympic_priv->olympic_laa); goto out; default: @@ -704,13 +700,12 @@ static int olympic_open(struct net_device *dev) u8 __iomem *opt; int i; u8 addr[6]; - DECLARE_MAC_BUF(mac); oat = (olympic_priv->olympic_lap + olympic_priv->olympic_addr_table_addr); opt = (olympic_priv->olympic_lap + olympic_priv->olympic_parms_addr); for (i = 0; i < 6; i++) addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr)+i); - printk("%s: Node Address: %s\n",dev->name, print_mac(mac, addr)); + printk("%s: Node Address: %pM\n", dev->name, addr); printk("%s: Functional Address: %02x:%02x:%02x:%02x\n",dev->name, readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), @@ -719,7 +714,7 @@ static int olympic_open(struct net_device *dev) for (i = 0; i < 6; i++) addr[i] = readb(opt+offsetof(struct olympic_parameters_table, up_node_addr)+i); - printk("%s: NAUN Address: %s\n",dev->name, print_mac(mac, addr)); + printk("%s: NAUN Address: %pM\n", dev->name, addr); } netif_start_queue(dev); @@ -867,7 +862,6 @@ static void olympic_rx(struct net_device *dev) skb->protocol = tr_type_trans(skb,dev); netif_rx(skb) ; } - dev->last_rx = jiffies ; olympic_priv->olympic_stats.rx_packets++ ; olympic_priv->olympic_stats.rx_bytes += length ; } /* if skb == null */ @@ -1440,19 +1434,12 @@ static void olympic_arb_cmd(struct net_device *dev) struct trh_hdr *mac_hdr; printk(KERN_WARNING "%s: Received MAC Frame, details: \n",dev->name); mac_hdr = tr_hdr(mac_frame); - printk(KERN_WARNING "%s: MAC Frame Dest. Addr: " - MAC_FMT " \n", dev->name, - mac_hdr->daddr[0], mac_hdr->daddr[1], - mac_hdr->daddr[2], mac_hdr->daddr[3], - mac_hdr->daddr[4], mac_hdr->daddr[5]); - printk(KERN_WARNING "%s: MAC Frame Srce. Addr: " - MAC_FMT " \n", dev->name, - mac_hdr->saddr[0], mac_hdr->saddr[1], - mac_hdr->saddr[2], mac_hdr->saddr[3], - mac_hdr->saddr[4], mac_hdr->saddr[5]); + printk(KERN_WARNING "%s: MAC Frame Dest. Addr: %pM\n", + dev->name, mac_hdr->daddr); + printk(KERN_WARNING "%s: MAC Frame Srce. Addr: %pM\n", + dev->name, mac_hdr->saddr); } netif_rx(mac_frame); - dev->last_rx = jiffies; drop_frame: /* Now tell the card we have dealt with the received frame */ @@ -1647,8 +1634,6 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt u8 addr[6]; u8 addr2[6]; int i; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); size = sprintf(buffer, "IBM Pit/Pit-Phy/Olympic Chipset Token Ring Adapter %s\n",dev->name); @@ -1658,10 +1643,9 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt for (i = 0 ; i < 6 ; i++) addr[i] = readb(oat+offsetof(struct olympic_adapter_addr_table,node_addr) + i); - size += sprintf(buffer+size, "%6s: %s : %s : %02x:%02x:%02x:%02x\n", + size += sprintf(buffer+size, "%6s: %pM : %pM : %02x:%02x:%02x:%02x\n", dev->name, - print_mac(mac, dev->dev_addr), - print_mac(mac2, addr), + dev->dev_addr, addr, readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+1), readb(oat+offsetof(struct olympic_adapter_addr_table,func_addr)+2), @@ -1677,14 +1661,13 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt for (i = 0 ; i < 6 ; i++) addr2[i] = readb(opt+offsetof(struct olympic_parameters_table, poll_addr) + i); - size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %s : %s : %04x : %04x : %04x :\n", + size += sprintf(buffer+size, "%6s: %02x:%02x:%02x:%02x : %pM : %pM : %04x : %04x : %04x :\n", dev->name, readb(opt+offsetof(struct olympic_parameters_table, phys_addr)), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+1), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+2), readb(opt+offsetof(struct olympic_parameters_table, phys_addr)+3), - print_mac(mac, addr), - print_mac(mac2, addr2), + addr, addr2, swab16(readw(opt+offsetof(struct olympic_parameters_table, acc_priority))), swab16(readw(opt+offsetof(struct olympic_parameters_table, auth_source_class))), swab16(readw(opt+offsetof(struct olympic_parameters_table, att_code)))); @@ -1694,9 +1677,8 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt for (i = 0 ; i < 6 ; i++) addr[i] = readb(opt+offsetof(struct olympic_parameters_table, source_addr) + i); - size += sprintf(buffer+size, "%6s: %s : %04x : %04x : %04x : %04x : %04x : %04x : \n", - dev->name, - print_mac(mac, addr), + size += sprintf(buffer+size, "%6s: %pM : %04x : %04x : %04x : %04x : %04x : %04x : \n", + dev->name, addr, swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_type))), swab16(readw(opt+offsetof(struct olympic_parameters_table, major_vector))), swab16(readw(opt+offsetof(struct olympic_parameters_table, lan_status))), @@ -1709,11 +1691,11 @@ static int olympic_proc_info(char *buffer, char **start, off_t offset, int lengt for (i = 0 ; i < 6 ; i++) addr[i] = readb(opt+offsetof(struct olympic_parameters_table, beacon_naun) + i); - size += sprintf(buffer+size, "%6s: : %02x : %02x : %s : %02x:%02x:%02x:%02x : \n", + size += sprintf(buffer+size, "%6s: : %02x : %02x : %pM : %02x:%02x:%02x:%02x : \n", dev->name, swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_transmit))), swab16(readw(opt+offsetof(struct olympic_parameters_table, beacon_receive))), - print_mac(mac, addr), + addr, readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+1), readb(opt+offsetof(struct olympic_parameters_table, beacon_phys)+2), diff --git a/drivers/net/tokenring/proteon.c b/drivers/net/tokenring/proteon.c index 00ea94513460d5e118b811a3496625b98ad4a9cb..b8c955f6d31ae8355307b872b9c55e6abb650937 100644 --- a/drivers/net/tokenring/proteon.c +++ b/drivers/net/tokenring/proteon.c @@ -122,7 +122,6 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) static int versionprinted; const unsigned *port; int j,err = 0; - DECLARE_MAC_BUF(mac); if (!dev) return -ENOMEM; @@ -153,8 +152,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) proteon_read_eeprom(dev); - printk(KERN_DEBUG "proteon.c: Ring Station Address: %s\n", - print_mac(mac, dev->dev_addr)); + printk(KERN_DEBUG "proteon.c: Ring Station Address: %pM\n", + dev->dev_addr); tp = netdev_priv(dev); tp->setnselout = proteon_setnselout_pins; @@ -284,7 +283,7 @@ static void proteon_read_eeprom(struct net_device *dev) dev->dev_addr[i] = proteon_sifreadw(dev, SIFINC) >> 8; } -unsigned short proteon_setnselout_pins(struct net_device *dev) +static unsigned short proteon_setnselout_pins(struct net_device *dev) { return 0; } diff --git a/drivers/net/tokenring/skisa.c b/drivers/net/tokenring/skisa.c index 41b6999a0f33487719f56898a489c9748b975f7f..c0f58f08782cd543d6df4bd3c4a883b4cc6aa269 100644 --- a/drivers/net/tokenring/skisa.c +++ b/drivers/net/tokenring/skisa.c @@ -139,7 +139,6 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) static int versionprinted; const unsigned *port; int j, err = 0; - DECLARE_MAC_BUF(mac); if (!dev) return -ENOMEM; @@ -170,8 +169,8 @@ static int __init setup_card(struct net_device *dev, struct device *pdev) sk_isa_read_eeprom(dev); - printk(KERN_DEBUG "skisa.c: Ring Station Address: %s\n", - print_mac(mac, dev->dev_addr)); + printk(KERN_DEBUG "skisa.c: Ring Station Address: %pM\n", + dev->dev_addr); tp = netdev_priv(dev); tp->setnselout = sk_isa_setnselout_pins; @@ -301,7 +300,7 @@ static void sk_isa_read_eeprom(struct net_device *dev) dev->dev_addr[i] = sk_isa_sifreadw(dev, SIFINC) >> 8; } -unsigned short sk_isa_setnselout_pins(struct net_device *dev) +static unsigned short sk_isa_setnselout_pins(struct net_device *dev) { return 0; } diff --git a/drivers/net/tokenring/smctr.c b/drivers/net/tokenring/smctr.c index ed50d288e4940a79bdefca127a6c92d5713ab45d..a011666342ffb62af52bdea2a8eba09980ee777f 100644 --- a/drivers/net/tokenring/smctr.c +++ b/drivers/net/tokenring/smctr.c @@ -3910,7 +3910,6 @@ static int smctr_process_rx_packet(MAC_HEADER *rmf, __u16 size, /* Kick the packet on up. */ skb->protocol = tr_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; err = 0; } @@ -4496,7 +4495,6 @@ static int smctr_rx_frame(struct net_device *dev) /* Kick the packet on up. */ skb->protocol = tr_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; } else { } } diff --git a/drivers/net/tokenring/tms380tr.c b/drivers/net/tokenring/tms380tr.c index d07c4523c847a1ceb3c4e98876c1cce025459b2c..5be34c2fd48385751844d82dc0c12b1e6d5390d4 100644 --- a/drivers/net/tokenring/tms380tr.c +++ b/drivers/net/tokenring/tms380tr.c @@ -180,10 +180,14 @@ void tms380tr_wait(unsigned long time); static void tms380tr_write_rpl_status(RPL *rpl, unsigned int Status); static void tms380tr_write_tpl_status(TPL *tpl, unsigned int Status); -#define SIFREADB(reg) (((struct net_local *)dev->priv)->sifreadb(dev, reg)) -#define SIFWRITEB(val, reg) (((struct net_local *)dev->priv)->sifwriteb(dev, val, reg)) -#define SIFREADW(reg) (((struct net_local *)dev->priv)->sifreadw(dev, reg)) -#define SIFWRITEW(val, reg) (((struct net_local *)dev->priv)->sifwritew(dev, val, reg)) +#define SIFREADB(reg) \ + (((struct net_local *)netdev_priv(dev))->sifreadb(dev, reg)) +#define SIFWRITEB(val, reg) \ + (((struct net_local *)netdev_priv(dev))->sifwriteb(dev, val, reg)) +#define SIFREADW(reg) \ + (((struct net_local *)netdev_priv(dev))->sifreadw(dev, reg)) +#define SIFWRITEW(val, reg) \ + (((struct net_local *)netdev_priv(dev))->sifwritew(dev, val, reg)) @@ -2186,7 +2190,6 @@ static void tms380tr_rcv_status_irq(struct net_device *dev) skb_trim(skb,Length); skb->protocol = tr_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; } } else /* Invalid frame */ @@ -2331,7 +2334,7 @@ int tmsdev_init(struct net_device *dev, struct device *pdev) { struct net_local *tms_local; - memset(dev->priv, 0, sizeof(struct net_local)); + memset(netdev_priv(dev), 0, sizeof(struct net_local)); tms_local = netdev_priv(dev); init_waitqueue_head(&tms_local->wait_for_tok_int); if (pdev->dma_mask) diff --git a/drivers/net/tokenring/tmspci.c b/drivers/net/tokenring/tmspci.c index 5f0ee880cfff1f7fa4d7c5096265322f043bef39..5f601773c26064e7962e6bc5026018f5f1c666af 100644 --- a/drivers/net/tokenring/tmspci.c +++ b/drivers/net/tokenring/tmspci.c @@ -100,7 +100,6 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic unsigned int pci_irq_line; unsigned long pci_ioaddr; struct card_info *cardinfo = &card_info_table[ent->driver_data]; - DECLARE_MAC_BUF(mac); if (versionprinted++ == 0) printk("%s", version); @@ -137,8 +136,8 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic tms_pci_read_eeprom(dev); - printk("%s: Ring Station Address: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk("%s: Ring Station Address: %pM\n", + dev->name, dev->dev_addr); ret = tmsdev_init(dev, &pdev->dev); if (ret) { diff --git a/drivers/net/tsi108_eth.c b/drivers/net/tsi108_eth.c index eb1da6f0b0863cbd827224ddebbc3d5e19275e35..75461dbd487657bd8e6a8002499db7c54fe2d774 100644 --- a/drivers/net/tsi108_eth.c +++ b/drivers/net/tsi108_eth.c @@ -788,7 +788,6 @@ static int tsi108_complete_rx(struct net_device *dev, int budget) skb_put(skb, data->rxring[rx].len); skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; } return done; @@ -889,7 +888,7 @@ static int tsi108_poll(struct napi_struct *napi, int budget) if (num_received < budget) { data->rxpending = 0; - netif_rx_complete(dev, napi); + netif_rx_complete(napi); TSI_WRITE(TSI108_EC_INTMASK, TSI_READ(TSI108_EC_INTMASK) @@ -920,7 +919,7 @@ static void tsi108_rx_int(struct net_device *dev) * from tsi108_check_rxring(). */ - if (netif_rx_schedule_prep(dev, &data->napi)) { + if (netif_rx_schedule_prep(&data->napi)) { /* Mask, rather than ack, the receive interrupts. The ack * will happen in tsi108_poll(). */ @@ -931,7 +930,7 @@ static void tsi108_rx_int(struct net_device *dev) | TSI108_INT_RXTHRESH | TSI108_INT_RXOVERRUN | TSI108_INT_RXERROR | TSI108_INT_RXWAIT); - __netif_rx_schedule(dev, &data->napi); + __netif_rx_schedule(&data->napi); } else { if (!netif_running(dev)) { /* This can happen if an interrupt occurs while the @@ -1569,7 +1568,6 @@ tsi108_init_one(struct platform_device *pdev) struct tsi108_prv_data *data = NULL; hw_info *einfo; int err = 0; - DECLARE_MAC_BUF(mac); einfo = pdev->dev.platform_data; @@ -1659,8 +1657,8 @@ tsi108_init_one(struct platform_device *pdev) } platform_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Tsi108 Gigabit Ethernet, MAC: %pM\n", + dev->name, dev->dev_addr); #ifdef DEBUG data->msg_enable = DEBUG; dump_eth_one(dev); diff --git a/drivers/net/tulip/de2104x.c b/drivers/net/tulip/de2104x.c index 124d5d690dde2508a29b8d5ae7bd907bcd259c38..5166be930a52c204f38d99394d4cdbff1fa6be94 100644 --- a/drivers/net/tulip/de2104x.c +++ b/drivers/net/tulip/de2104x.c @@ -459,7 +459,6 @@ static void de_rx (struct de_private *de) de->net_stats.rx_packets++; de->net_stats.rx_bytes += skb->len; - de->dev->last_rx = jiffies; rc = netif_rx (skb); if (rc == NET_RX_DROP) drop = 1; @@ -484,7 +483,7 @@ rx_next: static irqreturn_t de_interrupt (int irq, void *dev_instance) { struct net_device *dev = dev_instance; - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); u32 status; status = dr32(MacStatus); @@ -590,7 +589,7 @@ next: static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); unsigned int entry, tx_free; u32 mapping, len, flags = FirstFrag | LastFrag; struct de_desc *txd; @@ -653,7 +652,7 @@ static int de_start_xmit (struct sk_buff *skb, struct net_device *dev) static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); u16 hash_table[32]; struct dev_mc_list *mclist; int i; @@ -684,7 +683,7 @@ static void build_setup_frame_hash(u16 *setup_frm, struct net_device *dev) static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); struct dev_mc_list *mclist; int i; u16 *eaddrs; @@ -712,7 +711,7 @@ static void build_setup_frame_perfect(u16 *setup_frm, struct net_device *dev) static void __de_set_rx_mode (struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); u32 macmode; unsigned int entry; u32 mapping; @@ -797,7 +796,7 @@ out: static void de_set_rx_mode (struct net_device *dev) { unsigned long flags; - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); spin_lock_irqsave (&de->lock, flags); __de_set_rx_mode(dev); @@ -821,7 +820,7 @@ static void __de_get_stats(struct de_private *de) static struct net_device_stats *de_get_stats(struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); /* The chip only need report frame silently dropped. */ spin_lock_irq(&de->lock); @@ -1355,7 +1354,7 @@ static void de_free_rings (struct de_private *de) static int de_open (struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); int rc; if (netif_msg_ifup(de)) @@ -1400,7 +1399,7 @@ err_out_free: static int de_close (struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); unsigned long flags; if (netif_msg_ifdown(de)) @@ -1423,7 +1422,7 @@ static int de_close (struct net_device *dev) static void de_tx_timeout (struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); printk(KERN_DEBUG "%s: NIC status %08x mode %08x sia %08x desc %u/%u/%u\n", dev->name, dr32(MacStatus), dr32(MacMode), dr32(SIAStatus), @@ -1574,7 +1573,7 @@ static int __de_set_settings(struct de_private *de, struct ethtool_cmd *ecmd) static void de_get_drvinfo (struct net_device *dev,struct ethtool_drvinfo *info) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); strcpy (info->driver, DRV_NAME); strcpy (info->version, DRV_VERSION); @@ -1589,7 +1588,7 @@ static int de_get_regs_len(struct net_device *dev) static int de_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); int rc; spin_lock_irq(&de->lock); @@ -1601,7 +1600,7 @@ static int de_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static int de_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); int rc; spin_lock_irq(&de->lock); @@ -1613,14 +1612,14 @@ static int de_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) static u32 de_get_msglevel(struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); return de->msg_enable; } static void de_set_msglevel(struct net_device *dev, u32 msglvl) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); de->msg_enable = msglvl; } @@ -1628,7 +1627,7 @@ static void de_set_msglevel(struct net_device *dev, u32 msglvl) static int de_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); if (!de->ee_data) return -EOPNOTSUPP; @@ -1642,7 +1641,7 @@ static int de_get_eeprom(struct net_device *dev, static int de_nway_reset(struct net_device *dev) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); u32 status; if (de->media_type != DE_MEDIA_TP_AUTO) @@ -1661,7 +1660,7 @@ static int de_nway_reset(struct net_device *dev) static void de_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *data) { - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); regs->version = (DE_REGS_VER << 2) | de->de21040; @@ -1692,9 +1691,9 @@ static void __devinit de21040_get_mac_address (struct de_private *de) for (i = 0; i < 6; i++) { int value, boguscnt = 100000; - do + do { value = dr32(ROMCmd); - while (value < 0 && --boguscnt > 0); + } while (value < 0 && --boguscnt > 0); de->dev->dev_addr[i] = value; udelay(1); if (boguscnt <= 0) @@ -1932,7 +1931,6 @@ static int __devinit de_init_one (struct pci_dev *pdev, void __iomem *regs; unsigned long pciaddr; static int board_idx = -1; - DECLARE_MAC_BUF(mac); board_idx++; @@ -1956,7 +1954,7 @@ static int __devinit de_init_one (struct pci_dev *pdev, dev->tx_timeout = de_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; - de = dev->priv; + de = netdev_priv(dev); de->de21040 = ent->driver_data == 0 ? 1 : 0; de->pdev = pdev; de->dev = dev; @@ -2046,11 +2044,11 @@ static int __devinit de_init_one (struct pci_dev *pdev, goto err_out_iomap; /* print info about board and interface just registered */ - printk (KERN_INFO "%s: %s at 0x%lx, %s, IRQ %d\n", + printk (KERN_INFO "%s: %s at 0x%lx, %pM, IRQ %d\n", dev->name, de->de21040 ? "21040" : "21041", dev->base_addr, - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); pci_set_drvdata(pdev, dev); @@ -2078,7 +2076,7 @@ err_out_free: static void __devexit de_remove_one (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); BUG_ON(!dev); unregister_netdev(dev); @@ -2095,7 +2093,7 @@ static void __devexit de_remove_one (struct pci_dev *pdev) static int de_suspend (struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata (pdev); - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); rtnl_lock(); if (netif_running (dev)) { @@ -2130,7 +2128,7 @@ static int de_suspend (struct pci_dev *pdev, pm_message_t state) static int de_resume (struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata (pdev); - struct de_private *de = dev->priv; + struct de_private *de = netdev_priv(dev); int retval = 0; rtnl_lock(); diff --git a/drivers/net/tulip/de4x5.c b/drivers/net/tulip/de4x5.c index 6444cbec0bdc8dd02a0a9eca4c2066af15be2a96..67bfd6f4336617854f1c627544a4181b226ad585 100644 --- a/drivers/net/tulip/de4x5.c +++ b/drivers/net/tulip/de4x5.c @@ -1085,7 +1085,6 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) struct de4x5_private *lp = netdev_priv(dev); struct pci_dev *pdev = NULL; int i, status=0; - DECLARE_MAC_BUF(mac); gendev->driver_data = dev; @@ -1119,10 +1118,10 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) } dev->base_addr = iobase; - printk ("%s: %s at 0x%04lx", gendev->bus_id, name, iobase); + printk ("%s: %s at 0x%04lx", dev_name(gendev), name, iobase); status = get_hw_addr(dev); - printk(", h/w address %s\n", print_mac(mac, dev->dev_addr)); + printk(", h/w address %pM\n", dev->dev_addr); if (status != 0) { printk(" which has an Ethernet PROM CRC error.\n"); @@ -1154,7 +1153,7 @@ de4x5_hw_init(struct net_device *dev, u_long iobase, struct device *gendev) } } lp->fdx = lp->params.fdx; - sprintf(lp->adapter_name,"%s (%s)", name, gendev->bus_id); + sprintf(lp->adapter_name,"%s (%s)", name, dev_name(gendev)); lp->dma_size = (NUM_RX_DESC + NUM_TX_DESC) * sizeof(struct de4x5_desc); #if defined(__alpha__) || defined(__powerpc__) || defined(CONFIG_SPARC) || defined(DE4X5_DO_MEMCPY) @@ -1647,7 +1646,6 @@ de4x5_rx(struct net_device *dev) netif_rx(skb); /* Update stats */ - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += pkt_len; } @@ -5401,7 +5399,6 @@ static void de4x5_dbg_srom(struct de4x5_srom *p) { int i; - DECLARE_MAC_BUF(mac); if (de4x5_debug & DEBUG_SROM) { printk("Sub-system Vendor ID: %04x\n", *((u_short *)p->sub_vendor_id)); @@ -5410,7 +5407,7 @@ de4x5_dbg_srom(struct de4x5_srom *p) printk("SROM version: %02x\n", (u_char)(p->version)); printk("# controllers: %02x\n", (u_char)(p->num_controllers)); - printk("Hardware Address: %s\n", print_mac(mac, p->ieee_addr)); + printk("Hardware Address: %pM\n", p->ieee_addr); printk("CRC checksum: %04x\n", (u_short)(p->chksum)); for (i=0; i<64; i++) { printk("%3d %04x\n", i<<1, (u_short)*((u_short *)p+i)); @@ -5424,12 +5421,10 @@ static void de4x5_dbg_rx(struct sk_buff *skb, int len) { int i, j; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); if (de4x5_debug & DEBUG_RX) { - printk("R: %s <- %s len/SAP:%02x%02x [%d]\n", - print_mac(mac, skb->data), print_mac(mac2, &skb->data[6]), + printk("R: %pM <- %pM len/SAP:%02x%02x [%d]\n", + skb->data, &skb->data[6], (u_char)skb->data[12], (u_char)skb->data[13], len); diff --git a/drivers/net/tulip/dmfe.c b/drivers/net/tulip/dmfe.c index c91852f49a48e015cfc6056d337607087263f837..28a5c51b43a0654a846a2a4fa33f92f64d516602 100644 --- a/drivers/net/tulip/dmfe.c +++ b/drivers/net/tulip/dmfe.c @@ -362,7 +362,6 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, struct net_device *dev; u32 pci_pmr; int i, err; - DECLARE_MAC_BUF(mac); DMFE_DBUG(0, "dmfe_init_one()", 0); @@ -475,12 +474,11 @@ static int __devinit dmfe_init_one (struct pci_dev *pdev, if (err) goto err_out_free_buf; - printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, " - "%s, irq %d.\n", + printk(KERN_INFO "%s: Davicom DM%04lx at pci%s, %pM, irq %d.\n", dev->name, ent->driver_data >> 16, pci_name(pdev), - print_mac(mac, dev->dev_addr), + dev->dev_addr, dev->irq); pci_set_master(pdev); @@ -1010,7 +1008,6 @@ static void dmfe_rx_packet(struct DEVICE *dev, struct dmfe_board_info * db) skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; db->stats.rx_packets++; db->stats.rx_bytes += rxlen; } diff --git a/drivers/net/tulip/eeprom.c b/drivers/net/tulip/eeprom.c index 0dcced1263b9879fdf072b02d65f4d879da761d2..391acd32a6a5c04cc6234ddcb1b8833bff3f7a18 100644 --- a/drivers/net/tulip/eeprom.c +++ b/drivers/net/tulip/eeprom.c @@ -337,7 +337,7 @@ int __devinit tulip_read_eeprom(struct net_device *dev, int location, int addr_l { int i; unsigned retval = 0; - struct tulip_private *tp = dev->priv; + struct tulip_private *tp = netdev_priv(dev); void __iomem *ee_addr = tp->base_addr + CSR9; int read_cmd = location | (EE_READ_CMD << addr_len); diff --git a/drivers/net/tulip/interrupt.c b/drivers/net/tulip/interrupt.c index c6bad987d63e744c452ed9d8b999aa0affe441d0..6c3428a37c0b9d5c672e777b052a199710d01c97 100644 --- a/drivers/net/tulip/interrupt.c +++ b/drivers/net/tulip/interrupt.c @@ -103,7 +103,7 @@ void oom_timer(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct tulip_private *tp = netdev_priv(dev); - netif_rx_schedule(dev, &tp->napi); + netif_rx_schedule(&tp->napi); } int tulip_poll(struct napi_struct *napi, int budget) @@ -231,7 +231,6 @@ int tulip_poll(struct napi_struct *napi, int budget) netif_receive_skb(skb); - dev->last_rx = jiffies; tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; } @@ -301,7 +300,7 @@ int tulip_poll(struct napi_struct *napi, int budget) /* Remove us from polling list and enable RX intr. */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); iowrite32(tulip_tbl[tp->chip_id].valid_intrs, tp->base_addr+CSR7); /* The last op happens after poll completion. Which means the following: @@ -337,7 +336,7 @@ int tulip_poll(struct napi_struct *napi, int budget) * before we did netif_rx_complete(). See? We would lose it. */ /* remove ourselves from the polling list */ - netif_rx_complete(dev, napi); + netif_rx_complete(napi); return work_done; } @@ -444,7 +443,6 @@ static int tulip_rx(struct net_device *dev) netif_rx(skb); - dev->last_rx = jiffies; tp->stats.rx_packets++; tp->stats.rx_bytes += pkt_len; } @@ -521,7 +519,7 @@ irqreturn_t tulip_interrupt(int irq, void *dev_instance) rxd++; /* Mask RX intrs and add the device to poll list. */ iowrite32(tulip_tbl[tp->chip_id].valid_intrs&~RxPollInt, ioaddr + CSR7); - netif_rx_schedule(dev, &tp->napi); + netif_rx_schedule(&tp->napi); if (!(csr5&~(AbnormalIntr|NormalIntr|RxPollInt|TPLnkPass))) break; diff --git a/drivers/net/tulip/tulip_core.c b/drivers/net/tulip/tulip_core.c index cafa89e6016772b0a5442df05dd348ae4984c857..ff84babb3ff38af2954b8e348b04e40512171014 100644 --- a/drivers/net/tulip/tulip_core.c +++ b/drivers/net/tulip/tulip_core.c @@ -1050,13 +1050,11 @@ static void set_rx_mode(struct net_device *dev) filterbit = ether_crc(ETH_ALEN, mclist->dmi_addr) >> 26; filterbit &= 0x3f; mc_filter[filterbit >> 5] |= 1 << (filterbit & 31); - if (tulip_debug > 2) { - DECLARE_MAC_BUF(mac); - printk(KERN_INFO "%s: Added filter for %s" + if (tulip_debug > 2) + printk(KERN_INFO "%s: Added filter for %pM" " %8.8x bit %d.\n", - dev->name, print_mac(mac, mclist->dmi_addr), + dev->name, mclist->dmi_addr, ether_crc(ETH_ALEN, mclist->dmi_addr), filterbit); - } } if (mc_filter[0] == tp->mc_filter[0] && mc_filter[1] == tp->mc_filter[1]) @@ -1250,7 +1248,6 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, const char *chip_name = tulip_tbl[chip_idx].chip_name; unsigned int eeprom_missing = 0; unsigned int force_csr0 = 0; - DECLARE_MAC_BUF(mac); #ifndef MODULE static int did_version; /* Already printed version info. */ @@ -1432,9 +1429,9 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, for (i = 0; i < 3; i++) { int value, boguscnt = 100000; iowrite32(0x600 | i, ioaddr + 0x98); - do + do { value = ioread32(ioaddr + CSR9); - while (value < 0 && --boguscnt > 0); + } while (value < 0 && --boguscnt > 0); put_unaligned_le16(value, ((__le16 *)dev->dev_addr) + i); sum += value & 0xffff; } @@ -1635,7 +1632,7 @@ static int __devinit tulip_init_one (struct pci_dev *pdev, if (eeprom_missing) printk(" EEPROM not present,"); - printk(" %s", print_mac(mac, dev->dev_addr)); + printk(" %pM", dev->dev_addr); printk(", IRQ %d.\n", irq); if (tp->chip_id == PNIC2) diff --git a/drivers/net/tulip/uli526x.c b/drivers/net/tulip/uli526x.c index e9e628621639b6d5d8ceaf850086bf8da9587ab1..00cbc5251dccd16d083c69a93664fa5bb627e991 100644 --- a/drivers/net/tulip/uli526x.c +++ b/drivers/net/tulip/uli526x.c @@ -261,7 +261,6 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, struct uli526x_board_info *db; /* board information structure */ struct net_device *dev; int i, err; - DECLARE_MAC_BUF(mac); ULI526X_DBUG(0, "uli526x_init_one()", 0); @@ -379,9 +378,9 @@ static int __devinit uli526x_init_one (struct pci_dev *pdev, if (err) goto err_out_res; - printk(KERN_INFO "%s: ULi M%04lx at pci%s, %s, irq %d.\n", + printk(KERN_INFO "%s: ULi M%04lx at pci%s, %pM, irq %d.\n", dev->name,ent->driver_data >> 16,pci_name(pdev), - print_mac(mac, dev->dev_addr), dev->irq); + dev->dev_addr, dev->irq); pci_set_master(pdev); @@ -855,7 +854,6 @@ static void uli526x_rx_packet(struct net_device *dev, struct uli526x_board_info skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; db->stats.rx_packets++; db->stats.rx_bytes += rxlen; @@ -892,7 +890,7 @@ static struct net_device_stats * uli526x_get_stats(struct net_device *dev) static void uli526x_set_filter_mode(struct net_device * dev) { - struct uli526x_board_info *db = dev->priv; + struct uli526x_board_info *db = netdev_priv(dev); unsigned long flags; ULI526X_DBUG(0, "uli526x_set_filter_mode()", 0); diff --git a/drivers/net/tulip/winbond-840.c b/drivers/net/tulip/winbond-840.c index 50068194c163e55baec8c6e00bce96c970f56798..022d99af8646303bb25b1e0b7c7c4c6929fbee88 100644 --- a/drivers/net/tulip/winbond-840.c +++ b/drivers/net/tulip/winbond-840.c @@ -355,7 +355,6 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, int irq; int i, option = find_cnt < MAX_UNITS ? options[find_cnt] : 0; void __iomem *ioaddr; - DECLARE_MAC_BUF(mac); i = pci_enable_device(pdev); if (i) return i; @@ -435,9 +434,9 @@ static int __devinit w840_probe1 (struct pci_dev *pdev, if (i) goto err_out_cleardev; - printk(KERN_INFO "%s: %s at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s at %p, %pM, IRQ %d.\n", dev->name, pci_id_tbl[chip_idx].name, ioaddr, - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); if (np->drv_flags & CanHaveMII) { int phy, phy_idx = 0; @@ -1245,20 +1244,15 @@ static int netdev_rx(struct net_device *dev) } #ifndef final_version /* Remove after testing. */ /* You will want this info for the initial debug. */ - if (debug > 5) { - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - - printk(KERN_DEBUG " Rx data %s %s" + if (debug > 5) + printk(KERN_DEBUG " Rx data %pM %pM" " %2.2x%2.2x %d.%d.%d.%d.\n", - print_mac(mac, &skb->data[0]), print_mac(mac2, &skb->data[6]), + &skb->data[0], &skb->data[6], skb->data[12], skb->data[13], skb->data[14], skb->data[15], skb->data[16], skb->data[17]); - } #endif skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/tulip/xircom_cb.c b/drivers/net/tulip/xircom_cb.c index 6b93d016911650e0ef778ffeaf3dd9c06e370069..13c8703ecb9f0794e4ca718797a8ea0ea3ef8ed9 100644 --- a/drivers/net/tulip/xircom_cb.c +++ b/drivers/net/tulip/xircom_cb.c @@ -1072,7 +1072,6 @@ static void read_mac_address(struct xircom_private *card) unsigned char j, tuple, link, data_id, data_count; unsigned long flags; int i; - DECLARE_MAC_BUF(mac); enter("read_mac_address"); @@ -1102,7 +1101,7 @@ static void read_mac_address(struct xircom_private *card) } } spin_unlock_irqrestore(&card->lock, flags); - pr_debug(" %s\n", print_mac(mac, card->dev->dev_addr)); + pr_debug(" %pM\n", card->dev->dev_addr); leave("read_mac_address"); } @@ -1202,7 +1201,6 @@ static void investigate_read_descriptor(struct net_device *dev,struct xircom_pri skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; card->stats.rx_packets++; card->stats.rx_bytes += pkt_len; diff --git a/drivers/net/tun.c b/drivers/net/tun.c index 55dc70c6b4db093cc5c021bdd722cf59b4873888..666c1d98cdaf1d695aece39e195eac212d42e264 100644 --- a/drivers/net/tun.c +++ b/drivers/net/tun.c @@ -305,6 +305,23 @@ tun_net_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static const struct net_device_ops tun_netdev_ops = { + .ndo_open = tun_net_open, + .ndo_stop = tun_net_close, + .ndo_start_xmit = tun_net_xmit, + .ndo_change_mtu = tun_net_change_mtu, +}; + +static const struct net_device_ops tap_netdev_ops = { + .ndo_open = tun_net_open, + .ndo_stop = tun_net_close, + .ndo_start_xmit = tun_net_xmit, + .ndo_change_mtu = tun_net_change_mtu, + .ndo_set_multicast_list = tun_net_mclist, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, +}; + /* Initialize net device. */ static void tun_net_init(struct net_device *dev) { @@ -312,11 +329,12 @@ static void tun_net_init(struct net_device *dev) switch (tun->flags & TUN_TYPE_MASK) { case TUN_TUN_DEV: + dev->netdev_ops = &tun_netdev_ops; + /* Point-to-Point TUN Device */ dev->hard_header_len = 0; dev->addr_len = 0; dev->mtu = 1500; - dev->change_mtu = tun_net_change_mtu; /* Zero header length */ dev->type = ARPHRD_NONE; @@ -325,10 +343,9 @@ static void tun_net_init(struct net_device *dev) break; case TUN_TAP_DEV: + dev->netdev_ops = &tun_netdev_ops; /* Ethernet TAP Device */ ether_setup(dev); - dev->change_mtu = tun_net_change_mtu; - dev->set_multicast_list = tun_net_mclist; random_ether_addr(dev->dev_addr); @@ -529,7 +546,6 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun, struct iovec *iv, } netif_rx_ni(skb); - tun->dev->last_rx = jiffies; tun->dev->stats.rx_packets++; tun->dev->stats.rx_bytes += len; @@ -676,9 +692,6 @@ static void tun_setup(struct net_device *dev) tun->owner = -1; tun->group = -1; - dev->open = tun_net_open; - dev->hard_start_xmit = tun_net_xmit; - dev->stop = tun_net_close; dev->ethtool_ops = &tun_ethtool_ops; dev->destructor = free_netdev; dev->features |= NETIF_F_NETNS_LOCAL; @@ -752,6 +765,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr) return -ENOMEM; dev_net_set(dev, net); + tun = netdev_priv(dev); tun->dev = dev; tun->flags = flags; @@ -885,7 +899,6 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, void __user* argp = (void __user*)arg; struct ifreq ifr; int ret; - DECLARE_MAC_BUF(mac); if (cmd == TUNSETIFF || _IOC_TYPE(cmd) == 0x89) if (copy_from_user(&ifr, argp, sizeof ifr)) @@ -1013,8 +1026,8 @@ static int tun_chr_ioctl(struct inode *inode, struct file *file, case SIOCSIFHWADDR: /* Set hw address */ - DBG(KERN_DEBUG "%s: set hw address: %s\n", - tun->dev->name, print_mac(mac, ifr.ifr_hwaddr.sa_data)); + DBG(KERN_DEBUG "%s: set hw address: %pM\n", + tun->dev->name, ifr.ifr_hwaddr.sa_data); rtnl_lock(); ret = dev_set_mac_address(tun->dev, &ifr.ifr_hwaddr); diff --git a/drivers/net/typhoon.c b/drivers/net/typhoon.c index 734ce0977f02891e1c6d7a0ac0ba666e3f36ec49..0009f4e34433ee9f9130ca2c1a8122df612f07b7 100644 --- a/drivers/net/typhoon.c +++ b/drivers/net/typhoon.c @@ -1729,7 +1729,6 @@ typhoon_rx(struct typhoon *tp, struct basic_ring *rxRing, volatile __le32 * read netif_receive_skb(new_skb); spin_unlock(&tp->state_lock); - tp->dev->last_rx = jiffies; received++; budget--; } @@ -1756,7 +1755,6 @@ static int typhoon_poll(struct napi_struct *napi, int budget) { struct typhoon *tp = container_of(napi, struct typhoon, napi); - struct net_device *dev = tp->dev; struct typhoon_indexes *indexes = tp->indexes; int work_done; @@ -1785,7 +1783,7 @@ typhoon_poll(struct napi_struct *napi, int budget) } if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); iowrite32(TYPHOON_INTR_NONE, tp->ioaddr + TYPHOON_REG_INTR_MASK); typhoon_post_pci_writes(tp->ioaddr); @@ -1798,7 +1796,7 @@ static irqreturn_t typhoon_interrupt(int irq, void *dev_instance) { struct net_device *dev = dev_instance; - struct typhoon *tp = dev->priv; + struct typhoon *tp = netdev_priv(dev); void __iomem *ioaddr = tp->ioaddr; u32 intr_status; @@ -1808,10 +1806,10 @@ typhoon_interrupt(int irq, void *dev_instance) iowrite32(intr_status, ioaddr + TYPHOON_REG_INTR_STATUS); - if (netif_rx_schedule_prep(dev, &tp->napi)) { + if (netif_rx_schedule_prep(&tp->napi)) { iowrite32(TYPHOON_INTR_ALL, ioaddr + TYPHOON_REG_INTR_MASK); typhoon_post_pci_writes(ioaddr); - __netif_rx_schedule(dev, &tp->napi); + __netif_rx_schedule(&tp->napi); } else { printk(KERN_ERR "%s: Error, poll already scheduled\n", dev->name); @@ -2311,7 +2309,6 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) struct cmd_desc xp_cmd; struct resp_desc xp_resp[3]; int err = 0; - DECLARE_MAC_BUF(mac); if(!did_version++) printk(KERN_INFO "%s", version); @@ -2526,11 +2523,11 @@ typhoon_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) pci_set_drvdata(pdev, dev); - printk(KERN_INFO "%s: %s at %s 0x%llx, %s\n", + printk(KERN_INFO "%s: %s at %s 0x%llx, %pM\n", dev->name, typhoon_card_info[card_id].name, use_mmio ? "MMIO" : "IO", (unsigned long long)pci_resource_start(pdev, use_mmio), - print_mac(mac, dev->dev_addr)); + dev->dev_addr); /* xp_resp still contains the response to the READ_VERSIONS command. * For debugging, let the user know what version he has. diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c index c87747bb24c55eb9ea2ac58992eabfdf348b664b..7d5a1303e30d2976aa518c161bcec2f281000339 100644 --- a/drivers/net/ucc_geth.c +++ b/drivers/net/ucc_geth.c @@ -188,17 +188,6 @@ static void mem_disp(u8 *addr, int size) } #endif /* DEBUG */ -#ifdef CONFIG_UGETH_FILTERING -static void enqueue(struct list_head *node, struct list_head *lh) -{ - unsigned long flags; - - spin_lock_irqsave(&ugeth_lock, flags); - list_add_tail(node, lh); - spin_unlock_irqrestore(&ugeth_lock, flags); -} -#endif /* CONFIG_UGETH_FILTERING */ - static struct list_head *dequeue(struct list_head *lh) { unsigned long flags; @@ -391,23 +380,6 @@ static int dump_init_enet_entries(struct ucc_geth_private *ugeth, } #endif -#ifdef CONFIG_UGETH_FILTERING -static struct enet_addr_container *get_enet_addr_container(void) -{ - struct enet_addr_container *enet_addr_cont; - - /* allocate memory */ - enet_addr_cont = kmalloc(sizeof(struct enet_addr_container), GFP_KERNEL); - if (!enet_addr_cont) { - ugeth_err("%s: No memory for enet_addr_container object.", - __func__); - return NULL; - } - - return enet_addr_cont; -} -#endif /* CONFIG_UGETH_FILTERING */ - static void put_enet_addr_container(struct enet_addr_container *enet_addr_cont) { kfree(enet_addr_cont); @@ -420,28 +392,6 @@ static void set_mac_addr(__be16 __iomem *reg, u8 *mac) out_be16(®[2], ((u16)mac[1] << 8) | mac[0]); } -#ifdef CONFIG_UGETH_FILTERING -static int hw_add_addr_in_paddr(struct ucc_geth_private *ugeth, - u8 *p_enet_addr, u8 paddr_num) -{ - struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; - - if (!(paddr_num < NUM_OF_PADDRS)) { - ugeth_warn("%s: Illegal paddr_num.", __func__); - return -EINVAL; - } - - p_82xx_addr_filt = - (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram-> - addressfiltering; - - /* Ethernet frames are defined in Little Endian mode, */ - /* therefore to insert the address we reverse the bytes. */ - set_mac_addr(&p_82xx_addr_filt->paddr[paddr_num].h, p_enet_addr); - return 0; -} -#endif /* CONFIG_UGETH_FILTERING */ - static int hw_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num) { struct ucc_geth_82xx_address_filtering_pram __iomem *p_82xx_addr_filt; @@ -1615,8 +1565,8 @@ static int init_phy(struct net_device *dev) priv->oldspeed = 0; priv->oldduplex = -1; - snprintf(phy_id, BUS_ID_SIZE, PHY_ID_FMT, priv->ug_info->mdio_bus, - priv->ug_info->phy_address); + snprintf(phy_id, sizeof(phy_id), PHY_ID_FMT, priv->ug_info->mdio_bus, + priv->ug_info->phy_address); phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface); @@ -1647,6 +1597,7 @@ static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) struct ucc_fast_private *uccf; u32 cecr_subblock; u32 temp; + int i = 10; uccf = ugeth->uccf; @@ -1664,8 +1615,9 @@ static int ugeth_graceful_stop_tx(struct ucc_geth_private *ugeth) /* Wait for command to complete */ do { + msleep(10); temp = in_be32(uccf->p_ucce); - } while (!(temp & UCCE_GRA)); + } while (!(temp & UCCE_GRA) && --i); uccf->stopped_tx = 1; @@ -1677,6 +1629,7 @@ static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth) struct ucc_fast_private *uccf; u32 cecr_subblock; u8 temp; + int i = 10; uccf = ugeth->uccf; @@ -1694,9 +1647,9 @@ static int ugeth_graceful_stop_rx(struct ucc_geth_private * ugeth) ucc_num); qe_issue_cmd(QE_GRACEFUL_STOP_RX, cecr_subblock, QE_CR_PROTOCOL_ETHERNET, 0); - + msleep(10); temp = in_8(&ugeth->p_rx_glbl_pram->rxgstpack); - } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX)); + } while (!(temp & GRACEFUL_STOP_ACKNOWLEDGE_RX) && --i); uccf->stopped_rx = 1; @@ -1799,196 +1752,6 @@ static void ugeth_dump_regs(struct ucc_geth_private *ugeth) #endif } -#ifdef CONFIG_UGETH_FILTERING -static int ugeth_ext_filtering_serialize_tad(struct ucc_geth_tad_params * - p_UccGethTadParams, - struct qe_fltr_tad *qe_fltr_tad) -{ - u16 temp; - - /* Zero serialized TAD */ - memset(qe_fltr_tad, 0, QE_FLTR_TAD_SIZE); - - qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_V; /* Must have this */ - if (p_UccGethTadParams->rx_non_dynamic_extended_features_mode || - (p_UccGethTadParams->vtag_op != UCC_GETH_VLAN_OPERATION_TAGGED_NOP) - || (p_UccGethTadParams->vnontag_op != - UCC_GETH_VLAN_OPERATION_NON_TAGGED_NOP) - ) - qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_EF; - if (p_UccGethTadParams->reject_frame) - qe_fltr_tad->serialized[0] |= UCC_GETH_TAD_REJ; - temp = - (u16) (((u16) p_UccGethTadParams-> - vtag_op) << UCC_GETH_TAD_VTAG_OP_SHIFT); - qe_fltr_tad->serialized[0] |= (u8) (temp >> 8); /* upper bits */ - - qe_fltr_tad->serialized[1] |= (u8) (temp & 0x00ff); /* lower bits */ - if (p_UccGethTadParams->vnontag_op == - UCC_GETH_VLAN_OPERATION_NON_TAGGED_Q_TAG_INSERT) - qe_fltr_tad->serialized[1] |= UCC_GETH_TAD_V_NON_VTAG_OP; - qe_fltr_tad->serialized[1] |= - p_UccGethTadParams->rqos << UCC_GETH_TAD_RQOS_SHIFT; - - qe_fltr_tad->serialized[2] |= - p_UccGethTadParams->vpri << UCC_GETH_TAD_V_PRIORITY_SHIFT; - /* upper bits */ - qe_fltr_tad->serialized[2] |= (u8) (p_UccGethTadParams->vid >> 8); - /* lower bits */ - qe_fltr_tad->serialized[3] |= (u8) (p_UccGethTadParams->vid & 0x00ff); - - return 0; -} - -static struct enet_addr_container_t - *ugeth_82xx_filtering_get_match_addr_in_hash(struct ucc_geth_private *ugeth, - struct enet_addr *p_enet_addr) -{ - struct enet_addr_container *enet_addr_cont; - struct list_head *p_lh; - u16 i, num; - int32_t j; - u8 *p_counter; - - if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { - p_lh = &ugeth->group_hash_q; - p_counter = &(ugeth->numGroupAddrInHash); - } else { - p_lh = &ugeth->ind_hash_q; - p_counter = &(ugeth->numIndAddrInHash); - } - - if (!p_lh) - return NULL; - - num = *p_counter; - - for (i = 0; i < num; i++) { - enet_addr_cont = - (struct enet_addr_container *) - ENET_ADDR_CONT_ENTRY(dequeue(p_lh)); - for (j = ENET_NUM_OCTETS_PER_ADDRESS - 1; j >= 0; j--) { - if ((*p_enet_addr)[j] != (enet_addr_cont->address)[j]) - break; - if (j == 0) - return enet_addr_cont; /* Found */ - } - enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ - } - return NULL; -} - -static int ugeth_82xx_filtering_add_addr_in_hash(struct ucc_geth_private *ugeth, - struct enet_addr *p_enet_addr) -{ - enum ucc_geth_enet_address_recognition_location location; - struct enet_addr_container *enet_addr_cont; - struct list_head *p_lh; - u8 i; - u32 limit; - u8 *p_counter; - - if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { - p_lh = &ugeth->group_hash_q; - limit = ugeth->ug_info->maxGroupAddrInHash; - location = - UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_GROUP_HASH; - p_counter = &(ugeth->numGroupAddrInHash); - } else { - p_lh = &ugeth->ind_hash_q; - limit = ugeth->ug_info->maxIndAddrInHash; - location = - UCC_GETH_ENET_ADDRESS_RECOGNITION_LOCATION_INDIVIDUAL_HASH; - p_counter = &(ugeth->numIndAddrInHash); - } - - if ((enet_addr_cont = - ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr))) { - list_add(p_lh, &enet_addr_cont->node); /* Put it back */ - return 0; - } - if ((!p_lh) || (!(*p_counter < limit))) - return -EBUSY; - if (!(enet_addr_cont = get_enet_addr_container())) - return -ENOMEM; - for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) - (enet_addr_cont->address)[i] = (*p_enet_addr)[i]; - enet_addr_cont->location = location; - enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ - ++(*p_counter); - - hw_add_addr_in_hash(ugeth, enet_addr_cont->address); - return 0; -} - -static int ugeth_82xx_filtering_clear_addr_in_hash(struct ucc_geth_private *ugeth, - struct enet_addr *p_enet_addr) -{ - struct ucc_geth_82xx_address_filtering_pram *p_82xx_addr_filt; - struct enet_addr_container *enet_addr_cont; - struct ucc_fast_private *uccf; - enum comm_dir comm_dir; - u16 i, num; - struct list_head *p_lh; - u32 *addr_h, *addr_l; - u8 *p_counter; - - uccf = ugeth->uccf; - - p_82xx_addr_filt = - (struct ucc_geth_82xx_address_filtering_pram *) ugeth->p_rx_glbl_pram-> - addressfiltering; - - if (! - (enet_addr_cont = - ugeth_82xx_filtering_get_match_addr_in_hash(ugeth, p_enet_addr))) - return -ENOENT; - - /* It's been found and removed from the CQ. */ - /* Now destroy its container */ - put_enet_addr_container(enet_addr_cont); - - if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) { - addr_h = &(p_82xx_addr_filt->gaddr_h); - addr_l = &(p_82xx_addr_filt->gaddr_l); - p_lh = &ugeth->group_hash_q; - p_counter = &(ugeth->numGroupAddrInHash); - } else { - addr_h = &(p_82xx_addr_filt->iaddr_h); - addr_l = &(p_82xx_addr_filt->iaddr_l); - p_lh = &ugeth->ind_hash_q; - p_counter = &(ugeth->numIndAddrInHash); - } - - comm_dir = 0; - if (uccf->enabled_tx) - comm_dir |= COMM_DIR_TX; - if (uccf->enabled_rx) - comm_dir |= COMM_DIR_RX; - if (comm_dir) - ugeth_disable(ugeth, comm_dir); - - /* Clear the hash table. */ - out_be32(addr_h, 0x00000000); - out_be32(addr_l, 0x00000000); - - /* Add all remaining CQ elements back into hash */ - num = --(*p_counter); - for (i = 0; i < num; i++) { - enet_addr_cont = - (struct enet_addr_container *) - ENET_ADDR_CONT_ENTRY(dequeue(p_lh)); - hw_add_addr_in_hash(ugeth, enet_addr_cont->address); - enqueue(p_lh, &enet_addr_cont->node); /* Put it back */ - } - - if (comm_dir) - ugeth_enable(ugeth, comm_dir); - - return 0; -} -#endif /* CONFIG_UGETH_FILTERING */ - static int ugeth_82xx_filtering_clear_all_addr_in_hash(struct ucc_geth_private * ugeth, enum enet_addr_type @@ -2051,28 +1814,6 @@ static int ugeth_82xx_filtering_clear_all_addr_in_hash(struct ucc_geth_private * return 0; } -#ifdef CONFIG_UGETH_FILTERING -static int ugeth_82xx_filtering_add_addr_in_paddr(struct ucc_geth_private *ugeth, - struct enet_addr *p_enet_addr, - u8 paddr_num) -{ - int i; - - if ((*p_enet_addr)[0] & ENET_GROUP_ADDR) - ugeth_warn - ("%s: multicast address added to paddr will have no " - "effect - is this what you wanted?", - __func__); - - ugeth->indAddrRegUsed[paddr_num] = 1; /* mark this paddr as used */ - /* store address in our database */ - for (i = 0; i < ENET_NUM_OCTETS_PER_ADDRESS; i++) - ugeth->paddr[paddr_num][i] = (*p_enet_addr)[i]; - /* put in hardware */ - return hw_add_addr_in_paddr(ugeth, p_enet_addr, paddr_num); -} -#endif /* CONFIG_UGETH_FILTERING */ - static int ugeth_82xx_filtering_clear_addr_in_paddr(struct ucc_geth_private *ugeth, u8 paddr_num) { @@ -2215,7 +1956,10 @@ static void ucc_geth_memclean(struct ucc_geth_private *ugeth) while (!list_empty(&ugeth->ind_hash_q)) put_enet_addr_container(ENET_ADDR_CONT_ENTRY (dequeue(&ugeth->ind_hash_q))); - + if (ugeth->ug_regs) { + iounmap(ugeth->ug_regs); + ugeth->ug_regs = NULL; + } } static void ucc_geth_set_multi(struct net_device *dev) @@ -2297,8 +2041,6 @@ static void ucc_geth_stop(struct ucc_geth_private *ugeth) tempval &= ~(MACCFG1_ENABLE_RX | MACCFG1_ENABLE_TX); out_be32(&ug_regs->maccfg1, tempval); - free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); - ucc_geth_memclean(ugeth); } @@ -2419,11 +2161,15 @@ static int ucc_struct_init(struct ucc_geth_private *ugeth) if (ucc_fast_init(uf_info, &ugeth->uccf)) { if (netif_msg_probe(ugeth)) ugeth_err("%s: Failed to init uccf.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } - ugeth->ug_regs = (struct ucc_geth __iomem *) ioremap(uf_info->regs, sizeof(struct ucc_geth)); + ugeth->ug_regs = ioremap(uf_info->regs, sizeof(*ugeth->ug_regs)); + if (!ugeth->ug_regs) { + if (netif_msg_probe(ugeth)) + ugeth_err("%s: Failed to ioremap regs.", __func__); + return -ENOMEM; + } return 0; } @@ -2475,7 +2221,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Bad number of Rx threads value.", __func__); - ucc_geth_memclean(ugeth); return -EINVAL; break; } @@ -2500,7 +2245,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Bad number of Tx threads value.", __func__); - ucc_geth_memclean(ugeth); return -EINVAL; break; } @@ -2554,7 +2298,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: IPGIFG initialization parameter too large.", __func__); - ucc_geth_memclean(ugeth); return ret_val; } @@ -2572,7 +2315,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Half Duplex initialization parameter too large.", __func__); - ucc_geth_memclean(ugeth); return ret_val; } @@ -2627,7 +2369,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate memory for Tx bd rings.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } /* Zero unused end of bd ring, according to spec */ @@ -2663,7 +2404,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate memory for Rx bd rings.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } } @@ -2679,7 +2419,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Could not allocate tx_skbuff", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2711,7 +2450,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Could not allocate rx_skbuff", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2745,7 +2483,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_tx_glbl_pram.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } ugeth->p_tx_glbl_pram = @@ -2768,7 +2505,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_thread_data_tx.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2798,7 +2534,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_send_q_mem_reg.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2842,7 +2577,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_scheduler.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2893,7 +2627,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ("%s: Can not allocate DPRAM memory for" " p_tx_fw_statistics_pram.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } ugeth->p_tx_fw_statistics_pram = @@ -2933,7 +2666,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_rx_glbl_pram.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } ugeth->p_rx_glbl_pram = @@ -2955,7 +2687,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_thread_data_rx.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -2979,7 +2710,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for" " p_rx_fw_statistics_pram.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } ugeth->p_rx_fw_statistics_pram = @@ -3002,7 +2732,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for" " p_rx_irq_coalescing_tbl.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3071,7 +2800,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_rx_bd_qs_tbl.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3148,7 +2876,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Null Extended Filtering Chain Pointer.", __func__); - ucc_geth_memclean(ugeth); return -EINVAL; } @@ -3162,7 +2889,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for" " p_exf_glbl_param.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } @@ -3210,7 +2936,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate memory for" " p_UccInitEnetParamShadows.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } /* Zero out *p_init_enet_param_shadow */ @@ -3245,7 +2970,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Invalid largest External Lookup Key Size.", __func__); - ucc_geth_memclean(ugeth); return -EINVAL; } ugeth->p_init_enet_param_shadow->largestexternallookupkeysize = @@ -3272,7 +2996,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Can not fill p_init_enet_param_shadow.", __func__); - ucc_geth_memclean(ugeth); return ret_val; } @@ -3288,7 +3011,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Can not fill p_init_enet_param_shadow.", __func__); - ucc_geth_memclean(ugeth); return ret_val; } @@ -3298,7 +3020,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) if (netif_msg_ifup(ugeth)) ugeth_err("%s: Can not fill Rx bds with buffers.", __func__); - ucc_geth_memclean(ugeth); return ret_val; } } @@ -3310,7 +3031,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) ugeth_err ("%s: Can not allocate DPRAM memory for p_init_enet_pram.", __func__); - ucc_geth_memclean(ugeth); return -ENOMEM; } p_init_enet_pram = @@ -3352,28 +3072,6 @@ static int ucc_geth_startup(struct ucc_geth_private *ugeth) return 0; } -/* ucc_geth_timeout gets called when a packet has not been - * transmitted after a set amount of time. - * For now, assume that clearing out all the structures, and - * starting over will fix the problem. */ -static void ucc_geth_timeout(struct net_device *dev) -{ - struct ucc_geth_private *ugeth = netdev_priv(dev); - - ugeth_vdbg("%s: IN", __func__); - - dev->stats.tx_errors++; - - ugeth_dump_regs(ugeth); - - if (dev->flags & IFF_UP) { - ucc_geth_stop(ugeth); - ucc_geth_startup(ugeth); - } - - netif_tx_schedule_all(dev); -} - /* This is called by the kernel when a frame is ready for transmission. */ /* It is pointed to by the dev->hard_start_xmit function pointer */ static int ucc_geth_start_xmit(struct sk_buff *skb, struct net_device *dev) @@ -3502,8 +3200,6 @@ static int ucc_geth_rx(struct ucc_geth_private *ugeth, u8 rxQ, int rx_work_limit netif_receive_skb(skb); } - ugeth->dev->last_rx = jiffies; - skb = get_new_skb(ugeth, bd); if (!skb) { if (netif_msg_rx_err(ugeth)) @@ -3592,7 +3288,7 @@ static int ucc_geth_poll(struct napi_struct *napi, int budget) struct ucc_fast_private *uccf; u32 uccm; - netif_rx_complete(dev, napi); + netif_rx_complete(napi); uccf = ugeth->uccf; uccm = in_be32(uccf->p_uccm); uccm |= UCCE_RX_EVENTS; @@ -3626,10 +3322,10 @@ static irqreturn_t ucc_geth_irq_handler(int irq, void *info) /* check for receive events that require processing */ if (ucce & UCCE_RX_EVENTS) { - if (netif_rx_schedule_prep(dev, &ugeth->napi)) { + if (netif_rx_schedule_prep(&ugeth->napi)) { uccm &= ~UCCE_RX_EVENTS; out_be32(uccf->p_uccm, uccm); - __netif_rx_schedule(dev, &ugeth->napi); + __netif_rx_schedule(&ugeth->napi); } } @@ -3697,7 +3393,7 @@ static int ucc_geth_open(struct net_device *dev) if (err) { if (netif_msg_ifup(ugeth)) ugeth_err("%s: Cannot configure internal struct, aborting.", dev->name); - return err; + goto out_err_stop; } napi_enable(&ugeth->napi); @@ -3738,22 +3434,19 @@ static int ucc_geth_open(struct net_device *dev) phy_start(ugeth->phydev); - err = - request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, 0, - "UCC Geth", dev); + err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); if (err) { if (netif_msg_ifup(ugeth)) - ugeth_err("%s: Cannot get IRQ for net device, aborting.", - dev->name); - ucc_geth_stop(ugeth); + ugeth_err("%s: Cannot enable net device, aborting.", dev->name); goto out_err; } - err = ugeth_enable(ugeth, COMM_DIR_RX_AND_TX); + err = request_irq(ugeth->ug_info->uf_info.irq, ucc_geth_irq_handler, + 0, "UCC Geth", dev); if (err) { if (netif_msg_ifup(ugeth)) - ugeth_err("%s: Cannot enable net device, aborting.", dev->name); - ucc_geth_stop(ugeth); + ugeth_err("%s: Cannot get IRQ for net device, aborting.", + dev->name); goto out_err; } @@ -3763,7 +3456,8 @@ static int ucc_geth_open(struct net_device *dev) out_err: napi_disable(&ugeth->napi); - +out_err_stop: + ucc_geth_stop(ugeth); return err; } @@ -3778,6 +3472,8 @@ static int ucc_geth_close(struct net_device *dev) ucc_geth_stop(ugeth); + free_irq(ugeth->ug_info->uf_info.irq, ugeth->dev); + phy_disconnect(ugeth->phydev); ugeth->phydev = NULL; @@ -3786,6 +3482,45 @@ static int ucc_geth_close(struct net_device *dev) return 0; } +/* Reopen device. This will reset the MAC and PHY. */ +static void ucc_geth_timeout_work(struct work_struct *work) +{ + struct ucc_geth_private *ugeth; + struct net_device *dev; + + ugeth = container_of(work, struct ucc_geth_private, timeout_work); + dev = ugeth->dev; + + ugeth_vdbg("%s: IN", __func__); + + dev->stats.tx_errors++; + + ugeth_dump_regs(ugeth); + + if (dev->flags & IFF_UP) { + /* + * Must reset MAC *and* PHY. This is done by reopening + * the device. + */ + ucc_geth_close(dev); + ucc_geth_open(dev); + } + + netif_tx_schedule_all(dev); +} + +/* + * ucc_geth_timeout gets called when a packet has not been + * transmitted after a set amount of time. + */ +static void ucc_geth_timeout(struct net_device *dev) +{ + struct ucc_geth_private *ugeth = netdev_priv(dev); + + netif_carrier_off(dev); + schedule_work(&ugeth->timeout_work); +} + static phy_interface_t to_phy_interface(const char *phy_connection_type) { if (strcasecmp(phy_connection_type, "mii") == 0) @@ -4026,6 +3761,7 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma dev->hard_start_xmit = ucc_geth_start_xmit; dev->tx_timeout = ucc_geth_timeout; dev->watchdog_timeo = TX_TIMEOUT; + INIT_WORK(&ugeth->timeout_work, ucc_geth_timeout_work); netif_napi_add(dev, &ugeth->napi, ucc_geth_poll, UCC_GETH_DEV_WEIGHT); #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = ucc_netpoll; diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h index abc0e224263487efb7a28ab7a07f4d40bdce9d87..d74d2f7cb73968e8e98e3a7f1ef65f8ddb20c794 100644 --- a/drivers/net/ucc_geth.h +++ b/drivers/net/ucc_geth.h @@ -1186,6 +1186,7 @@ struct ucc_geth_private { struct ucc_fast_private *uccf; struct net_device *dev; struct napi_struct napi; + struct work_struct timeout_work; struct ucc_geth __iomem *ug_regs; struct ucc_geth_init_pram *p_init_enet_param_shadow; struct ucc_geth_exf_global_pram __iomem *p_exf_glbl_param; diff --git a/drivers/net/usb/asix.c b/drivers/net/usb/asix.c index de57490103fcd05e58a8610d7fb77b3dbc0ffc20..e009481c606c740cea0b2a30fd7bad7f30f3fe8d 100644 --- a/drivers/net/usb/asix.c +++ b/drivers/net/usb/asix.c @@ -246,10 +246,11 @@ out: static void asix_async_cmd_callback(struct urb *urb) { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + int status = urb->status; - if (urb->status < 0) + if (status < 0) printk(KERN_DEBUG "asix_async_cmd_callback() failed with %d", - urb->status); + status); kfree(req); usb_free_urb(urb); diff --git a/drivers/net/usb/catc.c b/drivers/net/usb/catc.c index 466a89e244445cb59bdd3a94c43c184be4fee185..cb7acbbb279875893a1fa3f398a8fe5eaa5fe22e 100644 --- a/drivers/net/usb/catc.c +++ b/drivers/net/usb/catc.c @@ -229,14 +229,15 @@ static void catc_rx_done(struct urb *urb) u8 *pkt_start = urb->transfer_buffer; struct sk_buff *skb; int pkt_len, pkt_offset = 0; + int status = urb->status; if (!catc->is_f5u011) { clear_bit(RX_RUNNING, &catc->flags); pkt_offset = 2; } - if (urb->status) { - dbg("rx_done, status %d, length %d", urb->status, urb->actual_length); + if (status) { + dbg("rx_done, status %d, length %d", status, urb->actual_length); return; } @@ -271,16 +272,14 @@ static void catc_rx_done(struct urb *urb) } while (pkt_start - (u8 *) urb->transfer_buffer < urb->actual_length); - catc->netdev->last_rx = jiffies; - if (catc->is_f5u011) { if (atomic_read(&catc->recq_sz)) { - int status; + int state; atomic_dec(&catc->recq_sz); dbg("getting extra packet"); urb->dev = catc->usbdev; - if ((status = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { - dbg("submit(rx_urb) status %d", status); + if ((state = usb_submit_urb(urb, GFP_ATOMIC)) < 0) { + dbg("submit(rx_urb) status %d", state); } } else { clear_bit(RX_RUNNING, &catc->flags); @@ -292,8 +291,9 @@ static void catc_irq_done(struct urb *urb) { struct catc *catc = urb->context; u8 *data = urb->transfer_buffer; - int status; + int status = urb->status; unsigned int hasdata = 0, linksts = LinkNoChange; + int res; if (!catc->is_f5u011) { hasdata = data[1] & 0x80; @@ -309,7 +309,7 @@ static void catc_irq_done(struct urb *urb) linksts = LinkBad; } - switch (urb->status) { + switch (status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ @@ -318,7 +318,7 @@ static void catc_irq_done(struct urb *urb) return; /* -EPIPE: should clear the halt */ default: /* error */ - dbg("irq_done, status %d, data %02x %02x.", urb->status, data[0], data[1]); + dbg("irq_done, status %d, data %02x %02x.", status, data[0], data[1]); goto resubmit; } @@ -338,17 +338,17 @@ static void catc_irq_done(struct urb *urb) atomic_inc(&catc->recq_sz); } else { catc->rx_urb->dev = catc->usbdev; - if ((status = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) { - err("submit(rx_urb) status %d", status); + if ((res = usb_submit_urb(catc->rx_urb, GFP_ATOMIC)) < 0) { + err("submit(rx_urb) status %d", res); } } } resubmit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status) + res = usb_submit_urb (urb, GFP_ATOMIC); + if (res) err ("can't resubmit intr, %s-%s, status %d", catc->usbdev->bus->bus_name, - catc->usbdev->devpath, status); + catc->usbdev->devpath, res); } /* @@ -380,9 +380,9 @@ static void catc_tx_done(struct urb *urb) { struct catc *catc = urb->context; unsigned long flags; - int r; + int r, status = urb->status; - if (urb->status == -ECONNRESET) { + if (status == -ECONNRESET) { dbg("Tx Reset."); urb->status = 0; catc->netdev->trans_start = jiffies; @@ -392,8 +392,8 @@ static void catc_tx_done(struct urb *urb) return; } - if (urb->status) { - dbg("tx_done, status %d, length %d", urb->status, urb->actual_length); + if (status) { + dbg("tx_done, status %d, length %d", status, urb->actual_length); return; } @@ -504,9 +504,10 @@ static void catc_ctrl_done(struct urb *urb) struct catc *catc = urb->context; struct ctrl_queue *q; unsigned long flags; + int status = urb->status; - if (urb->status) - dbg("ctrl_done, status %d, len %d.", urb->status, urb->actual_length); + if (status) + dbg("ctrl_done, status %d, len %d.", status, urb->actual_length); spin_lock_irqsave(&catc->ctrl_lock, flags); diff --git a/drivers/net/usb/dm9601.c b/drivers/net/usb/dm9601.c index db3377dae9d5f99156cf569008ca8795dc598fed..edd244f3acb50488c031863997101ff41469c797 100644 --- a/drivers/net/usb/dm9601.c +++ b/drivers/net/usb/dm9601.c @@ -123,10 +123,11 @@ static int dm_write_reg(struct usbnet *dev, u8 reg, u8 value) static void dm_write_async_callback(struct urb *urb) { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + int status = urb->status; - if (urb->status < 0) + if (status < 0) printk(KERN_DEBUG "dm_write_async_callback() failed with %d\n", - urb->status); + status); kfree(req); usb_free_urb(urb); diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c index 8e90891f0e422b8cc0f645c9eab388ff39b22d45..198ce3cf378ae2b884ce16b21a5fa1ba7a028d5c 100644 --- a/drivers/net/usb/hso.c +++ b/drivers/net/usb/hso.c @@ -417,6 +417,11 @@ static const struct usb_device_id hso_ids[] = { {USB_DEVICE(0x0af0, 0x7401)}, /* GI 0401 */ {USB_DEVICE(0x0af0, 0x7501)}, /* GTM 382 */ {USB_DEVICE(0x0af0, 0x7601)}, /* GE40x */ + {USB_DEVICE(0x0af0, 0x7701)}, + {USB_DEVICE(0x0af0, 0x7801)}, + {USB_DEVICE(0x0af0, 0x7901)}, + {USB_DEVICE(0x0af0, 0x7361)}, + {icon321_port_device(0x0af0, 0xd051)}, {} }; MODULE_DEVICE_TABLE(usb, hso_ids); @@ -658,10 +663,9 @@ static int hso_net_open(struct net_device *net) odev->rx_buf_missing = sizeof(struct iphdr); spin_unlock_irqrestore(&odev->net_lock, flags); - hso_start_net_device(odev->parent); - /* We are up and running. */ set_bit(HSO_NET_RUNNING, &odev->flags); + hso_start_net_device(odev->parent); /* Tell the kernel we are ready to start receiving from it */ netif_start_queue(net); @@ -2750,18 +2754,21 @@ static int hso_resume(struct usb_interface *iface) if (network_table[i] && (network_table[i]->interface == iface)) { hso_net = dev2net(network_table[i]); - /* First transmit any lingering data, then restart the - * device. */ - if (hso_net->skb_tx_buf) { - dev_dbg(&iface->dev, - "Transmitting lingering data\n"); - hso_net_start_xmit(hso_net->skb_tx_buf, - hso_net->net); - hso_net->skb_tx_buf = NULL; + if (hso_net->flags & IFF_UP) { + /* First transmit any lingering data, + then restart the device. */ + if (hso_net->skb_tx_buf) { + dev_dbg(&iface->dev, + "Transmitting" + " lingering data\n"); + hso_net_start_xmit(hso_net->skb_tx_buf, + hso_net->net); + hso_net->skb_tx_buf = NULL; + } + result = hso_start_net_device(network_table[i]); + if (result) + goto out; } - result = hso_start_net_device(network_table[i]); - if (result) - goto out; } } @@ -2894,6 +2901,7 @@ static struct usb_driver hso_driver = { .id_table = hso_ids, .suspend = hso_suspend, .resume = hso_resume, + .reset_resume = hso_resume, .supports_autosuspend = 1, }; diff --git a/drivers/net/usb/kaweth.c b/drivers/net/usb/kaweth.c index fdbf3be24fda499e5065b7b3c691ade64f56397e..2ee034f70d1c61a1cfd0cbb799f02485ce654bdc 100644 --- a/drivers/net/usb/kaweth.c +++ b/drivers/net/usb/kaweth.c @@ -516,8 +516,9 @@ static void int_callback(struct urb *u) { struct kaweth_device *kaweth = u->context; int act_state; + int status = u->status; - switch (u->status) { + switch (status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ @@ -598,6 +599,7 @@ static void kaweth_usb_receive(struct urb *urb) { struct kaweth_device *kaweth = urb->context; struct net_device *net = kaweth->net; + int status = urb->status; int count = urb->actual_length; int count2 = urb->transfer_buffer_length; @@ -606,7 +608,7 @@ static void kaweth_usb_receive(struct urb *urb) struct sk_buff *skb; - if(unlikely(urb->status == -ECONNRESET || urb->status == -ESHUTDOWN)) + if(unlikely(status == -ECONNRESET || status == -ESHUTDOWN)) /* we are killed - set a flag and wake the disconnect handler */ { kaweth->end = 1; @@ -621,10 +623,10 @@ static void kaweth_usb_receive(struct urb *urb) } spin_unlock(&kaweth->device_lock); - if(urb->status && urb->status != -EREMOTEIO && count != 1) { + if(status && status != -EREMOTEIO && count != 1) { err("%s RX status: %d count: %d packet_len: %d", net->name, - urb->status, + status, count, (int)pkt_len); kaweth_resubmit_rx_urb(kaweth, GFP_ATOMIC); @@ -775,10 +777,11 @@ static void kaweth_usb_transmit_complete(struct urb *urb) { struct kaweth_device *kaweth = urb->context; struct sk_buff *skb = kaweth->tx_skb; + int status = urb->status; - if (unlikely(urb->status != 0)) - if (urb->status != -ENOENT) - dbg("%s: TX status %d.", kaweth->net->name, urb->status); + if (unlikely(status != 0)) + if (status != -ENOENT) + dbg("%s: TX status %d.", kaweth->net->name, status); netif_wake_queue(kaweth->net); dev_kfree_skb_irq(skb); diff --git a/drivers/net/usb/mcs7830.c b/drivers/net/usb/mcs7830.c index b5143509e8be1f70e0433939d30ac44ef9a7e28f..5385d66b306ebd284ac973e87a9209b4b7aa89ff 100644 --- a/drivers/net/usb/mcs7830.c +++ b/drivers/net/usb/mcs7830.c @@ -115,10 +115,11 @@ static int mcs7830_set_reg(struct usbnet *dev, u16 index, u16 size, void *data) static void mcs7830_async_cmd_callback(struct urb *urb) { struct usb_ctrlrequest *req = (struct usb_ctrlrequest *)urb->context; + int status = urb->status; - if (urb->status < 0) + if (status < 0) printk(KERN_DEBUG "%s() failed with %d\n", - __func__, urb->status); + __func__, status); kfree(req); usb_free_urb(urb); @@ -344,14 +345,14 @@ out: static int mcs7830_mdio_read(struct net_device *netdev, int phy_id, int location) { - struct usbnet *dev = netdev->priv; + struct usbnet *dev = netdev_priv(netdev); return mcs7830_read_phy(dev, location); } static void mcs7830_mdio_write(struct net_device *netdev, int phy_id, int location, int val) { - struct usbnet *dev = netdev->priv; + struct usbnet *dev = netdev_priv(netdev); mcs7830_write_phy(dev, location, val); } diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index 7914867110ed74ef3e0f17f4dcba685ea4450d73..166880c113d6718ad00b87f75f0b84caa93867b3 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c @@ -99,11 +99,12 @@ static int update_eth_regs_async(pegasus_t *); static void ctrl_callback(struct urb *urb) { pegasus_t *pegasus = urb->context; + int status = urb->status; if (!pegasus) return; - switch (urb->status) { + switch (status) { case 0: if (pegasus->flags & ETH_REGS_CHANGE) { pegasus->flags &= ~ETH_REGS_CHANGE; @@ -119,7 +120,7 @@ static void ctrl_callback(struct urb *urb) default: if (netif_msg_drv(pegasus) && printk_ratelimit()) dev_dbg(&pegasus->intf->dev, "%s, status %d\n", - __func__, urb->status); + __func__, status); } pegasus->flags &= ~ETH_REGS_CHANGED; wake_up(&pegasus->ctrl_wait); @@ -611,6 +612,7 @@ static void read_bulk_callback(struct urb *urb) pegasus_t *pegasus = urb->context; struct net_device *net; int rx_status, count = urb->actual_length; + int status = urb->status; u8 *buf = urb->transfer_buffer; __u16 pkt_len; @@ -621,7 +623,7 @@ static void read_bulk_callback(struct urb *urb) if (!netif_device_present(net) || !netif_running(net)) return; - switch (urb->status) { + switch (status) { case 0: break; case -ETIME: @@ -639,11 +641,11 @@ static void read_bulk_callback(struct urb *urb) case -ECONNRESET: case -ESHUTDOWN: if (netif_msg_ifdown(pegasus)) - pr_debug("%s: rx unlink, %d\n", net->name, urb->status); + pr_debug("%s: rx unlink, %d\n", net->name, status); return; default: if (netif_msg_rx_err(pegasus)) - pr_debug("%s: RX status %d\n", net->name, urb->status); + pr_debug("%s: RX status %d\n", net->name, status); goto goon; } @@ -769,6 +771,7 @@ static void write_bulk_callback(struct urb *urb) { pegasus_t *pegasus = urb->context; struct net_device *net; + int status = urb->status; if (!pegasus) return; @@ -778,7 +781,7 @@ static void write_bulk_callback(struct urb *urb) if (!netif_device_present(net) || !netif_running(net)) return; - switch (urb->status) { + switch (status) { case -EPIPE: /* FIXME schedule_work() to clear the tx halt */ netif_stop_queue(net); @@ -790,11 +793,11 @@ static void write_bulk_callback(struct urb *urb) case -ECONNRESET: case -ESHUTDOWN: if (netif_msg_ifdown(pegasus)) - pr_debug("%s: tx unlink, %d\n", net->name, urb->status); + pr_debug("%s: tx unlink, %d\n", net->name, status); return; default: if (netif_msg_tx_err(pegasus)) - pr_info("%s: TX status %d\n", net->name, urb->status); + pr_info("%s: TX status %d\n", net->name, status); /* FALL THROUGH */ case 0: break; @@ -808,13 +811,13 @@ static void intr_callback(struct urb *urb) { pegasus_t *pegasus = urb->context; struct net_device *net; - int status; + int res, status = urb->status; if (!pegasus) return; net = pegasus->net; - switch (urb->status) { + switch (status) { case 0: break; case -ECONNRESET: /* unlink */ @@ -827,7 +830,7 @@ static void intr_callback(struct urb *urb) */ if (netif_msg_timer(pegasus)) pr_debug("%s: intr status %d\n", net->name, - urb->status); + status); } if (urb->actual_length >= 6) { @@ -854,12 +857,12 @@ static void intr_callback(struct urb *urb) pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4]; } - status = usb_submit_urb(urb, GFP_ATOMIC); - if (status == -ENODEV) + res = usb_submit_urb(urb, GFP_ATOMIC); + if (res == -ENODEV) netif_device_detach(pegasus->net); - if (status && netif_msg_timer(pegasus)) + if (res && netif_msg_timer(pegasus)) printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n", - net->name, status); + net->name, res); } static void pegasus_tx_timeout(struct net_device *net) @@ -1213,7 +1216,7 @@ static void pegasus_set_multicast(struct net_device *net) pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; if (netif_msg_link(pegasus)) - pr_info("%s: set allmulti\n", net->name); + pr_debug("%s: set allmulti\n", net->name); } else { pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; @@ -1273,6 +1276,7 @@ static inline void setup_pegasus_II(pegasus_t * pegasus) } +static int pegasus_count; static struct workqueue_struct *pegasus_workqueue = NULL; #define CARRIER_CHECK_DELAY (2 * HZ) @@ -1301,6 +1305,18 @@ static int pegasus_blacklisted(struct usb_device *udev) return 0; } +/* we rely on probe() and remove() being serialized so we + * don't need extra locking on pegasus_count. + */ +static void pegasus_dec_workqueue(void) +{ + pegasus_count--; + if (pegasus_count == 0) { + destroy_workqueue(pegasus_workqueue); + pegasus_workqueue = NULL; + } +} + static int pegasus_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1309,14 +1325,18 @@ static int pegasus_probe(struct usb_interface *intf, pegasus_t *pegasus; int dev_index = id - pegasus_ids; int res = -ENOMEM; - DECLARE_MAC_BUF(mac); - usb_get_dev(dev); + if (pegasus_blacklisted(dev)) + return -ENODEV; - if (pegasus_blacklisted(dev)) { - res = -ENODEV; - goto out; + if (pegasus_count == 0) { + pegasus_workqueue = create_singlethread_workqueue("pegasus"); + if (!pegasus_workqueue) + return -ENOMEM; } + pegasus_count++; + + usb_get_dev(dev); net = alloc_etherdev(sizeof(struct pegasus)); if (!net) { @@ -1386,10 +1406,10 @@ static int pegasus_probe(struct usb_interface *intf, queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check, CARRIER_CHECK_DELAY); - dev_info(&intf->dev, "%s, %s, %s\n", + dev_info(&intf->dev, "%s, %s, %pM\n", net->name, usb_dev_id[dev_index].name, - print_mac(mac, net->dev_addr)); + net->dev_addr); return 0; out3: @@ -1401,6 +1421,7 @@ out1: free_netdev(net); out: usb_put_dev(dev); + pegasus_dec_workqueue(); return res; } @@ -1426,6 +1447,7 @@ static void pegasus_disconnect(struct usb_interface *intf) pegasus->rx_skb = NULL; } free_netdev(pegasus->net); + pegasus_dec_workqueue(); } static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) @@ -1469,7 +1491,7 @@ static struct usb_driver pegasus_driver = { .resume = pegasus_resume, }; -static void parse_id(char *id) +static void __init parse_id(char *id) { unsigned int vendor_id=0, device_id=0, flags=0, i=0; char *token, *name=NULL; @@ -1505,15 +1527,11 @@ static int __init pegasus_init(void) pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION); if (devid) parse_id(devid); - pegasus_workqueue = create_singlethread_workqueue("pegasus"); - if (!pegasus_workqueue) - return -ENOMEM; return usb_register(&pegasus_driver); } static void __exit pegasus_exit(void) { - destroy_workqueue(pegasus_workqueue); usb_deregister(&pegasus_driver); } diff --git a/drivers/net/usb/rtl8150.c b/drivers/net/usb/rtl8150.c index 6133401ebc67c258aff5ca98f51a40cf9219f488..d8664bf18c0000bd77a93426d39a10e0f48b6589 100644 --- a/drivers/net/usb/rtl8150.c +++ b/drivers/net/usb/rtl8150.c @@ -212,8 +212,9 @@ static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data) static void ctrl_callback(struct urb *urb) { rtl8150_t *dev; + int status = urb->status; - switch (urb->status) { + switch (status) { case 0: break; case -EINPROGRESS: @@ -221,7 +222,7 @@ static void ctrl_callback(struct urb *urb) case -ENOENT: break; default: - dev_warn(&urb->dev->dev, "ctrl urb status %d\n", urb->status); + dev_warn(&urb->dev->dev, "ctrl urb status %d\n", status); } dev = urb->context; clear_bit(RX_REG_SET, &dev->flags); @@ -424,7 +425,8 @@ static void read_bulk_callback(struct urb *urb) struct sk_buff *skb; struct net_device *netdev; u16 rx_stat; - int status; + int status = urb->status; + int result; dev = urb->context; if (!dev) @@ -435,7 +437,7 @@ static void read_bulk_callback(struct urb *urb) if (!netif_device_present(netdev)) return; - switch (urb->status) { + switch (status) { case 0: break; case -ENOENT: @@ -444,7 +446,7 @@ static void read_bulk_callback(struct urb *urb) dev_warn(&urb->dev->dev, "may be reset is needed?..\n"); goto goon; default: - dev_warn(&urb->dev->dev, "Rx status %d\n", urb->status); + dev_warn(&urb->dev->dev, "Rx status %d\n", status); goto goon; } @@ -474,10 +476,10 @@ static void read_bulk_callback(struct urb *urb) goon: usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1), dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev); - status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); - if (status == -ENODEV) + result = usb_submit_urb(dev->rx_urb, GFP_ATOMIC); + if (result == -ENODEV) netif_device_detach(dev->netdev); - else if (status) { + else if (result) { set_bit(RX_URB_FAIL, &dev->flags); goto resched; } else { @@ -530,6 +532,7 @@ tlsched: static void write_bulk_callback(struct urb *urb) { rtl8150_t *dev; + int status = urb->status; dev = urb->context; if (!dev) @@ -537,9 +540,9 @@ static void write_bulk_callback(struct urb *urb) dev_kfree_skb_irq(dev->tx_skb); if (!netif_device_present(dev->netdev)) return; - if (urb->status) + if (status) dev_info(&urb->dev->dev, "%s: Tx status %d\n", - dev->netdev->name, urb->status); + dev->netdev->name, status); dev->netdev->trans_start = jiffies; netif_wake_queue(dev->netdev); } @@ -548,12 +551,13 @@ static void intr_callback(struct urb *urb) { rtl8150_t *dev; __u8 *d; - int status; + int status = urb->status; + int res; dev = urb->context; if (!dev) return; - switch (urb->status) { + switch (status) { case 0: /* success */ break; case -ECONNRESET: /* unlink */ @@ -563,7 +567,7 @@ static void intr_callback(struct urb *urb) /* -EPIPE: should clear the halt */ default: dev_info(&urb->dev->dev, "%s: intr status %d\n", - dev->netdev->name, urb->status); + dev->netdev->name, status); goto resubmit; } @@ -591,13 +595,13 @@ static void intr_callback(struct urb *urb) } resubmit: - status = usb_submit_urb (urb, GFP_ATOMIC); - if (status == -ENODEV) + res = usb_submit_urb (urb, GFP_ATOMIC); + if (res == -ENODEV) netif_device_detach(dev->netdev); - else if (status) + else if (res) err ("can't resubmit intr, %s-%s/input0, status %d", dev->udev->bus->bus_name, - dev->udev->devpath, status); + dev->udev->devpath, res); } static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message) diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c index 51e2f5d7d14e5d5eaead2064c64d9cdef7df51ac..5574abe29c73b64c63d0e123e132f3afb762e7f3 100644 --- a/drivers/net/usb/smsc95xx.c +++ b/drivers/net/usb/smsc95xx.c @@ -31,7 +31,7 @@ #include "smsc95xx.h" #define SMSC_CHIPNAME "smsc95xx" -#define SMSC_DRIVER_VERSION "1.0.3" +#define SMSC_DRIVER_VERSION "1.0.4" #define HS_USB_PKT_SIZE (512) #define FS_USB_PKT_SIZE (64) #define DEFAULT_HS_BURST_CAP_SIZE (16 * 1024 + 5 * HS_USB_PKT_SIZE) @@ -40,15 +40,16 @@ #define MAX_SINGLE_PACKET_SIZE (2048) #define LAN95XX_EEPROM_MAGIC (0x9500) #define EEPROM_MAC_OFFSET (0x01) +#define DEFAULT_TX_CSUM_ENABLE (true) #define DEFAULT_RX_CSUM_ENABLE (true) #define SMSC95XX_INTERNAL_PHY_ID (1) #define SMSC95XX_TX_OVERHEAD (8) -#define FLOW_CTRL_TX (1) -#define FLOW_CTRL_RX (2) +#define SMSC95XX_TX_OVERHEAD_CSUM (12) struct smsc95xx_priv { u32 mac_cr; spinlock_t mac_cr_lock; + bool use_tx_csum; bool use_rx_csum; }; @@ -310,9 +311,10 @@ static void smsc95xx_async_cmd_callback(struct urb *urb, struct pt_regs *regs) { struct usb_context *usb_context = urb->context; struct usbnet *dev = usb_context->dev; + int status = urb->status; - if (urb->status < 0) - devwarn(dev, "async callback failed with %d", urb->status); + if (status < 0) + devwarn(dev, "async callback failed with %d", status); complete(&usb_context->notify); @@ -434,28 +436,6 @@ static void smsc95xx_set_multicast(struct net_device *netdev) smsc95xx_write_reg_async(dev, MAC_CR, &pdata->mac_cr); } -static u8 smsc95xx_resolve_flowctrl_fulldplx(u16 lcladv, u16 rmtadv) -{ - u8 cap = 0; - - if (lcladv & ADVERTISE_PAUSE_CAP) { - if (lcladv & ADVERTISE_PAUSE_ASYM) { - if (rmtadv & LPA_PAUSE_CAP) - cap = FLOW_CTRL_TX | FLOW_CTRL_RX; - else if (rmtadv & LPA_PAUSE_ASYM) - cap = FLOW_CTRL_RX; - } else { - if (rmtadv & LPA_PAUSE_CAP) - cap = FLOW_CTRL_TX | FLOW_CTRL_RX; - } - } else if (lcladv & ADVERTISE_PAUSE_ASYM) { - if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) - cap = FLOW_CTRL_TX; - } - - return cap; -} - static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, u16 lcladv, u16 rmtadv) { @@ -468,7 +448,7 @@ static void smsc95xx_phy_update_flowcontrol(struct usbnet *dev, u8 duplex, } if (duplex == DUPLEX_FULL) { - u8 cap = smsc95xx_resolve_flowctrl_fulldplx(lcladv, rmtadv); + u8 cap = mii_resolve_flowctrl_fdx(lcladv, rmtadv); if (cap & FLOW_CTRL_RX) flow = 0xFFFF0002; @@ -556,9 +536,10 @@ static void smsc95xx_status(struct usbnet *dev, struct urb *urb) devwarn(dev, "unexpected interrupt, intdata=0x%08X", intdata); } -/* Enable or disable Rx checksum offload engine */ -static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable) +/* Enable or disable Tx & Rx checksum offload engines */ +static int smsc95xx_set_csums(struct usbnet *dev) { + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); u32 read_buf; int ret = smsc95xx_read_reg(dev, COE_CR, &read_buf); if (ret < 0) { @@ -566,7 +547,12 @@ static int smsc95xx_set_rx_csum(struct usbnet *dev, bool enable) return ret; } - if (enable) + if (pdata->use_tx_csum) + read_buf |= Tx_COE_EN_; + else + read_buf &= ~Tx_COE_EN_; + + if (pdata->use_rx_csum) read_buf |= Rx_COE_EN_; else read_buf &= ~Rx_COE_EN_; @@ -626,7 +612,26 @@ static int smsc95xx_ethtool_set_rx_csum(struct net_device *netdev, u32 val) pdata->use_rx_csum = !!val; - return smsc95xx_set_rx_csum(dev, pdata->use_rx_csum); + return smsc95xx_set_csums(dev); +} + +static u32 smsc95xx_ethtool_get_tx_csum(struct net_device *netdev) +{ + struct usbnet *dev = netdev_priv(netdev); + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + + return pdata->use_tx_csum; +} + +static int smsc95xx_ethtool_set_tx_csum(struct net_device *netdev, u32 val) +{ + struct usbnet *dev = netdev_priv(netdev); + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + + pdata->use_tx_csum = !!val; + + ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); + return smsc95xx_set_csums(dev); } static struct ethtool_ops smsc95xx_ethtool_ops = { @@ -640,6 +645,8 @@ static struct ethtool_ops smsc95xx_ethtool_ops = { .get_eeprom_len = smsc95xx_ethtool_get_eeprom_len, .get_eeprom = smsc95xx_ethtool_get_eeprom, .set_eeprom = smsc95xx_ethtool_set_eeprom, + .get_tx_csum = smsc95xx_ethtool_get_tx_csum, + .set_tx_csum = smsc95xx_ethtool_set_tx_csum, .get_rx_csum = smsc95xx_ethtool_get_rx_csum, .set_rx_csum = smsc95xx_ethtool_set_rx_csum, }; @@ -757,9 +764,9 @@ static int smsc95xx_phy_initialize(struct usbnet *dev) static int smsc95xx_reset(struct usbnet *dev) { struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + struct net_device *netdev = dev->net; u32 read_buf, write_buf, burst_cap; int ret = 0, timeout; - DECLARE_MAC_BUF(mac); if (netif_msg_ifup(dev)) devdbg(dev, "entering smsc95xx_reset"); @@ -818,8 +825,7 @@ static int smsc95xx_reset(struct usbnet *dev) return ret; if (netif_msg_ifup(dev)) - devdbg(dev, "MAC Address: %s", - print_mac(mac, dev->net->dev_addr)); + devdbg(dev, "MAC Address: %pM", dev->net->dev_addr); ret = smsc95xx_read_reg(dev, HW_CFG, &read_buf); if (ret < 0) { @@ -970,10 +976,11 @@ static int smsc95xx_reset(struct usbnet *dev) return ret; } - /* Enable or disable Rx checksum offload engine */ - ret = smsc95xx_set_rx_csum(dev, pdata->use_rx_csum); + /* Enable or disable checksum offload engines */ + ethtool_op_set_tx_hw_csum(netdev, pdata->use_tx_csum); + ret = smsc95xx_set_csums(dev); if (ret < 0) { - devwarn(dev, "Failed to set Rx csum offload: %d", ret); + devwarn(dev, "Failed to set csum offload: %d", ret); return ret; } @@ -1029,6 +1036,7 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf) spin_lock_init(&pdata->mac_cr_lock); + pdata->use_tx_csum = DEFAULT_TX_CSUM_ENABLE; pdata->use_rx_csum = DEFAULT_RX_CSUM_ENABLE; /* Init all registers */ @@ -1148,22 +1156,44 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) return 1; } +static u32 smsc95xx_calc_csum_preamble(struct sk_buff *skb) +{ + int len = skb->data - skb->head; + u16 high_16 = (u16)(skb->csum_offset + skb->csum_start - len); + u16 low_16 = (u16)(skb->csum_start - len); + return (high_16 << 16) | low_16; +} + static struct sk_buff *smsc95xx_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags) { + struct smsc95xx_priv *pdata = (struct smsc95xx_priv *)(dev->data[0]); + bool csum = pdata->use_tx_csum && (skb->ip_summed == CHECKSUM_PARTIAL); + int overhead = csum ? SMSC95XX_TX_OVERHEAD_CSUM : SMSC95XX_TX_OVERHEAD; u32 tx_cmd_a, tx_cmd_b; - if (skb_headroom(skb) < SMSC95XX_TX_OVERHEAD) { + /* We do not advertise SG, so skbs should be already linearized */ + BUG_ON(skb_shinfo(skb)->nr_frags); + + if (skb_headroom(skb) < overhead) { struct sk_buff *skb2 = skb_copy_expand(skb, - SMSC95XX_TX_OVERHEAD, 0, flags); + overhead, 0, flags); dev_kfree_skb_any(skb); skb = skb2; if (!skb) return NULL; } + if (csum) { + u32 csum_preamble = smsc95xx_calc_csum_preamble(skb); + skb_push(skb, 4); + memcpy(skb->data, &csum_preamble, 4); + } + skb_push(skb, 4); tx_cmd_b = (u32)(skb->len - 4); + if (csum) + tx_cmd_b |= TX_CMD_B_CSUM_ENABLE; cpu_to_le32s(&tx_cmd_b); memcpy(skb->data, &tx_cmd_b, 4); diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c index 02d25c743994e3f5539744587697ae1685187e16..aa31490788880bb3b609acae0a9ab7332cce28c7 100644 --- a/drivers/net/usb/usbnet.c +++ b/drivers/net/usb/usbnet.c @@ -1125,7 +1125,6 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) struct usb_device *xdev; int status; const char *name; - DECLARE_MAC_BUF(mac); name = udev->dev.driver->name; info = (struct driver_info *) prod->driver_info; @@ -1236,11 +1235,11 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod) if (status) goto out3; if (netif_msg_probe (dev)) - devinfo (dev, "register '%s' at usb-%s-%s, %s, %s", + devinfo (dev, "register '%s' at usb-%s-%s, %s, %pM", udev->dev.driver->name, xdev->bus->bus_name, xdev->devpath, dev->driver_info->description, - print_mac(mac, net->dev_addr)); + net->dev_addr); // ok, it's ready to go. usb_set_intfdata (udev, dev); diff --git a/drivers/net/veth.c b/drivers/net/veth.c index 31cd817f33f97be658d31bed4ba93ec101312255..852d0e7c4e62abbfb13421664293dd70182c4126 100644 --- a/drivers/net/veth.c +++ b/drivers/net/veth.c @@ -8,7 +8,6 @@ * */ -#include #include #include #include @@ -30,14 +29,10 @@ struct veth_net_stats { struct veth_priv { struct net_device *peer; - struct net_device *dev; - struct list_head list; struct veth_net_stats *stats; unsigned ip_summed; }; -static LIST_HEAD(veth_list); - /* * ethtool interface */ @@ -267,16 +262,20 @@ static void veth_dev_free(struct net_device *dev) free_netdev(dev); } +static const struct net_device_ops veth_netdev_ops = { + .ndo_init = veth_dev_init, + .ndo_open = veth_open, + .ndo_start_xmit = veth_xmit, + .ndo_get_stats = veth_get_stats, +}; + static void veth_setup(struct net_device *dev) { ether_setup(dev); - dev->hard_start_xmit = veth_xmit; - dev->get_stats = veth_get_stats; - dev->open = veth_open; + dev->netdev_ops = &veth_netdev_ops; dev->ethtool_ops = &veth_ethtool_ops; dev->features |= NETIF_F_LLTX; - dev->init = veth_dev_init; dev->destructor = veth_dev_free; } @@ -302,7 +301,7 @@ static int veth_device_event(struct notifier_block *unused, { struct net_device *dev = ptr; - if (dev->open != veth_open) + if (dev->netdev_ops->ndo_open != veth_open) goto out; switch (event) { @@ -420,14 +419,10 @@ static int veth_newlink(struct net_device *dev, */ priv = netdev_priv(dev); - priv->dev = dev; priv->peer = peer; - list_add(&priv->list, &veth_list); priv = netdev_priv(peer); - priv->dev = peer; priv->peer = dev; - INIT_LIST_HEAD(&priv->list); return 0; err_register_dev: @@ -449,13 +444,6 @@ static void veth_dellink(struct net_device *dev) priv = netdev_priv(dev); peer = priv->peer; - if (!list_empty(&priv->list)) - list_del(&priv->list); - - priv = netdev_priv(peer); - if (!list_empty(&priv->list)) - list_del(&priv->list); - unregister_netdevice(dev); unregister_netdevice(peer); } diff --git a/drivers/net/via-rhine.c b/drivers/net/via-rhine.c index 5b7870080c5661d36325c72c95ee9975d36fd4a3..ac07cc6e3cb214eb7a56336205836e0b50bdfb1c 100644 --- a/drivers/net/via-rhine.c +++ b/drivers/net/via-rhine.c @@ -191,12 +191,13 @@ IIId. Synchronization The driver runs as two independent, single-threaded flows of control. One is the send-packet routine, which enforces single-threaded use by the -dev->priv->lock spinlock. The other thread is the interrupt handler, which -is single threaded by the hardware and interrupt handling software. +netdev_priv(dev)->lock spinlock. The other thread is the interrupt handler, +which is single threaded by the hardware and interrupt handling software. The send packet thread has partial control over the Tx ring. It locks the -dev->priv->lock whenever it's queuing a Tx packet. If the next slot in the ring -is not available it stops the transmit queue by calling netif_stop_queue. +netdev_priv(dev)->lock whenever it's queuing a Tx packet. If the next slot in +the ring is not available it stops the transmit queue by +calling netif_stop_queue. The interrupt handler has exclusive control over the Rx ring and records stats from the Tx ring. After reaping the stats, it marks the Tx queue entry as @@ -588,7 +589,7 @@ static int rhine_napipoll(struct napi_struct *napi, int budget) work_done = rhine_rx(dev, budget); if (work_done < budget) { - netif_rx_complete(dev, napi); + netif_rx_complete(napi); iowrite16(IntrRxDone | IntrRxErr | IntrRxEmpty| IntrRxOverflow | IntrRxDropped | IntrRxNoBuf | IntrTxAborted | @@ -614,6 +615,20 @@ static void __devinit rhine_hw_init(struct net_device *dev, long pioaddr) rhine_reload_eeprom(pioaddr, dev); } +static const struct net_device_ops rhine_netdev_ops = { + .ndo_open = rhine_open, + .ndo_stop = rhine_close, + .ndo_start_xmit = rhine_start_tx, + .ndo_get_stats = rhine_get_stats, + .ndo_set_multicast_list = rhine_set_rx_mode, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = netdev_ioctl, + .ndo_tx_timeout = rhine_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = rhine_poll, +#endif +}; + static int __devinit rhine_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { @@ -631,7 +646,6 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, #else int bar = 0; #endif - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -765,18 +779,10 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, rp->mii_if.reg_num_mask = 0x1f; /* The chip-specific entries in the device structure. */ - dev->open = rhine_open; - dev->hard_start_xmit = rhine_start_tx; - dev->stop = rhine_close; - dev->get_stats = rhine_get_stats; - dev->set_multicast_list = rhine_set_rx_mode; - dev->do_ioctl = netdev_ioctl; - dev->ethtool_ops = &netdev_ethtool_ops; - dev->tx_timeout = rhine_tx_timeout; + dev->netdev_ops = &rhine_netdev_ops; + dev->ethtool_ops = &netdev_ethtool_ops, dev->watchdog_timeo = TX_TIMEOUT; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = rhine_poll; -#endif + netif_napi_add(dev, &rp->napi, rhine_napipoll, 64); if (rp->quirks & rqRhineI) @@ -787,14 +793,14 @@ static int __devinit rhine_init_one(struct pci_dev *pdev, if (rc) goto err_out_unmap; - printk(KERN_INFO "%s: VIA %s at 0x%lx, %s, IRQ %d.\n", + printk(KERN_INFO "%s: VIA %s at 0x%lx, %pM, IRQ %d.\n", dev->name, name, #ifdef USE_MMIO memaddr, #else (long)ioaddr, #endif - print_mac(mac, dev->dev_addr), pdev->irq); + dev->dev_addr, pdev->irq); pci_set_drvdata(pdev, dev); @@ -1312,7 +1318,7 @@ static irqreturn_t rhine_interrupt(int irq, void *dev_instance) IntrPCIErr | IntrStatsMax | IntrLinkChange, ioaddr + IntrEnable); - netif_rx_schedule(dev, &rp->napi); + netif_rx_schedule(&rp->napi); } if (intr_status & (IntrTxErrSummary | IntrTxDone)) { @@ -1505,7 +1511,6 @@ static int rhine_rx(struct net_device *dev, int limit) } skb->protocol = eth_type_trans(skb, dev); netif_receive_skb(skb); - dev->last_rx = jiffies; rp->stats.rx_bytes += pkt_len; rp->stats.rx_packets++; } diff --git a/drivers/net/via-velocity.c b/drivers/net/via-velocity.c index 11cb3e504e1cb43e16c4eb5b81dda369ab4c75c1..58e25d090ae0687b7ca05a762447df7c6408f414 100644 --- a/drivers/net/via-velocity.c +++ b/drivers/net/via-velocity.c @@ -849,6 +849,20 @@ static int velocity_soft_reset(struct velocity_info *vptr) return 0; } +static const struct net_device_ops velocity_netdev_ops = { + .ndo_open = velocity_open, + .ndo_stop = velocity_close, + .ndo_start_xmit = velocity_xmit, + .ndo_get_stats = velocity_get_stats, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_multicast_list = velocity_set_multi, + .ndo_change_mtu = velocity_change_mtu, + .ndo_do_ioctl = velocity_ioctl, + .ndo_vlan_rx_add_vid = velocity_vlan_rx_add_vid, + .ndo_vlan_rx_kill_vid = velocity_vlan_rx_kill_vid, + .ndo_vlan_rx_register = velocity_vlan_rx_register, +}; + /** * velocity_found1 - set up discovered velocity card * @pdev: PCI device @@ -958,18 +972,8 @@ static int __devinit velocity_found1(struct pci_dev *pdev, const struct pci_devi vptr->phy_id = MII_GET_PHY_ID(vptr->mac_regs); dev->irq = pdev->irq; - dev->open = velocity_open; - dev->hard_start_xmit = velocity_xmit; - dev->stop = velocity_close; - dev->get_stats = velocity_get_stats; - dev->set_multicast_list = velocity_set_multi; - dev->do_ioctl = velocity_ioctl; + dev->netdev_ops = &velocity_netdev_ops; dev->ethtool_ops = &velocity_ethtool_ops; - dev->change_mtu = velocity_change_mtu; - - dev->vlan_rx_add_vid = velocity_vlan_rx_add_vid; - dev->vlan_rx_kill_vid = velocity_vlan_rx_kill_vid; - dev->vlan_rx_register = velocity_vlan_rx_register; #ifdef VELOCITY_ZERO_COPY_SUPPORT dev->features |= NETIF_F_SG; @@ -1412,8 +1416,6 @@ static int velocity_rx_srv(struct velocity_info *vptr, int status) rd->size |= RX_INTEN; - vptr->dev->last_rx = jiffies; - rd_curr++; if (rd_curr >= vptr->options.numrx) rd_curr = 0; diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c index 0196a0df90210995ec6a5abe228eb23bb22d494c..b7004ff36451764278e47eac267ffb4cd6bcd4bf 100644 --- a/drivers/net/virtio_net.c +++ b/drivers/net/virtio_net.c @@ -34,6 +34,7 @@ module_param(gso, bool, 0444); /* FIXME: MTU in config. */ #define MAX_PACKET_LEN (ETH_HLEN+ETH_DATA_LEN) +#define GOOD_COPY_LEN 128 struct virtnet_info { @@ -58,6 +59,9 @@ struct virtnet_info /* I like... big packets and I cannot lie! */ bool big_packets; + /* Host will merge rx buffers for big packets (shake it! shake it!) */ + bool mergeable_rx_bufs; + /* Receive & send queues. */ struct sk_buff_head recv; struct sk_buff_head send; @@ -66,22 +70,27 @@ struct virtnet_info struct page *pages; }; -static inline struct virtio_net_hdr *skb_vnet_hdr(struct sk_buff *skb) +static inline void *skb_vnet_hdr(struct sk_buff *skb) { return (struct virtio_net_hdr *)skb->cb; } -static inline void vnet_hdr_to_sg(struct scatterlist *sg, struct sk_buff *skb) -{ - sg_init_one(sg, skb_vnet_hdr(skb), sizeof(struct virtio_net_hdr)); -} - static void give_a_page(struct virtnet_info *vi, struct page *page) { page->private = (unsigned long)vi->pages; vi->pages = page; } +static void trim_pages(struct virtnet_info *vi, struct sk_buff *skb) +{ + unsigned int i; + + for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) + give_a_page(vi, skb_shinfo(skb)->frags[i].page); + skb_shinfo(skb)->nr_frags = 0; + skb->data_len = 0; +} + static struct page *get_a_page(struct virtnet_info *vi, gfp_t gfp_mask) { struct page *p = vi->pages; @@ -111,31 +120,97 @@ static void skb_xmit_done(struct virtqueue *svq) static void receive_skb(struct net_device *dev, struct sk_buff *skb, unsigned len) { + struct virtnet_info *vi = netdev_priv(dev); struct virtio_net_hdr *hdr = skb_vnet_hdr(skb); int err; + int i; if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) { pr_debug("%s: short packet %i\n", dev->name, len); dev->stats.rx_length_errors++; goto drop; } - len -= sizeof(struct virtio_net_hdr); - if (len <= MAX_PACKET_LEN) { - unsigned int i; + if (vi->mergeable_rx_bufs) { + struct virtio_net_hdr_mrg_rxbuf *mhdr = skb_vnet_hdr(skb); + unsigned int copy; + char *p = page_address(skb_shinfo(skb)->frags[0].page); - for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) - give_a_page(dev->priv, skb_shinfo(skb)->frags[i].page); - skb->data_len = 0; - skb_shinfo(skb)->nr_frags = 0; - } + if (len > PAGE_SIZE) + len = PAGE_SIZE; + len -= sizeof(struct virtio_net_hdr_mrg_rxbuf); - err = pskb_trim(skb, len); - if (err) { - pr_debug("%s: pskb_trim failed %i %d\n", dev->name, len, err); - dev->stats.rx_dropped++; - goto drop; + memcpy(hdr, p, sizeof(*mhdr)); + p += sizeof(*mhdr); + + copy = len; + if (copy > skb_tailroom(skb)) + copy = skb_tailroom(skb); + + memcpy(skb_put(skb, copy), p, copy); + + len -= copy; + + if (!len) { + give_a_page(vi, skb_shinfo(skb)->frags[0].page); + skb_shinfo(skb)->nr_frags--; + } else { + skb_shinfo(skb)->frags[0].page_offset += + sizeof(*mhdr) + copy; + skb_shinfo(skb)->frags[0].size = len; + skb->data_len += len; + skb->len += len; + } + + while (--mhdr->num_buffers) { + struct sk_buff *nskb; + + i = skb_shinfo(skb)->nr_frags; + if (i >= MAX_SKB_FRAGS) { + pr_debug("%s: packet too long %d\n", dev->name, + len); + dev->stats.rx_length_errors++; + goto drop; + } + + nskb = vi->rvq->vq_ops->get_buf(vi->rvq, &len); + if (!nskb) { + pr_debug("%s: rx error: %d buffers missing\n", + dev->name, mhdr->num_buffers); + dev->stats.rx_length_errors++; + goto drop; + } + + __skb_unlink(nskb, &vi->recv); + vi->num--; + + skb_shinfo(skb)->frags[i] = skb_shinfo(nskb)->frags[0]; + skb_shinfo(nskb)->nr_frags = 0; + kfree_skb(nskb); + + if (len > PAGE_SIZE) + len = PAGE_SIZE; + + skb_shinfo(skb)->frags[i].size = len; + skb_shinfo(skb)->nr_frags++; + skb->data_len += len; + skb->len += len; + } + } else { + len -= sizeof(struct virtio_net_hdr); + + if (len <= MAX_PACKET_LEN) + trim_pages(vi, skb); + + err = pskb_trim(skb, len); + if (err) { + pr_debug("%s: pskb_trim failed %i %d\n", dev->name, + len, err); + dev->stats.rx_dropped++; + goto drop; + } } + skb->truesize += skb->data_len; dev->stats.rx_bytes += skb->len; dev->stats.rx_packets++; @@ -194,7 +269,7 @@ drop: dev_kfree_skb(skb); } -static void try_fill_recv(struct virtnet_info *vi) +static void try_fill_recv_maxbufs(struct virtnet_info *vi) { struct sk_buff *skb; struct scatterlist sg[2+MAX_SKB_FRAGS]; @@ -202,12 +277,16 @@ static void try_fill_recv(struct virtnet_info *vi) sg_init_table(sg, 2+MAX_SKB_FRAGS); for (;;) { + struct virtio_net_hdr *hdr; + skb = netdev_alloc_skb(vi->dev, MAX_PACKET_LEN); if (unlikely(!skb)) break; skb_put(skb, MAX_PACKET_LEN); - vnet_hdr_to_sg(sg, skb); + + hdr = skb_vnet_hdr(skb); + sg_init_one(sg, hdr, sizeof(*hdr)); if (vi->big_packets) { for (i = 0; i < MAX_SKB_FRAGS; i++) { @@ -230,6 +309,55 @@ static void try_fill_recv(struct virtnet_info *vi) skb_queue_head(&vi->recv, skb); err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, num, skb); + if (err) { + skb_unlink(skb, &vi->recv); + trim_pages(vi, skb); + kfree_skb(skb); + break; + } + vi->num++; + } + if (unlikely(vi->num > vi->max)) + vi->max = vi->num; + vi->rvq->vq_ops->kick(vi->rvq); +} + +static void try_fill_recv(struct virtnet_info *vi) +{ + struct sk_buff *skb; + struct scatterlist sg[1]; + int err; + + if (!vi->mergeable_rx_bufs) { + try_fill_recv_maxbufs(vi); + return; + } + + for (;;) { + skb_frag_t *f; + + skb = netdev_alloc_skb(vi->dev, GOOD_COPY_LEN + NET_IP_ALIGN); + if (unlikely(!skb)) + break; + + skb_reserve(skb, NET_IP_ALIGN); + + f = &skb_shinfo(skb)->frags[0]; + f->page = get_a_page(vi, GFP_ATOMIC); + if (!f->page) { + kfree_skb(skb); + break; + } + + f->page_offset = 0; + f->size = PAGE_SIZE; + + skb_shinfo(skb)->nr_frags++; + + sg_init_one(sg, page_address(f->page), PAGE_SIZE); + skb_queue_head(&vi->recv, skb); + + err = vi->rvq->vq_ops->add_buf(vi->rvq, sg, 0, 1, skb); if (err) { skb_unlink(skb, &vi->recv); kfree_skb(skb); @@ -246,9 +374,9 @@ static void skb_recv_done(struct virtqueue *rvq) { struct virtnet_info *vi = rvq->vdev->priv; /* Schedule NAPI, Suppress further interrupts if successful. */ - if (netif_rx_schedule_prep(vi->dev, &vi->napi)) { + if (netif_rx_schedule_prep(&vi->napi)) { rvq->vq_ops->disable_cb(rvq); - __netif_rx_schedule(vi->dev, &vi->napi); + __netif_rx_schedule(&vi->napi); } } @@ -274,11 +402,11 @@ again: /* Out of packets? */ if (received < budget) { - netif_rx_complete(vi->dev, napi); + netif_rx_complete(napi); if (unlikely(!vi->rvq->vq_ops->enable_cb(vi->rvq)) && napi_schedule_prep(napi)) { vi->rvq->vq_ops->disable_cb(vi->rvq); - __netif_rx_schedule(vi->dev, napi); + __netif_rx_schedule(napi); goto again; } } @@ -320,17 +448,14 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) { int num, err; struct scatterlist sg[2+MAX_SKB_FRAGS]; - struct virtio_net_hdr *hdr; + struct virtio_net_hdr_mrg_rxbuf *mhdr = skb_vnet_hdr(skb); + struct virtio_net_hdr *hdr = skb_vnet_hdr(skb); const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest; sg_init_table(sg, 2+MAX_SKB_FRAGS); - pr_debug("%s: xmit %p " MAC_FMT "\n", vi->dev->name, skb, - dest[0], dest[1], dest[2], - dest[3], dest[4], dest[5]); + pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest); - /* Encode metadata header at front. */ - hdr = skb_vnet_hdr(skb); if (skb->ip_summed == CHECKSUM_PARTIAL) { hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM; hdr->csum_start = skb->csum_start - skb_headroom(skb); @@ -358,7 +483,14 @@ static int xmit_skb(struct virtnet_info *vi, struct sk_buff *skb) hdr->gso_size = hdr->hdr_len = 0; } - vnet_hdr_to_sg(sg, skb); + mhdr->num_buffers = 0; + + /* Encode metadata header at front. */ + if (vi->mergeable_rx_bufs) + sg_init_one(sg, mhdr, sizeof(*mhdr)); + else + sg_init_one(sg, hdr, sizeof(*hdr)); + num = skb_to_sgvec(skb, sg+1, 0, skb->len) + 1; err = vi->svq->vq_ops->add_buf(vi->svq, sg, num, 0, skb); @@ -448,9 +580,9 @@ static int virtnet_open(struct net_device *dev) * won't get another interrupt, so process any outstanding packets * now. virtnet_poll wants re-enable the queue, so we disable here. * We synchronize against interrupts via NAPI_STATE_SCHED */ - if (netif_rx_schedule_prep(dev, &vi->napi)) { + if (netif_rx_schedule_prep(&vi->napi)) { vi->rvq->vq_ops->disable_cb(vi->rvq); - __netif_rx_schedule(dev, &vi->napi); + __netif_rx_schedule(&vi->napi); } return 0; } @@ -478,8 +610,20 @@ static int virtnet_set_tx_csum(struct net_device *dev, u32 data) static struct ethtool_ops virtnet_ethtool_ops = { .set_tx_csum = virtnet_set_tx_csum, .set_sg = ethtool_op_set_sg, + .set_tso = ethtool_op_set_tso, }; +#define MIN_MTU 68 +#define MAX_MTU 65535 + +static int virtnet_change_mtu(struct net_device *dev, int new_mtu) +{ + if (new_mtu < MIN_MTU || new_mtu > MAX_MTU) + return -EINVAL; + dev->mtu = new_mtu; + return 0; +} + static int virtnet_probe(struct virtio_device *vdev) { int err; @@ -495,6 +639,7 @@ static int virtnet_probe(struct virtio_device *vdev) dev->open = virtnet_open; dev->stop = virtnet_close; dev->hard_start_xmit = start_xmit; + dev->change_mtu = virtnet_change_mtu; dev->features = NETIF_F_HIGHDMA; #ifdef CONFIG_NET_POLL_CONTROLLER dev->poll_controller = virtnet_netpoll; @@ -547,6 +692,9 @@ static int virtnet_probe(struct virtio_device *vdev) || virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN)) vi->big_packets = true; + if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF)) + vi->mergeable_rx_bufs = true; + /* We expect two virtqueues, receive then send. */ vi->rvq = vdev->config->find_vq(vdev, 0, skb_recv_done); if (IS_ERR(vi->rvq)) { @@ -639,6 +787,7 @@ static unsigned int features[] = { VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6, VIRTIO_NET_F_GUEST_ECN, /* We don't yet handle UFO input. */ + VIRTIO_NET_F_MRG_RXBUF, VIRTIO_F_NOTIFY_ON_EMPTY, }; diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig index 21efd99b9294bac7a17ce21763f4074e65596ef1..d08ce6a264cb9cbe5cdfc0e5e79b4588f8ea775a 100644 --- a/drivers/net/wan/Kconfig +++ b/drivers/net/wan/Kconfig @@ -207,6 +207,8 @@ config PC300 tristate "Cyclades-PC300 support (RS-232/V.35, X.21, T1/E1 boards)" depends on HDLC && PCI && BROKEN ---help--- + This driver is broken because of struct tty_driver change. + Driver for the Cyclades-PC300 synchronous communication boards. These boards provide synchronous serial interfaces to your @@ -333,6 +335,13 @@ config DSCC4_PCI_RST Say Y if your card supports this feature. +config IXP4XX_HSS + tristate "Intel IXP4xx HSS (synchronous serial port) support" + depends on HDLC && ARM && ARCH_IXP4XX && IXP4XX_NPE && IXP4XX_QMGR + help + Say Y here if you want to use built-in HSS ports + on IXP4xx processor. + config DLCI tristate "Frame Relay DLCI support" ---help--- diff --git a/drivers/net/wan/Makefile b/drivers/net/wan/Makefile index 102549605d098681a26db81af6a393ea5476fdc9..19d14bc28356f097ccf3a091fc6a42174597eba3 100644 --- a/drivers/net/wan/Makefile +++ b/drivers/net/wan/Makefile @@ -14,7 +14,7 @@ obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o obj-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o obj-$(CONFIG_HDLC_FR) += hdlc_fr.o -obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o syncppp.o +obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o obj-$(CONFIG_HDLC_X25) += hdlc_x25.o pc300-y := pc300_drv.o @@ -41,6 +41,7 @@ obj-$(CONFIG_C101) += c101.o obj-$(CONFIG_WANXL) += wanxl.o obj-$(CONFIG_PCI200SYN) += pci200syn.o obj-$(CONFIG_PC300TOO) += pc300too.o +obj-$(CONFIG_IXP4XX_HSS) += ixp4xx_hss.o clean-files := wanxlfw.inc $(obj)/wanxl.o: $(obj)/wanxlfw.inc diff --git a/drivers/net/wan/c101.c b/drivers/net/wan/c101.c index c8e563106a4af357fad4513e393b480b2a2bfe4a..b46897996f7e3edf98645c3ec433f006d0f95059 100644 --- a/drivers/net/wan/c101.c +++ b/drivers/net/wan/c101.c @@ -88,7 +88,7 @@ static card_t **new_card = &first_card; /* EDA address register must be set in EDAL, EDAH order - 8 bit ISA bus */ #define sca_outw(value, reg, card) do { \ writeb(value & 0xFF, (card)->win0base + C101_SCA + (reg)); \ - writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg+1));\ + writeb((value >> 8 ) & 0xFF, (card)->win0base + C101_SCA + (reg + 1));\ } while(0) #define port_to_card(port) (port) @@ -113,7 +113,7 @@ static inline void openwin(card_t *card, u8 page) } -#include "hd6457x.c" +#include "hd64570.c" static inline void set_carrier(port_t *port) @@ -381,7 +381,7 @@ static int __init c101_run(unsigned long irq, unsigned long winbase) return result; } - sca_init_sync_port(card); /* Set up C101 memory */ + sca_init_port(card); /* Set up C101 memory */ set_carrier(card); printk(KERN_INFO "%s: Moxa C101 on IRQ%u," diff --git a/drivers/net/wan/cosa.c b/drivers/net/wan/cosa.c index 7f97f8d08c39eeba79eaa4da5cdfc5368d59487d..d80b72e22dea6be26d69b4e2d0fd016541a546f8 100644 --- a/drivers/net/wan/cosa.c +++ b/drivers/net/wan/cosa.c @@ -754,7 +754,6 @@ static int cosa_net_rx_done(struct channel_data *chan) chan->netdev->stats.rx_bytes += chan->cosa->rxsize; netif_rx(chan->rx_skb); chan->rx_skb = NULL; - chan->netdev->last_rx = jiffies; return 0; } diff --git a/drivers/net/wan/cycx_x25.c b/drivers/net/wan/cycx_x25.c index 5a7303dc0965e7b5db3f8af3aa35202755602a51..5fa52923efa80e7401852c11dfee6864874ded5b 100644 --- a/drivers/net/wan/cycx_x25.c +++ b/drivers/net/wan/cycx_x25.c @@ -199,6 +199,8 @@ static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev, static struct net_device * cycx_x25_get_dev_by_dte_addr(struct wan_device *wandev, char *dte); +static void cycx_x25_chan_setup(struct net_device *dev); + #ifdef CYCLOMX_X25_DEBUG static void hex_dump(char *msg, unsigned char *p, int len); static void cycx_x25_dump_config(struct cycx_x25_config *conf); @@ -353,6 +355,12 @@ static int cycx_wan_update(struct wan_device *wandev) return 0; } +/* callback to initialize device */ +static void cycx_x25_chan_setup(struct net_device *dev) +{ + dev->init = cycx_netdevice_init; +} + /* Create new logical channel. * This routine is called by the router when ROUTER_IFNEW IOCTL is being * handled. @@ -376,11 +384,12 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, return -EINVAL; } - /* allocate and initialize private data */ - chan = kzalloc(sizeof(struct cycx_x25_channel), GFP_KERNEL); - if (!chan) + dev = alloc_netdev(sizeof(struct cycx_x25_channel), conf->name, + cycx_x25_chan_setup); + if (!dev) return -ENOMEM; + chan = netdev_priv(dev); strcpy(chan->name, conf->name); chan->card = card; chan->link = conf->port; @@ -396,14 +405,14 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, if (len > WAN_ADDRESS_SZ) { printk(KERN_ERR "%s: %s local addr too long!\n", wandev->name, chan->name); - kfree(chan); - return -EINVAL; + err = -EINVAL; + goto error; } else { chan->local_addr = kmalloc(len + 1, GFP_KERNEL); if (!chan->local_addr) { - kfree(chan); - return -ENOMEM; + err = -ENOMEM; + goto error; } } @@ -429,41 +438,31 @@ static int cycx_wan_new_if(struct wan_device *wandev, struct net_device *dev, "%s: PVC %u is out of range on interface %s!\n", wandev->name, lcn, chan->name); err = -EINVAL; + goto error; } } else { printk(KERN_ERR "%s: invalid media address on interface %s!\n", wandev->name, chan->name); err = -EINVAL; + goto error; } - if (err) { - kfree(chan->local_addr); - kfree(chan); - return err; - } - - /* prepare network device data space for registration */ - strcpy(dev->name, chan->name); - dev->init = cycx_netdevice_init; - dev->priv = chan; - return 0; + +error: + free_netdev(dev); + return err; } /* Delete logical channel. */ static int cycx_wan_del_if(struct wan_device *wandev, struct net_device *dev) { - if (dev->priv) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); - if (chan->svc) { - kfree(chan->local_addr); - if (chan->state == WAN_CONNECTED) - del_timer(&chan->timer); - } - - kfree(chan); - dev->priv = NULL; + if (chan->svc) { + kfree(chan->local_addr); + if (chan->state == WAN_CONNECTED) + del_timer(&chan->timer); } return 0; @@ -484,7 +483,7 @@ static const struct header_ops cycx_header_ops = { * registration. */ static int cycx_netdevice_init(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; struct wan_device *wandev = &card->wandev; @@ -542,7 +541,7 @@ static int cycx_netdevice_open(struct net_device *dev) * o if there's no more open channels then disconnect physical link. */ static int cycx_netdevice_stop(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); netif_stop_queue(dev); @@ -596,7 +595,7 @@ static int cycx_netdevice_rebuild_header(struct sk_buff *skb) static int cycx_netdevice_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; if (!chan->svc) @@ -670,7 +669,7 @@ free_packet: * Return a pointer to struct net_device_stats */ static struct net_device_stats *cycx_netdevice_get_stats(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); return chan ? &chan->ifstats : NULL; } @@ -783,7 +782,7 @@ static void cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd) return; } - chan = dev->priv; + chan = netdev_priv(dev); reset_timer(dev); if (chan->drop_sequence) { @@ -843,7 +842,6 @@ static void cycx_x25_irq_rx(struct cycx_device *card, struct cycx_x25_cmd *cmd) skb_reset_mac_header(skb); netif_rx(skb); - dev->last_rx = jiffies; /* timestamp */ } /* Connect interrupt handler. */ @@ -884,7 +882,7 @@ static void cycx_x25_irq_connect(struct cycx_device *card, return; } - chan = dev->priv; + chan = netdev_priv(dev); chan->lcn = lcn; cycx_x25_connect_response(card, chan); cycx_x25_set_chan_state(dev, WAN_CONNECTED); @@ -914,7 +912,7 @@ static void cycx_x25_irq_connect_confirm(struct cycx_device *card, } clear_bit(--key, (void*)&card->u.x.connection_keys); - chan = dev->priv; + chan = netdev_priv(dev); chan->lcn = lcn; cycx_x25_set_chan_state(dev, WAN_CONNECTED); } @@ -954,7 +952,7 @@ static void cycx_x25_irq_disconnect(struct cycx_device *card, dev = cycx_x25_get_dev_by_lcn(wandev, lcn); if (dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); cycx_x25_disconnect_response(card, chan->link, lcn); cycx_x25_set_chan_state(dev, WAN_DISCONNECTED); @@ -1302,7 +1300,7 @@ static struct net_device *cycx_x25_get_dev_by_lcn(struct wan_device *wandev, struct cycx_x25_channel *chan; while (dev) { - chan = (struct cycx_x25_channel*)dev->priv; + chan = netdev_priv(dev); if (chan->lcn == lcn) break; @@ -1319,7 +1317,7 @@ static struct net_device * struct cycx_x25_channel *chan; while (dev) { - chan = (struct cycx_x25_channel*)dev->priv; + chan = netdev_priv(dev); if (!strcmp(chan->addr, dte)) break; @@ -1337,7 +1335,7 @@ static struct net_device * * <0 failure */ static int cycx_x25_chan_connect(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; if (chan->svc) { @@ -1362,7 +1360,7 @@ static int cycx_x25_chan_connect(struct net_device *dev) * o if SVC then clear X.25 call */ static void cycx_x25_chan_disconnect(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); if (chan->svc) { x25_clear_call(chan->card, chan->link, chan->lcn, 0, 0); @@ -1375,7 +1373,7 @@ static void cycx_x25_chan_disconnect(struct net_device *dev) static void cycx_x25_chan_timer(unsigned long d) { struct net_device *dev = (struct net_device *)d; - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); if (chan->state == WAN_CONNECTED) cycx_x25_chan_disconnect(dev); @@ -1387,7 +1385,7 @@ static void cycx_x25_chan_timer(unsigned long d) /* Set logical channel state. */ static void cycx_x25_set_chan_state(struct net_device *dev, u8 state) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; unsigned long flags; char *string_state = NULL; @@ -1453,7 +1451,7 @@ static void cycx_x25_set_chan_state(struct net_device *dev, u8 state) * to the router. */ static int cycx_x25_chan_send(struct net_device *dev, struct sk_buff *skb) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); struct cycx_device *card = chan->card; int bitm = 0; /* final packet */ unsigned len = skb->len; @@ -1494,7 +1492,6 @@ static void cycx_x25_chan_send_event(struct net_device *dev, u8 event) skb->protocol = x25_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; /* timestamp */ } /* Convert line speed in bps to a number used by cyclom 2x code. */ @@ -1547,7 +1544,7 @@ static unsigned dec_to_uint(u8 *str, int len) static void reset_timer(struct net_device *dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); if (chan->svc) mod_timer(&chan->timer, jiffies+chan->idle_tmout*HZ); @@ -1600,7 +1597,7 @@ static void cycx_x25_dump_devs(struct wan_device *wandev) printk(KERN_INFO "---------------------------------------\n"); while(dev) { - struct cycx_x25_channel *chan = dev->priv; + struct cycx_x25_channel *chan = netdev_priv(dev); printk(KERN_INFO "%-5.5s %-15.15s %d ETH_P_%s\n", chan->name, chan->addr, netif_queue_stopped(dev), diff --git a/drivers/net/wan/dlci.c b/drivers/net/wan/dlci.c index b14242768fad19c381cff1d3d232d4abcf5f7e24..a297e3efa05dd32369d0c1c23c14378675c51436 100644 --- a/drivers/net/wan/dlci.c +++ b/drivers/net/wan/dlci.c @@ -74,7 +74,7 @@ static int dlci_header(struct sk_buff *skb, struct net_device *dev, unsigned int hlen; char *dest; - dlp = dev->priv; + dlp = netdev_priv(dev); hdr.control = FRAD_I_UI; switch(type) @@ -110,7 +110,7 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) struct frhdr *hdr; int process, header; - dlp = dev->priv; + dlp = netdev_priv(dev); if (!pskb_may_pull(skb, sizeof(*hdr))) { printk(KERN_NOTICE "%s: invalid data no header\n", dev->name); @@ -181,7 +181,6 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev) dlp->stats.rx_bytes += skb->len; netif_rx(skb); dlp->stats.rx_packets++; - dev->last_rx = jiffies; } else dev_kfree_skb(skb); @@ -197,7 +196,7 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev) if (!skb || !dev) return(0); - dlp = dev->priv; + dlp = netdev_priv(dev); netif_stop_queue(dev); @@ -235,9 +234,9 @@ static int dlci_config(struct net_device *dev, struct dlci_conf __user *conf, in struct frad_local *flp; int err; - dlp = dev->priv; + dlp = netdev_priv(dev); - flp = dlp->slave->priv; + flp = netdev_priv(dlp->slave); if (!get) { @@ -269,7 +268,7 @@ static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) if (!capable(CAP_NET_ADMIN)) return(-EPERM); - dlp = dev->priv; + dlp = netdev_priv(dev); switch(cmd) { @@ -298,7 +297,7 @@ static int dlci_change_mtu(struct net_device *dev, int new_mtu) { struct dlci_local *dlp; - dlp = dev->priv; + dlp = netdev_priv(dev); return((*dlp->slave->change_mtu)(dlp->slave, new_mtu)); } @@ -309,7 +308,7 @@ static int dlci_open(struct net_device *dev) struct frad_local *flp; int err; - dlp = dev->priv; + dlp = netdev_priv(dev); if (!*(short *)(dev->dev_addr)) return(-EINVAL); @@ -317,7 +316,7 @@ static int dlci_open(struct net_device *dev) if (!netif_running(dlp->slave)) return(-ENOTCONN); - flp = dlp->slave->priv; + flp = netdev_priv(dlp->slave); err = (*flp->activate)(dlp->slave, dev); if (err) return(err); @@ -335,9 +334,9 @@ static int dlci_close(struct net_device *dev) netif_stop_queue(dev); - dlp = dev->priv; + dlp = netdev_priv(dev); - flp = dlp->slave->priv; + flp = netdev_priv(dlp->slave); err = (*flp->deactivate)(dlp->slave, dev); return 0; @@ -347,7 +346,7 @@ static struct net_device_stats *dlci_get_stats(struct net_device *dev) { struct dlci_local *dlp; - dlp = dev->priv; + dlp = netdev_priv(dev); return(&dlp->stats); } @@ -365,7 +364,7 @@ static int dlci_add(struct dlci_add *dlci) if (!slave) return -ENODEV; - if (slave->type != ARPHRD_FRAD || slave->priv == NULL) + if (slave->type != ARPHRD_FRAD || netdev_priv(slave) == NULL) goto err1; /* create device name */ @@ -391,11 +390,11 @@ static int dlci_add(struct dlci_add *dlci) *(short *)(master->dev_addr) = dlci->dlci; - dlp = (struct dlci_local *) master->priv; + dlp = netdev_priv(master); dlp->slave = slave; dlp->master = master; - flp = slave->priv; + flp = netdev_priv(slave); err = (*flp->assoc)(slave, master); if (err < 0) goto err2; @@ -435,9 +434,9 @@ static int dlci_del(struct dlci_add *dlci) return(-EBUSY); } - dlp = master->priv; + dlp = netdev_priv(master); slave = dlp->slave; - flp = slave->priv; + flp = netdev_priv(slave); rtnl_lock(); err = (*flp->deassoc)(slave, master); @@ -491,7 +490,7 @@ static const struct header_ops dlci_header_ops = { static void dlci_setup(struct net_device *dev) { - struct dlci_local *dlp = dev->priv; + struct dlci_local *dlp = netdev_priv(dev); dev->flags = 0; dev->open = dlci_open; diff --git a/drivers/net/wan/dscc4.c b/drivers/net/wan/dscc4.c index 5f1ccb2b08b11d1dbe0f4a7cab308b6ec92105ef..888025db2f022616d6c0bd4343835be5e5c6a989 100644 --- a/drivers/net/wan/dscc4.c +++ b/drivers/net/wan/dscc4.c @@ -659,7 +659,6 @@ static inline void dscc4_rx_skb(struct dscc4_dev_priv *dpriv, skb_put(skb, pkt_len); if (netif_running(dev)) skb->protocol = hdlc_type_trans(skb, dev); - skb->dev->last_rx = jiffies; netif_rx(skb); } else { if (skb->data[pkt_len] & FrameRdo) @@ -730,8 +729,7 @@ static int __devinit dscc4_init_one(struct pci_dev *pdev, goto err_free_mmio_region_1; } - ioaddr = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); + ioaddr = pci_ioremap_bar(pdev, 0); if (!ioaddr) { printk(KERN_ERR "%s: cannot remap MMIO region %llx @ %llx\n", DRV_NAME, (unsigned long long)pci_resource_len(pdev, 0), diff --git a/drivers/net/wan/farsync.c b/drivers/net/wan/farsync.c index 9557ad078ab802e711496516d950f2d04cff3727..48a2c9d28950fc875a72334623343300bda21181 100644 --- a/drivers/net/wan/farsync.c +++ b/drivers/net/wan/farsync.c @@ -896,7 +896,6 @@ fst_rx_dma_complete(struct fst_card_info *card, struct fst_port_info *port, fst_process_rx_status(rx_status, port_to_dev(port)->name); if (rx_status == NET_RX_DROP) dev->stats.rx_dropped++; - dev->last_rx = jiffies; } /* @@ -1322,7 +1321,6 @@ fst_intr_rx(struct fst_card_info *card, struct fst_port_info *port) fst_process_rx_status(rx_status, port_to_dev(port)->name); if (rx_status == NET_RX_DROP) dev->stats.rx_dropped++; - dev->last_rx = jiffies; } else { card->dma_skb_rx = skb; card->dma_port_rx = port; diff --git a/drivers/net/wan/hd6457x.c b/drivers/net/wan/hd64570.c similarity index 78% rename from drivers/net/wan/hd6457x.c rename to drivers/net/wan/hd64570.c index 591fb45a7c68d01748fa8a15c1581ae0debb5720..223238de475cdf2ed8802334dfa8addca693f90f 100644 --- a/drivers/net/wan/hd6457x.c +++ b/drivers/net/wan/hd64570.c @@ -1,5 +1,5 @@ /* - * Hitachi SCA HD64570 and HD64572 common driver for Linux + * Hitachi SCA HD64570 driver for Linux * * Copyright (C) 1998-2003 Krzysztof Halasa * @@ -7,9 +7,7 @@ * under the terms of version 2 of the GNU General Public License * as published by the Free Software Foundation. * - * Sources of information: - * Hitachi HD64570 SCA User's Manual - * Hitachi HD64572 SCA-II User's Manual + * Source of information: Hitachi HD64570 SCA User's Manual * * We use the following SCA memory map: * @@ -26,33 +24,26 @@ * tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers (if used) */ -#include -#include -#include -#include -#include +#include +#include #include -#include +#include #include -#include -#include #include +#include #include -#include - -#include -#include -#include - +#include +#include +#include #include #include - -#include - -#if (!defined (__HD64570_H) && !defined (__HD64572_H)) || \ - (defined (__HD64570_H) && defined (__HD64572_H)) -#error Either hd64570.h or hd64572.h must be included -#endif +#include +#include +#include +#include +#include +#include +#include "hd64570.h" #define get_msci(port) (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) #define get_dmac_rx(port) (phy_node(port) ? DMAC1RX_OFFSET : DMAC0RX_OFFSET) @@ -62,16 +53,6 @@ #define SCA_INTR_DMAC_RX(node) (node ? 0x20 : 0x02) #define SCA_INTR_DMAC_TX(node) (node ? 0x40 : 0x04) -#ifdef __HD64570_H /* HD64570 */ -#define sca_outa(value, reg, card) sca_outw(value, reg, card) -#define sca_ina(reg, card) sca_inw(reg, card) -#define writea(value, ptr) writew(value, ptr) - -#else /* HD64572 */ -#define sca_outa(value, reg, card) sca_outl(value, reg, card) -#define sca_ina(reg, card) sca_inl(reg, card) -#define writea(value, ptr) writel(value, ptr) -#endif static inline struct net_device *port_to_dev(port_t *port) { @@ -81,8 +62,6 @@ static inline struct net_device *port_to_dev(port_t *port) static inline int sca_intr_status(card_t *card) { u8 result = 0; - -#ifdef __HD64570_H /* HD64570 */ u8 isr0 = sca_in(ISR0, card); u8 isr1 = sca_in(ISR1, card); @@ -93,18 +72,6 @@ static inline int sca_intr_status(card_t *card) if (isr0 & 0x0F) result |= SCA_INTR_MSCI(0); if (isr0 & 0xF0) result |= SCA_INTR_MSCI(1); -#else /* HD64572 */ - u32 isr0 = sca_inl(ISR0, card); - - if (isr0 & 0x0000000F) result |= SCA_INTR_DMAC_RX(0); - if (isr0 & 0x000000F0) result |= SCA_INTR_DMAC_TX(0); - if (isr0 & 0x00000F00) result |= SCA_INTR_DMAC_RX(1); - if (isr0 & 0x0000F000) result |= SCA_INTR_DMAC_TX(1); - if (isr0 & 0x003E0000) result |= SCA_INTR_MSCI(0); - if (isr0 & 0x3E000000) result |= SCA_INTR_MSCI(1); - -#endif /* HD64570 vs HD64572 */ - if (!(result & SCA_INTR_DMAC_TX(0))) if (sca_in(DSR_TX(0), card) & DSR_EOM) result |= SCA_INTR_DMAC_TX(0); @@ -127,7 +94,6 @@ static inline u16 next_desc(port_t *port, u16 desc, int transmit) } - static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit) { u16 rx_buffs = port_to_card(port)->rx_ring_buffers; @@ -139,28 +105,26 @@ static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit) } - static inline u16 desc_offset(port_t *port, u16 desc, int transmit) { - /* Descriptor offset always fits in 16 bytes */ + /* Descriptor offset always fits in 16 bits */ return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc); } - -static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc, int transmit) +static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc, + int transmit) { #ifdef PAGE0_ALWAYS_MAPPED return (pkt_desc __iomem *)(win0base(port_to_card(port)) - + desc_offset(port, desc, transmit)); + + desc_offset(port, desc, transmit)); #else return (pkt_desc __iomem *)(winbase(port_to_card(port)) - + desc_offset(port, desc, transmit)); + + desc_offset(port, desc, transmit)); #endif } - static inline u32 buffer_offset(port_t *port, u16 desc, int transmit) { return port_to_card(port)->buff_offset + @@ -186,7 +150,7 @@ static inline void sca_set_carrier(port_t *port) } -static void sca_init_sync_port(port_t *port) +static void sca_init_port(port_t *port) { card_t *card = port_to_card(port); int transmit, i; @@ -195,7 +159,7 @@ static void sca_init_sync_port(port_t *port) port->txin = 0; port->txlast = 0; -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) +#ifndef PAGE0_ALWAYS_MAPPED openwin(card, 0); #endif @@ -209,7 +173,7 @@ static void sca_init_sync_port(port_t *port) u16 chain_off = desc_offset(port, i + 1, transmit); u32 buff_off = buffer_offset(port, i, transmit); - writea(chain_off, &desc->cp); + writew(chain_off, &desc->cp); writel(buff_off, &desc->bp); writew(0, &desc->len); writeb(0, &desc->stat); @@ -222,16 +186,14 @@ static void sca_init_sync_port(port_t *port) sca_out(DCR_ABORT, transmit ? DCR_TX(phy_node(port)) : DCR_RX(phy_node(port)), card); -#ifdef __HD64570_H - sca_out(0, dmac + CPB, card); /* pointer base */ -#endif /* current desc addr */ - sca_outa(desc_offset(port, 0, transmit), dmac + CDAL, card); + sca_out(0, dmac + CPB, card); /* pointer base */ + sca_outw(desc_offset(port, 0, transmit), dmac + CDAL, card); if (!transmit) - sca_outa(desc_offset(port, buffs - 1, transmit), + sca_outw(desc_offset(port, buffs - 1, transmit), dmac + EDAL, card); else - sca_outa(desc_offset(port, 0, transmit), dmac + EDAL, + sca_outw(desc_offset(port, 0, transmit), dmac + EDAL, card); /* clear frame end interrupt counter */ @@ -258,7 +220,6 @@ static void sca_init_sync_port(port_t *port) } - #ifdef NEED_SCA_MSCI_INTR /* MSCI interrupt service */ static inline void sca_msci_intr(port_t *port) @@ -282,17 +243,15 @@ static inline void sca_msci_intr(port_t *port) #endif - -static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u16 rxin) +static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, + u16 rxin) { struct net_device *dev = port_to_dev(port); struct sk_buff *skb; u16 len; u32 buff; -#ifndef ALL_PAGES_ALWAYS_MAPPED u32 maxlen; u8 page; -#endif len = readw(&desc->len); skb = dev_alloc_skb(len); @@ -302,7 +261,6 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1 } buff = buffer_offset(port, rxin, 0); -#ifndef ALL_PAGES_ALWAYS_MAPPED page = buff / winsize(card); buff = buff % winsize(card); maxlen = winsize(card) - buff; @@ -314,12 +272,10 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1 openwin(card, page + 1); memcpy_fromio(skb->data + maxlen, winbase(card), len - maxlen); } else -#endif - memcpy_fromio(skb->data, winbase(card) + buff, len); + memcpy_fromio(skb->data, winbase(card) + buff, len); -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) - /* select pkt_desc table page back */ - openwin(card, 0); +#ifndef PAGE0_ALWAYS_MAPPED + openwin(card, 0); /* select pkt_desc table page back */ #endif skb_put(skb, len); #ifdef DEBUG_PKT @@ -328,13 +284,11 @@ static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, u1 #endif dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; - dev->last_rx = jiffies; skb->protocol = hdlc_type_trans(skb, dev); netif_rx(skb); } - /* Receive DMA interrupt service */ static inline void sca_rx_intr(port_t *port) { @@ -354,7 +308,7 @@ static inline void sca_rx_intr(port_t *port) while (1) { u32 desc_off = desc_offset(port, port->rxin, 0); pkt_desc __iomem *desc; - u32 cda = sca_ina(dmac + CDAL, card); + u32 cda = sca_inw(dmac + CDAL, card); if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc))) break; /* No frame received */ @@ -378,7 +332,7 @@ static inline void sca_rx_intr(port_t *port) sca_rx(card, port, desc, port->rxin); /* Set new error descriptor address */ - sca_outa(desc_off, dmac + EDAL, card); + sca_outw(desc_off, dmac + EDAL, card); port->rxin = next_desc(port, port->rxin, 0); } @@ -387,7 +341,6 @@ static inline void sca_rx_intr(port_t *port) } - /* Transmit DMA interrupt service */ static inline void sca_tx_intr(port_t *port) { @@ -408,7 +361,7 @@ static inline void sca_tx_intr(port_t *port) pkt_desc __iomem *desc; u32 desc_off = desc_offset(port, port->txlast, 1); - u32 cda = sca_ina(dmac + CDAL, card); + u32 cda = sca_inw(dmac + CDAL, card); if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc))) break; /* Transmitter is/will_be sending this frame */ @@ -424,17 +377,13 @@ static inline void sca_tx_intr(port_t *port) } - static irqreturn_t sca_intr(int irq, void* dev_id) { card_t *card = dev_id; int i; u8 stat; int handled = 0; - -#ifndef ALL_PAGES_ALWAYS_MAPPED u8 page = sca_get_page(card); -#endif while((stat = sca_intr_status(card)) != 0) { handled = 1; @@ -453,14 +402,11 @@ static irqreturn_t sca_intr(int irq, void* dev_id) } } -#ifndef ALL_PAGES_ALWAYS_MAPPED openwin(card, page); /* Restore original page */ -#endif return IRQ_RETVAL(handled); } - static void sca_set_port(port_t *port) { card_t* card = port_to_card(port); @@ -498,12 +444,7 @@ static void sca_set_port(port_t *port) port->tmc = tmc; /* baud divisor - time constant*/ -#ifdef __HD64570_H sca_out(port->tmc, msci + TMC, card); -#else - sca_out(port->tmc, msci + TMCR, card); - sca_out(port->tmc, msci + TMCT, card); -#endif /* Set BRG bits */ sca_out(port->rxs, msci + RXS, card); @@ -519,7 +460,6 @@ static void sca_set_port(port_t *port) } - static void sca_open(struct net_device *dev) { port_t *port = dev_to_port(dev); @@ -541,11 +481,7 @@ static void sca_open(struct net_device *dev) switch(port->parity) { case PARITY_CRC16_PR0: md0 = MD0_HDLC | MD0_CRC_16_0; break; case PARITY_CRC16_PR1: md0 = MD0_HDLC | MD0_CRC_16; break; -#ifdef __HD64570_H case PARITY_CRC16_PR0_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU_0; break; -#else - case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break; -#endif case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU; break; default: md0 = MD0_HDLC | MD0_CRC_NONE; } @@ -555,35 +491,20 @@ static void sca_open(struct net_device *dev) sca_out(0x00, msci + MD1, card); /* no address field check */ sca_out(md2, msci + MD2, card); sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */ -#ifdef __HD64570_H sca_out(CTL_IDLE, msci + CTL, card); -#else - /* Skip the rest of underrun frame */ - sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card); -#endif -#ifdef __HD64570_H /* Allow at least 8 bytes before requesting RX DMA operation */ /* TX with higher priority and possibly with shorter transfers */ sca_out(0x07, msci + RRC, card); /* +1=RXRDY/DMA activation condition*/ sca_out(0x10, msci + TRC0, card); /* = TXRDY/DMA activation condition*/ sca_out(0x14, msci + TRC1, card); /* +1=TXRDY/DMA deactiv condition */ -#else - sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */ - sca_out(0x3C, msci + TFS, card); /* +1 = TX start */ - sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */ - sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */ - sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/ -#endif /* We're using the following interrupts: - TXINT (DMAC completed all transmisions, underrun or DCD change) - all DMA interrupts */ - sca_set_carrier(port); -#ifdef __HD64570_H /* MSCI TX INT and RX INT A IRQ enable */ sca_out(IE0_TXINT | IE0_RXINTA, msci + IE0, card); sca_out(IE1_UDRN | IE1_CDCD, msci + IE1, card); @@ -592,21 +513,8 @@ static void sca_open(struct net_device *dev) /* enable DMA IRQ */ sca_out(sca_in(IER1, card) | (phy_node(port) ? 0xF0 : 0x0F), IER1, card); -#else - /* MSCI TXINT and RXINTA interrupt enable */ - sca_outl(IE0_TXINT | IE0_RXINTA | IE0_UDRN | IE0_CDCD, msci + IE0, - card); - /* DMA & MSCI IRQ enable */ - sca_outl(sca_inl(IER0, card) | - (phy_node(port) ? 0x0A006600 : 0x000A0066), IER0, card); -#endif -#ifdef __HD64570_H sca_out(port->tmc, msci + TMC, card); /* Restore registers */ -#else - sca_out(port->tmc, msci + TMCR, card); - sca_out(port->tmc, msci + TMCT, card); -#endif sca_out(port->rxs, msci + RXS, card); sca_out(port->txs, msci + TXS, card); sca_out(CMD_TX_ENABLE, msci + CMD, card); @@ -616,7 +524,6 @@ static void sca_open(struct net_device *dev) } - static void sca_close(struct net_device *dev) { port_t *port = dev_to_port(dev); @@ -624,23 +531,17 @@ static void sca_close(struct net_device *dev) /* reset channel */ sca_out(CMD_RESET, get_msci(port) + CMD, port_to_card(port)); -#ifdef __HD64570_H /* disable MSCI interrupts */ sca_out(sca_in(IER0, card) & (phy_node(port) ? 0x0F : 0xF0), IER0, card); /* disable DMA interrupts */ sca_out(sca_in(IER1, card) & (phy_node(port) ? 0x0F : 0xF0), IER1, card); -#else - /* disable DMA & MSCI IRQ */ - sca_outl(sca_inl(IER0, card) & - (phy_node(port) ? 0x00FF00FF : 0xFF00FF00), IER0, card); -#endif + netif_stop_queue(dev); } - static int sca_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) { @@ -654,11 +555,7 @@ static int sca_attach(struct net_device *dev, unsigned short encoding, if (parity != PARITY_NONE && parity != PARITY_CRC16_PR0 && parity != PARITY_CRC16_PR1 && -#ifdef __HD64570_H parity != PARITY_CRC16_PR0_CCITT && -#else - parity != PARITY_CRC32_PR1_CCITT && -#endif parity != PARITY_CRC16_PR1_CCITT) return -EINVAL; @@ -668,34 +565,30 @@ static int sca_attach(struct net_device *dev, unsigned short encoding, } - #ifdef DEBUG_RINGS static void sca_dump_rings(struct net_device *dev) { port_t *port = dev_to_port(dev); card_t *card = port_to_card(port); u16 cnt; -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) - u8 page; -#endif +#ifndef PAGE0_ALWAYS_MAPPED + u8 page = sca_get_page(card); -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) - page = sca_get_page(card); openwin(card, 0); #endif printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", - sca_ina(get_dmac_rx(port) + CDAL, card), - sca_ina(get_dmac_rx(port) + EDAL, card), + sca_inw(get_dmac_rx(port) + CDAL, card), + sca_inw(get_dmac_rx(port) + EDAL, card), sca_in(DSR_RX(phy_node(port)), card), port->rxin, - sca_in(DSR_RX(phy_node(port)), card) & DSR_DE?"":"in"); + sca_in(DSR_RX(phy_node(port)), card) & DSR_DE ? "" : "in"); for (cnt = 0; cnt < port_to_card(port)->rx_ring_buffers; cnt++) printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat))); printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " "last=%u %sactive", - sca_ina(get_dmac_tx(port) + CDAL, card), - sca_ina(get_dmac_tx(port) + EDAL, card), + sca_inw(get_dmac_tx(port) + CDAL, card), + sca_inw(get_dmac_tx(port) + EDAL, card), sca_in(DSR_TX(phy_node(port)), card), port->txin, port->txlast, sca_in(DSR_TX(phy_node(port)), card) & DSR_DE ? "" : "in"); @@ -703,12 +596,8 @@ static void sca_dump_rings(struct net_device *dev) printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat))); printk("\n"); - printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, " - "ST: %02x %02x %02x %02x" -#ifdef __HD64572_H - " %02x" -#endif - ", FST: %02x CST: %02x %02x\n", + printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x, ST: %02x %02x %02x %02x," + " FST: %02x CST: %02x %02x\n", sca_in(get_msci(port) + MD0, card), sca_in(get_msci(port) + MD1, card), sca_in(get_msci(port) + MD2, card), @@ -716,52 +605,33 @@ static void sca_dump_rings(struct net_device *dev) sca_in(get_msci(port) + ST1, card), sca_in(get_msci(port) + ST2, card), sca_in(get_msci(port) + ST3, card), -#ifdef __HD64572_H - sca_in(get_msci(port) + ST4, card), -#endif sca_in(get_msci(port) + FST, card), sca_in(get_msci(port) + CST0, card), sca_in(get_msci(port) + CST1, card)); -#ifdef __HD64572_H - printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card), - sca_inl(ISR0, card), sca_inl(ISR1, card)); -#else printk(KERN_DEBUG "ISR: %02x %02x %02x\n", sca_in(ISR0, card), sca_in(ISR1, card), sca_in(ISR2, card)); -#endif -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) +#ifndef PAGE0_ALWAYS_MAPPED openwin(card, page); /* Restore original page */ #endif } #endif /* DEBUG_RINGS */ - static int sca_xmit(struct sk_buff *skb, struct net_device *dev) { port_t *port = dev_to_port(dev); card_t *card = port_to_card(port); pkt_desc __iomem *desc; u32 buff, len; -#ifndef ALL_PAGES_ALWAYS_MAPPED u8 page; u32 maxlen; -#endif spin_lock_irq(&port->lock); desc = desc_address(port, port->txin + 1, 1); - if (readb(&desc->stat)) { /* allow 1 packet gap */ - /* should never happen - previous xmit should stop queue */ -#ifdef DEBUG_PKT - printk(KERN_DEBUG "%s: transmitter buffer full\n", dev->name); -#endif - netif_stop_queue(dev); - spin_unlock_irq(&port->lock); - return 1; /* request packet to be queued */ - } + BUG_ON(readb(&desc->stat)); /* previous xmit should stop queue */ #ifdef DEBUG_PKT printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len); @@ -771,7 +641,6 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) desc = desc_address(port, port->txin, 1); buff = buffer_offset(port, port->txin, 1); len = skb->len; -#ifndef ALL_PAGES_ALWAYS_MAPPED page = buff / winsize(card); buff = buff % winsize(card); maxlen = winsize(card) - buff; @@ -781,12 +650,10 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) memcpy_toio(winbase(card) + buff, skb->data, maxlen); openwin(card, page + 1); memcpy_toio(winbase(card), skb->data + maxlen, len - maxlen); - } - else -#endif + } else memcpy_toio(winbase(card) + buff, skb->data, len); -#if !defined(PAGE0_ALWAYS_MAPPED) && !defined(ALL_PAGES_ALWAYS_MAPPED) +#ifndef PAGE0_ALWAYS_MAPPED openwin(card, 0); /* select pkt_desc table page back */ #endif writew(len, &desc->len); @@ -794,7 +661,7 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) dev->trans_start = jiffies; port->txin = next_desc(port, port->txin, 1); - sca_outa(desc_offset(port, port->txin, 1), + sca_outw(desc_offset(port, port->txin, 1), get_dmac_tx(port) + EDAL, card); sca_out(DSR_DE, DSR_TX(phy_node(port)), card); /* Enable TX DMA */ @@ -810,40 +677,29 @@ static int sca_xmit(struct sk_buff *skb, struct net_device *dev) } - #ifdef NEED_DETECT_RAM -static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsize) +static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, + u32 ramsize) { /* Round RAM size to 32 bits, fill from end to start */ u32 i = ramsize &= ~3; - -#ifndef ALL_PAGES_ALWAYS_MAPPED u32 size = winsize(card); openwin(card, (i - 4) / size); /* select last window */ -#endif + do { i -= 4; -#ifndef ALL_PAGES_ALWAYS_MAPPED if ((i + 4) % size == 0) openwin(card, i / size); writel(i ^ 0x12345678, rambase + i % size); -#else - writel(i ^ 0x12345678, rambase + i); -#endif - }while (i > 0); + } while (i > 0); for (i = 0; i < ramsize ; i += 4) { -#ifndef ALL_PAGES_ALWAYS_MAPPED if (i % size == 0) openwin(card, i / size); if (readl(rambase + i % size) != (i ^ 0x12345678)) break; -#else - if (readl(rambase + i) != (i ^ 0x12345678)) - break; -#endif } return i; @@ -851,7 +707,6 @@ static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, u32 ramsi #endif /* NEED_DETECT_RAM */ - static void __devinit sca_init(card_t *card, int wait_states) { sca_out(wait_states, WCRL, card); /* Wait Control */ diff --git a/drivers/net/wan/hd64572.c b/drivers/net/wan/hd64572.c new file mode 100644 index 0000000000000000000000000000000000000000..08b3536944fe034544c74dc2470d7745393b89aa --- /dev/null +++ b/drivers/net/wan/hd64572.c @@ -0,0 +1,640 @@ +/* + * Hitachi (now Renesas) SCA-II HD64572 driver for Linux + * + * Copyright (C) 1998-2008 Krzysztof Halasa + * + * 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. + * + * Source of information: HD64572 SCA-II User's Manual + * + * We use the following SCA memory map: + * + * Packet buffer descriptor rings - starting from card->rambase: + * rx_ring_buffers * sizeof(pkt_desc) = logical channel #0 RX ring + * tx_ring_buffers * sizeof(pkt_desc) = logical channel #0 TX ring + * rx_ring_buffers * sizeof(pkt_desc) = logical channel #1 RX ring (if used) + * tx_ring_buffers * sizeof(pkt_desc) = logical channel #1 TX ring (if used) + * + * Packet data buffers - starting from card->rambase + buff_offset: + * rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers + * tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers + * rx_ring_buffers * HDLC_MAX_MRU = logical channel #0 RX buffers (if used) + * tx_ring_buffers * HDLC_MAX_MRU = logical channel #0 TX buffers (if used) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "hd64572.h" + +#define NAPI_WEIGHT 16 + +#define get_msci(port) (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) +#define get_dmac_rx(port) (port->chan ? DMAC1RX_OFFSET : DMAC0RX_OFFSET) +#define get_dmac_tx(port) (port->chan ? DMAC1TX_OFFSET : DMAC0TX_OFFSET) + +#define sca_in(reg, card) readb(card->scabase + (reg)) +#define sca_out(value, reg, card) writeb(value, card->scabase + (reg)) +#define sca_inw(reg, card) readw(card->scabase + (reg)) +#define sca_outw(value, reg, card) writew(value, card->scabase + (reg)) +#define sca_inl(reg, card) readl(card->scabase + (reg)) +#define sca_outl(value, reg, card) writel(value, card->scabase + (reg)) + +static int sca_poll(struct napi_struct *napi, int budget); + +static inline port_t* dev_to_port(struct net_device *dev) +{ + return dev_to_hdlc(dev)->priv; +} + +static inline void enable_intr(port_t *port) +{ + /* enable DMIB and MSCI RXINTA interrupts */ + sca_outl(sca_inl(IER0, port->card) | + (port->chan ? 0x08002200 : 0x00080022), IER0, port->card); +} + +static inline void disable_intr(port_t *port) +{ + sca_outl(sca_inl(IER0, port->card) & + (port->chan ? 0x00FF00FF : 0xFF00FF00), IER0, port->card); +} + +static inline u16 desc_abs_number(port_t *port, u16 desc, int transmit) +{ + u16 rx_buffs = port->card->rx_ring_buffers; + u16 tx_buffs = port->card->tx_ring_buffers; + + desc %= (transmit ? tx_buffs : rx_buffs); // called with "X + 1" etc. + return port->chan * (rx_buffs + tx_buffs) + transmit * rx_buffs + desc; +} + + +static inline u16 desc_offset(port_t *port, u16 desc, int transmit) +{ + /* Descriptor offset always fits in 16 bits */ + return desc_abs_number(port, desc, transmit) * sizeof(pkt_desc); +} + + +static inline pkt_desc __iomem *desc_address(port_t *port, u16 desc, + int transmit) +{ + return (pkt_desc __iomem *)(port->card->rambase + + desc_offset(port, desc, transmit)); +} + + +static inline u32 buffer_offset(port_t *port, u16 desc, int transmit) +{ + return port->card->buff_offset + + desc_abs_number(port, desc, transmit) * (u32)HDLC_MAX_MRU; +} + + +static inline void sca_set_carrier(port_t *port) +{ + if (!(sca_in(get_msci(port) + ST3, port->card) & ST3_DCD)) { +#ifdef DEBUG_LINK + printk(KERN_DEBUG "%s: sca_set_carrier on\n", + port->netdev.name); +#endif + netif_carrier_on(port->netdev); + } else { +#ifdef DEBUG_LINK + printk(KERN_DEBUG "%s: sca_set_carrier off\n", + port->netdev.name); +#endif + netif_carrier_off(port->netdev); + } +} + + +static void sca_init_port(port_t *port) +{ + card_t *card = port->card; + u16 dmac_rx = get_dmac_rx(port), dmac_tx = get_dmac_tx(port); + int transmit, i; + + port->rxin = 0; + port->txin = 0; + port->txlast = 0; + + for (transmit = 0; transmit < 2; transmit++) { + u16 buffs = transmit ? card->tx_ring_buffers + : card->rx_ring_buffers; + + for (i = 0; i < buffs; i++) { + pkt_desc __iomem *desc = desc_address(port, i, transmit); + u16 chain_off = desc_offset(port, i + 1, transmit); + u32 buff_off = buffer_offset(port, i, transmit); + + writel(chain_off, &desc->cp); + writel(buff_off, &desc->bp); + writew(0, &desc->len); + writeb(0, &desc->stat); + } + } + + /* DMA disable - to halt state */ + sca_out(0, DSR_RX(port->chan), card); + sca_out(0, DSR_TX(port->chan), card); + + /* software ABORT - to initial state */ + sca_out(DCR_ABORT, DCR_RX(port->chan), card); + sca_out(DCR_ABORT, DCR_TX(port->chan), card); + + /* current desc addr */ + sca_outl(desc_offset(port, 0, 0), dmac_rx + CDAL, card); + sca_outl(desc_offset(port, card->tx_ring_buffers - 1, 0), + dmac_rx + EDAL, card); + sca_outl(desc_offset(port, 0, 1), dmac_tx + CDAL, card); + sca_outl(desc_offset(port, 0, 1), dmac_tx + EDAL, card); + + /* clear frame end interrupt counter */ + sca_out(DCR_CLEAR_EOF, DCR_RX(port->chan), card); + sca_out(DCR_CLEAR_EOF, DCR_TX(port->chan), card); + + /* Receive */ + sca_outw(HDLC_MAX_MRU, dmac_rx + BFLL, card); /* set buffer length */ + sca_out(0x14, DMR_RX(port->chan), card); /* Chain mode, Multi-frame */ + sca_out(DIR_EOME, DIR_RX(port->chan), card); /* enable interrupts */ + sca_out(DSR_DE, DSR_RX(port->chan), card); /* DMA enable */ + + /* Transmit */ + sca_out(0x14, DMR_TX(port->chan), card); /* Chain mode, Multi-frame */ + sca_out(DIR_EOME, DIR_TX(port->chan), card); /* enable interrupts */ + + sca_set_carrier(port); + netif_napi_add(port->netdev, &port->napi, sca_poll, NAPI_WEIGHT); +} + + +/* MSCI interrupt service */ +static inline void sca_msci_intr(port_t *port) +{ + u16 msci = get_msci(port); + card_t* card = port->card; + + if (sca_in(msci + ST1, card) & ST1_CDCD) { + /* Reset MSCI CDCD status bit */ + sca_out(ST1_CDCD, msci + ST1, card); + sca_set_carrier(port); + } +} + + +static inline void sca_rx(card_t *card, port_t *port, pkt_desc __iomem *desc, + u16 rxin) +{ + struct net_device *dev = port->netdev; + struct sk_buff *skb; + u16 len; + u32 buff; + + len = readw(&desc->len); + skb = dev_alloc_skb(len); + if (!skb) { + dev->stats.rx_dropped++; + return; + } + + buff = buffer_offset(port, rxin, 0); + memcpy_fromio(skb->data, card->rambase + buff, len); + + skb_put(skb, len); +#ifdef DEBUG_PKT + printk(KERN_DEBUG "%s RX(%i):", dev->name, skb->len); + debug_frame(skb); +#endif + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + skb->protocol = hdlc_type_trans(skb, dev); + netif_receive_skb(skb); +} + + +/* Receive DMA service */ +static inline int sca_rx_done(port_t *port, int budget) +{ + struct net_device *dev = port->netdev; + u16 dmac = get_dmac_rx(port); + card_t *card = port->card; + u8 stat = sca_in(DSR_RX(port->chan), card); /* read DMA Status */ + int received = 0; + + /* Reset DSR status bits */ + sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, + DSR_RX(port->chan), card); + + if (stat & DSR_BOF) + /* Dropped one or more frames */ + dev->stats.rx_over_errors++; + + while (received < budget) { + u32 desc_off = desc_offset(port, port->rxin, 0); + pkt_desc __iomem *desc; + u32 cda = sca_inl(dmac + CDAL, card); + + if ((cda >= desc_off) && (cda < desc_off + sizeof(pkt_desc))) + break; /* No frame received */ + + desc = desc_address(port, port->rxin, 0); + stat = readb(&desc->stat); + if (!(stat & ST_RX_EOM)) + port->rxpart = 1; /* partial frame received */ + else if ((stat & ST_ERROR_MASK) || port->rxpart) { + dev->stats.rx_errors++; + if (stat & ST_RX_OVERRUN) + dev->stats.rx_fifo_errors++; + else if ((stat & (ST_RX_SHORT | ST_RX_ABORT | + ST_RX_RESBIT)) || port->rxpart) + dev->stats.rx_frame_errors++; + else if (stat & ST_RX_CRC) + dev->stats.rx_crc_errors++; + if (stat & ST_RX_EOM) + port->rxpart = 0; /* received last fragment */ + } else { + sca_rx(card, port, desc, port->rxin); + received++; + } + + /* Set new error descriptor address */ + sca_outl(desc_off, dmac + EDAL, card); + port->rxin = (port->rxin + 1) % card->rx_ring_buffers; + } + + /* make sure RX DMA is enabled */ + sca_out(DSR_DE, DSR_RX(port->chan), card); + return received; +} + + +/* Transmit DMA service */ +static inline void sca_tx_done(port_t *port) +{ + struct net_device *dev = port->netdev; + card_t* card = port->card; + u8 stat; + + spin_lock(&port->lock); + + stat = sca_in(DSR_TX(port->chan), card); /* read DMA Status */ + + /* Reset DSR status bits */ + sca_out((stat & (DSR_EOT | DSR_EOM | DSR_BOF | DSR_COF)) | DSR_DWE, + DSR_TX(port->chan), card); + + while (1) { + pkt_desc __iomem *desc = desc_address(port, port->txlast, 1); + u8 stat = readb(&desc->stat); + + if (!(stat & ST_TX_OWNRSHP)) + break; /* not yet transmitted */ + if (stat & ST_TX_UNDRRUN) { + dev->stats.tx_errors++; + dev->stats.tx_fifo_errors++; + } else { + dev->stats.tx_packets++; + dev->stats.tx_bytes += readw(&desc->len); + } + writeb(0, &desc->stat); /* Free descriptor */ + port->txlast = (port->txlast + 1) % card->tx_ring_buffers; + } + + netif_wake_queue(dev); + spin_unlock(&port->lock); +} + + +static int sca_poll(struct napi_struct *napi, int budget) +{ + port_t *port = container_of(napi, port_t, napi); + u32 isr0 = sca_inl(ISR0, port->card); + int received = 0; + + if (isr0 & (port->chan ? 0x08000000 : 0x00080000)) + sca_msci_intr(port); + + if (isr0 & (port->chan ? 0x00002000 : 0x00000020)) + sca_tx_done(port); + + if (isr0 & (port->chan ? 0x00000200 : 0x00000002)) + received = sca_rx_done(port, budget); + + if (received < budget) { + netif_rx_complete(napi); + enable_intr(port); + } + + return received; +} + +static irqreturn_t sca_intr(int irq, void *dev_id) +{ + card_t *card = dev_id; + u32 isr0 = sca_inl(ISR0, card); + int i, handled = 0; + + for (i = 0; i < 2; i++) { + port_t *port = get_port(card, i); + if (port && (isr0 & (i ? 0x08002200 : 0x00080022))) { + handled = 1; + disable_intr(port); + netif_rx_schedule(&port->napi); + } + } + + return IRQ_RETVAL(handled); +} + + +static void sca_set_port(port_t *port) +{ + card_t* card = port->card; + u16 msci = get_msci(port); + u8 md2 = sca_in(msci + MD2, card); + unsigned int tmc, br = 10, brv = 1024; + + + if (port->settings.clock_rate > 0) { + /* Try lower br for better accuracy*/ + do { + br--; + brv >>= 1; /* brv = 2^9 = 512 max in specs */ + + /* Baud Rate = CLOCK_BASE / TMC / 2^BR */ + tmc = CLOCK_BASE / brv / port->settings.clock_rate; + }while (br > 1 && tmc <= 128); + + if (tmc < 1) { + tmc = 1; + br = 0; /* For baud=CLOCK_BASE we use tmc=1 br=0 */ + brv = 1; + } else if (tmc > 255) + tmc = 256; /* tmc=0 means 256 - low baud rates */ + + port->settings.clock_rate = CLOCK_BASE / brv / tmc; + } else { + br = 9; /* Minimum clock rate */ + tmc = 256; /* 8bit = 0 */ + port->settings.clock_rate = CLOCK_BASE / (256 * 512); + } + + port->rxs = (port->rxs & ~CLK_BRG_MASK) | br; + port->txs = (port->txs & ~CLK_BRG_MASK) | br; + port->tmc = tmc; + + /* baud divisor - time constant*/ + sca_out(port->tmc, msci + TMCR, card); + sca_out(port->tmc, msci + TMCT, card); + + /* Set BRG bits */ + sca_out(port->rxs, msci + RXS, card); + sca_out(port->txs, msci + TXS, card); + + if (port->settings.loopback) + md2 |= MD2_LOOPBACK; + else + md2 &= ~MD2_LOOPBACK; + + sca_out(md2, msci + MD2, card); + +} + + +static void sca_open(struct net_device *dev) +{ + port_t *port = dev_to_port(dev); + card_t* card = port->card; + u16 msci = get_msci(port); + u8 md0, md2; + + switch(port->encoding) { + case ENCODING_NRZ: md2 = MD2_NRZ; break; + case ENCODING_NRZI: md2 = MD2_NRZI; break; + case ENCODING_FM_MARK: md2 = MD2_FM_MARK; break; + case ENCODING_FM_SPACE: md2 = MD2_FM_SPACE; break; + default: md2 = MD2_MANCHESTER; + } + + if (port->settings.loopback) + md2 |= MD2_LOOPBACK; + + switch(port->parity) { + case PARITY_CRC16_PR0: md0 = MD0_HDLC | MD0_CRC_16_0; break; + case PARITY_CRC16_PR1: md0 = MD0_HDLC | MD0_CRC_16; break; + case PARITY_CRC32_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU32; break; + case PARITY_CRC16_PR1_CCITT: md0 = MD0_HDLC | MD0_CRC_ITU; break; + default: md0 = MD0_HDLC | MD0_CRC_NONE; + } + + sca_out(CMD_RESET, msci + CMD, card); + sca_out(md0, msci + MD0, card); + sca_out(0x00, msci + MD1, card); /* no address field check */ + sca_out(md2, msci + MD2, card); + sca_out(0x7E, msci + IDL, card); /* flag character 0x7E */ + /* Skip the rest of underrun frame */ + sca_out(CTL_IDLE | CTL_URCT | CTL_URSKP, msci + CTL, card); + sca_out(0x0F, msci + RNR, card); /* +1=RX DMA activation condition */ + sca_out(0x3C, msci + TFS, card); /* +1 = TX start */ + sca_out(0x38, msci + TCR, card); /* =Critical TX DMA activ condition */ + sca_out(0x38, msci + TNR0, card); /* =TX DMA activation condition */ + sca_out(0x3F, msci + TNR1, card); /* +1=TX DMA deactivation condition*/ + +/* We're using the following interrupts: + - RXINTA (DCD changes only) + - DMIB (EOM - single frame transfer complete) +*/ + sca_outl(IE0_RXINTA | IE0_CDCD, msci + IE0, card); + + sca_out(port->tmc, msci + TMCR, card); + sca_out(port->tmc, msci + TMCT, card); + sca_out(port->rxs, msci + RXS, card); + sca_out(port->txs, msci + TXS, card); + sca_out(CMD_TX_ENABLE, msci + CMD, card); + sca_out(CMD_RX_ENABLE, msci + CMD, card); + + sca_set_carrier(port); + enable_intr(port); + napi_enable(&port->napi); + netif_start_queue(dev); +} + + +static void sca_close(struct net_device *dev) +{ + port_t *port = dev_to_port(dev); + + /* reset channel */ + sca_out(CMD_RESET, get_msci(port) + CMD, port->card); + disable_intr(port); + napi_disable(&port->napi); + netif_stop_queue(dev); +} + + +static int sca_attach(struct net_device *dev, unsigned short encoding, + unsigned short parity) +{ + if (encoding != ENCODING_NRZ && + encoding != ENCODING_NRZI && + encoding != ENCODING_FM_MARK && + encoding != ENCODING_FM_SPACE && + encoding != ENCODING_MANCHESTER) + return -EINVAL; + + if (parity != PARITY_NONE && + parity != PARITY_CRC16_PR0 && + parity != PARITY_CRC16_PR1 && + parity != PARITY_CRC32_PR1_CCITT && + parity != PARITY_CRC16_PR1_CCITT) + return -EINVAL; + + dev_to_port(dev)->encoding = encoding; + dev_to_port(dev)->parity = parity; + return 0; +} + + +#ifdef DEBUG_RINGS +static void sca_dump_rings(struct net_device *dev) +{ + port_t *port = dev_to_port(dev); + card_t *card = port->card; + u16 cnt; + + printk(KERN_DEBUG "RX ring: CDA=%u EDA=%u DSR=%02X in=%u %sactive", + sca_inl(get_dmac_rx(port) + CDAL, card), + sca_inl(get_dmac_rx(port) + EDAL, card), + sca_in(DSR_RX(port->chan), card), port->rxin, + sca_in(DSR_RX(port->chan), card) & DSR_DE ? "" : "in"); + for (cnt = 0; cnt < port->card->rx_ring_buffers; cnt++) + printk(" %02X", readb(&(desc_address(port, cnt, 0)->stat))); + + printk("\n" KERN_DEBUG "TX ring: CDA=%u EDA=%u DSR=%02X in=%u " + "last=%u %sactive", + sca_inl(get_dmac_tx(port) + CDAL, card), + sca_inl(get_dmac_tx(port) + EDAL, card), + sca_in(DSR_TX(port->chan), card), port->txin, port->txlast, + sca_in(DSR_TX(port->chan), card) & DSR_DE ? "" : "in"); + + for (cnt = 0; cnt < port->card->tx_ring_buffers; cnt++) + printk(" %02X", readb(&(desc_address(port, cnt, 1)->stat))); + printk("\n"); + + printk(KERN_DEBUG "MSCI: MD: %02x %02x %02x," + " ST: %02x %02x %02x %02x %02x, FST: %02x CST: %02x %02x\n", + sca_in(get_msci(port) + MD0, card), + sca_in(get_msci(port) + MD1, card), + sca_in(get_msci(port) + MD2, card), + sca_in(get_msci(port) + ST0, card), + sca_in(get_msci(port) + ST1, card), + sca_in(get_msci(port) + ST2, card), + sca_in(get_msci(port) + ST3, card), + sca_in(get_msci(port) + ST4, card), + sca_in(get_msci(port) + FST, card), + sca_in(get_msci(port) + CST0, card), + sca_in(get_msci(port) + CST1, card)); + + printk(KERN_DEBUG "ILAR: %02x ISR: %08x %08x\n", sca_in(ILAR, card), + sca_inl(ISR0, card), sca_inl(ISR1, card)); +} +#endif /* DEBUG_RINGS */ + + +static int sca_xmit(struct sk_buff *skb, struct net_device *dev) +{ + port_t *port = dev_to_port(dev); + card_t *card = port->card; + pkt_desc __iomem *desc; + u32 buff, len; + + spin_lock_irq(&port->lock); + + desc = desc_address(port, port->txin + 1, 1); + BUG_ON(readb(&desc->stat)); /* previous xmit should stop queue */ + +#ifdef DEBUG_PKT + printk(KERN_DEBUG "%s TX(%i):", dev->name, skb->len); + debug_frame(skb); +#endif + + desc = desc_address(port, port->txin, 1); + buff = buffer_offset(port, port->txin, 1); + len = skb->len; + memcpy_toio(card->rambase + buff, skb->data, len); + + writew(len, &desc->len); + writeb(ST_TX_EOM, &desc->stat); + dev->trans_start = jiffies; + + port->txin = (port->txin + 1) % card->tx_ring_buffers; + sca_outl(desc_offset(port, port->txin, 1), + get_dmac_tx(port) + EDAL, card); + + sca_out(DSR_DE, DSR_TX(port->chan), card); /* Enable TX DMA */ + + desc = desc_address(port, port->txin + 1, 1); + if (readb(&desc->stat)) /* allow 1 packet gap */ + netif_stop_queue(dev); + + spin_unlock_irq(&port->lock); + + dev_kfree_skb(skb); + return 0; +} + + +static u32 __devinit sca_detect_ram(card_t *card, u8 __iomem *rambase, + u32 ramsize) +{ + /* Round RAM size to 32 bits, fill from end to start */ + u32 i = ramsize &= ~3; + + do { + i -= 4; + writel(i ^ 0x12345678, rambase + i); + } while (i > 0); + + for (i = 0; i < ramsize ; i += 4) { + if (readl(rambase + i) != (i ^ 0x12345678)) + break; + } + + return i; +} + + +static void __devinit sca_init(card_t *card, int wait_states) +{ + sca_out(wait_states, WCRL, card); /* Wait Control */ + sca_out(wait_states, WCRM, card); + sca_out(wait_states, WCRH, card); + + sca_out(0, DMER, card); /* DMA Master disable */ + sca_out(0x03, PCR, card); /* DMA priority */ + sca_out(0, DSR_RX(0), card); /* DMA disable - to halt state */ + sca_out(0, DSR_TX(0), card); + sca_out(0, DSR_RX(1), card); + sca_out(0, DSR_TX(1), card); + sca_out(DMER_DME, DMER, card); /* DMA Master enable */ +} diff --git a/drivers/net/wan/hdlc_fr.c b/drivers/net/wan/hdlc_fr.c index d3d5055741ad3f181b4fb79bc9cb0099ca5691a1..f1ddd7c3459cdfeeccc1884de43e80e0fb189a9c 100644 --- a/drivers/net/wan/hdlc_fr.c +++ b/drivers/net/wan/hdlc_fr.c @@ -342,7 +342,7 @@ static int fr_hard_header(struct sk_buff **skb_p, u16 dlci) static int pvc_open(struct net_device *dev) { - pvc_device *pvc = dev->priv; + pvc_device *pvc = dev->ml_priv; if ((pvc->frad->flags & IFF_UP) == 0) return -EIO; /* Frad must be UP in order to activate PVC */ @@ -362,7 +362,7 @@ static int pvc_open(struct net_device *dev) static int pvc_close(struct net_device *dev) { - pvc_device *pvc = dev->priv; + pvc_device *pvc = dev->ml_priv; if (--pvc->open_count == 0) { hdlc_device *hdlc = dev_to_hdlc(pvc->frad); @@ -381,7 +381,7 @@ static int pvc_close(struct net_device *dev) static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - pvc_device *pvc = dev->priv; + pvc_device *pvc = dev->ml_priv; fr_proto_pvc_info info; if (ifr->ifr_settings.type == IF_GET_PROTO) { @@ -409,7 +409,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) static int pvc_xmit(struct sk_buff *skb, struct net_device *dev) { - pvc_device *pvc = dev->priv; + pvc_device *pvc = dev->ml_priv; if (pvc->state.active) { if (dev->type == ARPHRD_ETHER) { @@ -1111,7 +1111,7 @@ static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type) dev->change_mtu = pvc_change_mtu; dev->mtu = HDLC_MAX_MTU; dev->tx_queue_len = 0; - dev->priv = pvc; + dev->ml_priv = pvc; result = dev_alloc_name(dev, dev->name); if (result < 0) { diff --git a/drivers/net/wan/hdlc_ppp.c b/drivers/net/wan/hdlc_ppp.c index 4efe9e6d32d5fb5b37b7397a77d4898e3e7db4f4..57fe714c1c7f63376e1694fc84d2f73788e50c2a 100644 --- a/drivers/net/wan/hdlc_ppp.c +++ b/drivers/net/wan/hdlc_ppp.c @@ -2,7 +2,7 @@ * Generic HDLC support routines for Linux * Point-to-point protocol support * - * Copyright (C) 1999 - 2006 Krzysztof Halasa + * Copyright (C) 1999 - 2008 Krzysztof Halasa * * 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 @@ -18,87 +18,633 @@ #include #include #include -#include #include #include -#include +#include + +#define DEBUG_CP 0 /* also bytes# to dump */ +#define DEBUG_STATE 0 +#define DEBUG_HARD_HEADER 0 + +#define HDLC_ADDR_ALLSTATIONS 0xFF +#define HDLC_CTRL_UI 0x03 + +#define PID_LCP 0xC021 +#define PID_IP 0x0021 +#define PID_IPCP 0x8021 +#define PID_IPV6 0x0057 +#define PID_IPV6CP 0x8057 + +enum {IDX_LCP = 0, IDX_IPCP, IDX_IPV6CP, IDX_COUNT}; +enum {CP_CONF_REQ = 1, CP_CONF_ACK, CP_CONF_NAK, CP_CONF_REJ, CP_TERM_REQ, + CP_TERM_ACK, CP_CODE_REJ, LCP_PROTO_REJ, LCP_ECHO_REQ, LCP_ECHO_REPLY, + LCP_DISC_REQ, CP_CODES}; +#if DEBUG_CP +static const char *const code_names[CP_CODES] = { + "0", "ConfReq", "ConfAck", "ConfNak", "ConfRej", "TermReq", + "TermAck", "CodeRej", "ProtoRej", "EchoReq", "EchoReply", "Discard" +}; +static char debug_buffer[64 + 3 * DEBUG_CP]; +#endif + +enum {LCP_OPTION_MRU = 1, LCP_OPTION_ACCM, LCP_OPTION_MAGIC = 5}; + +struct hdlc_header { + u8 address; + u8 control; + __be16 protocol; +}; + +struct cp_header { + u8 code; + u8 id; + __be16 len; +}; + -struct ppp_state { - struct ppp_device pppdev; - struct ppp_device *syncppp_ptr; - int (*old_change_mtu)(struct net_device *dev, int new_mtu); +struct proto { + struct net_device *dev; + struct timer_list timer; + unsigned long timeout; + u16 pid; /* protocol ID */ + u8 state; + u8 cr_id; /* ID of last Configuration-Request */ + u8 restart_counter; }; +struct ppp { + struct proto protos[IDX_COUNT]; + spinlock_t lock; + unsigned long last_pong; + unsigned int req_timeout, cr_retries, term_retries; + unsigned int keepalive_interval, keepalive_timeout; + u8 seq; /* local sequence number for requests */ + u8 echo_id; /* ID of last Echo-Request (LCP) */ +}; + +enum {CLOSED = 0, STOPPED, STOPPING, REQ_SENT, ACK_RECV, ACK_SENT, OPENED, + STATES, STATE_MASK = 0xF}; +enum {START = 0, STOP, TO_GOOD, TO_BAD, RCR_GOOD, RCR_BAD, RCA, RCN, RTR, RTA, + RUC, RXJ_GOOD, RXJ_BAD, EVENTS}; +enum {INV = 0x10, IRC = 0x20, ZRC = 0x40, SCR = 0x80, SCA = 0x100, + SCN = 0x200, STR = 0x400, STA = 0x800, SCJ = 0x1000}; + +#if DEBUG_STATE +static const char *const state_names[STATES] = { + "Closed", "Stopped", "Stopping", "ReqSent", "AckRecv", "AckSent", + "Opened" +}; +static const char *const event_names[EVENTS] = { + "Start", "Stop", "TO+", "TO-", "RCR+", "RCR-", "RCA", "RCN", + "RTR", "RTA", "RUC", "RXJ+", "RXJ-" +}; +#endif + +static struct sk_buff_head tx_queue; /* used when holding the spin lock */ + static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr); +static inline struct ppp* get_ppp(struct net_device *dev) +{ + return (struct ppp *)dev_to_hdlc(dev)->state; +} -static inline struct ppp_state* state(hdlc_device *hdlc) +static inline struct proto* get_proto(struct net_device *dev, u16 pid) { - return(struct ppp_state *)(hdlc->state); + struct ppp *ppp = get_ppp(dev); + + switch (pid) { + case PID_LCP: + return &ppp->protos[IDX_LCP]; + case PID_IPCP: + return &ppp->protos[IDX_IPCP]; + case PID_IPV6CP: + return &ppp->protos[IDX_IPV6CP]; + default: + return NULL; + } } +static inline const char* proto_name(u16 pid) +{ + switch (pid) { + case PID_LCP: + return "LCP"; + case PID_IPCP: + return "IPCP"; + case PID_IPV6CP: + return "IPV6CP"; + default: + return NULL; + } +} -static int ppp_open(struct net_device *dev) +static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev) { - hdlc_device *hdlc = dev_to_hdlc(dev); - int (*old_ioctl)(struct net_device *, struct ifreq *, int); - int result; + struct hdlc_header *data = (struct hdlc_header*)skb->data; + + if (skb->len < sizeof(struct hdlc_header)) + return htons(ETH_P_HDLC); + if (data->address != HDLC_ADDR_ALLSTATIONS || + data->control != HDLC_CTRL_UI) + return htons(ETH_P_HDLC); + + switch (data->protocol) { + case __constant_htons(PID_IP): + skb_pull(skb, sizeof(struct hdlc_header)); + return htons(ETH_P_IP); - dev->ml_priv = &state(hdlc)->syncppp_ptr; - state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev; - state(hdlc)->pppdev.dev = dev; + case __constant_htons(PID_IPV6): + skb_pull(skb, sizeof(struct hdlc_header)); + return htons(ETH_P_IPV6); - old_ioctl = dev->do_ioctl; - state(hdlc)->old_change_mtu = dev->change_mtu; - sppp_attach(&state(hdlc)->pppdev); - /* sppp_attach nukes them. We don't need syncppp's ioctl */ - dev->do_ioctl = old_ioctl; - state(hdlc)->pppdev.sppp.pp_flags &= ~PP_CISCO; - dev->type = ARPHRD_PPP; - result = sppp_open(dev); - if (result) { - sppp_detach(dev); - return result; + default: + return htons(ETH_P_HDLC); } +} - return 0; + +static int ppp_hard_header(struct sk_buff *skb, struct net_device *dev, + u16 type, const void *daddr, const void *saddr, + unsigned int len) +{ + struct hdlc_header *data; +#if DEBUG_HARD_HEADER + printk(KERN_DEBUG "%s: ppp_hard_header() called\n", dev->name); +#endif + + skb_push(skb, sizeof(struct hdlc_header)); + data = (struct hdlc_header*)skb->data; + + data->address = HDLC_ADDR_ALLSTATIONS; + data->control = HDLC_CTRL_UI; + switch (type) { + case ETH_P_IP: + data->protocol = htons(PID_IP); + break; + case ETH_P_IPV6: + data->protocol = htons(PID_IPV6); + break; + case PID_LCP: + case PID_IPCP: + case PID_IPV6CP: + data->protocol = htons(type); + break; + default: /* unknown protocol */ + data->protocol = 0; + } + return sizeof(struct hdlc_header); } +static void ppp_tx_flush(void) +{ + struct sk_buff *skb; + while ((skb = skb_dequeue(&tx_queue)) != NULL) + dev_queue_xmit(skb); +} -static void ppp_close(struct net_device *dev) +static void ppp_tx_cp(struct net_device *dev, u16 pid, u8 code, + u8 id, unsigned int len, const void *data) { - hdlc_device *hdlc = dev_to_hdlc(dev); + struct sk_buff *skb; + struct cp_header *cp; + unsigned int magic_len = 0; + static u32 magic; + +#if DEBUG_CP + int i; + char *ptr; +#endif + + if (pid == PID_LCP && (code == LCP_ECHO_REQ || code == LCP_ECHO_REPLY)) + magic_len = sizeof(magic); + + skb = dev_alloc_skb(sizeof(struct hdlc_header) + + sizeof(struct cp_header) + magic_len + len); + if (!skb) { + printk(KERN_WARNING "%s: out of memory in ppp_tx_cp()\n", + dev->name); + return; + } + skb_reserve(skb, sizeof(struct hdlc_header)); + + cp = (struct cp_header *)skb_put(skb, sizeof(struct cp_header)); + cp->code = code; + cp->id = id; + cp->len = htons(sizeof(struct cp_header) + magic_len + len); + + if (magic_len) + memcpy(skb_put(skb, magic_len), &magic, magic_len); + if (len) + memcpy(skb_put(skb, len), data, len); + +#if DEBUG_CP + BUG_ON(code >= CP_CODES); + ptr = debug_buffer; + *ptr = '\x0'; + for (i = 0; i < min_t(unsigned int, magic_len + len, DEBUG_CP); i++) { + sprintf(ptr, " %02X", skb->data[sizeof(struct cp_header) + i]); + ptr += strlen(ptr); + } + printk(KERN_DEBUG "%s: TX %s [%s id 0x%X]%s\n", dev->name, + proto_name(pid), code_names[code], id, debug_buffer); +#endif - sppp_close(dev); - sppp_detach(dev); + ppp_hard_header(skb, dev, pid, NULL, NULL, 0); - dev->change_mtu = state(hdlc)->old_change_mtu; - dev->mtu = HDLC_MAX_MTU; - dev->hard_header_len = 16; + skb->priority = TC_PRIO_CONTROL; + skb->dev = dev; + skb_reset_network_header(skb); + skb_queue_tail(&tx_queue, skb); } +/* State transition table (compare STD-51) + Events Actions + TO+ = Timeout with counter > 0 irc = Initialize-Restart-Count + TO- = Timeout with counter expired zrc = Zero-Restart-Count + + RCR+ = Receive-Configure-Request (Good) scr = Send-Configure-Request + RCR- = Receive-Configure-Request (Bad) + RCA = Receive-Configure-Ack sca = Send-Configure-Ack + RCN = Receive-Configure-Nak/Rej scn = Send-Configure-Nak/Rej + + RTR = Receive-Terminate-Request str = Send-Terminate-Request + RTA = Receive-Terminate-Ack sta = Send-Terminate-Ack + + RUC = Receive-Unknown-Code scj = Send-Code-Reject + RXJ+ = Receive-Code-Reject (permitted) + or Receive-Protocol-Reject + RXJ- = Receive-Code-Reject (catastrophic) + or Receive-Protocol-Reject +*/ +static int cp_table[EVENTS][STATES] = { + /* CLOSED STOPPED STOPPING REQ_SENT ACK_RECV ACK_SENT OPENED + 0 1 2 3 4 5 6 */ + {IRC|SCR|3, INV , INV , INV , INV , INV , INV }, /* START */ + { INV , 0 , 0 , 0 , 0 , 0 , 0 }, /* STOP */ + { INV , INV ,STR|2, SCR|3 ,SCR|3, SCR|5 , INV }, /* TO+ */ + { INV , INV , 1 , 1 , 1 , 1 , INV }, /* TO- */ + { STA|0 ,IRC|SCR|SCA|5, 2 , SCA|5 ,SCA|6, SCA|5 ,SCR|SCA|5}, /* RCR+ */ + { STA|0 ,IRC|SCR|SCN|3, 2 , SCN|3 ,SCN|4, SCN|3 ,SCR|SCN|3}, /* RCR- */ + { STA|0 , STA|1 , 2 , IRC|4 ,SCR|3, 6 , SCR|3 }, /* RCA */ + { STA|0 , STA|1 , 2 ,IRC|SCR|3,SCR|3,IRC|SCR|5, SCR|3 }, /* RCN */ + { STA|0 , STA|1 ,STA|2, STA|3 ,STA|3, STA|3 ,ZRC|STA|2}, /* RTR */ + { 0 , 1 , 1 , 3 , 3 , 5 , SCR|3 }, /* RTA */ + { SCJ|0 , SCJ|1 ,SCJ|2, SCJ|3 ,SCJ|4, SCJ|5 , SCJ|6 }, /* RUC */ + { 0 , 1 , 2 , 3 , 3 , 5 , 6 }, /* RXJ+ */ + { 0 , 1 , 1 , 1 , 1 , 1 ,IRC|STR|2}, /* RXJ- */ +}; + -static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev) +/* SCA: RCR+ must supply id, len and data + SCN: RCR- must supply code, id, len and data + STA: RTR must supply id + SCJ: RUC must supply CP packet len and data */ +static void ppp_cp_event(struct net_device *dev, u16 pid, u16 event, u8 code, + u8 id, unsigned int len, const void *data) { - return __constant_htons(ETH_P_WAN_PPP); + int old_state, action; + struct ppp *ppp = get_ppp(dev); + struct proto *proto = get_proto(dev, pid); + + old_state = proto->state; + BUG_ON(old_state >= STATES); + BUG_ON(event >= EVENTS); + +#if DEBUG_STATE + printk(KERN_DEBUG "%s: %s ppp_cp_event(%s) %s ...\n", dev->name, + proto_name(pid), event_names[event], state_names[proto->state]); +#endif + + action = cp_table[event][old_state]; + + proto->state = action & STATE_MASK; + if (action & (SCR | STR)) /* set Configure-Req/Terminate-Req timer */ + mod_timer(&proto->timer, proto->timeout = + jiffies + ppp->req_timeout * HZ); + if (action & ZRC) + proto->restart_counter = 0; + if (action & IRC) + proto->restart_counter = (proto->state == STOPPING) ? + ppp->term_retries : ppp->cr_retries; + + if (action & SCR) /* send Configure-Request */ + ppp_tx_cp(dev, pid, CP_CONF_REQ, proto->cr_id = ++ppp->seq, + 0, NULL); + if (action & SCA) /* send Configure-Ack */ + ppp_tx_cp(dev, pid, CP_CONF_ACK, id, len, data); + if (action & SCN) /* send Configure-Nak/Reject */ + ppp_tx_cp(dev, pid, code, id, len, data); + if (action & STR) /* send Terminate-Request */ + ppp_tx_cp(dev, pid, CP_TERM_REQ, ++ppp->seq, 0, NULL); + if (action & STA) /* send Terminate-Ack */ + ppp_tx_cp(dev, pid, CP_TERM_ACK, id, 0, NULL); + if (action & SCJ) /* send Code-Reject */ + ppp_tx_cp(dev, pid, CP_CODE_REJ, ++ppp->seq, len, data); + + if (old_state != OPENED && proto->state == OPENED) { + printk(KERN_INFO "%s: %s up\n", dev->name, proto_name(pid)); + if (pid == PID_LCP) { + netif_dormant_off(dev); + ppp_cp_event(dev, PID_IPCP, START, 0, 0, 0, NULL); + ppp_cp_event(dev, PID_IPV6CP, START, 0, 0, 0, NULL); + ppp->last_pong = jiffies; + mod_timer(&proto->timer, proto->timeout = + jiffies + ppp->keepalive_interval * HZ); + } + } + if (old_state == OPENED && proto->state != OPENED) { + printk(KERN_INFO "%s: %s down\n", dev->name, proto_name(pid)); + if (pid == PID_LCP) { + netif_dormant_on(dev); + ppp_cp_event(dev, PID_IPCP, STOP, 0, 0, 0, NULL); + ppp_cp_event(dev, PID_IPV6CP, STOP, 0, 0, 0, NULL); + } + } + if (old_state != CLOSED && proto->state == CLOSED) + del_timer(&proto->timer); + +#if DEBUG_STATE + printk(KERN_DEBUG "%s: %s ppp_cp_event(%s) ... %s\n", dev->name, + proto_name(pid), event_names[event], state_names[proto->state]); +#endif +} + + +static void ppp_cp_parse_cr(struct net_device *dev, u16 pid, u8 id, + unsigned int req_len, const u8 *data) +{ + static u8 const valid_accm[6] = { LCP_OPTION_ACCM, 6, 0, 0, 0, 0 }; + const u8 *opt; + u8 *out; + unsigned int len = req_len, nak_len = 0, rej_len = 0; + + if (!(out = kmalloc(len, GFP_ATOMIC))) { + dev->stats.rx_dropped++; + return; /* out of memory, ignore CR packet */ + } + + for (opt = data; len; len -= opt[1], opt += opt[1]) { + if (len < 2 || len < opt[1]) { + dev->stats.rx_errors++; + return; /* bad packet, drop silently */ + } + + if (pid == PID_LCP) + switch (opt[0]) { + case LCP_OPTION_MRU: + continue; /* MRU always OK and > 1500 bytes? */ + + case LCP_OPTION_ACCM: /* async control character map */ + if (!memcmp(opt, valid_accm, + sizeof(valid_accm))) + continue; + if (!rej_len) { /* NAK it */ + memcpy(out + nak_len, valid_accm, + sizeof(valid_accm)); + nak_len += sizeof(valid_accm); + continue; + } + break; + case LCP_OPTION_MAGIC: + if (opt[1] != 6 || (!opt[2] && !opt[3] && + !opt[4] && !opt[5])) + break; /* reject invalid magic number */ + continue; + } + /* reject this option */ + memcpy(out + rej_len, opt, opt[1]); + rej_len += opt[1]; + } + + if (rej_len) + ppp_cp_event(dev, pid, RCR_BAD, CP_CONF_REJ, id, rej_len, out); + else if (nak_len) + ppp_cp_event(dev, pid, RCR_BAD, CP_CONF_NAK, id, nak_len, out); + else + ppp_cp_event(dev, pid, RCR_GOOD, CP_CONF_ACK, id, req_len, data); + + kfree(out); +} + +static int ppp_rx(struct sk_buff *skb) +{ + struct hdlc_header *hdr = (struct hdlc_header*)skb->data; + struct net_device *dev = skb->dev; + struct ppp *ppp = get_ppp(dev); + struct proto *proto; + struct cp_header *cp; + unsigned long flags; + unsigned int len; + u16 pid; +#if DEBUG_CP + int i; + char *ptr; +#endif + + spin_lock_irqsave(&ppp->lock, flags); + /* Check HDLC header */ + if (skb->len < sizeof(struct hdlc_header)) + goto rx_error; + cp = (struct cp_header*)skb_pull(skb, sizeof(struct hdlc_header)); + if (hdr->address != HDLC_ADDR_ALLSTATIONS || + hdr->control != HDLC_CTRL_UI) + goto rx_error; + + pid = ntohs(hdr->protocol); + proto = get_proto(dev, pid); + if (!proto) { + if (ppp->protos[IDX_LCP].state == OPENED) + ppp_tx_cp(dev, PID_LCP, LCP_PROTO_REJ, + ++ppp->seq, skb->len + 2, &hdr->protocol); + goto rx_error; + } + + len = ntohs(cp->len); + if (len < sizeof(struct cp_header) /* no complete CP header? */ || + skb->len < len /* truncated packet? */) + goto rx_error; + skb_pull(skb, sizeof(struct cp_header)); + len -= sizeof(struct cp_header); + + /* HDLC and CP headers stripped from skb */ +#if DEBUG_CP + if (cp->code < CP_CODES) + sprintf(debug_buffer, "[%s id 0x%X]", code_names[cp->code], + cp->id); + else + sprintf(debug_buffer, "[code %u id 0x%X]", cp->code, cp->id); + ptr = debug_buffer + strlen(debug_buffer); + for (i = 0; i < min_t(unsigned int, len, DEBUG_CP); i++) { + sprintf(ptr, " %02X", skb->data[i]); + ptr += strlen(ptr); + } + printk(KERN_DEBUG "%s: RX %s %s\n", dev->name, proto_name(pid), + debug_buffer); +#endif + + /* LCP only */ + if (pid == PID_LCP) + switch (cp->code) { + case LCP_PROTO_REJ: + pid = ntohs(*(__be16*)skb->data); + if (pid == PID_LCP || pid == PID_IPCP || + pid == PID_IPV6CP) + ppp_cp_event(dev, pid, RXJ_BAD, 0, 0, + 0, NULL); + goto out; + + case LCP_ECHO_REQ: /* send Echo-Reply */ + if (len >= 4 && proto->state == OPENED) + ppp_tx_cp(dev, PID_LCP, LCP_ECHO_REPLY, + cp->id, len - 4, skb->data + 4); + goto out; + + case LCP_ECHO_REPLY: + if (cp->id == ppp->echo_id) + ppp->last_pong = jiffies; + goto out; + + case LCP_DISC_REQ: /* discard */ + goto out; + } + + /* LCP, IPCP and IPV6CP */ + switch (cp->code) { + case CP_CONF_REQ: + ppp_cp_parse_cr(dev, pid, cp->id, len, skb->data); + goto out; + + case CP_CONF_ACK: + if (cp->id == proto->cr_id) + ppp_cp_event(dev, pid, RCA, 0, 0, 0, NULL); + goto out; + + case CP_CONF_REJ: + case CP_CONF_NAK: + if (cp->id == proto->cr_id) + ppp_cp_event(dev, pid, RCN, 0, 0, 0, NULL); + goto out; + + case CP_TERM_REQ: + ppp_cp_event(dev, pid, RTR, 0, cp->id, 0, NULL); + goto out; + + case CP_TERM_ACK: + ppp_cp_event(dev, pid, RTA, 0, 0, 0, NULL); + goto out; + + case CP_CODE_REJ: + ppp_cp_event(dev, pid, RXJ_BAD, 0, 0, 0, NULL); + goto out; + + default: + len += sizeof(struct cp_header); + if (len > dev->mtu) + len = dev->mtu; + ppp_cp_event(dev, pid, RUC, 0, 0, len, cp); + goto out; + } + goto out; + +rx_error: + dev->stats.rx_errors++; +out: + spin_unlock_irqrestore(&ppp->lock, flags); + dev_kfree_skb_any(skb); + ppp_tx_flush(); + return NET_RX_DROP; } +static void ppp_timer(unsigned long arg) +{ + struct proto *proto = (struct proto *)arg; + struct ppp *ppp = get_ppp(proto->dev); + unsigned long flags; + + spin_lock_irqsave(&ppp->lock, flags); + switch (proto->state) { + case STOPPING: + case REQ_SENT: + case ACK_RECV: + case ACK_SENT: + if (proto->restart_counter) { + ppp_cp_event(proto->dev, proto->pid, TO_GOOD, 0, 0, + 0, NULL); + proto->restart_counter--; + } else + ppp_cp_event(proto->dev, proto->pid, TO_BAD, 0, 0, + 0, NULL); + break; + + case OPENED: + if (proto->pid != PID_LCP) + break; + if (time_after(jiffies, ppp->last_pong + + ppp->keepalive_timeout * HZ)) { + printk(KERN_INFO "%s: Link down\n", proto->dev->name); + ppp_cp_event(proto->dev, PID_LCP, STOP, 0, 0, 0, NULL); + ppp_cp_event(proto->dev, PID_LCP, START, 0, 0, 0, NULL); + } else { /* send keep-alive packet */ + ppp->echo_id = ++ppp->seq; + ppp_tx_cp(proto->dev, PID_LCP, LCP_ECHO_REQ, + ppp->echo_id, 0, NULL); + proto->timer.expires = jiffies + + ppp->keepalive_interval * HZ; + add_timer(&proto->timer); + } + break; + } + spin_unlock_irqrestore(&ppp->lock, flags); + ppp_tx_flush(); +} + + +static void ppp_start(struct net_device *dev) +{ + struct ppp *ppp = get_ppp(dev); + int i; + + for (i = 0; i < IDX_COUNT; i++) { + struct proto *proto = &ppp->protos[i]; + proto->dev = dev; + init_timer(&proto->timer); + proto->timer.function = ppp_timer; + proto->timer.data = (unsigned long)proto; + proto->state = CLOSED; + } + ppp->protos[IDX_LCP].pid = PID_LCP; + ppp->protos[IDX_IPCP].pid = PID_IPCP; + ppp->protos[IDX_IPV6CP].pid = PID_IPV6CP; + + ppp_cp_event(dev, PID_LCP, START, 0, 0, 0, NULL); +} + +static void ppp_stop(struct net_device *dev) +{ + ppp_cp_event(dev, PID_LCP, STOP, 0, 0, 0, NULL); +} static struct hdlc_proto proto = { - .open = ppp_open, - .close = ppp_close, + .start = ppp_start, + .stop = ppp_stop, .type_trans = ppp_type_trans, .ioctl = ppp_ioctl, + .netif_rx = ppp_rx, .module = THIS_MODULE, }; +static const struct header_ops ppp_header_ops = { + .create = ppp_hard_header, +}; static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr) { hdlc_device *hdlc = dev_to_hdlc(dev); + struct ppp *ppp; int result; switch (ifr->ifr_settings.type) { @@ -109,25 +655,35 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr) return 0; /* return protocol only, no settable parameters */ case IF_PROTO_PPP: - if(!capable(CAP_NET_ADMIN)) + if (!capable(CAP_NET_ADMIN)) return -EPERM; - if(dev->flags & IFF_UP) + if (dev->flags & IFF_UP) return -EBUSY; /* no settable parameters */ - result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); + result = hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT); if (result) return result; - result = attach_hdlc_protocol(dev, &proto, - sizeof(struct ppp_state)); + result = attach_hdlc_protocol(dev, &proto, sizeof(struct ppp)); if (result) return result; + + ppp = get_ppp(dev); + spin_lock_init(&ppp->lock); + ppp->req_timeout = 2; + ppp->cr_retries = 10; + ppp->term_retries = 2; + ppp->keepalive_interval = 10; + ppp->keepalive_timeout = 60; + dev->hard_start_xmit = hdlc->xmit; + dev->hard_header_len = sizeof(struct hdlc_header); + dev->header_ops = &ppp_header_ops; dev->type = ARPHRD_PPP; - netif_dormant_off(dev); + netif_dormant_on(dev); return 0; } @@ -137,12 +693,11 @@ static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr) static int __init mod_init(void) { + skb_queue_head_init(&tx_queue); register_hdlc_protocol(&proto); return 0; } - - static void __exit mod_exit(void) { unregister_hdlc_protocol(&proto); diff --git a/drivers/net/wan/hostess_sv11.c b/drivers/net/wan/hostess_sv11.c index e299313f828a74e20aee499e39739d1c79eef0fd..af54f0cf1b35fcc2d6f0130411df5432d5b55cc2 100644 --- a/drivers/net/wan/hostess_sv11.c +++ b/drivers/net/wan/hostess_sv11.c @@ -66,7 +66,6 @@ static void hostess_input(struct z8530_channel *c, struct sk_buff *skb) * it right now. */ netif_rx(skb); - c->netdevice->last_rx = jiffies; } /* diff --git a/drivers/net/wan/ixp4xx_hss.c b/drivers/net/wan/ixp4xx_hss.c new file mode 100644 index 0000000000000000000000000000000000000000..0c6802507a79817840e36194a0ec49b0993adb73 --- /dev/null +++ b/drivers/net/wan/ixp4xx_hss.c @@ -0,0 +1,1325 @@ +/* + * Intel IXP4xx HSS (synchronous serial port) driver for Linux + * + * Copyright (C) 2007-2008 Krzysztof HaÅ‚asa + * + * 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. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DEBUG_DESC 0 +#define DEBUG_RX 0 +#define DEBUG_TX 0 +#define DEBUG_PKT_BYTES 0 +#define DEBUG_CLOSE 0 + +#define DRV_NAME "ixp4xx_hss" + +#define PKT_EXTRA_FLAGS 0 /* orig 1 */ +#define PKT_NUM_PIPES 1 /* 1, 2 or 4 */ +#define PKT_PIPE_FIFO_SIZEW 4 /* total 4 dwords per HSS */ + +#define RX_DESCS 16 /* also length of all RX queues */ +#define TX_DESCS 16 /* also length of all TX queues */ + +#define POOL_ALLOC_SIZE (sizeof(struct desc) * (RX_DESCS + TX_DESCS)) +#define RX_SIZE (HDLC_MAX_MRU + 4) /* NPE needs more space */ +#define MAX_CLOSE_WAIT 1000 /* microseconds */ +#define HSS_COUNT 2 +#define FRAME_SIZE 256 /* doesn't matter at this point */ +#define FRAME_OFFSET 0 +#define MAX_CHANNELS (FRAME_SIZE / 8) + +#define NAPI_WEIGHT 16 + +/* Queue IDs */ +#define HSS0_CHL_RXTRIG_QUEUE 12 /* orig size = 32 dwords */ +#define HSS0_PKT_RX_QUEUE 13 /* orig size = 32 dwords */ +#define HSS0_PKT_TX0_QUEUE 14 /* orig size = 16 dwords */ +#define HSS0_PKT_TX1_QUEUE 15 +#define HSS0_PKT_TX2_QUEUE 16 +#define HSS0_PKT_TX3_QUEUE 17 +#define HSS0_PKT_RXFREE0_QUEUE 18 /* orig size = 16 dwords */ +#define HSS0_PKT_RXFREE1_QUEUE 19 +#define HSS0_PKT_RXFREE2_QUEUE 20 +#define HSS0_PKT_RXFREE3_QUEUE 21 +#define HSS0_PKT_TXDONE_QUEUE 22 /* orig size = 64 dwords */ + +#define HSS1_CHL_RXTRIG_QUEUE 10 +#define HSS1_PKT_RX_QUEUE 0 +#define HSS1_PKT_TX0_QUEUE 5 +#define HSS1_PKT_TX1_QUEUE 6 +#define HSS1_PKT_TX2_QUEUE 7 +#define HSS1_PKT_TX3_QUEUE 8 +#define HSS1_PKT_RXFREE0_QUEUE 1 +#define HSS1_PKT_RXFREE1_QUEUE 2 +#define HSS1_PKT_RXFREE2_QUEUE 3 +#define HSS1_PKT_RXFREE3_QUEUE 4 +#define HSS1_PKT_TXDONE_QUEUE 9 + +#define NPE_PKT_MODE_HDLC 0 +#define NPE_PKT_MODE_RAW 1 +#define NPE_PKT_MODE_56KMODE 2 +#define NPE_PKT_MODE_56KENDIAN_MSB 4 + +/* PKT_PIPE_HDLC_CFG_WRITE flags */ +#define PKT_HDLC_IDLE_ONES 0x1 /* default = flags */ +#define PKT_HDLC_CRC_32 0x2 /* default = CRC-16 */ +#define PKT_HDLC_MSB_ENDIAN 0x4 /* default = LE */ + + +/* hss_config, PCRs */ +/* Frame sync sampling, default = active low */ +#define PCR_FRM_SYNC_ACTIVE_HIGH 0x40000000 +#define PCR_FRM_SYNC_FALLINGEDGE 0x80000000 +#define PCR_FRM_SYNC_RISINGEDGE 0xC0000000 + +/* Frame sync pin: input (default) or output generated off a given clk edge */ +#define PCR_FRM_SYNC_OUTPUT_FALLING 0x20000000 +#define PCR_FRM_SYNC_OUTPUT_RISING 0x30000000 + +/* Frame and data clock sampling on edge, default = falling */ +#define PCR_FCLK_EDGE_RISING 0x08000000 +#define PCR_DCLK_EDGE_RISING 0x04000000 + +/* Clock direction, default = input */ +#define PCR_SYNC_CLK_DIR_OUTPUT 0x02000000 + +/* Generate/Receive frame pulses, default = enabled */ +#define PCR_FRM_PULSE_DISABLED 0x01000000 + + /* Data rate is full (default) or half the configured clk speed */ +#define PCR_HALF_CLK_RATE 0x00200000 + +/* Invert data between NPE and HSS FIFOs? (default = no) */ +#define PCR_DATA_POLARITY_INVERT 0x00100000 + +/* TX/RX endianness, default = LSB */ +#define PCR_MSB_ENDIAN 0x00080000 + +/* Normal (default) / open drain mode (TX only) */ +#define PCR_TX_PINS_OPEN_DRAIN 0x00040000 + +/* No framing bit transmitted and expected on RX? (default = framing bit) */ +#define PCR_SOF_NO_FBIT 0x00020000 + +/* Drive data pins? */ +#define PCR_TX_DATA_ENABLE 0x00010000 + +/* Voice 56k type: drive the data pins low (default), high, high Z */ +#define PCR_TX_V56K_HIGH 0x00002000 +#define PCR_TX_V56K_HIGH_IMP 0x00004000 + +/* Unassigned type: drive the data pins low (default), high, high Z */ +#define PCR_TX_UNASS_HIGH 0x00000800 +#define PCR_TX_UNASS_HIGH_IMP 0x00001000 + +/* T1 @ 1.544MHz only: Fbit dictated in FIFO (default) or high Z */ +#define PCR_TX_FB_HIGH_IMP 0x00000400 + +/* 56k data endiannes - which bit unused: high (default) or low */ +#define PCR_TX_56KE_BIT_0_UNUSED 0x00000200 + +/* 56k data transmission type: 32/8 bit data (default) or 56K data */ +#define PCR_TX_56KS_56K_DATA 0x00000100 + +/* hss_config, cCR */ +/* Number of packetized clients, default = 1 */ +#define CCR_NPE_HFIFO_2_HDLC 0x04000000 +#define CCR_NPE_HFIFO_3_OR_4HDLC 0x08000000 + +/* default = no loopback */ +#define CCR_LOOPBACK 0x02000000 + +/* HSS number, default = 0 (first) */ +#define CCR_SECOND_HSS 0x01000000 + + +/* hss_config, clkCR: main:10, num:10, denom:12 */ +#define CLK42X_SPEED_EXP ((0x3FF << 22) | ( 2 << 12) | 15) /*65 KHz*/ + +#define CLK42X_SPEED_512KHZ (( 130 << 22) | ( 2 << 12) | 15) +#define CLK42X_SPEED_1536KHZ (( 43 << 22) | ( 18 << 12) | 47) +#define CLK42X_SPEED_1544KHZ (( 43 << 22) | ( 33 << 12) | 192) +#define CLK42X_SPEED_2048KHZ (( 32 << 22) | ( 34 << 12) | 63) +#define CLK42X_SPEED_4096KHZ (( 16 << 22) | ( 34 << 12) | 127) +#define CLK42X_SPEED_8192KHZ (( 8 << 22) | ( 34 << 12) | 255) + +#define CLK46X_SPEED_512KHZ (( 130 << 22) | ( 24 << 12) | 127) +#define CLK46X_SPEED_1536KHZ (( 43 << 22) | (152 << 12) | 383) +#define CLK46X_SPEED_1544KHZ (( 43 << 22) | ( 66 << 12) | 385) +#define CLK46X_SPEED_2048KHZ (( 32 << 22) | (280 << 12) | 511) +#define CLK46X_SPEED_4096KHZ (( 16 << 22) | (280 << 12) | 1023) +#define CLK46X_SPEED_8192KHZ (( 8 << 22) | (280 << 12) | 2047) + + +/* hss_config, LUT entries */ +#define TDMMAP_UNASSIGNED 0 +#define TDMMAP_HDLC 1 /* HDLC - packetized */ +#define TDMMAP_VOICE56K 2 /* Voice56K - 7-bit channelized */ +#define TDMMAP_VOICE64K 3 /* Voice64K - 8-bit channelized */ + +/* offsets into HSS config */ +#define HSS_CONFIG_TX_PCR 0x00 /* port configuration registers */ +#define HSS_CONFIG_RX_PCR 0x04 +#define HSS_CONFIG_CORE_CR 0x08 /* loopback control, HSS# */ +#define HSS_CONFIG_CLOCK_CR 0x0C /* clock generator control */ +#define HSS_CONFIG_TX_FCR 0x10 /* frame configuration registers */ +#define HSS_CONFIG_RX_FCR 0x14 +#define HSS_CONFIG_TX_LUT 0x18 /* channel look-up tables */ +#define HSS_CONFIG_RX_LUT 0x38 + + +/* NPE command codes */ +/* writes the ConfigWord value to the location specified by offset */ +#define PORT_CONFIG_WRITE 0x40 + +/* triggers the NPE to load the contents of the configuration table */ +#define PORT_CONFIG_LOAD 0x41 + +/* triggers the NPE to return an HssErrorReadResponse message */ +#define PORT_ERROR_READ 0x42 + +/* triggers the NPE to reset internal status and enable the HssPacketized + operation for the flow specified by pPipe */ +#define PKT_PIPE_FLOW_ENABLE 0x50 +#define PKT_PIPE_FLOW_DISABLE 0x51 +#define PKT_NUM_PIPES_WRITE 0x52 +#define PKT_PIPE_FIFO_SIZEW_WRITE 0x53 +#define PKT_PIPE_HDLC_CFG_WRITE 0x54 +#define PKT_PIPE_IDLE_PATTERN_WRITE 0x55 +#define PKT_PIPE_RX_SIZE_WRITE 0x56 +#define PKT_PIPE_MODE_WRITE 0x57 + +/* HDLC packet status values - desc->status */ +#define ERR_SHUTDOWN 1 /* stop or shutdown occurrance */ +#define ERR_HDLC_ALIGN 2 /* HDLC alignment error */ +#define ERR_HDLC_FCS 3 /* HDLC Frame Check Sum error */ +#define ERR_RXFREE_Q_EMPTY 4 /* RX-free queue became empty while receiving + this packet (if buf_len < pkt_len) */ +#define ERR_HDLC_TOO_LONG 5 /* HDLC frame size too long */ +#define ERR_HDLC_ABORT 6 /* abort sequence received */ +#define ERR_DISCONNECTING 7 /* disconnect is in progress */ + + +#ifdef __ARMEB__ +typedef struct sk_buff buffer_t; +#define free_buffer dev_kfree_skb +#define free_buffer_irq dev_kfree_skb_irq +#else +typedef void buffer_t; +#define free_buffer kfree +#define free_buffer_irq kfree +#endif + +struct port { + struct device *dev; + struct npe *npe; + struct net_device *netdev; + struct napi_struct napi; + struct hss_plat_info *plat; + buffer_t *rx_buff_tab[RX_DESCS], *tx_buff_tab[TX_DESCS]; + struct desc *desc_tab; /* coherent */ + u32 desc_tab_phys; + unsigned int id; + unsigned int clock_type, clock_rate, loopback; + unsigned int initialized, carrier; + u8 hdlc_cfg; +}; + +/* NPE message structure */ +struct msg { +#ifdef __ARMEB__ + u8 cmd, unused, hss_port, index; + union { + struct { u8 data8a, data8b, data8c, data8d; }; + struct { u16 data16a, data16b; }; + struct { u32 data32; }; + }; +#else + u8 index, hss_port, unused, cmd; + union { + struct { u8 data8d, data8c, data8b, data8a; }; + struct { u16 data16b, data16a; }; + struct { u32 data32; }; + }; +#endif +}; + +/* HDLC packet descriptor */ +struct desc { + u32 next; /* pointer to next buffer, unused */ + +#ifdef __ARMEB__ + u16 buf_len; /* buffer length */ + u16 pkt_len; /* packet length */ + u32 data; /* pointer to data buffer in RAM */ + u8 status; + u8 error_count; + u16 __reserved; +#else + u16 pkt_len; /* packet length */ + u16 buf_len; /* buffer length */ + u32 data; /* pointer to data buffer in RAM */ + u16 __reserved; + u8 error_count; + u8 status; +#endif + u32 __reserved1[4]; +}; + + +#define rx_desc_phys(port, n) ((port)->desc_tab_phys + \ + (n) * sizeof(struct desc)) +#define rx_desc_ptr(port, n) (&(port)->desc_tab[n]) + +#define tx_desc_phys(port, n) ((port)->desc_tab_phys + \ + ((n) + RX_DESCS) * sizeof(struct desc)) +#define tx_desc_ptr(port, n) (&(port)->desc_tab[(n) + RX_DESCS]) + +/***************************************************************************** + * global variables + ****************************************************************************/ + +static int ports_open; +static struct dma_pool *dma_pool; +static spinlock_t npe_lock; + +static const struct { + int tx, txdone, rx, rxfree; +}queue_ids[2] = {{HSS0_PKT_TX0_QUEUE, HSS0_PKT_TXDONE_QUEUE, HSS0_PKT_RX_QUEUE, + HSS0_PKT_RXFREE0_QUEUE}, + {HSS1_PKT_TX0_QUEUE, HSS1_PKT_TXDONE_QUEUE, HSS1_PKT_RX_QUEUE, + HSS1_PKT_RXFREE0_QUEUE}, +}; + +/***************************************************************************** + * utility functions + ****************************************************************************/ + +static inline struct port* dev_to_port(struct net_device *dev) +{ + return dev_to_hdlc(dev)->priv; +} + +#ifndef __ARMEB__ +static inline void memcpy_swab32(u32 *dest, u32 *src, int cnt) +{ + int i; + for (i = 0; i < cnt; i++) + dest[i] = swab32(src[i]); +} +#endif + +/***************************************************************************** + * HSS access + ****************************************************************************/ + +static void hss_npe_send(struct port *port, struct msg *msg, const char* what) +{ + u32 *val = (u32*)msg; + if (npe_send_message(port->npe, msg, what)) { + printk(KERN_CRIT "HSS-%i: unable to send command [%08X:%08X]" + " to %s\n", port->id, val[0], val[1], + npe_name(port->npe)); + BUG(); + } +} + +static void hss_config_set_lut(struct port *port) +{ + struct msg msg; + int ch; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + + for (ch = 0; ch < MAX_CHANNELS; ch++) { + msg.data32 >>= 2; + msg.data32 |= TDMMAP_HDLC << 30; + + if (ch % 16 == 15) { + msg.index = HSS_CONFIG_TX_LUT + ((ch / 4) & ~3); + hss_npe_send(port, &msg, "HSS_SET_TX_LUT"); + + msg.index += HSS_CONFIG_RX_LUT - HSS_CONFIG_TX_LUT; + hss_npe_send(port, &msg, "HSS_SET_RX_LUT"); + } + } +} + +static void hss_config(struct port *port) +{ + struct msg msg; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + msg.index = HSS_CONFIG_TX_PCR; + msg.data32 = PCR_FRM_SYNC_OUTPUT_RISING | PCR_MSB_ENDIAN | + PCR_TX_DATA_ENABLE | PCR_SOF_NO_FBIT; + if (port->clock_type == CLOCK_INT) + msg.data32 |= PCR_SYNC_CLK_DIR_OUTPUT; + hss_npe_send(port, &msg, "HSS_SET_TX_PCR"); + + msg.index = HSS_CONFIG_RX_PCR; + msg.data32 ^= PCR_TX_DATA_ENABLE | PCR_DCLK_EDGE_RISING; + hss_npe_send(port, &msg, "HSS_SET_RX_PCR"); + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + msg.index = HSS_CONFIG_CORE_CR; + msg.data32 = (port->loopback ? CCR_LOOPBACK : 0) | + (port->id ? CCR_SECOND_HSS : 0); + hss_npe_send(port, &msg, "HSS_SET_CORE_CR"); + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + msg.index = HSS_CONFIG_CLOCK_CR; + msg.data32 = CLK42X_SPEED_2048KHZ /* FIXME */; + hss_npe_send(port, &msg, "HSS_SET_CLOCK_CR"); + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + msg.index = HSS_CONFIG_TX_FCR; + msg.data16a = FRAME_OFFSET; + msg.data16b = FRAME_SIZE - 1; + hss_npe_send(port, &msg, "HSS_SET_TX_FCR"); + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_WRITE; + msg.hss_port = port->id; + msg.index = HSS_CONFIG_RX_FCR; + msg.data16a = FRAME_OFFSET; + msg.data16b = FRAME_SIZE - 1; + hss_npe_send(port, &msg, "HSS_SET_RX_FCR"); + + hss_config_set_lut(port); + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_CONFIG_LOAD; + msg.hss_port = port->id; + hss_npe_send(port, &msg, "HSS_LOAD_CONFIG"); + + if (npe_recv_message(port->npe, &msg, "HSS_LOAD_CONFIG") || + /* HSS_LOAD_CONFIG for port #1 returns port_id = #4 */ + msg.cmd != PORT_CONFIG_LOAD || msg.data32) { + printk(KERN_CRIT "HSS-%i: HSS_LOAD_CONFIG failed\n", + port->id); + BUG(); + } + + /* HDLC may stop working without this - check FIXME */ + npe_recv_message(port->npe, &msg, "FLUSH_IT"); +} + +static void hss_set_hdlc_cfg(struct port *port) +{ + struct msg msg; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PKT_PIPE_HDLC_CFG_WRITE; + msg.hss_port = port->id; + msg.data8a = port->hdlc_cfg; /* rx_cfg */ + msg.data8b = port->hdlc_cfg | (PKT_EXTRA_FLAGS << 3); /* tx_cfg */ + hss_npe_send(port, &msg, "HSS_SET_HDLC_CFG"); +} + +static u32 hss_get_status(struct port *port) +{ + struct msg msg; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PORT_ERROR_READ; + msg.hss_port = port->id; + hss_npe_send(port, &msg, "PORT_ERROR_READ"); + if (npe_recv_message(port->npe, &msg, "PORT_ERROR_READ")) { + printk(KERN_CRIT "HSS-%i: unable to read HSS status\n", + port->id); + BUG(); + } + + return msg.data32; +} + +static void hss_start_hdlc(struct port *port) +{ + struct msg msg; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PKT_PIPE_FLOW_ENABLE; + msg.hss_port = port->id; + msg.data32 = 0; + hss_npe_send(port, &msg, "HSS_ENABLE_PKT_PIPE"); +} + +static void hss_stop_hdlc(struct port *port) +{ + struct msg msg; + + memset(&msg, 0, sizeof(msg)); + msg.cmd = PKT_PIPE_FLOW_DISABLE; + msg.hss_port = port->id; + hss_npe_send(port, &msg, "HSS_DISABLE_PKT_PIPE"); + hss_get_status(port); /* make sure it's halted */ +} + +static int hss_load_firmware(struct port *port) +{ + struct msg msg; + int err; + + if (port->initialized) + return 0; + + if (!npe_running(port->npe) && + (err = npe_load_firmware(port->npe, npe_name(port->npe), + port->dev))) + return err; + + /* HDLC mode configuration */ + memset(&msg, 0, sizeof(msg)); + msg.cmd = PKT_NUM_PIPES_WRITE; + msg.hss_port = port->id; + msg.data8a = PKT_NUM_PIPES; + hss_npe_send(port, &msg, "HSS_SET_PKT_PIPES"); + + msg.cmd = PKT_PIPE_FIFO_SIZEW_WRITE; + msg.data8a = PKT_PIPE_FIFO_SIZEW; + hss_npe_send(port, &msg, "HSS_SET_PKT_FIFO"); + + msg.cmd = PKT_PIPE_MODE_WRITE; + msg.data8a = NPE_PKT_MODE_HDLC; + /* msg.data8b = inv_mask */ + /* msg.data8c = or_mask */ + hss_npe_send(port, &msg, "HSS_SET_PKT_MODE"); + + msg.cmd = PKT_PIPE_RX_SIZE_WRITE; + msg.data16a = HDLC_MAX_MRU; /* including CRC */ + hss_npe_send(port, &msg, "HSS_SET_PKT_RX_SIZE"); + + msg.cmd = PKT_PIPE_IDLE_PATTERN_WRITE; + msg.data32 = 0x7F7F7F7F; /* ??? FIXME */ + hss_npe_send(port, &msg, "HSS_SET_PKT_IDLE"); + + port->initialized = 1; + return 0; +} + +/***************************************************************************** + * packetized (HDLC) operation + ****************************************************************************/ + +static inline void debug_pkt(struct net_device *dev, const char *func, + u8 *data, int len) +{ +#if DEBUG_PKT_BYTES + int i; + + printk(KERN_DEBUG "%s: %s(%i)", dev->name, func, len); + for (i = 0; i < len; i++) { + if (i >= DEBUG_PKT_BYTES) + break; + printk("%s%02X", !(i % 4) ? " " : "", data[i]); + } + printk("\n"); +#endif +} + + +static inline void debug_desc(u32 phys, struct desc *desc) +{ +#if DEBUG_DESC + printk(KERN_DEBUG "%X: %X %3X %3X %08X %X %X\n", + phys, desc->next, desc->buf_len, desc->pkt_len, + desc->data, desc->status, desc->error_count); +#endif +} + +static inline int queue_get_desc(unsigned int queue, struct port *port, + int is_tx) +{ + u32 phys, tab_phys, n_desc; + struct desc *tab; + + if (!(phys = qmgr_get_entry(queue))) + return -1; + + BUG_ON(phys & 0x1F); + tab_phys = is_tx ? tx_desc_phys(port, 0) : rx_desc_phys(port, 0); + tab = is_tx ? tx_desc_ptr(port, 0) : rx_desc_ptr(port, 0); + n_desc = (phys - tab_phys) / sizeof(struct desc); + BUG_ON(n_desc >= (is_tx ? TX_DESCS : RX_DESCS)); + debug_desc(phys, &tab[n_desc]); + BUG_ON(tab[n_desc].next); + return n_desc; +} + +static inline void queue_put_desc(unsigned int queue, u32 phys, + struct desc *desc) +{ + debug_desc(phys, desc); + BUG_ON(phys & 0x1F); + qmgr_put_entry(queue, phys); + BUG_ON(qmgr_stat_overflow(queue)); +} + + +static inline void dma_unmap_tx(struct port *port, struct desc *desc) +{ +#ifdef __ARMEB__ + dma_unmap_single(&port->netdev->dev, desc->data, + desc->buf_len, DMA_TO_DEVICE); +#else + dma_unmap_single(&port->netdev->dev, desc->data & ~3, + ALIGN((desc->data & 3) + desc->buf_len, 4), + DMA_TO_DEVICE); +#endif +} + + +static void hss_hdlc_set_carrier(void *pdev, int carrier) +{ + struct net_device *netdev = pdev; + struct port *port = dev_to_port(netdev); + unsigned long flags; + + spin_lock_irqsave(&npe_lock, flags); + port->carrier = carrier; + if (!port->loopback) { + if (carrier) + netif_carrier_on(netdev); + else + netif_carrier_off(netdev); + } + spin_unlock_irqrestore(&npe_lock, flags); +} + +static void hss_hdlc_rx_irq(void *pdev) +{ + struct net_device *dev = pdev; + struct port *port = dev_to_port(dev); + +#if DEBUG_RX + printk(KERN_DEBUG "%s: hss_hdlc_rx_irq\n", dev->name); +#endif + qmgr_disable_irq(queue_ids[port->id].rx); + netif_rx_schedule(dev, &port->napi); +} + +static int hss_hdlc_poll(struct napi_struct *napi, int budget) +{ + struct port *port = container_of(napi, struct port, napi); + struct net_device *dev = port->netdev; + unsigned int rxq = queue_ids[port->id].rx; + unsigned int rxfreeq = queue_ids[port->id].rxfree; + int received = 0; + +#if DEBUG_RX + printk(KERN_DEBUG "%s: hss_hdlc_poll\n", dev->name); +#endif + + while (received < budget) { + struct sk_buff *skb; + struct desc *desc; + int n; +#ifdef __ARMEB__ + struct sk_buff *temp; + u32 phys; +#endif + + if ((n = queue_get_desc(rxq, port, 0)) < 0) { +#if DEBUG_RX + printk(KERN_DEBUG "%s: hss_hdlc_poll" + " netif_rx_complete\n", dev->name); +#endif + netif_rx_complete(dev, napi); + qmgr_enable_irq(rxq); + if (!qmgr_stat_empty(rxq) && + netif_rx_reschedule(dev, napi)) { +#if DEBUG_RX + printk(KERN_DEBUG "%s: hss_hdlc_poll" + " netif_rx_reschedule succeeded\n", + dev->name); +#endif + qmgr_disable_irq(rxq); + continue; + } +#if DEBUG_RX + printk(KERN_DEBUG "%s: hss_hdlc_poll all done\n", + dev->name); +#endif + return received; /* all work done */ + } + + desc = rx_desc_ptr(port, n); +#if 0 /* FIXME - error_count counts modulo 256, perhaps we should use it */ + if (desc->error_count) + printk(KERN_DEBUG "%s: hss_hdlc_poll status 0x%02X" + " errors %u\n", dev->name, desc->status, + desc->error_count); +#endif + skb = NULL; + switch (desc->status) { + case 0: +#ifdef __ARMEB__ + if ((skb = netdev_alloc_skb(dev, RX_SIZE)) != NULL) { + phys = dma_map_single(&dev->dev, skb->data, + RX_SIZE, + DMA_FROM_DEVICE); + if (dma_mapping_error(&dev->dev, phys)) { + dev_kfree_skb(skb); + skb = NULL; + } + } +#else + skb = netdev_alloc_skb(dev, desc->pkt_len); +#endif + if (!skb) + dev->stats.rx_dropped++; + break; + case ERR_HDLC_ALIGN: + case ERR_HDLC_ABORT: + dev->stats.rx_frame_errors++; + dev->stats.rx_errors++; + break; + case ERR_HDLC_FCS: + dev->stats.rx_crc_errors++; + dev->stats.rx_errors++; + break; + case ERR_HDLC_TOO_LONG: + dev->stats.rx_length_errors++; + dev->stats.rx_errors++; + break; + default: /* FIXME - remove printk */ + printk(KERN_ERR "%s: hss_hdlc_poll: status 0x%02X" + " errors %u\n", dev->name, desc->status, + desc->error_count); + dev->stats.rx_errors++; + } + + if (!skb) { + /* put the desc back on RX-ready queue */ + desc->buf_len = RX_SIZE; + desc->pkt_len = desc->status = 0; + queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc); + continue; + } + + /* process received frame */ +#ifdef __ARMEB__ + temp = skb; + skb = port->rx_buff_tab[n]; + dma_unmap_single(&dev->dev, desc->data, + RX_SIZE, DMA_FROM_DEVICE); +#else + dma_sync_single(&dev->dev, desc->data, + RX_SIZE, DMA_FROM_DEVICE); + memcpy_swab32((u32 *)skb->data, (u32 *)port->rx_buff_tab[n], + ALIGN(desc->pkt_len, 4) / 4); +#endif + skb_put(skb, desc->pkt_len); + + debug_pkt(dev, "hss_hdlc_poll", skb->data, skb->len); + + skb->protocol = hdlc_type_trans(skb, dev); + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + netif_receive_skb(skb); + + /* put the new buffer on RX-free queue */ +#ifdef __ARMEB__ + port->rx_buff_tab[n] = temp; + desc->data = phys; +#endif + desc->buf_len = RX_SIZE; + desc->pkt_len = 0; + queue_put_desc(rxfreeq, rx_desc_phys(port, n), desc); + received++; + } +#if DEBUG_RX + printk(KERN_DEBUG "hss_hdlc_poll: end, not all work done\n"); +#endif + return received; /* not all work done */ +} + + +static void hss_hdlc_txdone_irq(void *pdev) +{ + struct net_device *dev = pdev; + struct port *port = dev_to_port(dev); + int n_desc; + +#if DEBUG_TX + printk(KERN_DEBUG DRV_NAME ": hss_hdlc_txdone_irq\n"); +#endif + while ((n_desc = queue_get_desc(queue_ids[port->id].txdone, + port, 1)) >= 0) { + struct desc *desc; + int start; + + desc = tx_desc_ptr(port, n_desc); + + dev->stats.tx_packets++; + dev->stats.tx_bytes += desc->pkt_len; + + dma_unmap_tx(port, desc); +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_txdone_irq free %p\n", + dev->name, port->tx_buff_tab[n_desc]); +#endif + free_buffer_irq(port->tx_buff_tab[n_desc]); + port->tx_buff_tab[n_desc] = NULL; + + start = qmgr_stat_empty(port->plat->txreadyq); + queue_put_desc(port->plat->txreadyq, + tx_desc_phys(port, n_desc), desc); + if (start) { +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_txdone_irq xmit" + " ready\n", dev->name); +#endif + netif_wake_queue(dev); + } + } +} + +static int hss_hdlc_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct port *port = dev_to_port(dev); + unsigned int txreadyq = port->plat->txreadyq; + int len, offset, bytes, n; + void *mem; + u32 phys; + struct desc *desc; + +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_xmit\n", dev->name); +#endif + + if (unlikely(skb->len > HDLC_MAX_MRU)) { + dev_kfree_skb(skb); + dev->stats.tx_errors++; + return NETDEV_TX_OK; + } + + debug_pkt(dev, "hss_hdlc_xmit", skb->data, skb->len); + + len = skb->len; +#ifdef __ARMEB__ + offset = 0; /* no need to keep alignment */ + bytes = len; + mem = skb->data; +#else + offset = (int)skb->data & 3; /* keep 32-bit alignment */ + bytes = ALIGN(offset + len, 4); + if (!(mem = kmalloc(bytes, GFP_ATOMIC))) { + dev_kfree_skb(skb); + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + memcpy_swab32(mem, (u32 *)((int)skb->data & ~3), bytes / 4); + dev_kfree_skb(skb); +#endif + + phys = dma_map_single(&dev->dev, mem, bytes, DMA_TO_DEVICE); + if (dma_mapping_error(&dev->dev, phys)) { +#ifdef __ARMEB__ + dev_kfree_skb(skb); +#else + kfree(mem); +#endif + dev->stats.tx_dropped++; + return NETDEV_TX_OK; + } + + n = queue_get_desc(txreadyq, port, 1); + BUG_ON(n < 0); + desc = tx_desc_ptr(port, n); + +#ifdef __ARMEB__ + port->tx_buff_tab[n] = skb; +#else + port->tx_buff_tab[n] = mem; +#endif + desc->data = phys + offset; + desc->buf_len = desc->pkt_len = len; + + wmb(); + queue_put_desc(queue_ids[port->id].tx, tx_desc_phys(port, n), desc); + dev->trans_start = jiffies; + + if (qmgr_stat_empty(txreadyq)) { +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_xmit queue full\n", dev->name); +#endif + netif_stop_queue(dev); + /* we could miss TX ready interrupt */ + if (!qmgr_stat_empty(txreadyq)) { +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_xmit ready again\n", + dev->name); +#endif + netif_wake_queue(dev); + } + } + +#if DEBUG_TX + printk(KERN_DEBUG "%s: hss_hdlc_xmit end\n", dev->name); +#endif + return NETDEV_TX_OK; +} + + +static int request_hdlc_queues(struct port *port) +{ + int err; + + err = qmgr_request_queue(queue_ids[port->id].rxfree, RX_DESCS, 0, 0, + "%s:RX-free", port->netdev->name); + if (err) + return err; + + err = qmgr_request_queue(queue_ids[port->id].rx, RX_DESCS, 0, 0, + "%s:RX", port->netdev->name); + if (err) + goto rel_rxfree; + + err = qmgr_request_queue(queue_ids[port->id].tx, TX_DESCS, 0, 0, + "%s:TX", port->netdev->name); + if (err) + goto rel_rx; + + err = qmgr_request_queue(port->plat->txreadyq, TX_DESCS, 0, 0, + "%s:TX-ready", port->netdev->name); + if (err) + goto rel_tx; + + err = qmgr_request_queue(queue_ids[port->id].txdone, TX_DESCS, 0, 0, + "%s:TX-done", port->netdev->name); + if (err) + goto rel_txready; + return 0; + +rel_txready: + qmgr_release_queue(port->plat->txreadyq); +rel_tx: + qmgr_release_queue(queue_ids[port->id].tx); +rel_rx: + qmgr_release_queue(queue_ids[port->id].rx); +rel_rxfree: + qmgr_release_queue(queue_ids[port->id].rxfree); + printk(KERN_DEBUG "%s: unable to request hardware queues\n", + port->netdev->name); + return err; +} + +static void release_hdlc_queues(struct port *port) +{ + qmgr_release_queue(queue_ids[port->id].rxfree); + qmgr_release_queue(queue_ids[port->id].rx); + qmgr_release_queue(queue_ids[port->id].txdone); + qmgr_release_queue(queue_ids[port->id].tx); + qmgr_release_queue(port->plat->txreadyq); +} + +static int init_hdlc_queues(struct port *port) +{ + int i; + + if (!ports_open) + if (!(dma_pool = dma_pool_create(DRV_NAME, NULL, + POOL_ALLOC_SIZE, 32, 0))) + return -ENOMEM; + + if (!(port->desc_tab = dma_pool_alloc(dma_pool, GFP_KERNEL, + &port->desc_tab_phys))) + return -ENOMEM; + memset(port->desc_tab, 0, POOL_ALLOC_SIZE); + memset(port->rx_buff_tab, 0, sizeof(port->rx_buff_tab)); /* tables */ + memset(port->tx_buff_tab, 0, sizeof(port->tx_buff_tab)); + + /* Setup RX buffers */ + for (i = 0; i < RX_DESCS; i++) { + struct desc *desc = rx_desc_ptr(port, i); + buffer_t *buff; + void *data; +#ifdef __ARMEB__ + if (!(buff = netdev_alloc_skb(port->netdev, RX_SIZE))) + return -ENOMEM; + data = buff->data; +#else + if (!(buff = kmalloc(RX_SIZE, GFP_KERNEL))) + return -ENOMEM; + data = buff; +#endif + desc->buf_len = RX_SIZE; + desc->data = dma_map_single(&port->netdev->dev, data, + RX_SIZE, DMA_FROM_DEVICE); + if (dma_mapping_error(&port->netdev->dev, desc->data)) { + free_buffer(buff); + return -EIO; + } + port->rx_buff_tab[i] = buff; + } + + return 0; +} + +static void destroy_hdlc_queues(struct port *port) +{ + int i; + + if (port->desc_tab) { + for (i = 0; i < RX_DESCS; i++) { + struct desc *desc = rx_desc_ptr(port, i); + buffer_t *buff = port->rx_buff_tab[i]; + if (buff) { + dma_unmap_single(&port->netdev->dev, + desc->data, RX_SIZE, + DMA_FROM_DEVICE); + free_buffer(buff); + } + } + for (i = 0; i < TX_DESCS; i++) { + struct desc *desc = tx_desc_ptr(port, i); + buffer_t *buff = port->tx_buff_tab[i]; + if (buff) { + dma_unmap_tx(port, desc); + free_buffer(buff); + } + } + dma_pool_free(dma_pool, port->desc_tab, port->desc_tab_phys); + port->desc_tab = NULL; + } + + if (!ports_open && dma_pool) { + dma_pool_destroy(dma_pool); + dma_pool = NULL; + } +} + +static int hss_hdlc_open(struct net_device *dev) +{ + struct port *port = dev_to_port(dev); + unsigned long flags; + int i, err = 0; + + if ((err = hdlc_open(dev))) + return err; + + if ((err = hss_load_firmware(port))) + goto err_hdlc_close; + + if ((err = request_hdlc_queues(port))) + goto err_hdlc_close; + + if ((err = init_hdlc_queues(port))) + goto err_destroy_queues; + + spin_lock_irqsave(&npe_lock, flags); + if (port->plat->open) + if ((err = port->plat->open(port->id, dev, + hss_hdlc_set_carrier))) + goto err_unlock; + spin_unlock_irqrestore(&npe_lock, flags); + + /* Populate queues with buffers, no failure after this point */ + for (i = 0; i < TX_DESCS; i++) + queue_put_desc(port->plat->txreadyq, + tx_desc_phys(port, i), tx_desc_ptr(port, i)); + + for (i = 0; i < RX_DESCS; i++) + queue_put_desc(queue_ids[port->id].rxfree, + rx_desc_phys(port, i), rx_desc_ptr(port, i)); + + napi_enable(&port->napi); + netif_start_queue(dev); + + qmgr_set_irq(queue_ids[port->id].rx, QUEUE_IRQ_SRC_NOT_EMPTY, + hss_hdlc_rx_irq, dev); + + qmgr_set_irq(queue_ids[port->id].txdone, QUEUE_IRQ_SRC_NOT_EMPTY, + hss_hdlc_txdone_irq, dev); + qmgr_enable_irq(queue_ids[port->id].txdone); + + ports_open++; + + hss_set_hdlc_cfg(port); + hss_config(port); + + hss_start_hdlc(port); + + /* we may already have RX data, enables IRQ */ + netif_rx_schedule(dev, &port->napi); + return 0; + +err_unlock: + spin_unlock_irqrestore(&npe_lock, flags); +err_destroy_queues: + destroy_hdlc_queues(port); + release_hdlc_queues(port); +err_hdlc_close: + hdlc_close(dev); + return err; +} + +static int hss_hdlc_close(struct net_device *dev) +{ + struct port *port = dev_to_port(dev); + unsigned long flags; + int i, buffs = RX_DESCS; /* allocated RX buffers */ + + spin_lock_irqsave(&npe_lock, flags); + ports_open--; + qmgr_disable_irq(queue_ids[port->id].rx); + netif_stop_queue(dev); + napi_disable(&port->napi); + + hss_stop_hdlc(port); + + while (queue_get_desc(queue_ids[port->id].rxfree, port, 0) >= 0) + buffs--; + while (queue_get_desc(queue_ids[port->id].rx, port, 0) >= 0) + buffs--; + + if (buffs) + printk(KERN_CRIT "%s: unable to drain RX queue, %i buffer(s)" + " left in NPE\n", dev->name, buffs); + + buffs = TX_DESCS; + while (queue_get_desc(queue_ids[port->id].tx, port, 1) >= 0) + buffs--; /* cancel TX */ + + i = 0; + do { + while (queue_get_desc(port->plat->txreadyq, port, 1) >= 0) + buffs--; + if (!buffs) + break; + } while (++i < MAX_CLOSE_WAIT); + + if (buffs) + printk(KERN_CRIT "%s: unable to drain TX queue, %i buffer(s) " + "left in NPE\n", dev->name, buffs); +#if DEBUG_CLOSE + if (!buffs) + printk(KERN_DEBUG "Draining TX queues took %i cycles\n", i); +#endif + qmgr_disable_irq(queue_ids[port->id].txdone); + + if (port->plat->close) + port->plat->close(port->id, dev); + spin_unlock_irqrestore(&npe_lock, flags); + + destroy_hdlc_queues(port); + release_hdlc_queues(port); + hdlc_close(dev); + return 0; +} + + +static int hss_hdlc_attach(struct net_device *dev, unsigned short encoding, + unsigned short parity) +{ + struct port *port = dev_to_port(dev); + + if (encoding != ENCODING_NRZ) + return -EINVAL; + + switch(parity) { + case PARITY_CRC16_PR1_CCITT: + port->hdlc_cfg = 0; + return 0; + + case PARITY_CRC32_PR1_CCITT: + port->hdlc_cfg = PKT_HDLC_CRC_32; + return 0; + + default: + return -EINVAL; + } +} + + +static int hss_hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) +{ + const size_t size = sizeof(sync_serial_settings); + sync_serial_settings new_line; + sync_serial_settings __user *line = ifr->ifr_settings.ifs_ifsu.sync; + struct port *port = dev_to_port(dev); + unsigned long flags; + int clk; + + if (cmd != SIOCWANDEV) + return hdlc_ioctl(dev, ifr, cmd); + + switch(ifr->ifr_settings.type) { + case IF_GET_IFACE: + ifr->ifr_settings.type = IF_IFACE_V35; + if (ifr->ifr_settings.size < size) { + ifr->ifr_settings.size = size; /* data size wanted */ + return -ENOBUFS; + } + memset(&new_line, 0, sizeof(new_line)); + new_line.clock_type = port->clock_type; + new_line.clock_rate = 2048000; /* FIXME */ + new_line.loopback = port->loopback; + if (copy_to_user(line, &new_line, size)) + return -EFAULT; + return 0; + + case IF_IFACE_SYNC_SERIAL: + case IF_IFACE_V35: + if(!capable(CAP_NET_ADMIN)) + return -EPERM; + if (copy_from_user(&new_line, line, size)) + return -EFAULT; + + clk = new_line.clock_type; + if (port->plat->set_clock) + clk = port->plat->set_clock(port->id, clk); + + if (clk != CLOCK_EXT && clk != CLOCK_INT) + return -EINVAL; /* No such clock setting */ + + if (new_line.loopback != 0 && new_line.loopback != 1) + return -EINVAL; + + port->clock_type = clk; /* Update settings */ + /* FIXME port->clock_rate = new_line.clock_rate */; + port->loopback = new_line.loopback; + + spin_lock_irqsave(&npe_lock, flags); + + if (dev->flags & IFF_UP) + hss_config(port); + + if (port->loopback || port->carrier) + netif_carrier_on(port->netdev); + else + netif_carrier_off(port->netdev); + spin_unlock_irqrestore(&npe_lock, flags); + + return 0; + + default: + return hdlc_ioctl(dev, ifr, cmd); + } +} + +/***************************************************************************** + * initialization + ****************************************************************************/ + +static int __devinit hss_init_one(struct platform_device *pdev) +{ + struct port *port; + struct net_device *dev; + hdlc_device *hdlc; + int err; + + if ((port = kzalloc(sizeof(*port), GFP_KERNEL)) == NULL) + return -ENOMEM; + + if ((port->npe = npe_request(0)) == NULL) { + err = -ENOSYS; + goto err_free; + } + + if ((port->netdev = dev = alloc_hdlcdev(port)) == NULL) { + err = -ENOMEM; + goto err_plat; + } + + SET_NETDEV_DEV(dev, &pdev->dev); + hdlc = dev_to_hdlc(dev); + hdlc->attach = hss_hdlc_attach; + hdlc->xmit = hss_hdlc_xmit; + dev->open = hss_hdlc_open; + dev->stop = hss_hdlc_close; + dev->do_ioctl = hss_hdlc_ioctl; + dev->tx_queue_len = 100; + port->clock_type = CLOCK_EXT; + port->clock_rate = 2048000; + port->id = pdev->id; + port->dev = &pdev->dev; + port->plat = pdev->dev.platform_data; + netif_napi_add(dev, &port->napi, hss_hdlc_poll, NAPI_WEIGHT); + + if ((err = register_hdlc_device(dev))) + goto err_free_netdev; + + platform_set_drvdata(pdev, port); + + printk(KERN_INFO "%s: HSS-%i\n", dev->name, port->id); + return 0; + +err_free_netdev: + free_netdev(dev); +err_plat: + npe_release(port->npe); +err_free: + kfree(port); + return err; +} + +static int __devexit hss_remove_one(struct platform_device *pdev) +{ + struct port *port = platform_get_drvdata(pdev); + + unregister_hdlc_device(port->netdev); + free_netdev(port->netdev); + npe_release(port->npe); + platform_set_drvdata(pdev, NULL); + kfree(port); + return 0; +} + +static struct platform_driver ixp4xx_hss_driver = { + .driver.name = DRV_NAME, + .probe = hss_init_one, + .remove = hss_remove_one, +}; + +static int __init hss_init_module(void) +{ + if ((ixp4xx_read_feature_bits() & + (IXP4XX_FEATURE_HDLC | IXP4XX_FEATURE_HSS)) != + (IXP4XX_FEATURE_HDLC | IXP4XX_FEATURE_HSS)) + return -ENOSYS; + + spin_lock_init(&npe_lock); + + return platform_driver_register(&ixp4xx_hss_driver); +} + +static void __exit hss_cleanup_module(void) +{ + platform_driver_unregister(&ixp4xx_hss_driver); +} + +MODULE_AUTHOR("Krzysztof Halasa"); +MODULE_DESCRIPTION("Intel IXP4xx HSS driver"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:ixp4xx_hss"); +module_init(hss_init_module); +module_exit(hss_cleanup_module); diff --git a/drivers/net/wan/lapbether.c b/drivers/net/wan/lapbether.c index 24fd613466b7ea0925d5c98c5aada6a82a1fc6cc..5b61b3eef45f5b19da53e8e249b02895eaa6657a 100644 --- a/drivers/net/wan/lapbether.c +++ b/drivers/net/wan/lapbether.c @@ -143,7 +143,6 @@ static int lapbeth_data_indication(struct net_device *dev, struct sk_buff *skb) *ptr = 0x00; skb->protocol = x25_type_trans(skb, dev); - skb->dev->last_rx = jiffies; return netif_rx(skb); } @@ -235,7 +234,6 @@ static void lapbeth_connected(struct net_device *dev, int reason) *ptr = 0x01; skb->protocol = x25_type_trans(skb, dev); - skb->dev->last_rx = jiffies; netif_rx(skb); } @@ -253,7 +251,6 @@ static void lapbeth_disconnected(struct net_device *dev, int reason) *ptr = 0x02; skb->protocol = x25_type_trans(skb, dev); - skb->dev->last_rx = jiffies; netif_rx(skb); } diff --git a/drivers/net/wan/lmc/lmc_main.c b/drivers/net/wan/lmc/lmc_main.c index d7bb63e616b5e41f9ca72f2c52fa583dddcff113..feac3b99f8fe7f42192062fca6b63189b73ec62b 100644 --- a/drivers/net/wan/lmc/lmc_main.c +++ b/drivers/net/wan/lmc/lmc_main.c @@ -1594,7 +1594,6 @@ static int lmc_rx(struct net_device *dev) goto skip_packet; } - dev->last_rx = jiffies; sc->lmc_device->stats.rx_packets++; sc->lmc_device->stats.rx_bytes += len; diff --git a/drivers/net/wan/lmc/lmc_proto.c b/drivers/net/wan/lmc/lmc_proto.c index be9877ff551e23da4ca16ad1bc4ac24ae2537901..94b4c208b013e1a0a936ed25afc46785f90ab5a0 100644 --- a/drivers/net/wan/lmc/lmc_proto.c +++ b/drivers/net/wan/lmc/lmc_proto.c @@ -142,7 +142,6 @@ void lmc_proto_netif(lmc_softc_t *sc, struct sk_buff *skb) /*FOLD00*/ case LMC_PPP: case LMC_NET: default: - skb->dev->last_rx = jiffies; netif_rx(skb); break; case LMC_RAW: diff --git a/drivers/net/wan/n2.c b/drivers/net/wan/n2.c index 0a566b0daacb51d0d979cb00af07ae341db76625..697715ae80f46917a463b5be6936c1f200ce8473 100644 --- a/drivers/net/wan/n2.c +++ b/drivers/net/wan/n2.c @@ -53,7 +53,7 @@ static const char* devname = "RISCom/N2"; #define NEED_SCA_MSCI_INTR #define MAX_TX_BUFFERS 10 -static char *hw = NULL; /* pointer to hw=xxx command line string */ +static char *hw; /* pointer to hw=xxx command line string */ /* RISCom/N2 Board Registers */ @@ -145,7 +145,6 @@ static card_t **new_card = &first_card; &(card)->ports[port] : NULL) - static __inline__ u8 sca_get_page(card_t *card) { return inb(card->io + N2_PSR) & PSR_PAGEBITS; @@ -159,9 +158,7 @@ static __inline__ void openwin(card_t *card, u8 page) } - -#include "hd6457x.c" - +#include "hd64570.c" static void n2_set_iface(port_t *port) @@ -478,7 +475,7 @@ static int __init n2_run(unsigned long io, unsigned long irq, n2_destroy_card(card); return -ENOBUFS; } - sca_init_sync_port(port); /* Set up SCA memory */ + sca_init_port(port); /* Set up SCA memory */ printk(KERN_INFO "%s: RISCom/N2 node %d\n", dev->name, port->phy_node); diff --git a/drivers/net/wan/pc300_drv.c b/drivers/net/wan/pc300_drv.c index d0a8d1e352ac1cf2787a3eda74cb2451ec7b27b7..c23fde0c0344cc6893c2d912d9cebfa10ba7e9f6 100644 --- a/drivers/net/wan/pc300_drv.c +++ b/drivers/net/wan/pc300_drv.c @@ -1769,7 +1769,7 @@ cpc_trace(struct net_device *dev, struct sk_buff *skb_main, char rx_tx) static void cpc_tx_timeout(struct net_device *dev) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; int ch = chan->channel; @@ -1796,7 +1796,7 @@ static void cpc_tx_timeout(struct net_device *dev) static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; int ch = chan->channel; @@ -1874,7 +1874,7 @@ static int cpc_queue_xmit(struct sk_buff *skb, struct net_device *dev) static void cpc_net_rx(struct net_device *dev) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; int ch = chan->channel; @@ -2522,7 +2522,7 @@ static int cpc_change_mtu(struct net_device *dev, int new_mtu) static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; pc300conf_t conf_aux; @@ -2718,9 +2718,8 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } pc300patrntst.num_errors = falc_pattern_test_error(card, ch); - if (!arg - || copy_to_user(arg, &pc300patrntst, - sizeof (pc300patterntst_t))) + if (copy_to_user(arg, &pc300patrntst, + sizeof(pc300patterntst_t))) return -EINVAL; } else { falc_pattern_test(card, ch, pc300patrntst.patrntst_on); @@ -3058,7 +3057,7 @@ static int tx_config(pc300dev_t * d) static int cpc_attach(struct net_device *dev, unsigned short encoding, unsigned short parity) { - pc300dev_t *d = (pc300dev_t *)dev->priv; + pc300dev_t *d = (pc300dev_t *)dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *)d->chan; pc300_t *card = (pc300_t *)chan->card; pc300chconf_t *conf = (pc300chconf_t *)&chan->conf; @@ -3138,7 +3137,7 @@ static void cpc_closech(pc300dev_t * d) int cpc_open(struct net_device *dev) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; struct ifreq ifr; int result; @@ -3166,7 +3165,7 @@ err_out: static int cpc_close(struct net_device *dev) { - pc300dev_t *d = (pc300dev_t *) dev->priv; + pc300dev_t *d = (pc300dev_t *) dev_to_hdlc(dev)->priv; pc300ch_t *chan = (pc300ch_t *) d->chan; pc300_t *card = (pc300_t *) chan->card; unsigned long flags; @@ -3347,7 +3346,7 @@ static void cpc_init_card(pc300_t * card) d->line_on = 0; d->line_off = 0; - dev = alloc_hdlcdev(NULL); + dev = alloc_hdlcdev(d); if (dev == NULL) continue; @@ -3372,7 +3371,6 @@ static void cpc_init_card(pc300_t * card) dev->do_ioctl = cpc_ioctl; if (register_hdlc_device(dev) == 0) { - dev->priv = d; /* We need 'priv', hdlc doesn't */ printk("%s: Cyclades-PC300/", dev->name); switch (card->hw.type) { case PC300_TE: diff --git a/drivers/net/wan/pc300too.c b/drivers/net/wan/pc300too.c index bf1b01590429d00ee45f3947c632726c4078b4de..f247e5d9002a3b8837f64e390583c3efcb1470c5 100644 --- a/drivers/net/wan/pc300too.c +++ b/drivers/net/wan/pc300too.c @@ -1,7 +1,7 @@ /* * Cyclades PC300 synchronous serial card driver for Linux * - * Copyright (C) 2000-2007 Krzysztof Halasa + * Copyright (C) 2000-2008 Krzysztof Halasa * * 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 @@ -11,7 +11,7 @@ * * Sources of information: * Hitachi HD64572 SCA-II User's Manual - * Cyclades PC300 Linux driver + * Original Cyclades PC300 Linux driver * * This driver currently supports only PC300/RSV (V.24/V.35) and * PC300/X21 cards. @@ -37,17 +37,11 @@ #include "hd64572.h" -static const char* version = "Cyclades PC300 driver version: 1.17"; -static const char* devname = "PC300"; - #undef DEBUG_PKT #define DEBUG_RINGS #define PC300_PLX_SIZE 0x80 /* PLX control window size (128 B) */ #define PC300_SCA_SIZE 0x400 /* SCA window size (1 KB) */ -#define ALL_PAGES_ALWAYS_MAPPED -#define NEED_DETECT_RAM -#define NEED_SCA_MSCI_INTR #define MAX_TX_BUFFERS 10 static int pci_clock_freq = 33000000; @@ -81,7 +75,8 @@ typedef struct { typedef struct port_s { - struct net_device *dev; + struct napi_struct napi; + struct net_device *netdev; struct card_s *card; spinlock_t lock; /* TX lock */ sync_serial_settings settings; @@ -93,7 +88,7 @@ typedef struct port_s { u16 txin; /* tx ring buffer 'in' and 'last' pointers */ u16 txlast; u8 rxs, txs, tmc; /* SCA registers */ - u8 phy_node; /* physical port # - 0 or 1 */ + u8 chan; /* physical port # - 0 or 1 */ }port_t; @@ -114,21 +109,10 @@ typedef struct card_s { }card_t; -#define sca_in(reg, card) readb(card->scabase + (reg)) -#define sca_out(value, reg, card) writeb(value, card->scabase + (reg)) -#define sca_inw(reg, card) readw(card->scabase + (reg)) -#define sca_outw(value, reg, card) writew(value, card->scabase + (reg)) -#define sca_inl(reg, card) readl(card->scabase + (reg)) -#define sca_outl(value, reg, card) writel(value, card->scabase + (reg)) - -#define port_to_card(port) (port->card) -#define log_node(port) (port->phy_node) -#define phy_node(port) (port->phy_node) -#define winbase(card) (card->rambase) #define get_port(card, port) ((port) < (card)->n_ports ? \ (&(card)->ports[port]) : (NULL)) -#include "hd6457x.c" +#include "hd64572.c" static void pc300_set_iface(port_t *port) @@ -139,8 +123,8 @@ static void pc300_set_iface(port_t *port) u8 rxs = port->rxs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK; - sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, - port_to_card(port)); + sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, + port->card); switch(port->settings.clock_type) { case CLOCK_INT: rxs |= CLK_BRG; /* BRG output */ @@ -172,10 +156,10 @@ static void pc300_set_iface(port_t *port) if (port->card->type == PC300_RSV) { if (port->iface == IF_IFACE_V35) writel(card->init_ctrl_value | - PC300_CHMEDIA_MASK(port->phy_node), init_ctrl); + PC300_CHMEDIA_MASK(port->chan), init_ctrl); else writel(card->init_ctrl_value & - ~PC300_CHMEDIA_MASK(port->phy_node), init_ctrl); + ~PC300_CHMEDIA_MASK(port->chan), init_ctrl); } } @@ -280,10 +264,8 @@ static void pc300_pci_remove_one(struct pci_dev *pdev) card_t *card = pci_get_drvdata(pdev); for (i = 0; i < 2; i++) - if (card->ports[i].card) { - struct net_device *dev = port_to_dev(&card->ports[i]); - unregister_hdlc_device(dev); - } + if (card->ports[i].card) + unregister_hdlc_device(card->ports[i].netdev); if (card->irq) free_irq(card->irq, card); @@ -298,10 +280,10 @@ static void pc300_pci_remove_one(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - if (card->ports[0].dev) - free_netdev(card->ports[0].dev); - if (card->ports[1].dev) - free_netdev(card->ports[1].dev); + if (card->ports[0].netdev) + free_netdev(card->ports[0].netdev); + if (card->ports[1].netdev) + free_netdev(card->ports[1].netdev); kfree(card); } @@ -318,12 +300,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, u32 scaphys; /* SCA memory base */ u32 plxphys; /* PLX registers memory base */ -#ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(KERN_INFO "%s\n", version); -#endif - i = pci_enable_device(pdev); if (i) return i; @@ -343,27 +319,6 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, } pci_set_drvdata(pdev, card); - if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 || - pdev->device == PCI_DEVICE_ID_PC300_TE_2) - card->type = PC300_TE; /* not fully supported */ - else if (card->init_ctrl_value & PC300_CTYPE_MASK) - card->type = PC300_X21; - else - card->type = PC300_RSV; - - if (pdev->device == PCI_DEVICE_ID_PC300_RX_1 || - pdev->device == PCI_DEVICE_ID_PC300_TE_1) - card->n_ports = 1; - else - card->n_ports = 2; - - for (i = 0; i < card->n_ports; i++) - if (!(card->ports[i].dev = alloc_hdlcdev(&card->ports[i]))) { - printk(KERN_ERR "pc300: unable to allocate memory\n"); - pc300_pci_remove_one(pdev); - return -ENOMEM; - } - if (pci_resource_len(pdev, 0) != PC300_PLX_SIZE || pci_resource_len(pdev, 2) != PC300_SCA_SIZE || pci_resource_len(pdev, 3) < 16384) { @@ -372,14 +327,14 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, return -EFAULT; } - plxphys = pci_resource_start(pdev,0) & PCI_BASE_ADDRESS_MEM_MASK; + plxphys = pci_resource_start(pdev, 0) & PCI_BASE_ADDRESS_MEM_MASK; card->plxbase = ioremap(plxphys, PC300_PLX_SIZE); - scaphys = pci_resource_start(pdev,2) & PCI_BASE_ADDRESS_MEM_MASK; + scaphys = pci_resource_start(pdev, 2) & PCI_BASE_ADDRESS_MEM_MASK; card->scabase = ioremap(scaphys, PC300_SCA_SIZE); - ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK; - card->rambase = ioremap(ramphys, pci_resource_len(pdev,3)); + ramphys = pci_resource_start(pdev, 3) & PCI_BASE_ADDRESS_MEM_MASK; + card->rambase = pci_ioremap_bar(pdev, 3); if (card->plxbase == NULL || card->scabase == NULL || @@ -393,6 +348,27 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, card->init_ctrl_value = readl(&((plx9050 __iomem *)card->scabase)->init_ctrl); pci_write_config_dword(pdev, PCI_BASE_ADDRESS_0, plxphys); + if (pdev->device == PCI_DEVICE_ID_PC300_TE_1 || + pdev->device == PCI_DEVICE_ID_PC300_TE_2) + card->type = PC300_TE; /* not fully supported */ + else if (card->init_ctrl_value & PC300_CTYPE_MASK) + card->type = PC300_X21; + else + card->type = PC300_RSV; + + if (pdev->device == PCI_DEVICE_ID_PC300_RX_1 || + pdev->device == PCI_DEVICE_ID_PC300_TE_1) + card->n_ports = 1; + else + card->n_ports = 2; + + for (i = 0; i < card->n_ports; i++) + if (!(card->ports[i].netdev = alloc_hdlcdev(&card->ports[i]))) { + printk(KERN_ERR "pc300: unable to allocate memory\n"); + pc300_pci_remove_one(pdev); + return -ENOMEM; + } + /* Reset PLX */ p = &card->plxbase->init_ctrl; writel(card->init_ctrl_value | 0x40000000, p); @@ -446,7 +422,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, writew(0x0041, &card->plxbase->intr_ctrl_stat); /* Allocate IRQ */ - if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) { + if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, "pc300", card)) { printk(KERN_WARNING "pc300: could not allocate IRQ%d.\n", pdev->irq); pc300_pci_remove_one(pdev); @@ -463,9 +439,9 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, for (i = 0; i < card->n_ports; i++) { port_t *port = &card->ports[i]; - struct net_device *dev = port_to_dev(port); + struct net_device *dev = port->netdev; hdlc_device *hdlc = dev_to_hdlc(dev); - port->phy_node = i; + port->chan = i; spin_lock_init(&port->lock); dev->irq = card->irq; @@ -484,6 +460,7 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, else port->iface = IF_IFACE_V35; + sca_init_port(port); if (register_hdlc_device(dev)) { printk(KERN_ERR "pc300: unable to register hdlc " "device\n"); @@ -491,10 +468,9 @@ static int __devinit pc300_pci_init_one(struct pci_dev *pdev, pc300_pci_remove_one(pdev); return -ENOBUFS; } - sca_init_sync_port(port); /* Set up SCA memory */ - printk(KERN_INFO "%s: PC300 node %d\n", - dev->name, port->phy_node); + printk(KERN_INFO "%s: PC300 channel %d\n", + dev->name, port->chan); } return 0; } @@ -524,9 +500,6 @@ static struct pci_driver pc300_pci_driver = { static int __init pc300_init_module(void) { -#ifdef MODULE - printk(KERN_INFO "%s\n", version); -#endif if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) { printk(KERN_ERR "pc300: Invalid PCI clock frequency\n"); return -EINVAL; diff --git a/drivers/net/wan/pci200syn.c b/drivers/net/wan/pci200syn.c index b595b64e753809205151ae658d61ca2014f46d43..1104d3a692f77b52b72bc4b3b6d7cb3056b5646e 100644 --- a/drivers/net/wan/pci200syn.c +++ b/drivers/net/wan/pci200syn.c @@ -1,7 +1,7 @@ /* * Goramo PCI200SYN synchronous serial card driver for Linux * - * Copyright (C) 2002-2003 Krzysztof Halasa + * Copyright (C) 2002-2008 Krzysztof Halasa * * 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 @@ -33,17 +33,11 @@ #include "hd64572.h" -static const char* version = "Goramo PCI200SYN driver version: 1.16"; -static const char* devname = "PCI200SYN"; - #undef DEBUG_PKT #define DEBUG_RINGS #define PCI200SYN_PLX_SIZE 0x80 /* PLX control window size (128b) */ #define PCI200SYN_SCA_SIZE 0x400 /* SCA window size (1Kb) */ -#define ALL_PAGES_ALWAYS_MAPPED -#define NEED_DETECT_RAM -#define NEED_SCA_MSCI_INTR #define MAX_TX_BUFFERS 10 static int pci_clock_freq = 33000000; @@ -68,7 +62,8 @@ typedef struct { typedef struct port_s { - struct net_device *dev; + struct napi_struct napi; + struct net_device *netdev; struct card_s *card; spinlock_t lock; /* TX lock */ sync_serial_settings settings; @@ -79,7 +74,7 @@ typedef struct port_s { u16 txin; /* tx ring buffer 'in' and 'last' pointers */ u16 txlast; u8 rxs, txs, tmc; /* SCA registers */ - u8 phy_node; /* physical port # - 0 or 1 */ + u8 chan; /* physical port # - 0 or 1 */ }port_t; @@ -97,17 +92,6 @@ typedef struct card_s { }card_t; -#define sca_in(reg, card) readb(card->scabase + (reg)) -#define sca_out(value, reg, card) writeb(value, card->scabase + (reg)) -#define sca_inw(reg, card) readw(card->scabase + (reg)) -#define sca_outw(value, reg, card) writew(value, card->scabase + (reg)) -#define sca_inl(reg, card) readl(card->scabase + (reg)) -#define sca_outl(value, reg, card) writel(value, card->scabase + (reg)) - -#define port_to_card(port) (port->card) -#define log_node(port) (port->phy_node) -#define phy_node(port) (port->phy_node) -#define winbase(card) (card->rambase) #define get_port(card, port) (&card->ports[port]) #define sca_flush(card) (sca_in(IER0, card)); @@ -127,7 +111,7 @@ static inline void new_memcpy_toio(char __iomem *dest, char *src, int length) #undef memcpy_toio #define memcpy_toio new_memcpy_toio -#include "hd6457x.c" +#include "hd64572.c" static void pci200_set_iface(port_t *port) @@ -137,8 +121,8 @@ static void pci200_set_iface(port_t *port) u8 rxs = port->rxs & CLK_BRG_MASK; u8 txs = port->txs & CLK_BRG_MASK; - sca_out(EXS_TES1, (phy_node(port) ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, - port_to_card(port)); + sca_out(EXS_TES1, (port->chan ? MSCI1_OFFSET : MSCI0_OFFSET) + EXS, + port->card); switch(port->settings.clock_type) { case CLOCK_INT: rxs |= CLK_BRG; /* BRG output */ @@ -180,7 +164,7 @@ static int pci200_open(struct net_device *dev) sca_open(dev); pci200_set_iface(port); - sca_flush(port_to_card(port)); + sca_flush(port->card); return 0; } @@ -189,7 +173,7 @@ static int pci200_open(struct net_device *dev) static int pci200_close(struct net_device *dev) { sca_close(dev); - sca_flush(port_to_card(dev_to_port(dev))); + sca_flush(dev_to_port(dev)->card); hdlc_close(dev); return 0; } @@ -242,7 +226,7 @@ static int pci200_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) memcpy(&port->settings, &new_line, size); /* Update settings */ pci200_set_iface(port); - sca_flush(port_to_card(port)); + sca_flush(port->card); return 0; default: @@ -258,10 +242,8 @@ static void pci200_pci_remove_one(struct pci_dev *pdev) card_t *card = pci_get_drvdata(pdev); for (i = 0; i < 2; i++) - if (card->ports[i].card) { - struct net_device *dev = port_to_dev(&card->ports[i]); - unregister_hdlc_device(dev); - } + if (card->ports[i].card) + unregister_hdlc_device(card->ports[i].netdev); if (card->irq) free_irq(card->irq, card); @@ -276,10 +258,10 @@ static void pci200_pci_remove_one(struct pci_dev *pdev) pci_release_regions(pdev); pci_disable_device(pdev); pci_set_drvdata(pdev, NULL); - if (card->ports[0].dev) - free_netdev(card->ports[0].dev); - if (card->ports[1].dev) - free_netdev(card->ports[1].dev); + if (card->ports[0].netdev) + free_netdev(card->ports[0].netdev); + if (card->ports[1].netdev) + free_netdev(card->ports[1].netdev); kfree(card); } @@ -296,12 +278,6 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, u32 scaphys; /* SCA memory base */ u32 plxphys; /* PLX registers memory base */ -#ifndef MODULE - static int printed_version; - if (!printed_version++) - printk(KERN_INFO "%s\n", version); -#endif - i = pci_enable_device(pdev); if (i) return i; @@ -320,9 +296,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, return -ENOBUFS; } pci_set_drvdata(pdev, card); - card->ports[0].dev = alloc_hdlcdev(&card->ports[0]); - card->ports[1].dev = alloc_hdlcdev(&card->ports[1]); - if (!card->ports[0].dev || !card->ports[1].dev) { + card->ports[0].netdev = alloc_hdlcdev(&card->ports[0]); + card->ports[1].netdev = alloc_hdlcdev(&card->ports[1]); + if (!card->ports[0].netdev || !card->ports[1].netdev) { printk(KERN_ERR "pci200syn: unable to allocate memory\n"); pci200_pci_remove_one(pdev); return -ENOMEM; @@ -343,7 +319,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, card->scabase = ioremap(scaphys, PCI200SYN_SCA_SIZE); ramphys = pci_resource_start(pdev,3) & PCI_BASE_ADDRESS_MEM_MASK; - card->rambase = ioremap(ramphys, pci_resource_len(pdev,3)); + card->rambase = pci_ioremap_bar(pdev, 3); if (card->plxbase == NULL || card->scabase == NULL || @@ -398,7 +374,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, writew(readw(p) | 0x0040, p); /* Allocate IRQ */ - if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, devname, card)) { + if (request_irq(pdev->irq, sca_intr, IRQF_SHARED, "pci200syn", card)) { printk(KERN_WARNING "pci200syn: could not allocate IRQ%d.\n", pdev->irq); pci200_pci_remove_one(pdev); @@ -410,9 +386,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, for (i = 0; i < 2; i++) { port_t *port = &card->ports[i]; - struct net_device *dev = port_to_dev(port); + struct net_device *dev = port->netdev; hdlc_device *hdlc = dev_to_hdlc(dev); - port->phy_node = i; + port->chan = i; spin_lock_init(&port->lock); dev->irq = card->irq; @@ -426,6 +402,7 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, hdlc->xmit = sca_xmit; port->settings.clock_type = CLOCK_EXT; port->card = card; + sca_init_port(port); if (register_hdlc_device(dev)) { printk(KERN_ERR "pci200syn: unable to register hdlc " "device\n"); @@ -433,10 +410,9 @@ static int __devinit pci200_pci_init_one(struct pci_dev *pdev, pci200_pci_remove_one(pdev); return -ENOBUFS; } - sca_init_sync_port(port); /* Set up SCA memory */ - printk(KERN_INFO "%s: PCI200SYN node %d\n", - dev->name, port->phy_node); + printk(KERN_INFO "%s: PCI200SYN channel %d\n", + dev->name, port->chan); } sca_flush(card); @@ -464,9 +440,6 @@ static struct pci_driver pci200_pci_driver = { static int __init pci200_init_module(void) { -#ifdef MODULE - printk(KERN_INFO "%s\n", version); -#endif if (pci_clock_freq < 1000000 || pci_clock_freq > 80000000) { printk(KERN_ERR "pci200syn: Invalid PCI clock frequency\n"); return -EINVAL; diff --git a/drivers/net/wan/sbni.c b/drivers/net/wan/sbni.c index ee51b6a5e60569be9d955e2bb0259a5341d0f6f5..0aa28e1d436614bc98fa1954fda862d8eeec8574 100644 --- a/drivers/net/wan/sbni.c +++ b/drivers/net/wan/sbni.c @@ -186,6 +186,7 @@ static unsigned int netcard_portlist[ ] __initdata = { 0x2b0, 0x2b4, 0x2c0, 0x2c4, 0x2d0, 0x2d4, 0x2e0, 0x2e4, 0x2f0, 0x2f4, 0 }; +#define NET_LOCAL_LOCK(dev) (((struct net_local *)netdev_priv(dev))->lock) /* * Look for SBNI card which addr stored in dev->base_addr, if nonzero. @@ -287,7 +288,7 @@ static int __init sbni_init(struct net_device *dev) } -int __init +static int __init sbni_pci_probe( struct net_device *dev ) { struct pci_dev *pdev = NULL; @@ -378,22 +379,23 @@ sbni_probe1( struct net_device *dev, unsigned long ioaddr, int irq ) dev->irq = irq; dev->base_addr = ioaddr; - /* Allocate dev->priv and fill in sbni-specific dev fields. */ - nl = dev->priv; + /* Fill in sbni-specific dev fields. */ + nl = netdev_priv(dev); if( !nl ) { printk( KERN_ERR "%s: unable to get memory!\n", dev->name ); release_region( ioaddr, SBNI_IO_EXTENT ); return NULL; } - dev->priv = nl; memset( nl, 0, sizeof(struct net_local) ); spin_lock_init( &nl->lock ); /* store MAC address (generate if that isn't known) */ *(__be16 *)dev->dev_addr = htons( 0x00ff ); *(__be32 *)(dev->dev_addr + 2) = htonl( 0x01000000 | - ( (mac[num] ? mac[num] : (u32)((long)dev->priv)) & 0x00ffffff) ); + ((mac[num] ? + mac[num] : + (u32)((long)netdev_priv(dev))) & 0x00ffffff)); /* store link settings (speed, receive level ) */ nl->maxframe = DEFAULT_FRAME_LEN; @@ -447,7 +449,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) /* Looking for idle device in the list */ for( p = dev; p; ) { - struct net_local *nl = (struct net_local *) p->priv; + struct net_local *nl = netdev_priv(p); spin_lock( &nl->lock ); if( nl->tx_buf_p || (nl->state & FL_LINE_DOWN) ) { p = nl->link; @@ -469,7 +471,7 @@ sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) static int sbni_start_xmit( struct sk_buff *skb, struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); netif_stop_queue( dev ); spin_lock( &nl->lock ); @@ -503,12 +505,12 @@ static irqreturn_t sbni_interrupt( int irq, void *dev_id ) { struct net_device *dev = dev_id; - struct net_local *nl = dev->priv; + struct net_local *nl = netdev_priv(dev); int repeat; spin_lock( &nl->lock ); if( nl->second ) - spin_lock( &((struct net_local *) nl->second->priv)->lock ); + spin_lock(&NET_LOCAL_LOCK(nl->second)); do { repeat = 0; @@ -522,7 +524,7 @@ sbni_interrupt( int irq, void *dev_id ) } while( repeat ); if( nl->second ) - spin_unlock( &((struct net_local *)nl->second->priv)->lock ); + spin_unlock(&NET_LOCAL_LOCK(nl->second)); spin_unlock( &nl->lock ); return IRQ_HANDLED; } @@ -531,7 +533,7 @@ sbni_interrupt( int irq, void *dev_id ) static void handle_channel( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; int req_ans; @@ -540,7 +542,7 @@ handle_channel( struct net_device *dev ) #ifdef CONFIG_SBNI_MULTILINE /* Lock the master device because we going to change its local data */ if( nl->state & FL_SLAVE ) - spin_lock( &((struct net_local *) nl->master->priv)->lock ); + spin_lock(&NET_LOCAL_LOCK(nl->master)); #endif outb( (inb( ioaddr + CSR0 ) & ~EN_INT) | TR_REQ, ioaddr + CSR0 ); @@ -576,7 +578,7 @@ handle_channel( struct net_device *dev ) #ifdef CONFIG_SBNI_MULTILINE if( nl->state & FL_SLAVE ) - spin_unlock( &((struct net_local *) nl->master->priv)->lock ); + spin_unlock(&NET_LOCAL_LOCK(nl->master)); #endif } @@ -589,7 +591,7 @@ handle_channel( struct net_device *dev ) static int recv_frame( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u32 crc = CRC32_INITIAL; @@ -623,7 +625,7 @@ recv_frame( struct net_device *dev ) static void send_frame( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); u32 crc = CRC32_INITIAL; @@ -680,7 +682,7 @@ do_send: static void download_data( struct net_device *dev, u32 *crc_p ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct sk_buff *skb = nl->tx_buf_p; unsigned len = min_t(unsigned int, skb->len - nl->outpos, nl->framelen); @@ -699,7 +701,7 @@ static int upload_data( struct net_device *dev, unsigned framelen, unsigned frameno, unsigned is_first, u32 crc ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); int frame_ok; @@ -721,9 +723,9 @@ upload_data( struct net_device *dev, unsigned framelen, unsigned frameno, nl->wait_frameno = 0, nl->inppos = 0, #ifdef CONFIG_SBNI_MULTILINE - ((struct net_local *) nl->master->priv) + ((struct net_local *)netdev_priv(nl->master)) ->stats.rx_errors++, - ((struct net_local *) nl->master->priv) + ((struct net_local *)netdev_priv(nl->master)) ->stats.rx_missed_errors++; #else nl->stats.rx_errors++, @@ -740,8 +742,10 @@ upload_data( struct net_device *dev, unsigned framelen, unsigned frameno, */ nl->wait_frameno = 0, #ifdef CONFIG_SBNI_MULTILINE - ((struct net_local *) nl->master->priv)->stats.rx_errors++, - ((struct net_local *) nl->master->priv)->stats.rx_crc_errors++; + ((struct net_local *)netdev_priv(nl->master)) + ->stats.rx_errors++, + ((struct net_local *)netdev_priv(nl->master)) + ->stats.rx_crc_errors++; #else nl->stats.rx_errors++, nl->stats.rx_crc_errors++; @@ -755,8 +759,8 @@ static inline void send_complete( struct net_local *nl ) { #ifdef CONFIG_SBNI_MULTILINE - ((struct net_local *) nl->master->priv)->stats.tx_packets++; - ((struct net_local *) nl->master->priv)->stats.tx_bytes + ((struct net_local *)netdev_priv(nl->master))->stats.tx_packets++; + ((struct net_local *)netdev_priv(nl->master))->stats.tx_bytes += nl->tx_buf_p->len; #else nl->stats.tx_packets++; @@ -775,7 +779,7 @@ send_complete( struct net_local *nl ) static void interpret_ack( struct net_device *dev, unsigned ack ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); if( ack == FRAME_SENT_OK ) { nl->state &= ~FL_NEED_RESEND; @@ -809,7 +813,7 @@ interpret_ack( struct net_device *dev, unsigned ack ) static int append_frame_to_pkt( struct net_device *dev, unsigned framelen, u32 crc ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); u8 *p; @@ -840,7 +844,7 @@ append_frame_to_pkt( struct net_device *dev, unsigned framelen, u32 crc ) static void prepare_to_send( struct sk_buff *skb, struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); unsigned int len; @@ -871,15 +875,15 @@ prepare_to_send( struct sk_buff *skb, struct net_device *dev ) static void drop_xmit_queue( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); if( nl->tx_buf_p ) dev_kfree_skb_any( nl->tx_buf_p ), nl->tx_buf_p = NULL, #ifdef CONFIG_SBNI_MULTILINE - ((struct net_local *) nl->master->priv) + ((struct net_local *)netdev_priv(nl->master)) ->stats.tx_errors++, - ((struct net_local *) nl->master->priv) + ((struct net_local *)netdev_priv(nl->master)) ->stats.tx_carrier_errors++; #else nl->stats.tx_errors++, @@ -903,7 +907,7 @@ drop_xmit_queue( struct net_device *dev ) static void send_frame_header( struct net_device *dev, u32 *crc_p ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); u32 crc = *crc_p; u32 len_field = nl->framelen + 6; /* CRC + frameno + reserved */ @@ -1005,7 +1009,7 @@ get_rx_buf( struct net_device *dev ) static void indicate_pkt( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct sk_buff *skb = nl->rx_buf_p; skb_put( skb, nl->inppos ); @@ -1013,13 +1017,12 @@ indicate_pkt( struct net_device *dev ) #ifdef CONFIG_SBNI_MULTILINE skb->protocol = eth_type_trans( skb, nl->master ); netif_rx( skb ); - dev->last_rx = jiffies; - ++((struct net_local *) nl->master->priv)->stats.rx_packets; - ((struct net_local *) nl->master->priv)->stats.rx_bytes += nl->inppos; + ++((struct net_local *)netdev_priv(nl->master))->stats.rx_packets; + ((struct net_local *)netdev_priv(nl->master))->stats.rx_bytes += + nl->inppos; #else skb->protocol = eth_type_trans( skb, dev ); netif_rx( skb ); - dev->last_rx = jiffies; ++nl->stats.rx_packets; nl->stats.rx_bytes += nl->inppos; #endif @@ -1038,7 +1041,7 @@ static void sbni_watchdog( unsigned long arg ) { struct net_device *dev = (struct net_device *) arg; - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct timer_list *w = &nl->watchdog; unsigned long flags; unsigned char csr0; @@ -1091,7 +1094,7 @@ static unsigned char timeout_rxl_tab[] = { static void card_start( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); nl->timer_ticks = CHANGE_LEVEL_START_TICKS; nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND); @@ -1113,7 +1116,7 @@ card_start( struct net_device *dev ) static void change_level( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); if( nl->delta_rxl == 0 ) /* do not auto-negotiate RxL */ return; @@ -1137,7 +1140,7 @@ change_level( struct net_device *dev ) static void timeout_change_level( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); nl->cur_rxl_index = timeout_rxl_tab[ nl->timeout_rxl ]; if( ++nl->timeout_rxl >= 4 ) @@ -1160,7 +1163,7 @@ timeout_change_level( struct net_device *dev ) static int sbni_open( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct timer_list *w = &nl->watchdog; /* @@ -1176,7 +1179,7 @@ sbni_open( struct net_device *dev ) || (*p)->base_addr == dev->base_addr - 4) && (*p)->flags & IFF_UP ) { - ((struct net_local *) ((*p)->priv)) + ((struct net_local *) (netdev_priv(*p))) ->second = dev; printk( KERN_NOTICE "%s: using shared irq " "with %s\n", dev->name, (*p)->name ); @@ -1216,7 +1219,7 @@ handler_attached: static int sbni_close( struct net_device *dev ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); if( nl->second && nl->second->flags & IFF_UP ) { printk( KERN_NOTICE "Secondary channel (%s) is active!\n", @@ -1300,7 +1303,7 @@ sbni_card_probe( unsigned long ioaddr ) static int sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd ) { - struct net_local *nl = (struct net_local *) dev->priv; + struct net_local *nl = netdev_priv(dev); struct sbni_flags flags; int error = 0; @@ -1390,8 +1393,8 @@ sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd ) static int enslave( struct net_device *dev, struct net_device *slave_dev ) { - struct net_local *nl = (struct net_local *) dev->priv; - struct net_local *snl = (struct net_local *) slave_dev->priv; + struct net_local *nl = netdev_priv(dev); + struct net_local *snl = netdev_priv(slave_dev); if( nl->state & FL_SLAVE ) /* This isn't master or free device */ return -EBUSY; @@ -1425,9 +1428,9 @@ enslave( struct net_device *dev, struct net_device *slave_dev ) static int emancipate( struct net_device *dev ) { - struct net_local *snl = (struct net_local *) dev->priv; + struct net_local *snl = netdev_priv(dev); struct net_device *p = snl->master; - struct net_local *nl = (struct net_local *) p->priv; + struct net_local *nl = netdev_priv(p); if( !(snl->state & FL_SLAVE) ) return -EINVAL; @@ -1438,7 +1441,7 @@ emancipate( struct net_device *dev ) /* exclude from list */ for(;;) { /* must be in list */ - struct net_local *t = (struct net_local *) p->priv; + struct net_local *t = netdev_priv(p); if( t->link == dev ) { t->link = snl->link; break; @@ -1465,7 +1468,7 @@ emancipate( struct net_device *dev ) static struct net_device_stats * sbni_get_stats( struct net_device *dev ) { - return &((struct net_local *) dev->priv)->stats; + return &((struct net_local *)netdev_priv(dev))->stats; } diff --git a/drivers/net/wan/sdla.c b/drivers/net/wan/sdla.c index 73e2f278093220e4bd3f8f5094c9ab55a1d190f5..6a07ba9371dbd5b0cd257eb87c1cf11cecd7bdcd 100644 --- a/drivers/net/wan/sdla.c +++ b/drivers/net/wan/sdla.c @@ -185,7 +185,7 @@ static void sdla_stop(struct net_device *dev) { struct frad_local *flp; - flp = dev->priv; + flp = netdev_priv(dev); switch(flp->type) { case SDLA_S502A: @@ -212,7 +212,7 @@ static void sdla_start(struct net_device *dev) { struct frad_local *flp; - flp = dev->priv; + flp = netdev_priv(dev); switch(flp->type) { case SDLA_S502A: @@ -432,7 +432,7 @@ static int sdla_cmd(struct net_device *dev, int cmd, short dlci, short flags, int ret, waiting, len; long window; - flp = dev->priv; + flp = netdev_priv(dev); window = flp->type == SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF; cmd_buf = (struct sdla_cmd *)(dev->mem_start + (window & SDLA_ADDR_MASK)); ret = 0; @@ -509,7 +509,7 @@ static int sdla_activate(struct net_device *slave, struct net_device *master) struct frad_local *flp; int i; - flp = slave->priv; + flp = netdev_priv(slave); for(i=0;imaster[i] == master) @@ -531,7 +531,7 @@ static int sdla_deactivate(struct net_device *slave, struct net_device *master) struct frad_local *flp; int i; - flp = slave->priv; + flp = netdev_priv(slave); for(i=0;imaster[i] == master) @@ -556,7 +556,7 @@ static int sdla_assoc(struct net_device *slave, struct net_device *master) if (master->type != ARPHRD_DLCI) return(-EINVAL); - flp = slave->priv; + flp = netdev_priv(slave); for(i=0;ipriv; + flp = netdev_priv(slave); for(i=0;imaster[i] == master) @@ -619,7 +619,7 @@ static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, i int i; short len, ret; - flp = slave->priv; + flp = netdev_priv(slave); for(i=0;imaster[i] == master) @@ -628,7 +628,7 @@ static int sdla_dlci_conf(struct net_device *slave, struct net_device *master, i if (i == CONFIG_DLCI_MAX) return(-ENODEV); - dlp = master->priv; + dlp = netdev_priv(master); ret = SDLA_RET_OK; len = sizeof(struct dlci_conf); @@ -659,7 +659,7 @@ static int sdla_transmit(struct sk_buff *skb, struct net_device *dev) unsigned long flags; struct buf_entry *pbuf; - flp = dev->priv; + flp = netdev_priv(dev); ret = 0; accept = 1; @@ -755,7 +755,7 @@ static void sdla_receive(struct net_device *dev) int i=0, received, success, addr, buf_base, buf_top; short dlci, len, len2, split; - flp = dev->priv; + flp = netdev_priv(dev); success = 1; received = addr = buf_top = buf_base = 0; len = dlci = 0; @@ -860,7 +860,7 @@ static void sdla_receive(struct net_device *dev) if (success) { flp->stats.rx_packets++; - dlp = master->priv; + dlp = netdev_priv(master); (*dlp->receive)(skb, master); } @@ -925,7 +925,7 @@ static void sdla_poll(unsigned long device) struct frad_local *flp; dev = (struct net_device *) device; - flp = dev->priv; + flp = netdev_priv(dev); if (sdla_byte(dev, SDLA_502_RCV_BUF)) sdla_receive(dev); @@ -941,7 +941,7 @@ static int sdla_close(struct net_device *dev) int len, i; short dlcis[CONFIG_DLCI_MAX]; - flp = dev->priv; + flp = netdev_priv(dev); len = 0; for(i=0;ipriv; + flp = netdev_priv(dev); if (!flp->initialized) return(-EPERM); @@ -1079,7 +1079,7 @@ static int sdla_open(struct net_device *dev) for(i=0;idlci[i]) { - dlp = flp->master[i]->priv; + dlp = netdev_priv(flp->master[i]); if (dlp->configured) sdla_cmd(dev, SDLA_SET_DLCI_CONFIGURATION, abs(flp->dlci[i]), 0, &dlp->config, sizeof(struct dlci_conf), NULL, NULL); } @@ -1099,7 +1099,7 @@ static int sdla_config(struct net_device *dev, struct frad_conf __user *conf, in if (dev->type == 0xFFFF) return(-EUNATCH); - flp = dev->priv; + flp = netdev_priv(dev); if (!get) { @@ -1230,7 +1230,7 @@ static int sdla_reconfig(struct net_device *dev) struct conf_data data; int i, len; - flp = dev->priv; + flp = netdev_priv(dev); len = 0; for(i=0;ipriv; + flp = netdev_priv(dev); if (!flp->initialized) return(-EINVAL); @@ -1321,7 +1321,7 @@ static int sdla_change_mtu(struct net_device *dev, int new_mtu) { struct frad_local *flp; - flp = dev->priv; + flp = netdev_priv(dev); if (netif_running(dev)) return(-EBUSY); @@ -1338,7 +1338,7 @@ static int sdla_set_config(struct net_device *dev, struct ifmap *map) unsigned base; int err = -EINVAL; - flp = dev->priv; + flp = netdev_priv(dev); if (flp->initialized) return(-EINVAL); @@ -1593,14 +1593,14 @@ fail: static struct net_device_stats *sdla_stats(struct net_device *dev) { struct frad_local *flp; - flp = dev->priv; + flp = netdev_priv(dev); return(&flp->stats); } static void setup_sdla(struct net_device *dev) { - struct frad_local *flp = dev->priv; + struct frad_local *flp = netdev_priv(dev); netdev_boot_setup_check(dev); @@ -1651,7 +1651,7 @@ static int __init init_sdla(void) static void __exit exit_sdla(void) { - struct frad_local *flp = sdla->priv; + struct frad_local *flp = netdev_priv(sdla); unregister_netdev(sdla); if (flp->initialized) { diff --git a/drivers/net/wan/sealevel.c b/drivers/net/wan/sealevel.c index c0235844a4d594e5cee2b243d4105b54c0f47eb9..0941a26f6e3f9b94d794bc2f43ecce49a35290cb 100644 --- a/drivers/net/wan/sealevel.c +++ b/drivers/net/wan/sealevel.c @@ -68,7 +68,6 @@ static void sealevel_input(struct z8530_channel *c, struct sk_buff *skb) skb_reset_mac_header(skb); skb->dev = c->netdevice; netif_rx(skb); - c->netdevice->last_rx = jiffies; } /* diff --git a/drivers/net/wan/syncppp.c b/drivers/net/wan/syncppp.c deleted file mode 100644 index 6e92f7b44b1aa6d315d84898ce6a990b96ed3a0a..0000000000000000000000000000000000000000 --- a/drivers/net/wan/syncppp.c +++ /dev/null @@ -1,1480 +0,0 @@ -/* - * NET3: A (fairly minimal) implementation of synchronous PPP for Linux - * as well as a CISCO HDLC implementation. See the copyright - * message below for the original source. - * - * 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. - * - * Note however. This code is also used in a different form by FreeBSD. - * Therefore when making any non OS specific change please consider - * contributing it back to the original author under the terms - * below in addition. - * -- Alan - * - * Port for Linux-2.1 by Jan "Yenya" Kasprzak - */ - -/* - * Synchronous PPP/Cisco link level subroutines. - * Keepalive protocol implemented in both Cisco and PPP modes. - * - * Copyright (C) 1994 Cronyx Ltd. - * Author: Serge Vakulenko, - * - * This software is distributed with NO WARRANTIES, not even the implied - * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Authors grant any other persons or organisations permission to use - * or modify this software as long as this message is kept with the software, - * all derivative works or modified versions. - * - * Version 1.9, Wed Oct 4 18:58:15 MSK 1995 - * - * $Id: syncppp.c,v 1.18 2000/04/11 05:25:31 asj Exp $ - */ -#undef DEBUG - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -#define MAXALIVECNT 6 /* max. alive packets */ - -#define PPP_ALLSTATIONS 0xff /* All-Stations broadcast address */ -#define PPP_UI 0x03 /* Unnumbered Information */ -#define PPP_IP 0x0021 /* Internet Protocol */ -#define PPP_ISO 0x0023 /* ISO OSI Protocol */ -#define PPP_XNS 0x0025 /* Xerox NS Protocol */ -#define PPP_IPX 0x002b /* Novell IPX Protocol */ -#define PPP_LCP 0xc021 /* Link Control Protocol */ -#define PPP_IPCP 0x8021 /* Internet Protocol Control Protocol */ - -#define LCP_CONF_REQ 1 /* PPP LCP configure request */ -#define LCP_CONF_ACK 2 /* PPP LCP configure acknowledge */ -#define LCP_CONF_NAK 3 /* PPP LCP configure negative ack */ -#define LCP_CONF_REJ 4 /* PPP LCP configure reject */ -#define LCP_TERM_REQ 5 /* PPP LCP terminate request */ -#define LCP_TERM_ACK 6 /* PPP LCP terminate acknowledge */ -#define LCP_CODE_REJ 7 /* PPP LCP code reject */ -#define LCP_PROTO_REJ 8 /* PPP LCP protocol reject */ -#define LCP_ECHO_REQ 9 /* PPP LCP echo request */ -#define LCP_ECHO_REPLY 10 /* PPP LCP echo reply */ -#define LCP_DISC_REQ 11 /* PPP LCP discard request */ - -#define LCP_OPT_MRU 1 /* maximum receive unit */ -#define LCP_OPT_ASYNC_MAP 2 /* async control character map */ -#define LCP_OPT_AUTH_PROTO 3 /* authentication protocol */ -#define LCP_OPT_QUAL_PROTO 4 /* quality protocol */ -#define LCP_OPT_MAGIC 5 /* magic number */ -#define LCP_OPT_RESERVED 6 /* reserved */ -#define LCP_OPT_PROTO_COMP 7 /* protocol field compression */ -#define LCP_OPT_ADDR_COMP 8 /* address/control field compression */ - -#define IPCP_CONF_REQ LCP_CONF_REQ /* PPP IPCP configure request */ -#define IPCP_CONF_ACK LCP_CONF_ACK /* PPP IPCP configure acknowledge */ -#define IPCP_CONF_NAK LCP_CONF_NAK /* PPP IPCP configure negative ack */ -#define IPCP_CONF_REJ LCP_CONF_REJ /* PPP IPCP configure reject */ -#define IPCP_TERM_REQ LCP_TERM_REQ /* PPP IPCP terminate request */ -#define IPCP_TERM_ACK LCP_TERM_ACK /* PPP IPCP terminate acknowledge */ -#define IPCP_CODE_REJ LCP_CODE_REJ /* PPP IPCP code reject */ - -#define CISCO_MULTICAST 0x8f /* Cisco multicast address */ -#define CISCO_UNICAST 0x0f /* Cisco unicast address */ -#define CISCO_KEEPALIVE 0x8035 /* Cisco keepalive protocol */ -#define CISCO_ADDR_REQ 0 /* Cisco address request */ -#define CISCO_ADDR_REPLY 1 /* Cisco address reply */ -#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */ - -struct ppp_header { - u8 address; - u8 control; - __be16 protocol; -}; -#define PPP_HEADER_LEN sizeof (struct ppp_header) - -struct lcp_header { - u8 type; - u8 ident; - __be16 len; -}; -#define LCP_HEADER_LEN sizeof (struct lcp_header) - -struct cisco_packet { - __be32 type; - __be32 par1; - __be32 par2; - __be16 rel; - __be16 time0; - __be16 time1; -}; -#define CISCO_PACKET_LEN 18 -#define CISCO_BIG_PACKET_LEN 20 - -static struct sppp *spppq; -static struct timer_list sppp_keepalive_timer; -static DEFINE_SPINLOCK(spppq_lock); - -/* global xmit queue for sending packets while spinlock is held */ -static struct sk_buff_head tx_queue; - -static void sppp_keepalive (unsigned long dummy); -static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, - u8 ident, u16 len, void *data); -static void sppp_cisco_send (struct sppp *sp, int type, u32 par1, u32 par2); -static void sppp_lcp_input (struct sppp *sp, struct sk_buff *m); -static void sppp_cisco_input (struct sppp *sp, struct sk_buff *m); -static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *m); -static void sppp_lcp_open (struct sppp *sp); -static void sppp_ipcp_open (struct sppp *sp); -static int sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, - int len, u32 *magic); -static void sppp_cp_timeout (unsigned long arg); -static char *sppp_lcp_type_name (u8 type); -static char *sppp_ipcp_type_name (u8 type); -static void sppp_print_bytes (u8 *p, u16 len); - -static int debug; - -/* Flush global outgoing packet queue to dev_queue_xmit(). - * - * dev_queue_xmit() must be called with interrupts enabled - * which means it can't be called with spinlocks held. - * If a packet needs to be sent while a spinlock is held, - * then put the packet into tx_queue, and call sppp_flush_xmit() - * after spinlock is released. - */ -static void sppp_flush_xmit(void) -{ - struct sk_buff *skb; - while ((skb = skb_dequeue(&tx_queue)) != NULL) - dev_queue_xmit(skb); -} - -/* - * Interface down stub - */ - -static void if_down(struct net_device *dev) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - - sp->pp_link_state=SPPP_LINK_DOWN; -} - -/* - * Timeout routine activations. - */ - -static void sppp_set_timeout(struct sppp *p,int s) -{ - if (! (p->pp_flags & PP_TIMO)) - { - init_timer(&p->pp_timer); - p->pp_timer.function=sppp_cp_timeout; - p->pp_timer.expires=jiffies+s*HZ; - p->pp_timer.data=(unsigned long)p; - p->pp_flags |= PP_TIMO; - add_timer(&p->pp_timer); - } -} - -static void sppp_clear_timeout(struct sppp *p) -{ - if (p->pp_flags & PP_TIMO) - { - del_timer(&p->pp_timer); - p->pp_flags &= ~PP_TIMO; - } -} - -/** - * sppp_input - receive and process a WAN PPP frame - * @skb: The buffer to process - * @dev: The device it arrived on - * - * This can be called directly by cards that do not have - * timing constraints but is normally called from the network layer - * after interrupt servicing to process frames queued via netif_rx(). - * - * We process the options in the card. If the frame is destined for - * the protocol stacks then it requeues the frame for the upper level - * protocol. If it is a control from it is processed and discarded - * here. - */ - -static void sppp_input (struct net_device *dev, struct sk_buff *skb) -{ - struct ppp_header *h; - struct sppp *sp = (struct sppp *)sppp_of(dev); - unsigned long flags; - - skb->dev=dev; - skb_reset_mac_header(skb); - - if (!pskb_may_pull(skb, PPP_HEADER_LEN)) { - /* Too small packet, drop it. */ - if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG "%s: input packet is too small, %d bytes\n", - dev->name, skb->len); - kfree_skb(skb); - return; - } - - /* Get PPP header. */ - h = (struct ppp_header *)skb->data; - skb_pull(skb,sizeof(struct ppp_header)); - - spin_lock_irqsave(&sp->lock, flags); - - switch (h->address) { - default: /* Invalid PPP packet. */ - goto invalid; - case PPP_ALLSTATIONS: - if (h->control != PPP_UI) - goto invalid; - if (sp->pp_flags & PP_CISCO) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: PPP packet in Cisco mode <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; - } - switch (ntohs (h->protocol)) { - default: - if (sp->lcp.state == LCP_STATE_OPENED) - sppp_cp_send (sp, PPP_LCP, LCP_PROTO_REJ, - ++sp->pp_seq, skb->len + 2, - &h->protocol); - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid input protocol <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; - case PPP_LCP: - sppp_lcp_input (sp, skb); - goto drop; - case PPP_IPCP: - if (sp->lcp.state == LCP_STATE_OPENED) - sppp_ipcp_input (sp, skb); - else - printk(KERN_DEBUG "IPCP when still waiting LCP finish.\n"); - goto drop; - case PPP_IP: - if (sp->ipcp.state == IPCP_STATE_OPENED) { - if(sp->pp_flags&PP_DEBUG) - printk(KERN_DEBUG "Yow an IP frame.\n"); - skb->protocol=htons(ETH_P_IP); - netif_rx(skb); - dev->last_rx = jiffies; - goto done; - } - break; -#ifdef IPX - case PPP_IPX: - /* IPX IPXCP not implemented yet */ - if (sp->lcp.state == LCP_STATE_OPENED) { - skb->protocol=htons(ETH_P_IPX); - netif_rx(skb); - dev->last_rx = jiffies; - goto done; - } - break; -#endif - } - break; - case CISCO_MULTICAST: - case CISCO_UNICAST: - /* Don't check the control field here (RFC 1547). */ - if (! (sp->pp_flags & PP_CISCO)) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: Cisco packet in PPP mode <0x%x 0x%x 0x%x>\n", - dev->name, - h->address, h->control, ntohs (h->protocol)); - goto drop; - } - switch (ntohs (h->protocol)) { - default: - goto invalid; - case CISCO_KEEPALIVE: - sppp_cisco_input (sp, skb); - goto drop; -#ifdef CONFIG_INET - case ETH_P_IP: - skb->protocol=htons(ETH_P_IP); - netif_rx(skb); - dev->last_rx = jiffies; - goto done; -#endif -#ifdef CONFIG_IPX - case ETH_P_IPX: - skb->protocol=htons(ETH_P_IPX); - netif_rx(skb); - dev->last_rx = jiffies; - goto done; -#endif - } - break; - } - goto drop; - -invalid: - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid input packet <0x%x 0x%x 0x%x>\n", - dev->name, h->address, h->control, ntohs (h->protocol)); -drop: - kfree_skb(skb); -done: - spin_unlock_irqrestore(&sp->lock, flags); - sppp_flush_xmit(); - return; -} - -/* - * Handle transmit packets. - */ - -static int sppp_hard_header(struct sk_buff *skb, - struct net_device *dev, __u16 type, - const void *daddr, const void *saddr, - unsigned int len) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - struct ppp_header *h; - skb_push(skb,sizeof(struct ppp_header)); - h=(struct ppp_header *)skb->data; - if(sp->pp_flags&PP_CISCO) - { - h->address = CISCO_UNICAST; - h->control = 0; - } - else - { - h->address = PPP_ALLSTATIONS; - h->control = PPP_UI; - } - if(sp->pp_flags & PP_CISCO) - { - h->protocol = htons(type); - } - else switch(type) - { - case ETH_P_IP: - h->protocol = htons(PPP_IP); - break; - case ETH_P_IPX: - h->protocol = htons(PPP_IPX); - break; - } - return sizeof(struct ppp_header); -} - -static const struct header_ops sppp_header_ops = { - .create = sppp_hard_header, -}; - -/* - * Send keepalive packets, every 10 seconds. - */ - -static void sppp_keepalive (unsigned long dummy) -{ - struct sppp *sp; - unsigned long flags; - - spin_lock_irqsave(&spppq_lock, flags); - - for (sp=spppq; sp; sp=sp->pp_next) - { - struct net_device *dev = sp->pp_if; - - /* Keepalive mode disabled or channel down? */ - if (! (sp->pp_flags & PP_KEEPALIVE) || - ! (dev->flags & IFF_UP)) - continue; - - spin_lock(&sp->lock); - - /* No keepalive in PPP mode if LCP not opened yet. */ - if (! (sp->pp_flags & PP_CISCO) && - sp->lcp.state != LCP_STATE_OPENED) { - spin_unlock(&sp->lock); - continue; - } - - if (sp->pp_alivecnt == MAXALIVECNT) { - /* No keepalive packets got. Stop the interface. */ - printk (KERN_WARNING "%s: protocol down\n", dev->name); - if_down (dev); - if (! (sp->pp_flags & PP_CISCO)) { - /* Shut down the PPP link. */ - sp->lcp.magic = jiffies; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sppp_clear_timeout (sp); - /* Initiate negotiation. */ - sppp_lcp_open (sp); - } - } - if (sp->pp_alivecnt <= MAXALIVECNT) - ++sp->pp_alivecnt; - if (sp->pp_flags & PP_CISCO) - sppp_cisco_send (sp, CISCO_KEEPALIVE_REQ, ++sp->pp_seq, - sp->pp_rseq); - else if (sp->lcp.state == LCP_STATE_OPENED) { - __be32 nmagic = htonl (sp->lcp.magic); - sp->lcp.echoid = ++sp->pp_seq; - sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REQ, - sp->lcp.echoid, 4, &nmagic); - } - - spin_unlock(&sp->lock); - } - spin_unlock_irqrestore(&spppq_lock, flags); - sppp_flush_xmit(); - sppp_keepalive_timer.expires=jiffies+10*HZ; - add_timer(&sppp_keepalive_timer); -} - -/* - * Handle incoming PPP Link Control Protocol packets. - */ - -static void sppp_lcp_input (struct sppp *sp, struct sk_buff *skb) -{ - struct lcp_header *h; - struct net_device *dev = sp->pp_if; - int len = skb->len; - u8 *p, opt[6]; - u32 rmagic = 0; - - if (!pskb_may_pull(skb, sizeof(struct lcp_header))) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid lcp packet length: %d bytes\n", - dev->name, len); - return; - } - h = (struct lcp_header *)skb->data; - skb_pull(skb,sizeof(struct lcp_header *)); - - if (sp->pp_flags & PP_DEBUG) - { - char state = '?'; - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: state = 'C'; break; - case LCP_STATE_ACK_RCVD: state = 'R'; break; - case LCP_STATE_ACK_SENT: state = 'S'; break; - case LCP_STATE_OPENED: state = 'O'; break; - } - printk (KERN_WARNING "%s: lcp input(%c): %d bytes <%s id=%xh len=%xh", - dev->name, state, len, - sppp_lcp_type_name (h->type), h->ident, ntohs (h->len)); - if (len > 4) - sppp_print_bytes ((u8*) (h+1), len-4); - printk (">\n"); - } - if (len > ntohs (h->len)) - len = ntohs (h->len); - switch (h->type) { - default: - /* Unknown packet type -- send Code-Reject packet. */ - sppp_cp_send (sp, PPP_LCP, LCP_CODE_REJ, ++sp->pp_seq, - skb->len, h); - break; - case LCP_CONF_REQ: - if (len < 4) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG"%s: invalid lcp configure request packet length: %d bytes\n", - dev->name, len); - break; - } - if (len>4 && !sppp_lcp_conf_parse_options (sp, h, len, &rmagic)) - goto badreq; - if (rmagic == sp->lcp.magic) { - /* Local and remote magics equal -- loopback? */ - if (sp->pp_loopcnt >= MAXALIVECNT*5) { - printk (KERN_WARNING "%s: loopback\n", - dev->name); - sp->pp_loopcnt = 0; - if (dev->flags & IFF_UP) { - if_down (dev); - } - } else if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG "%s: conf req: magic glitch\n", - dev->name); - ++sp->pp_loopcnt; - - /* MUST send Conf-Nack packet. */ - rmagic = ~sp->lcp.magic; - opt[0] = LCP_OPT_MAGIC; - opt[1] = sizeof (opt); - opt[2] = rmagic >> 24; - opt[3] = rmagic >> 16; - opt[4] = rmagic >> 8; - opt[5] = rmagic; - sppp_cp_send (sp, PPP_LCP, LCP_CONF_NAK, - h->ident, sizeof (opt), &opt); -badreq: - switch (sp->lcp.state) { - case LCP_STATE_OPENED: - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - /* fall through... */ - case LCP_STATE_ACK_SENT: - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - } - break; - } - /* Send Configure-Ack packet. */ - sp->pp_loopcnt = 0; - if (sp->lcp.state != LCP_STATE_OPENED) { - sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, - h->ident, len-4, h+1); - } - /* Change the state. */ - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: - sp->lcp.state = LCP_STATE_ACK_SENT; - break; - case LCP_STATE_ACK_RCVD: - sp->lcp.state = LCP_STATE_OPENED; - sppp_ipcp_open (sp); - break; - case LCP_STATE_OPENED: - /* Remote magic changed -- close session. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - /* Send ACK after our REQ in attempt to break loop */ - sppp_cp_send (sp, PPP_LCP, LCP_CONF_ACK, - h->ident, len-4, h+1); - sp->lcp.state = LCP_STATE_ACK_SENT; - break; - } - break; - case LCP_CONF_ACK: - if (h->ident != sp->lcp.confid) - break; - sppp_clear_timeout (sp); - if ((sp->pp_link_state != SPPP_LINK_UP) && - (dev->flags & IFF_UP)) { - /* Coming out of loopback mode. */ - sp->pp_link_state=SPPP_LINK_UP; - printk (KERN_INFO "%s: protocol up\n", dev->name); - } - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: - sp->lcp.state = LCP_STATE_ACK_RCVD; - sppp_set_timeout (sp, 5); - break; - case LCP_STATE_ACK_SENT: - sp->lcp.state = LCP_STATE_OPENED; - sppp_ipcp_open (sp); - break; - } - break; - case LCP_CONF_NAK: - if (h->ident != sp->lcp.confid) - break; - p = (u8*) (h+1); - if (len>=10 && p[0] == LCP_OPT_MAGIC && p[1] >= 4) { - rmagic = (u32)p[2] << 24 | - (u32)p[3] << 16 | p[4] << 8 | p[5]; - if (rmagic == ~sp->lcp.magic) { - int newmagic; - if (sp->pp_flags & PP_DEBUG) - printk (KERN_DEBUG "%s: conf nak: magic glitch\n", - dev->name); - get_random_bytes(&newmagic, sizeof(newmagic)); - sp->lcp.magic += newmagic; - } else - sp->lcp.magic = rmagic; - } - if (sp->lcp.state != LCP_STATE_ACK_SENT) { - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - } - /* The link will be renegotiated after timeout, - * to avoid endless req-nack loop. */ - sppp_clear_timeout (sp); - sppp_set_timeout (sp, 2); - break; - case LCP_CONF_REJ: - if (h->ident != sp->lcp.confid) - break; - sppp_clear_timeout (sp); - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - if (sp->lcp.state != LCP_STATE_ACK_SENT) { - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - } - break; - case LCP_TERM_REQ: - sppp_clear_timeout (sp); - /* Send Terminate-Ack packet. */ - sppp_cp_send (sp, PPP_LCP, LCP_TERM_ACK, h->ident, 0, NULL); - /* Go to closed state. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Initiate renegotiation. */ - sppp_lcp_open (sp); - break; - case LCP_TERM_ACK: - case LCP_CODE_REJ: - case LCP_PROTO_REJ: - /* Ignore for now. */ - break; - case LCP_DISC_REQ: - /* Discard the packet. */ - break; - case LCP_ECHO_REQ: - if (sp->lcp.state != LCP_STATE_OPENED) - break; - if (len < 8) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid lcp echo request packet length: %d bytes\n", - dev->name, len); - break; - } - if (ntohl (*(__be32*)(h+1)) == sp->lcp.magic) { - /* Line loopback mode detected. */ - printk (KERN_WARNING "%s: loopback\n", dev->name); - if_down (dev); - - /* Shut down the PPP link. */ - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sppp_clear_timeout (sp); - /* Initiate negotiation. */ - sppp_lcp_open (sp); - break; - } - *(__be32 *)(h+1) = htonl (sp->lcp.magic); - sppp_cp_send (sp, PPP_LCP, LCP_ECHO_REPLY, h->ident, len-4, h+1); - break; - case LCP_ECHO_REPLY: - if (h->ident != sp->lcp.echoid) - break; - if (len < 8) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid lcp echo reply packet length: %d bytes\n", - dev->name, len); - break; - } - if (ntohl(*(__be32 *)(h+1)) != sp->lcp.magic) - sp->pp_alivecnt = 0; - break; - } -} - -/* - * Handle incoming Cisco keepalive protocol packets. - */ - -static void sppp_cisco_input (struct sppp *sp, struct sk_buff *skb) -{ - struct cisco_packet *h; - struct net_device *dev = sp->pp_if; - - if (!pskb_may_pull(skb, sizeof(struct cisco_packet)) - || (skb->len != CISCO_PACKET_LEN - && skb->len != CISCO_BIG_PACKET_LEN)) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid cisco packet length: %d bytes\n", - dev->name, skb->len); - return; - } - h = (struct cisco_packet *)skb->data; - skb_pull(skb, sizeof(struct cisco_packet*)); - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: cisco input: %d bytes <%xh %xh %xh %xh %xh-%xh>\n", - dev->name, skb->len, - ntohl (h->type), h->par1, h->par2, h->rel, - h->time0, h->time1); - switch (ntohl (h->type)) { - default: - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: unknown cisco packet type: 0x%x\n", - dev->name, ntohl (h->type)); - break; - case CISCO_ADDR_REPLY: - /* Reply on address request, ignore */ - break; - case CISCO_KEEPALIVE_REQ: - sp->pp_alivecnt = 0; - sp->pp_rseq = ntohl (h->par1); - if (sp->pp_seq == sp->pp_rseq) { - /* Local and remote sequence numbers are equal. - * Probably, the line is in loopback mode. */ - int newseq; - if (sp->pp_loopcnt >= MAXALIVECNT) { - printk (KERN_WARNING "%s: loopback\n", - dev->name); - sp->pp_loopcnt = 0; - if (dev->flags & IFF_UP) { - if_down (dev); - } - } - ++sp->pp_loopcnt; - - /* Generate new local sequence number */ - get_random_bytes(&newseq, sizeof(newseq)); - sp->pp_seq ^= newseq; - break; - } - sp->pp_loopcnt = 0; - if (sp->pp_link_state==SPPP_LINK_DOWN && - (dev->flags & IFF_UP)) { - sp->pp_link_state=SPPP_LINK_UP; - printk (KERN_INFO "%s: protocol up\n", dev->name); - } - break; - case CISCO_ADDR_REQ: - /* Stolen from net/ipv4/devinet.c -- SIOCGIFADDR ioctl */ - { - __be32 addr = 0, mask = htonl(~0U); /* FIXME: is the mask correct? */ -#ifdef CONFIG_INET - struct in_device *in_dev; - struct in_ifaddr *ifa; - - rcu_read_lock(); - if ((in_dev = __in_dev_get_rcu(dev)) != NULL) - { - for (ifa=in_dev->ifa_list; ifa != NULL; - ifa=ifa->ifa_next) { - if (strcmp(dev->name, ifa->ifa_label) == 0) - { - addr = ifa->ifa_local; - mask = ifa->ifa_mask; - break; - } - } - } - rcu_read_unlock(); -#endif - sppp_cisco_send (sp, CISCO_ADDR_REPLY, ntohl(addr), ntohl(mask)); - break; - } - } -} - - -/* - * Send PPP LCP packet. - */ - -static void sppp_cp_send (struct sppp *sp, u16 proto, u8 type, - u8 ident, u16 len, void *data) -{ - struct ppp_header *h; - struct lcp_header *lh; - struct sk_buff *skb; - struct net_device *dev = sp->pp_if; - - skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+LCP_HEADER_LEN+len, - GFP_ATOMIC); - if (skb==NULL) - return; - - skb_reserve(skb,dev->hard_header_len); - - h = (struct ppp_header *)skb_put(skb, sizeof(struct ppp_header)); - h->address = PPP_ALLSTATIONS; /* broadcast address */ - h->control = PPP_UI; /* Unnumbered Info */ - h->protocol = htons (proto); /* Link Control Protocol */ - - lh = (struct lcp_header *)skb_put(skb, sizeof(struct lcp_header)); - lh->type = type; - lh->ident = ident; - lh->len = htons (LCP_HEADER_LEN + len); - - if (len) - memcpy(skb_put(skb,len),data, len); - - if (sp->pp_flags & PP_DEBUG) { - printk (KERN_WARNING "%s: %s output <%s id=%xh len=%xh", - dev->name, - proto==PPP_LCP ? "lcp" : "ipcp", - proto==PPP_LCP ? sppp_lcp_type_name (lh->type) : - sppp_ipcp_type_name (lh->type), lh->ident, - ntohs (lh->len)); - if (len) - sppp_print_bytes ((u8*) (lh+1), len); - printk (">\n"); - } - /* Control is high priority so it doesn't get queued behind data */ - skb->priority=TC_PRIO_CONTROL; - skb->dev = dev; - skb_queue_tail(&tx_queue, skb); -} - -/* - * Send Cisco keepalive packet. - */ - -static void sppp_cisco_send (struct sppp *sp, int type, u32 par1, u32 par2) -{ - struct ppp_header *h; - struct cisco_packet *ch; - struct sk_buff *skb; - struct net_device *dev = sp->pp_if; - u32 t = jiffies * 1000/HZ; - - skb=alloc_skb(dev->hard_header_len+PPP_HEADER_LEN+CISCO_PACKET_LEN, - GFP_ATOMIC); - - if(skb==NULL) - return; - - skb_reserve(skb, dev->hard_header_len); - h = (struct ppp_header *)skb_put (skb, sizeof(struct ppp_header)); - h->address = CISCO_MULTICAST; - h->control = 0; - h->protocol = htons (CISCO_KEEPALIVE); - - ch = (struct cisco_packet*)skb_put(skb, CISCO_PACKET_LEN); - ch->type = htonl (type); - ch->par1 = htonl (par1); - ch->par2 = htonl (par2); - ch->rel = htons(0xffff); - ch->time0 = htons ((u16) (t >> 16)); - ch->time1 = htons ((u16) t); - - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: cisco output: <%xh %xh %xh %xh %xh-%xh>\n", - dev->name, ntohl (ch->type), ch->par1, - ch->par2, ch->rel, ch->time0, ch->time1); - skb->priority=TC_PRIO_CONTROL; - skb->dev = dev; - skb_queue_tail(&tx_queue, skb); -} - -/** - * sppp_close - close down a synchronous PPP or Cisco HDLC link - * @dev: The network device to drop the link of - * - * This drops the logical interface to the channel. It is not - * done politely as we assume we will also be dropping DTR. Any - * timeouts are killed. - */ - -int sppp_close (struct net_device *dev) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - unsigned long flags; - - spin_lock_irqsave(&sp->lock, flags); - sp->pp_link_state = SPPP_LINK_DOWN; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sppp_clear_timeout (sp); - spin_unlock_irqrestore(&sp->lock, flags); - - return 0; -} - -EXPORT_SYMBOL(sppp_close); - -/** - * sppp_open - open a synchronous PPP or Cisco HDLC link - * @dev: Network device to activate - * - * Close down any existing synchronous session and commence - * from scratch. In the PPP case this means negotiating LCP/IPCP - * and friends, while for Cisco HDLC we simply need to start sending - * keepalives - */ - -int sppp_open (struct net_device *dev) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - unsigned long flags; - - sppp_close(dev); - - spin_lock_irqsave(&sp->lock, flags); - if (!(sp->pp_flags & PP_CISCO)) { - sppp_lcp_open (sp); - } - sp->pp_link_state = SPPP_LINK_DOWN; - spin_unlock_irqrestore(&sp->lock, flags); - sppp_flush_xmit(); - - return 0; -} - -EXPORT_SYMBOL(sppp_open); - -/** - * sppp_reopen - notify of physical link loss - * @dev: Device that lost the link - * - * This function informs the synchronous protocol code that - * the underlying link died (for example a carrier drop on X.21) - * - * We increment the magic numbers to ensure that if the other end - * failed to notice we will correctly start a new session. It happens - * do to the nature of telco circuits is that you can lose carrier on - * one endonly. - * - * Having done this we go back to negotiating. This function may - * be called from an interrupt context. - */ - -int sppp_reopen (struct net_device *dev) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - unsigned long flags; - - sppp_close(dev); - - spin_lock_irqsave(&sp->lock, flags); - if (!(sp->pp_flags & PP_CISCO)) - { - sp->lcp.magic = jiffies; - ++sp->pp_seq; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Give it a moment for the line to settle then go */ - sppp_set_timeout (sp, 1); - } - sp->pp_link_state=SPPP_LINK_DOWN; - spin_unlock_irqrestore(&sp->lock, flags); - - return 0; -} - -EXPORT_SYMBOL(sppp_reopen); - -/** - * sppp_change_mtu - Change the link MTU - * @dev: Device to change MTU on - * @new_mtu: New MTU - * - * Change the MTU on the link. This can only be called with - * the link down. It returns an error if the link is up or - * the mtu is out of range. - */ - -static int sppp_change_mtu(struct net_device *dev, int new_mtu) -{ - if(new_mtu<128||new_mtu>PPP_MTU||(dev->flags&IFF_UP)) - return -EINVAL; - dev->mtu=new_mtu; - return 0; -} - -/** - * sppp_do_ioctl - Ioctl handler for ppp/hdlc - * @dev: Device subject to ioctl - * @ifr: Interface request block from the user - * @cmd: Command that is being issued - * - * This function handles the ioctls that may be issued by the user - * to control the settings of a PPP/HDLC link. It does both busy - * and security checks. This function is intended to be wrapped by - * callers who wish to add additional ioctl calls of their own. - */ - -int sppp_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) -{ - struct sppp *sp = (struct sppp *)sppp_of(dev); - - if(dev->flags&IFF_UP) - return -EBUSY; - - if(!capable(CAP_NET_ADMIN)) - return -EPERM; - - switch(cmd) - { - case SPPPIOCCISCO: - sp->pp_flags|=PP_CISCO; - dev->type = ARPHRD_HDLC; - break; - case SPPPIOCPPP: - sp->pp_flags&=~PP_CISCO; - dev->type = ARPHRD_PPP; - break; - case SPPPIOCDEBUG: - sp->pp_flags&=~PP_DEBUG; - if(ifr->ifr_flags) - sp->pp_flags|=PP_DEBUG; - break; - case SPPPIOCGFLAGS: - if(copy_to_user(ifr->ifr_data, &sp->pp_flags, sizeof(sp->pp_flags))) - return -EFAULT; - break; - case SPPPIOCSFLAGS: - if(copy_from_user(&sp->pp_flags, ifr->ifr_data, sizeof(sp->pp_flags))) - return -EFAULT; - break; - default: - return -EINVAL; - } - return 0; -} - -EXPORT_SYMBOL(sppp_do_ioctl); - -/** - * sppp_attach - attach synchronous PPP/HDLC to a device - * @pd: PPP device to initialise - * - * This initialises the PPP/HDLC support on an interface. At the - * time of calling the dev element must point to the network device - * that this interface is attached to. The interface should not yet - * be registered. - */ - -void sppp_attach(struct ppp_device *pd) -{ - struct net_device *dev = pd->dev; - struct sppp *sp = &pd->sppp; - unsigned long flags; - - /* Make sure embedding is safe for sppp_of */ - BUG_ON(sppp_of(dev) != sp); - - spin_lock_irqsave(&spppq_lock, flags); - /* Initialize keepalive handler. */ - if (! spppq) - { - init_timer(&sppp_keepalive_timer); - sppp_keepalive_timer.expires=jiffies+10*HZ; - sppp_keepalive_timer.function=sppp_keepalive; - add_timer(&sppp_keepalive_timer); - } - /* Insert new entry into the keepalive list. */ - sp->pp_next = spppq; - spppq = sp; - spin_unlock_irqrestore(&spppq_lock, flags); - - sp->pp_loopcnt = 0; - sp->pp_alivecnt = 0; - sp->pp_seq = 0; - sp->pp_rseq = 0; - sp->pp_flags = PP_KEEPALIVE|PP_CISCO|debug;/*PP_DEBUG;*/ - sp->lcp.magic = 0; - sp->lcp.state = LCP_STATE_CLOSED; - sp->ipcp.state = IPCP_STATE_CLOSED; - sp->pp_if = dev; - spin_lock_init(&sp->lock); - - /* - * Device specific setup. All but interrupt handler and - * hard_start_xmit. - */ - - dev->header_ops = &sppp_header_ops; - - dev->tx_queue_len = 10; - dev->type = ARPHRD_HDLC; - dev->addr_len = 0; - dev->hard_header_len = sizeof(struct ppp_header); - dev->mtu = PPP_MTU; - /* - * These 4 are callers but MUST also call sppp_ functions - */ - dev->do_ioctl = sppp_do_ioctl; -#if 0 - dev->get_stats = NULL; /* Let the driver override these */ - dev->open = sppp_open; - dev->stop = sppp_close; -#endif - dev->change_mtu = sppp_change_mtu; - dev->flags = IFF_MULTICAST|IFF_POINTOPOINT|IFF_NOARP; -} - -EXPORT_SYMBOL(sppp_attach); - -/** - * sppp_detach - release PPP resources from a device - * @dev: Network device to release - * - * Stop and free up any PPP/HDLC resources used by this - * interface. This must be called before the device is - * freed. - */ - -void sppp_detach (struct net_device *dev) -{ - struct sppp **q, *p, *sp = (struct sppp *)sppp_of(dev); - unsigned long flags; - - spin_lock_irqsave(&spppq_lock, flags); - /* Remove the entry from the keepalive list. */ - for (q = &spppq; (p = *q); q = &p->pp_next) - if (p == sp) { - *q = p->pp_next; - break; - } - - /* Stop keepalive handler. */ - if (! spppq) - del_timer(&sppp_keepalive_timer); - sppp_clear_timeout (sp); - spin_unlock_irqrestore(&spppq_lock, flags); -} - -EXPORT_SYMBOL(sppp_detach); - -/* - * Analyze the LCP Configure-Request options list - * for the presence of unknown options. - * If the request contains unknown options, build and - * send Configure-reject packet, containing only unknown options. - */ -static int -sppp_lcp_conf_parse_options (struct sppp *sp, struct lcp_header *h, - int len, u32 *magic) -{ - u8 *buf, *r, *p; - int rlen; - - len -= 4; - buf = r = kmalloc (len, GFP_ATOMIC); - if (! buf) - return (0); - - p = (void*) (h+1); - for (rlen=0; len>1 && p[1]; len-=p[1], p+=p[1]) { - switch (*p) { - case LCP_OPT_MAGIC: - /* Magic number -- extract. */ - if (len >= 6 && p[1] == 6) { - *magic = (u32)p[2] << 24 | - (u32)p[3] << 16 | p[4] << 8 | p[5]; - continue; - } - break; - case LCP_OPT_ASYNC_MAP: - /* Async control character map -- check to be zero. */ - if (len >= 6 && p[1] == 6 && ! p[2] && ! p[3] && - ! p[4] && ! p[5]) - continue; - break; - case LCP_OPT_MRU: - /* Maximum receive unit -- always OK. */ - continue; - default: - /* Others not supported. */ - break; - } - /* Add the option to rejected list. */ - memcpy(r, p, p[1]); - r += p[1]; - rlen += p[1]; - } - if (rlen) - sppp_cp_send (sp, PPP_LCP, LCP_CONF_REJ, h->ident, rlen, buf); - kfree(buf); - return (rlen == 0); -} - -static void sppp_ipcp_input (struct sppp *sp, struct sk_buff *skb) -{ - struct lcp_header *h; - struct net_device *dev = sp->pp_if; - int len = skb->len; - - if (!pskb_may_pull(skb, sizeof(struct lcp_header))) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid ipcp packet length: %d bytes\n", - dev->name, len); - return; - } - h = (struct lcp_header *)skb->data; - skb_pull(skb,sizeof(struct lcp_header)); - if (sp->pp_flags & PP_DEBUG) { - printk (KERN_WARNING "%s: ipcp input: %d bytes <%s id=%xh len=%xh", - dev->name, len, - sppp_ipcp_type_name (h->type), h->ident, ntohs (h->len)); - if (len > 4) - sppp_print_bytes ((u8*) (h+1), len-4); - printk (">\n"); - } - if (len > ntohs (h->len)) - len = ntohs (h->len); - switch (h->type) { - default: - /* Unknown packet type -- send Code-Reject packet. */ - sppp_cp_send (sp, PPP_IPCP, IPCP_CODE_REJ, ++sp->pp_seq, len, h); - break; - case IPCP_CONF_REQ: - if (len < 4) { - if (sp->pp_flags & PP_DEBUG) - printk (KERN_WARNING "%s: invalid ipcp configure request packet length: %d bytes\n", - dev->name, len); - return; - } - if (len > 4) { - sppp_cp_send (sp, PPP_IPCP, LCP_CONF_REJ, h->ident, - len-4, h+1); - - switch (sp->ipcp.state) { - case IPCP_STATE_OPENED: - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - /* fall through... */ - case IPCP_STATE_ACK_SENT: - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; - } - } else { - /* Send Configure-Ack packet. */ - sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_ACK, h->ident, - 0, NULL); - /* Change the state. */ - if (sp->ipcp.state == IPCP_STATE_ACK_RCVD) - sp->ipcp.state = IPCP_STATE_OPENED; - else - sp->ipcp.state = IPCP_STATE_ACK_SENT; - } - break; - case IPCP_CONF_ACK: - if (h->ident != sp->ipcp.confid) - break; - sppp_clear_timeout (sp); - switch (sp->ipcp.state) { - case IPCP_STATE_CLOSED: - sp->ipcp.state = IPCP_STATE_ACK_RCVD; - sppp_set_timeout (sp, 5); - break; - case IPCP_STATE_ACK_SENT: - sp->ipcp.state = IPCP_STATE_OPENED; - break; - } - break; - case IPCP_CONF_NAK: - case IPCP_CONF_REJ: - if (h->ident != sp->ipcp.confid) - break; - sppp_clear_timeout (sp); - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - if (sp->ipcp.state != IPCP_STATE_ACK_SENT) - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; - break; - case IPCP_TERM_REQ: - /* Send Terminate-Ack packet. */ - sppp_cp_send (sp, PPP_IPCP, IPCP_TERM_ACK, h->ident, 0, NULL); - /* Go to closed state. */ - sp->ipcp.state = IPCP_STATE_CLOSED; - /* Initiate renegotiation. */ - sppp_ipcp_open (sp); - break; - case IPCP_TERM_ACK: - /* Ignore for now. */ - case IPCP_CODE_REJ: - /* Ignore for now. */ - break; - } -} - -static void sppp_lcp_open (struct sppp *sp) -{ - char opt[6]; - - if (! sp->lcp.magic) - sp->lcp.magic = jiffies; - opt[0] = LCP_OPT_MAGIC; - opt[1] = sizeof (opt); - opt[2] = sp->lcp.magic >> 24; - opt[3] = sp->lcp.magic >> 16; - opt[4] = sp->lcp.magic >> 8; - opt[5] = sp->lcp.magic; - sp->lcp.confid = ++sp->pp_seq; - sppp_cp_send (sp, PPP_LCP, LCP_CONF_REQ, sp->lcp.confid, - sizeof (opt), &opt); - sppp_set_timeout (sp, 2); -} - -static void sppp_ipcp_open (struct sppp *sp) -{ - sp->ipcp.confid = ++sp->pp_seq; - sppp_cp_send (sp, PPP_IPCP, IPCP_CONF_REQ, sp->ipcp.confid, 0, NULL); - sppp_set_timeout (sp, 2); -} - -/* - * Process PPP control protocol timeouts. - */ - -static void sppp_cp_timeout (unsigned long arg) -{ - struct sppp *sp = (struct sppp*) arg; - unsigned long flags; - - spin_lock_irqsave(&sp->lock, flags); - - sp->pp_flags &= ~PP_TIMO; - if (! (sp->pp_if->flags & IFF_UP) || (sp->pp_flags & PP_CISCO)) { - spin_unlock_irqrestore(&sp->lock, flags); - return; - } - switch (sp->lcp.state) { - case LCP_STATE_CLOSED: - /* No ACK for Configure-Request, retry. */ - sppp_lcp_open (sp); - break; - case LCP_STATE_ACK_RCVD: - /* ACK got, but no Configure-Request for peer, retry. */ - sppp_lcp_open (sp); - sp->lcp.state = LCP_STATE_CLOSED; - break; - case LCP_STATE_ACK_SENT: - /* ACK sent but no ACK for Configure-Request, retry. */ - sppp_lcp_open (sp); - break; - case LCP_STATE_OPENED: - /* LCP is already OK, try IPCP. */ - switch (sp->ipcp.state) { - case IPCP_STATE_CLOSED: - /* No ACK for Configure-Request, retry. */ - sppp_ipcp_open (sp); - break; - case IPCP_STATE_ACK_RCVD: - /* ACK got, but no Configure-Request for peer, retry. */ - sppp_ipcp_open (sp); - sp->ipcp.state = IPCP_STATE_CLOSED; - break; - case IPCP_STATE_ACK_SENT: - /* ACK sent but no ACK for Configure-Request, retry. */ - sppp_ipcp_open (sp); - break; - case IPCP_STATE_OPENED: - /* IPCP is OK. */ - break; - } - break; - } - spin_unlock_irqrestore(&sp->lock, flags); - sppp_flush_xmit(); -} - -static char *sppp_lcp_type_name (u8 type) -{ - static char buf [8]; - switch (type) { - case LCP_CONF_REQ: return ("conf-req"); - case LCP_CONF_ACK: return ("conf-ack"); - case LCP_CONF_NAK: return ("conf-nack"); - case LCP_CONF_REJ: return ("conf-rej"); - case LCP_TERM_REQ: return ("term-req"); - case LCP_TERM_ACK: return ("term-ack"); - case LCP_CODE_REJ: return ("code-rej"); - case LCP_PROTO_REJ: return ("proto-rej"); - case LCP_ECHO_REQ: return ("echo-req"); - case LCP_ECHO_REPLY: return ("echo-reply"); - case LCP_DISC_REQ: return ("discard-req"); - } - sprintf (buf, "%xh", type); - return (buf); -} - -static char *sppp_ipcp_type_name (u8 type) -{ - static char buf [8]; - switch (type) { - case IPCP_CONF_REQ: return ("conf-req"); - case IPCP_CONF_ACK: return ("conf-ack"); - case IPCP_CONF_NAK: return ("conf-nack"); - case IPCP_CONF_REJ: return ("conf-rej"); - case IPCP_TERM_REQ: return ("term-req"); - case IPCP_TERM_ACK: return ("term-ack"); - case IPCP_CODE_REJ: return ("code-rej"); - } - sprintf (buf, "%xh", type); - return (buf); -} - -static void sppp_print_bytes (u_char *p, u16 len) -{ - printk (" %x", *p++); - while (--len > 0) - printk ("-%x", *p++); -} - -/** - * sppp_rcv - receive and process a WAN PPP frame - * @skb: The buffer to process - * @dev: The device it arrived on - * @p: Unused - * @orig_dev: Unused - * - * Protocol glue. This drives the deferred processing mode the poorer - * cards use. This can be called directly by cards that do not have - * timing constraints but is normally called from the network layer - * after interrupt servicing to process frames queued via netif_rx. - */ - -static int sppp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *p, struct net_device *orig_dev) -{ - if (dev_net(dev) != &init_net) { - kfree_skb(skb); - return 0; - } - - if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) - return NET_RX_DROP; - sppp_input(dev,skb); - return 0; -} - -static struct packet_type sppp_packet_type = { - .type = __constant_htons(ETH_P_WAN_PPP), - .func = sppp_rcv, -}; - -static char banner[] __initdata = - KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n" - KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & " - "Jan \"Yenya\" Kasprzak.\n"; - -static int __init sync_ppp_init(void) -{ - if(debug) - debug=PP_DEBUG; - printk(banner); - skb_queue_head_init(&tx_queue); - dev_add_pack(&sppp_packet_type); - return 0; -} - - -static void __exit sync_ppp_cleanup(void) -{ - dev_remove_pack(&sppp_packet_type); -} - -module_init(sync_ppp_init); -module_exit(sync_ppp_cleanup); -module_param(debug, int, 0); -MODULE_LICENSE("GPL"); - diff --git a/drivers/net/wan/wanxl.c b/drivers/net/wan/wanxl.c index a8a5ca0ee6c2dc8d59f16ee5e29a48d2b5db4dce..4bffb67ebcae32b9fbd2676bcb6e151fa16f9edf 100644 --- a/drivers/net/wan/wanxl.c +++ b/drivers/net/wan/wanxl.c @@ -220,7 +220,6 @@ static inline void wanxl_rx_intr(card_t *card) #endif dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; - dev->last_rx = jiffies; skb->protocol = hdlc_type_trans(skb, dev); netif_rx(skb); skb = NULL; @@ -411,12 +410,12 @@ static int wanxl_open(struct net_device *dev) writel(1 << (DOORBELL_TO_CARD_OPEN_0 + port->node), dbr); timeout = jiffies + HZ; - do + do { if (get_status(port)->open) { netif_start_queue(dev); return 0; } - while (time_after(timeout, jiffies)); + } while (time_after(timeout, jiffies)); printk(KERN_ERR "%s: unable to open port\n", dev->name); /* ask the card to close the port, should it be still alive */ @@ -438,10 +437,10 @@ static int wanxl_close(struct net_device *dev) port->card->plx + PLX_DOORBELL_TO_CARD); timeout = jiffies + HZ; - do + do { if (!get_status(port)->open) break; - while (time_after(timeout, jiffies)); + } while (time_after(timeout, jiffies)); if (get_status(port)->open) printk(KERN_ERR "%s: unable to close port\n", dev->name); diff --git a/drivers/net/wan/x25_asy.c b/drivers/net/wan/x25_asy.c index 2a6c7a60756f38a8c5ad00064562c4059de1089c..e6e2ce3e7bcf6a1b15d8b9f3cc79ccf1f2ba57f4 100644 --- a/drivers/net/wan/x25_asy.c +++ b/drivers/net/wan/x25_asy.c @@ -64,7 +64,7 @@ static struct x25_asy *x25_asy_alloc(void) if (dev == NULL) break; - sl = dev->priv; + sl = netdev_priv(dev); /* Not in use ? */ if (!test_and_set_bit(SLF_INUSE, &sl->flags)) return sl; @@ -86,7 +86,7 @@ static struct x25_asy *x25_asy_alloc(void) return NULL; /* Initialize channel control data */ - sl = dev->priv; + sl = netdev_priv(dev); dev->base_addr = i; /* register device so that it can be ifconfig'ed */ @@ -120,7 +120,7 @@ static void x25_asy_free(struct x25_asy *sl) static int x25_asy_change_mtu(struct net_device *dev, int newmtu) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); unsigned char *xbuff, *rbuff; int len = 2 * newmtu; @@ -211,7 +211,6 @@ static void x25_asy_bump(struct x25_asy *sl) printk(KERN_DEBUG "x25_asy: data received err - %d\n", err); } else { netif_rx(skb); - sl->dev->last_rx = jiffies; sl->stats.rx_packets++; } } @@ -243,7 +242,7 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len) * if we did not request it before write operation. * 14 Oct 1994 Dmitry Gorodchanin. */ - sl->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); actual = sl->tty->ops->write(sl->tty, sl->xbuff, count); sl->xleft = count - actual; sl->xhead = sl->xbuff + actual; @@ -258,7 +257,7 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len) static void x25_asy_write_wakeup(struct tty_struct *tty) { int actual; - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + struct x25_asy *sl = tty->disc_data; /* First make sure we're connected. */ if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev)) @@ -268,7 +267,7 @@ static void x25_asy_write_wakeup(struct tty_struct *tty) /* Now serial buffer is almost free & we can start * transmission of another packet */ sl->stats.tx_packets++; - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); x25_asy_unlock(sl); return; } @@ -280,7 +279,7 @@ static void x25_asy_write_wakeup(struct tty_struct *tty) static void x25_asy_timeout(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); spin_lock(&sl->lock); if (netif_queue_stopped(dev)) { @@ -291,7 +290,7 @@ static void x25_asy_timeout(struct net_device *dev) (tty_chars_in_buffer(sl->tty) || sl->xleft) ? "bad line quality" : "driver error"); sl->xleft = 0; - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); x25_asy_unlock(sl); } spin_unlock(&sl->lock); @@ -301,7 +300,7 @@ static void x25_asy_timeout(struct net_device *dev) static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); int err; if (!netif_running(sl->dev)) { @@ -361,7 +360,6 @@ static int x25_asy_xmit(struct sk_buff *skb, struct net_device *dev) static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb) { - skb->dev->last_rx = jiffies; return netif_rx(skb); } @@ -373,7 +371,7 @@ static int x25_asy_data_indication(struct net_device *dev, struct sk_buff *skb) static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); spin_lock(&sl->lock); if (netif_queue_stopped(sl->dev) || sl->tty == NULL) { @@ -398,7 +396,7 @@ static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb) static void x25_asy_connected(struct net_device *dev, int reason) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); struct sk_buff *skb; unsigned char *ptr; @@ -413,12 +411,11 @@ static void x25_asy_connected(struct net_device *dev, int reason) skb->protocol = x25_type_trans(skb, sl->dev); netif_rx(skb); - sl->dev->last_rx = jiffies; } static void x25_asy_disconnected(struct net_device *dev, int reason) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); struct sk_buff *skb; unsigned char *ptr; @@ -433,7 +430,6 @@ static void x25_asy_disconnected(struct net_device *dev, int reason) skb->protocol = x25_type_trans(skb, sl->dev); netif_rx(skb); - sl->dev->last_rx = jiffies; } static struct lapb_register_struct x25_asy_callbacks = { @@ -450,7 +446,7 @@ static struct lapb_register_struct x25_asy_callbacks = { /* Open the low-level part of the X.25 channel. Easy! */ static int x25_asy_open(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); unsigned long len; int err; @@ -499,12 +495,12 @@ norbuff: /* Close the low-level part of the X.25 channel. Easy! */ static int x25_asy_close(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); int err; spin_lock(&sl->lock); if (sl->tty) - sl->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags); netif_stop_queue(dev); sl->rcount = 0; @@ -527,7 +523,7 @@ static int x25_asy_close(struct net_device *dev) static void x25_asy_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + struct x25_asy *sl = tty->disc_data; if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev)) return; @@ -555,7 +551,7 @@ static void x25_asy_receive_buf(struct tty_struct *tty, static int x25_asy_open_tty(struct tty_struct *tty) { - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + struct x25_asy *sl = tty->disc_data; int err; if (tty->ops->write == NULL) @@ -596,7 +592,7 @@ static int x25_asy_open_tty(struct tty_struct *tty) */ static void x25_asy_close_tty(struct tty_struct *tty) { - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + struct x25_asy *sl = tty->disc_data; /* First make sure we're connected. */ if (!sl || sl->magic != X25_ASY_MAGIC) @@ -615,7 +611,7 @@ static void x25_asy_close_tty(struct tty_struct *tty) static struct net_device_stats *x25_asy_get_stats(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); return &sl->stats; } @@ -624,7 +620,7 @@ static struct net_device_stats *x25_asy_get_stats(struct net_device *dev) * STANDARD X.25 ENCAPSULATION * ************************************************************************/ -int x25_asy_esc(unsigned char *s, unsigned char *d, int len) +static int x25_asy_esc(unsigned char *s, unsigned char *d, int len) { unsigned char *ptr = d; unsigned char c; @@ -696,7 +692,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s) static int x25_asy_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct x25_asy *sl = (struct x25_asy *) tty->disc_data; + struct x25_asy *sl = tty->disc_data; /* First make sure we're connected. */ if (!sl || sl->magic != X25_ASY_MAGIC) @@ -717,7 +713,7 @@ static int x25_asy_ioctl(struct tty_struct *tty, struct file *file, static int x25_asy_open_dev(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); if (sl->tty == NULL) return -ENODEV; return 0; @@ -726,7 +722,7 @@ static int x25_asy_open_dev(struct net_device *dev) /* Initialise the X.25 driver. Called by the device init code */ static void x25_asy_setup(struct net_device *dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); sl->magic = X25_ASY_MAGIC; sl->dev = dev; @@ -793,7 +789,7 @@ static void __exit exit_x25_asy(void) for (i = 0; i < x25_asy_maxdev; i++) { dev = x25_asy_devs[i]; if (dev) { - struct x25_asy *sl = dev->priv; + struct x25_asy *sl = netdev_priv(dev); spin_lock_bh(&sl->lock); if (sl->tty) diff --git a/drivers/net/wan/z85230.c b/drivers/net/wan/z85230.c index 5bf7e01ef0e9fe3c408408e24dc8e43a772f6161..3d00971fe5ee6a6dc488d99bf72e262cf06f8a6f 100644 --- a/drivers/net/wan/z85230.c +++ b/drivers/net/wan/z85230.c @@ -601,24 +601,18 @@ static void z8530_dma_status(struct z8530_channel *chan) write_zsctrl(chan, RES_H_IUS); } -struct z8530_irqhandler z8530_dma_sync= -{ +static struct z8530_irqhandler z8530_dma_sync = { z8530_dma_rx, z8530_dma_tx, z8530_dma_status }; -EXPORT_SYMBOL(z8530_dma_sync); - -struct z8530_irqhandler z8530_txdma_sync= -{ +static struct z8530_irqhandler z8530_txdma_sync = { z8530_rx, z8530_dma_tx, z8530_dma_status }; -EXPORT_SYMBOL(z8530_txdma_sync); - /** * z8530_rx_clear - Handle RX events from a stopped chip * @c: Z8530 channel to shut up @@ -710,7 +704,7 @@ EXPORT_SYMBOL(z8530_nop); irqreturn_t z8530_interrupt(int irq, void *dev_id) { struct z8530_dev *dev=dev_id; - u8 intr; + u8 uninitialized_var(intr); static volatile int locker=0; int work=0; struct z8530_irqhandler *irqs; diff --git a/drivers/net/wd.c b/drivers/net/wd.c index fa14255282afe96770d5b44cc887fbaba22814df..3c1edda08d3d5d6827f32618690db332b01b7b55 100644 --- a/drivers/net/wd.c +++ b/drivers/net/wd.c @@ -147,6 +147,20 @@ out: } #endif +static const struct net_device_ops wd_netdev_ops = { + .ndo_open = wd_open, + .ndo_stop = wd_close, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __init wd_probe1(struct net_device *dev, int ioaddr) { int i; @@ -156,7 +170,6 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) int word16 = 0; /* 0 = 8 bit, 1 = 16 bit */ const char *model_name; static unsigned version_printed; - DECLARE_MAC_BUF(mac); for (i = 0; i < 8; i++) checksum += inb(ioaddr + 8 + i); @@ -178,8 +191,8 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) for (i = 0; i < 6; i++) dev->dev_addr[i] = inb(ioaddr + 8 + i); - printk("%s: WD80x3 at %#3x, %s", - dev->name, ioaddr, print_mac(mac, dev->dev_addr)); + printk("%s: WD80x3 at %#3x, %pM", + dev->name, ioaddr, dev->dev_addr); /* The following PureData probe code was contributed by Mike Jagdis . Puredata does software @@ -332,11 +345,8 @@ static int __init wd_probe1(struct net_device *dev, int ioaddr) ei_status.block_input = &wd_block_input; ei_status.block_output = &wd_block_output; ei_status.get_8390_hdr = &wd_get_8390_hdr; - dev->open = &wd_open; - dev->stop = &wd_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = ei_poll; -#endif + + dev->netdev_ops = &wd_netdev_ops; NS8390_init(dev, 0); #if 1 @@ -366,8 +376,7 @@ wd_open(struct net_device *dev) outb(ei_status.reg5, ioaddr+WD_CMDREG5); outb(ei_status.reg0, ioaddr); /* WD_CMDREG */ - ei_open(dev); - return 0; + return ei_open(dev); } static void diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index 45bdf0b339bb55f0aa132b2256385014079a8731..ea543fcf2687aa9e0bacea24dad83dbe44897233 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -123,154 +123,11 @@ config PCMCIA_RAYCS To compile this driver as a module, choose M here: the module will be called ray_cs. If unsure, say N. -config IPW2100 - tristate "Intel PRO/Wireless 2100 Network Connection" - depends on PCI && WLAN_80211 - select WIRELESS_EXT - select FW_LOADER - select IEEE80211 - ---help--- - A driver for the Intel PRO/Wireless 2100 Network - Connection 802.11b wireless network adapter. - - See for information on - the capabilities currently enabled in this driver and for tips - for debugging issues and problems. - - In order to use this driver, you will need a firmware image for it. - You can obtain the firmware from - . Once you have the firmware image, you - will need to place it in /lib/firmware. - - You will also very likely need the Wireless Tools in order to - configure your card: - - . - - 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 IPW2100_MONITOR - bool "Enable promiscuous mode" - depends on IPW2100 - ---help--- - Enables promiscuous/monitor mode support for the ipw2100 driver. - With this feature compiled into the driver, you can switch to - promiscuous mode via the Wireless Tool's Monitor mode. While in this - mode, no packets can be sent. - -config IPW2100_DEBUG - bool "Enable full debugging output in IPW2100 module." - depends on IPW2100 - ---help--- - This option will enable debug tracing output for the IPW2100. - - This will result in the kernel module being ~60k larger. You can - control which debug output is sent to the kernel log by setting the - value in - - /sys/bus/pci/drivers/ipw2100/debug_level - - This entry will only exist if this option is enabled. - - If you are not trying to debug or develop the IPW2100 driver, you - most likely want to say N here. - -config IPW2200 - tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" - depends on PCI && WLAN_80211 - select WIRELESS_EXT - select FW_LOADER - select IEEE80211 - ---help--- - A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network - Connection adapters. - - See for - information on the capabilities currently enabled in this - driver and for tips for debugging issues and problems. - - In order to use this driver, you will need a firmware image for it. - You can obtain the firmware from - . See the above referenced README.ipw2200 - for information on where to install the firmware images. - - You will also very likely need the Wireless Tools in order to - configure your card: - - . - - 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" - depends on IPW2200 - ---help--- - Enables promiscuous/monitor mode support for the ipw2200 driver. - With this feature compiled into the driver, you can switch to - promiscuous mode via the Wireless Tool's Monitor mode. While in this - mode, no packets can be sent. - -config IPW2200_RADIOTAP - bool "Enable radiotap format 802.11 raw packet support" - depends on IPW2200_MONITOR - -config IPW2200_PROMISCUOUS - bool "Enable creation of a RF radiotap promiscuous interface" - depends on IPW2200_MONITOR - select IPW2200_RADIOTAP - ---help--- - Enables the creation of a second interface prefixed 'rtap'. - This second interface will provide every received in radiotap - format. - - This is useful for performing wireless network analysis while - maintaining an active association. - - Example usage: - - % modprobe ipw2200 rtap_iface=1 - % ifconfig rtap0 up - % tethereal -i rtap0 - - If you do not specify 'rtap_iface=1' as a module parameter then - the rtap interface will not be created and you will need to turn - it on via sysfs: - - % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface - -config IPW2200_QOS - bool "Enable QoS support" - depends on IPW2200 && EXPERIMENTAL - -config IPW2200_DEBUG - bool "Enable full debugging output in IPW2200 module." - depends on IPW2200 - ---help--- - This option will enable low level debug tracing output for IPW2200. - - Note, normal debug code is already compiled in. This low level - debug option enables debug on hot paths (e.g Tx, Rx, ISR) and - will result in the kernel module being ~70 larger. Most users - will typically not need this high verbosity debug information. - - If you are not sure, say N here. - config LIBERTAS tristate "Marvell 8xxx Libertas WLAN driver support" depends on WLAN_80211 select WIRELESS_EXT + select LIB80211 select FW_LOADER ---help--- A library for Marvell Libertas 8xxx devices. @@ -357,6 +214,21 @@ config HERMES configure your card and that /etc/pcmcia/wireless.opts works : +config HERMES_CACHE_FW_ON_INIT + bool "Cache Hermes firmware on driver initialisation" + depends on HERMES + default y + ---help--- + Say Y to cache any firmware required by the Hermes drivers + on startup. The firmware will remain cached until the + driver is unloaded. The cache uses 64K of RAM. + + Otherwise load the firmware from userspace as required. In + this case the driver should be unloaded and restarted + whenever the firmware is changed. + + If you are not sure, say Y. + config APPLE_AIRPORT tristate "Apple Airport support (built-in)" depends on PPC_PMAC && HERMES @@ -651,7 +523,7 @@ config RTL8180 config RTL8187 tristate "Realtek 8187 and 8187B USB support" - depends on MAC80211 && USB && WLAN_80211 && EXPERIMENTAL + depends on MAC80211 && USB && WLAN_80211 select EEPROM_93CX6 ---help--- This is a driver for RTL8187 and RTL8187B based cards. @@ -711,6 +583,7 @@ config MAC80211_HWSIM source "drivers/net/wireless/p54/Kconfig" source "drivers/net/wireless/ath5k/Kconfig" source "drivers/net/wireless/ath9k/Kconfig" +source "drivers/net/wireless/ipw2x00/Kconfig" source "drivers/net/wireless/iwlwifi/Kconfig" source "drivers/net/wireless/hostap/Kconfig" source "drivers/net/wireless/b43/Kconfig" diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 59d2d805f60b4591b1332944b51ac7cf380b5006..ac590e1ca8beecf788cbe10a2d36f4e043e44799 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -2,9 +2,8 @@ # Makefile for the Linux Wireless network device drivers. # -obj-$(CONFIG_IPW2100) += ipw2100.o - -obj-$(CONFIG_IPW2200) += ipw2200.o +obj-$(CONFIG_IPW2100) += ipw2x00/ +obj-$(CONFIG_IPW2200) += ipw2x00/ obj-$(CONFIG_STRIP) += strip.o obj-$(CONFIG_ARLAN) += arlan.o @@ -16,14 +15,7 @@ obj-$(CONFIG_WAVELAN) += wavelan.o obj-$(CONFIG_PCMCIA_NETWAVE) += netwave_cs.o obj-$(CONFIG_PCMCIA_WAVELAN) += wavelan_cs.o -obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o -obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o -obj-$(CONFIG_APPLE_AIRPORT) += airport.o -obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o -obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o -obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o -obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o -obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o +obj-$(CONFIG_HERMES) += orinoco/ obj-$(CONFIG_AIRO) += airo.o obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o @@ -38,6 +30,8 @@ obj-$(CONFIG_HOSTAP) += hostap/ obj-$(CONFIG_B43) += b43/ obj-$(CONFIG_B43LEGACY) += b43legacy/ obj-$(CONFIG_ZD1211RW) += zd1211rw/ +obj-$(CONFIG_RTL8180) += rtl818x/ +obj-$(CONFIG_RTL8187) += rtl818x/ # 16-bit wireless PCMCIA client drivers obj-$(CONFIG_PCMCIA_RAYCS) += ray_cs.o @@ -50,12 +44,6 @@ obj-$(CONFIG_LIBERTAS) += libertas/ obj-$(CONFIG_LIBERTAS_THINFIRM) += libertas_tf/ -rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o -rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o - -obj-$(CONFIG_RTL8180) += rtl8180.o -obj-$(CONFIG_RTL8187) += rtl8187.o - obj-$(CONFIG_ADM8211) += adm8211.o obj-$(CONFIG_IWLWIFI) += iwlwifi/ diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c index b2c050b68890a2f0d496a85d39314c95282d07e9..fc0897fb22390c87d908ceefdc0a4ea05193e383 100644 --- a/drivers/net/wireless/adm8211.c +++ b/drivers/net/wireless/adm8211.c @@ -341,15 +341,14 @@ static void adm8211_interrupt_tci(struct ieee80211_hw *dev) pci_unmap_single(priv->pdev, info->mapping, info->skb->len, PCI_DMA_TODEVICE); - memset(&txi->status, 0, sizeof(txi->status)); + ieee80211_tx_info_clear_status(txi); + skb_pull(skb, sizeof(struct adm8211_tx_hdr)); memcpy(skb_push(skb, info->hdrlen), skb->cb, info->hdrlen); - if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (status & TDES0_STATUS_ES) - txi->status.excessive_retries = 1; - else - txi->flags |= IEEE80211_TX_STAT_ACK; - } + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && + !(status & TDES0_STATUS_ES)) + txi->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(dev, skb); info->skb = NULL; @@ -1298,25 +1297,10 @@ static void adm8211_set_bssid(struct ieee80211_hw *dev, const u8 *bssid) ADM8211_CSR_WRITE(ABDA1, reg); } -static int adm8211_set_ssid(struct ieee80211_hw *dev, u8 *ssid, size_t ssid_len) -{ - struct adm8211_priv *priv = dev->priv; - u8 buf[36]; - - if (ssid_len > 32) - return -EINVAL; - - memset(buf, 0, sizeof(buf)); - buf[0] = ssid_len; - memcpy(buf + 1, ssid, ssid_len); - adm8211_write_sram_bytes(dev, ADM8211_SRAM_SSID, buf, 33); - /* TODO: configure beacon for adhoc? */ - return 0; -} - -static int adm8211_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int adm8211_config(struct ieee80211_hw *dev, u32 changed) { struct adm8211_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; int channel = ieee80211_frequency_to_channel(conf->channel->center_freq); if (channel != priv->channel) { @@ -1338,13 +1322,6 @@ static int adm8211_config_interface(struct ieee80211_hw *dev, memcpy(priv->bssid, conf->bssid, ETH_ALEN); } - if (conf->ssid_len != priv->ssid_len || - memcmp(conf->ssid, priv->ssid, conf->ssid_len)) { - adm8211_set_ssid(dev, conf->ssid, conf->ssid_len); - priv->ssid_len = conf->ssid_len; - memcpy(priv->ssid, conf->ssid, conf->ssid_len); - } - return 0; } @@ -1690,8 +1667,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) struct ieee80211_hdr *hdr; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ieee80211_rate *txrate = ieee80211_get_tx_rate(dev, info); + u8 rc_flags; - short_preamble = !!(txrate->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE); + rc_flags = info->control.rates[0].flags; + short_preamble = !!(rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE); plcp_signal = txrate->bitrate; hdr = (struct ieee80211_hdr *)skb->data; @@ -1723,10 +1702,10 @@ static int adm8211_tx(struct ieee80211_hw *dev, struct sk_buff *skb) if (short_preamble) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_SHORT_PREAMBLE); - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) txhdr->header_control |= cpu_to_le16(ADM8211_TXHDRCTL_ENABLE_RTS); - txhdr->retry_limit = info->control.retry_limit; + txhdr->retry_limit = info->control.rates[0].count; adm8211_tx_raw(dev, skb, plcp_signal, hdrlen); @@ -1791,7 +1770,6 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, int err; u32 reg; u8 perm_addr[ETH_ALEN]; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if (err) { @@ -1925,8 +1903,8 @@ static int __devinit adm8211_probe(struct pci_dev *pdev, goto err_free_desc; } - printk(KERN_INFO "%s: hwaddr %s, Rev 0x%02x\n", - wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %pM, Rev 0x%02x\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, pdev->revision); return 0; diff --git a/drivers/net/wireless/adm8211.h b/drivers/net/wireless/adm8211.h index 9b190ee26e903c291fa54aaa0c51e5153ace4d67..4f6ab1322189805660e99b0e5b3bc3acf2fba9d8 100644 --- a/drivers/net/wireless/adm8211.h +++ b/drivers/net/wireless/adm8211.h @@ -553,8 +553,6 @@ struct adm8211_priv { int channel; u8 bssid[ETH_ALEN]; - u8 ssid[32]; - size_t ssid_len; u8 soft_rx_crc; u8 retry_limit; diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index 370133e492d259431df941fc3eee94bb770fa117..fc4322ca669fa3a33c56650a784debdc15e8dab3 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c @@ -47,10 +47,11 @@ #include #include #include -#include #include #include +#include + #include "airo.h" #define DRV_NAME "airo" @@ -1270,6 +1271,7 @@ static int flashrestart(struct airo_info *ai,struct net_device *dev); #define airo_print_err(name, fmt, args...) \ airo_print(KERN_ERR, name, fmt, ##args) +#define AIRO_FLASH(dev) (((struct airo_info *)dev->ml_priv)->flash) /*********************************************************************** * MIC ROUTINES * @@ -1865,7 +1867,7 @@ static void try_auto_wep(struct airo_info *ai) } static int airo_open(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int rc = 0; if (test_bit(FLAG_FLASHING, &ai->flags)) @@ -1912,7 +1914,7 @@ static int airo_open(struct net_device *dev) { static int mpi_start_xmit(struct sk_buff *skb, struct net_device *dev) { int npacks, pending; unsigned long flags; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if (!skb) { airo_print_err(dev->name, "%s: skb == NULL!",__func__); @@ -1956,7 +1958,7 @@ static int mpi_send_packet (struct net_device *dev) unsigned char *buffer; s16 len; __le16 *payloadLen; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; u8 *sendbuf; /* get a packet to send */ @@ -2085,7 +2087,7 @@ static void get_tx_error(struct airo_info *ai, s32 fid) static void airo_end_xmit(struct net_device *dev) { u16 status; int i; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; struct sk_buff *skb = priv->xmit.skb; int fid = priv->xmit.fid; u32 *fids = priv->fids; @@ -2111,7 +2113,7 @@ static void airo_end_xmit(struct net_device *dev) { static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { s16 len; int i, j; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; u32 *fids = priv->fids; if ( skb == NULL ) { @@ -2150,7 +2152,7 @@ static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) { static void airo_end_xmit11(struct net_device *dev) { u16 status; int i; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; struct sk_buff *skb = priv->xmit11.skb; int fid = priv->xmit11.fid; u32 *fids = priv->fids; @@ -2176,7 +2178,7 @@ static void airo_end_xmit11(struct net_device *dev) { static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { s16 len; int i, j; - struct airo_info *priv = dev->priv; + struct airo_info *priv = dev->ml_priv; u32 *fids = priv->fids; if (test_bit(FLAG_MPI, &priv->flags)) { @@ -2220,7 +2222,7 @@ static int airo_start_xmit11(struct sk_buff *skb, struct net_device *dev) { static void airo_read_stats(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; StatsRid stats_rid; __le32 *vals = stats_rid.vals; @@ -2254,7 +2256,7 @@ static void airo_read_stats(struct net_device *dev) static struct net_device_stats *airo_get_stats(struct net_device *dev) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; if (!test_bit(JOB_STATS, &local->jobs)) { /* Get stats out of the card if available */ @@ -2281,7 +2283,7 @@ static void airo_set_promisc(struct airo_info *ai) { } static void airo_set_multicast_list(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if ((dev->flags ^ ai->flags) & IFF_PROMISC) { change_bit(FLAG_PROMISC, &ai->flags); @@ -2299,7 +2301,7 @@ static void airo_set_multicast_list(struct net_device *dev) { static int airo_set_mac_address(struct net_device *dev, void *p) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; struct sockaddr *addr = p; readConfigRid(ai, 1); @@ -2339,7 +2341,7 @@ static void del_airo_dev(struct airo_info *ai) } static int airo_close(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; netif_stop_queue(dev); @@ -2365,7 +2367,7 @@ static int airo_close(struct net_device *dev) { void stop_airo_card( struct net_device *dev, int freeres ) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; set_bit(FLAG_RADIO_DOWN, &ai->flags); disable_MAC(ai, 1); @@ -2665,7 +2667,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, struct net_device *dev = alloc_netdev(0, "wifi%d", wifi_setup); if (!dev) return NULL; - dev->priv = ethdev->priv; + dev->ml_priv = ethdev->ml_priv; dev->irq = ethdev->irq; dev->base_addr = ethdev->base_addr; dev->wireless_data = ethdev->wireless_data; @@ -2680,7 +2682,7 @@ static struct net_device *init_wifidev(struct airo_info *ai, } static int reset_card( struct net_device *dev , int lock) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if (lock && down_interruptible(&ai->sem)) return -1; @@ -2757,7 +2759,6 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, struct net_device *dev; struct airo_info *ai; int i, rc; - DECLARE_MAC_BUF(mac); /* Create the network device object. */ dev = alloc_netdev(sizeof(*ai), "", ether_setup); @@ -2766,7 +2767,7 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, return NULL; } - ai = dev->priv; + ai = dev->ml_priv = netdev_priv(dev); ai->wifidev = NULL; ai->flags = 1 << FLAG_RADIO_DOWN; ai->jobs = 0; @@ -2860,15 +2861,14 @@ static struct net_device *_init_airo_card( unsigned short irq, int port, goto err_out_reg; set_bit(FLAG_REGISTERED,&ai->flags); - airo_print_info(dev->name, "MAC enabled %s", - print_mac(mac, dev->dev_addr)); + airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); /* Allocate the transmit buffers */ if (probe && !test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) ai->fids[i] = transmit_allocate(ai,AIRO_DEF_MTU,i>=MAX_FIDS/2); - if (setup_proc_entry(dev, dev->priv) < 0) + if (setup_proc_entry(dev, dev->ml_priv) < 0) goto err_out_wifi; return dev; @@ -2917,8 +2917,7 @@ static int waitbusy (struct airo_info *ai) { int reset_airo_card( struct net_device *dev ) { int i; - struct airo_info *ai = dev->priv; - DECLARE_MAC_BUF(mac); + struct airo_info *ai = dev->ml_priv; if (reset_card (dev, 1)) return -1; @@ -2927,8 +2926,7 @@ int reset_airo_card( struct net_device *dev ) airo_print_err(dev->name, "MAC could not be enabled"); return -1; } - airo_print_info(dev->name, "MAC enabled %s", - print_mac(mac, dev->dev_addr)); + airo_print_info(dev->name, "MAC enabled %pM", dev->dev_addr); /* Allocate the transmit buffers if needed */ if (!test_bit(FLAG_MPI,&ai->flags)) for( i = 0; i < MAX_FIDS; i++ ) @@ -2942,7 +2940,7 @@ int reset_airo_card( struct net_device *dev ) EXPORT_SYMBOL(reset_airo_card); static void airo_send_event(struct net_device *dev) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; union iwreq_data wrqu; StatusRid status_rid; @@ -3019,7 +3017,7 @@ out: static int airo_thread(void *data) { struct net_device *dev = data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int locked; set_freezable(); @@ -3134,7 +3132,7 @@ static irqreturn_t airo_interrupt(int irq, void *dev_id) struct net_device *dev = dev_id; u16 status; u16 fid; - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; u16 savedInterrupts = 0; int handled = 0; @@ -3369,7 +3367,6 @@ badrx: skb->protocol = htons(ETH_P_802_2); } else skb->protocol = eth_type_trans(skb,dev); - skb->dev->last_rx = jiffies; skb->ip_summed = CHECKSUM_NONE; netif_rx( skb ); @@ -3599,7 +3596,6 @@ badmic: skb->ip_summed = CHECKSUM_NONE; skb->protocol = eth_type_trans(skb, ai->dev); - skb->dev->last_rx = jiffies; netif_rx(skb); } badrx: @@ -3611,7 +3607,7 @@ badrx: } } -void mpi_receive_802_11 (struct airo_info *ai) +static void mpi_receive_802_11(struct airo_info *ai) { RxFid rxd; struct sk_buff *skb = NULL; @@ -3693,7 +3689,6 @@ void mpi_receive_802_11 (struct airo_info *ai) skb->pkt_type = PACKET_OTHERHOST; skb->dev = ai->wifidev; skb->protocol = htons(ETH_P_802_2); - skb->dev->last_rx = jiffies; skb->ip_summed = CHECKSUM_NONE; netif_rx( skb ); badrx: @@ -4604,7 +4599,7 @@ static int proc_status_open(struct inode *inode, struct file *file) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; CapabilityRid cap_rid; StatusRid status_rid; u16 mode; @@ -4687,7 +4682,7 @@ static int proc_stats_rid_open( struct inode *inode, struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; StatsRid stats; int i, j; __le32 *vals = stats.vals; @@ -4750,7 +4745,7 @@ static void proc_config_on_close(struct inode *inode, struct file *file) struct proc_data *data = file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; char *line; if ( !data->writelen ) return; @@ -4962,7 +4957,7 @@ static int proc_config_open(struct inode *inode, struct file *file) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; __le16 mode; @@ -5053,7 +5048,7 @@ static void proc_SSID_on_close(struct inode *inode, struct file *file) struct proc_data *data = (struct proc_data *)file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; SsidRid SSID_rid; int i; char *p = data->wbuffer; @@ -5096,7 +5091,7 @@ static void proc_APList_on_close( struct inode *inode, struct file *file ) { struct proc_data *data = (struct proc_data *)file->private_data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; APListRid APList_rid; int i; @@ -5191,7 +5186,7 @@ static void proc_wepkey_on_close( struct inode *inode, struct file *file ) { struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; char key[16]; u16 index = 0; @@ -5233,7 +5228,7 @@ static int proc_wepkey_open( struct inode *inode, struct file *file ) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; char *ptr; WepKeyRid wkr; __le16 lastindex; @@ -5282,7 +5277,7 @@ static int proc_SSID_open(struct inode *inode, struct file *file) struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; char *ptr; SsidRid SSID_rid; @@ -5326,11 +5321,10 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int i; char *ptr; APListRid APList_rid; - DECLARE_MAC_BUF(mac); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5354,8 +5348,7 @@ static int proc_APList_open( struct inode *inode, struct file *file ) { // We end when we find a zero MAC if ( !*(int*)APList_rid.ap[i] && !*(int*)&APList_rid.ap[i][2]) break; - ptr += sprintf(ptr, "%s\n", - print_mac(mac, APList_rid.ap[i])); + ptr += sprintf(ptr, "%pM\n", APList_rid.ap[i]); } if (i==0) ptr += sprintf(ptr, "Not using specific APs\n"); @@ -5368,13 +5361,12 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { struct proc_data *data; struct proc_dir_entry *dp = PDE(inode); struct net_device *dev = dp->data; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; char *ptr; BSSListRid BSSList_rid; int rc; /* If doLoseSync is not 1, we won't do a Lose Sync */ int doLoseSync = -1; - DECLARE_MAC_BUF(mac); if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL) return -ENOMEM; @@ -5411,8 +5403,8 @@ static int proc_BSSList_open( struct inode *inode, struct file *file ) { we have to add a spin lock... */ rc = readBSSListRid(ai, doLoseSync, &BSSList_rid); while(rc == 0 && BSSList_rid.index != cpu_to_le16(0xffff)) { - ptr += sprintf(ptr, "%s %*s rssi = %d", - print_mac(mac, BSSList_rid.bssid), + ptr += sprintf(ptr, "%pM %*s rssi = %d", + BSSList_rid.bssid, (int)BSSList_rid.ssidLen, BSSList_rid.ssid, le16_to_cpu(BSSList_rid.dBm)); @@ -5447,7 +5439,7 @@ static int proc_close( struct inode *inode, struct file *file ) associated we will check every minute to see if anything has changed. */ static void timer_func( struct net_device *dev ) { - struct airo_info *apriv = dev->priv; + struct airo_info *apriv = dev->ml_priv; /* We don't have a link so try changing the authtype */ readConfigRid(apriv, 0); @@ -5518,7 +5510,7 @@ static void __devexit airo_pci_remove(struct pci_dev *pdev) static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *dev = pci_get_drvdata(pdev); - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; Cmd cmd; Resp rsp; @@ -5550,7 +5542,7 @@ static int airo_pci_suspend(struct pci_dev *pdev, pm_message_t state) static int airo_pci_resume(struct pci_dev *pdev) { struct net_device *dev = pci_get_drvdata(pdev); - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; pci_power_t prev_state = pdev->current_state; pci_set_power_state(pdev, PCI_D0); @@ -5729,7 +5721,7 @@ static int airo_set_freq(struct net_device *dev, struct iw_freq *fwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int rc = -EINPROGRESS; /* Call commit handler */ /* If setting by frequency, convert to a channel */ @@ -5774,7 +5766,7 @@ static int airo_get_freq(struct net_device *dev, struct iw_freq *fwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ int ch; @@ -5805,7 +5797,7 @@ static int airo_set_essid(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; SsidRid SSID_rid; /* SSIDs */ /* Reload the list of current SSID */ @@ -5851,7 +5843,7 @@ static int airo_get_essid(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ readStatusRid(local, &status_rid, 1); @@ -5879,7 +5871,7 @@ static int airo_set_wap(struct net_device *dev, struct sockaddr *awrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; Cmd cmd; Resp rsp; APListRid APList_rid; @@ -5916,7 +5908,7 @@ static int airo_get_wap(struct net_device *dev, struct sockaddr *awrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ readStatusRid(local, &status_rid, 1); @@ -5937,7 +5929,7 @@ static int airo_set_nick(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; /* Check the size of the string */ if(dwrq->length > 16) { @@ -5960,7 +5952,7 @@ static int airo_get_nick(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); strncpy(extra, local->config.nodeName, 16); @@ -5979,7 +5971,7 @@ static int airo_set_rate(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; CapabilityRid cap_rid; /* Card capability info */ u8 brate = 0; int i; @@ -6049,7 +6041,7 @@ static int airo_get_rate(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; StatusRid status_rid; /* Card status info */ readStatusRid(local, &status_rid, 1); @@ -6071,7 +6063,7 @@ static int airo_set_rts(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int rthr = vwrq->value; if(vwrq->disabled) @@ -6095,7 +6087,7 @@ static int airo_get_rts(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.rtsThres); @@ -6114,7 +6106,7 @@ static int airo_set_frag(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int fthr = vwrq->value; if(vwrq->disabled) @@ -6139,7 +6131,7 @@ static int airo_get_frag(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.fragThresh); @@ -6158,7 +6150,7 @@ static int airo_set_mode(struct net_device *dev, __u32 *uwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int reset = 0; readConfigRid(local, 1); @@ -6221,7 +6213,7 @@ static int airo_get_mode(struct net_device *dev, __u32 *uwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); /* If not managed, assume it's ad-hoc */ @@ -6258,7 +6250,7 @@ static int airo_set_encode(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; CapabilityRid cap_rid; /* Card capability info */ int perm = ( dwrq->flags & IW_ENCODE_TEMP ? 0 : 1 ); __le16 currentAuthType = local->config.authType; @@ -6345,7 +6337,7 @@ static int airo_get_encode(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; CapabilityRid cap_rid; /* Card capability info */ @@ -6393,7 +6385,7 @@ static int airo_set_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; CapabilityRid cap_rid; /* Card capability info */ @@ -6479,7 +6471,7 @@ static int airo_get_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_point *encoding = &wrqu->encoding; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; CapabilityRid cap_rid; /* Card capability info */ @@ -6542,7 +6534,7 @@ static int airo_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_param *param = &wrqu->param; __le16 currentAuthType = local->config.authType; @@ -6610,7 +6602,7 @@ static int airo_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_param *param = &wrqu->param; __le16 currentAuthType = local->config.authType; @@ -6659,7 +6651,7 @@ static int airo_set_txpow(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; CapabilityRid cap_rid; /* Card capability info */ int i; int rc = -EINVAL; @@ -6696,7 +6688,7 @@ static int airo_get_txpow(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.txPower); @@ -6716,7 +6708,7 @@ static int airo_set_retry(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; int rc = -EINVAL; if(vwrq->disabled) { @@ -6754,7 +6746,7 @@ static int airo_get_retry(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; vwrq->disabled = 0; /* Can't be disabled */ @@ -6785,7 +6777,7 @@ static int airo_get_range(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct iw_range *range = (struct iw_range *) extra; CapabilityRid cap_rid; /* Card capability info */ int i; @@ -6910,7 +6902,7 @@ static int airo_set_power(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); if (vwrq->disabled) { @@ -6967,7 +6959,7 @@ static int airo_get_power(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; __le16 mode; readConfigRid(local, 1); @@ -6998,7 +6990,7 @@ static int airo_set_sens(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); local->config.rssiThreshold = @@ -7017,7 +7009,7 @@ static int airo_get_sens(struct net_device *dev, struct iw_param *vwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; readConfigRid(local, 1); vwrq->value = le16_to_cpu(local->config.rssiThreshold); @@ -7037,7 +7029,7 @@ static int airo_get_aplist(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; struct sockaddr *address = (struct sockaddr *) extra; struct iw_quality qual[IW_MAX_AP]; BSSListRid BSSList; @@ -7110,7 +7102,7 @@ static int airo_set_scan(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; Cmd cmd; Resp rsp; int wake = 0; @@ -7156,7 +7148,7 @@ static inline char *airo_translate_scan(struct net_device *dev, char *end_buf, BSSListRid *bss) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; struct iw_event iwe; /* Temporary buffer */ __le16 capabilities; char * current_val; /* For rates */ @@ -7274,56 +7266,53 @@ static inline char *airo_translate_scan(struct net_device *dev, if (test_bit(FLAG_WPA_CAPABLE, &ai->flags)) { unsigned int num_null_ies = 0; u16 length = sizeof (bss->extra.iep); - struct ieee80211_info_element *info_element = - (struct ieee80211_info_element *) &bss->extra.iep; + u8 *ie = (void *)&bss->extra.iep; - while ((length >= sizeof(*info_element)) && (num_null_ies < 2)) { - if (sizeof(*info_element) + info_element->len > length) { + while ((length >= 2) && (num_null_ies < 2)) { + if (2 + ie[1] > length) { /* Invalid element, don't continue parsing IE */ break; } - switch (info_element->id) { - case MFIE_TYPE_SSID: + switch (ie[0]) { + case WLAN_EID_SSID: /* Two zero-length SSID elements * mean we're done parsing elements */ - if (!info_element->len) + if (!ie[1]) num_null_ies++; break; - case MFIE_TYPE_GENERIC: - if (info_element->len >= 4 && - info_element->data[0] == 0x00 && - info_element->data[1] == 0x50 && - info_element->data[2] == 0xf2 && - info_element->data[3] == 0x01) { + case WLAN_EID_GENERIC: + if (ie[1] >= 4 && + ie[2] == 0x00 && + ie[3] == 0x50 && + ie[4] == 0xf2 && + ie[5] == 0x01) { iwe.cmd = IWEVGENIE; - iwe.u.data.length = min(info_element->len + 2, - MAX_WPA_IE_LEN); + /* 64 is an arbitrary cut-off */ + iwe.u.data.length = min(ie[1] + 2, + 64); current_ev = iwe_stream_add_point( info, current_ev, - end_buf, &iwe, - (char *) info_element); + end_buf, &iwe, ie); } break; - case MFIE_TYPE_RSN: + case WLAN_EID_RSN: iwe.cmd = IWEVGENIE; - iwe.u.data.length = min(info_element->len + 2, - MAX_WPA_IE_LEN); + /* 64 is an arbitrary cut-off */ + iwe.u.data.length = min(ie[1] + 2, 64); current_ev = iwe_stream_add_point( info, current_ev, end_buf, - &iwe, (char *) info_element); + &iwe, ie); break; default: break; } - length -= sizeof(*info_element) + info_element->len; - info_element = - (struct ieee80211_info_element *)&info_element-> - data[info_element->len]; + length -= 2 + ie[1]; + ie += 2 + ie[1]; } } return current_ev; @@ -7338,7 +7327,7 @@ static int airo_get_scan(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; BSSListElement *net; int err = 0; char *current_ev = extra; @@ -7382,7 +7371,7 @@ static int airo_config_commit(struct net_device *dev, void *zwrq, /* NULL */ char *extra) /* NULL */ { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; if (!test_bit (FLAG_COMMIT, &local->flags)) return 0; @@ -7527,7 +7516,7 @@ static const struct iw_handler_def airo_handler_def = static int airo_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) { int rc = 0; - struct airo_info *ai = (struct airo_info *)dev->priv; + struct airo_info *ai = dev->ml_priv; if (ai->power.event) return 0; @@ -7655,7 +7644,7 @@ static void airo_read_wireless_stats(struct airo_info *local) static struct iw_statistics *airo_get_wireless_stats(struct net_device *dev) { - struct airo_info *local = dev->priv; + struct airo_info *local = dev->ml_priv; if (!test_bit(JOB_WSTATS, &local->jobs)) { /* Get stats out of the card if available */ @@ -7680,7 +7669,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { unsigned short ridcode; unsigned char *iobuf; int len; - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; if (test_bit(FLAG_FLASHING, &ai->flags)) return -EIO; @@ -7746,7 +7735,7 @@ static int readrids(struct net_device *dev, aironet_ioctl *comp) { */ static int writerids(struct net_device *dev, aironet_ioctl *comp) { - struct airo_info *ai = dev->priv; + struct airo_info *ai = dev->ml_priv; int ridcode; int enabled; static int (* writer)(struct airo_info *, u16 rid, const void *, int, int); @@ -7869,41 +7858,41 @@ static int flashcard(struct net_device *dev, aironet_ioctl *comp) { switch(comp->command) { case AIROFLSHRST: - return cmdreset((struct airo_info *)dev->priv); + return cmdreset((struct airo_info *)dev->ml_priv); case AIROFLSHSTFL: - if (!((struct airo_info *)dev->priv)->flash && - (((struct airo_info *)dev->priv)->flash = kmalloc (FLASHSIZE, GFP_KERNEL)) == NULL) + if (!AIRO_FLASH(dev) && + (AIRO_FLASH(dev) = kmalloc(FLASHSIZE, GFP_KERNEL)) == NULL) return -ENOMEM; - return setflashmode((struct airo_info *)dev->priv); + return setflashmode((struct airo_info *)dev->ml_priv); case AIROFLSHGCHR: /* Get char from aux */ if(comp->len != sizeof(int)) return -EINVAL; if (copy_from_user(&z,comp->data,comp->len)) return -EFAULT; - return flashgchar((struct airo_info *)dev->priv,z,8000); + return flashgchar((struct airo_info *)dev->ml_priv, z, 8000); case AIROFLSHPCHR: /* Send char to card. */ if(comp->len != sizeof(int)) return -EINVAL; if (copy_from_user(&z,comp->data,comp->len)) return -EFAULT; - return flashpchar((struct airo_info *)dev->priv,z,8000); + return flashpchar((struct airo_info *)dev->ml_priv, z, 8000); case AIROFLPUTBUF: /* Send 32k to card */ - if (!((struct airo_info *)dev->priv)->flash) + if (!AIRO_FLASH(dev)) return -ENOMEM; if(comp->len > FLASHSIZE) return -EINVAL; - if(copy_from_user(((struct airo_info *)dev->priv)->flash,comp->data,comp->len)) + if (copy_from_user(AIRO_FLASH(dev), comp->data, comp->len)) return -EFAULT; - flashputbuf((struct airo_info *)dev->priv); + flashputbuf((struct airo_info *)dev->ml_priv); return 0; case AIRORESTART: - if(flashrestart((struct airo_info *)dev->priv,dev)) + if (flashrestart((struct airo_info *)dev->ml_priv, dev)) return -EIO; return 0; } diff --git a/drivers/net/wireless/arlan-main.c b/drivers/net/wireless/arlan-main.c index dec5e874a54db0aef692c1a4c6966631ad144121..bfca15da6f0f844fa379bcb7c7eade8914139e3c 100644 --- a/drivers/net/wireless/arlan-main.c +++ b/drivers/net/wireless/arlan-main.c @@ -1467,19 +1467,17 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short else if (hw_dst_addr[1] == 0x40) printk(KERN_ERR "%s m/bcast 0x0140 \n", dev->name); while (dmi) - { if (dmi->dmi_addrlen == 6) - { - DECLARE_MAC_BUF(mac); + { + if (dmi->dmi_addrlen == 6) { if (arlan_debug & ARLAN_DEBUG_HEADER_DUMP) - printk(KERN_ERR "%s mcl %s\n", - dev->name, print_mac(mac, dmi->dmi_addr)); + printk(KERN_ERR "%s mcl %pM\n", + dev->name, dmi->dmi_addr); for (i = 0; i < 6; i++) if (dmi->dmi_addr[i] != hw_dst_addr[i]) break; if (i == 6) break; - } - else + } else printk(KERN_ERR "%s: invalid multicast address length given.\n", dev->name); dmi = dmi->next; } @@ -1512,18 +1510,14 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short { char immedDestAddress[6]; char immedSrcAddress[6]; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); memcpy_fromio(immedDestAddress, arlan->immedDestAddress, 6); memcpy_fromio(immedSrcAddress, arlan->immedSrcAddress, 6); - printk(KERN_WARNING "%s t %s f %s imd %s ims %s\n", - dev->name, print_mac(mac, skbtmp), - print_mac(mac2, &skbtmp[6]), - print_mac(mac3, immedDestAddress), - print_mac(mac4, immedSrcAddress)); + printk(KERN_WARNING "%s t %pM f %pM imd %pM ims %pM\n", + dev->name, skbtmp, + &skbtmp[6], + immedDestAddress, + immedSrcAddress); } skb->protocol = eth_type_trans(skb, dev); IFDEBUG(ARLAN_DEBUG_HEADER_DUMP) @@ -1535,7 +1529,6 @@ static void arlan_rx_interrupt(struct net_device *dev, u_char rxStatus, u_short printk(KERN_WARNING "arlan kernel pkt type trans %x \n", skb->protocol); } netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } diff --git a/drivers/net/wireless/ath5k/ath5k.h b/drivers/net/wireless/ath5k/ath5k.h index 53ea439aff48a3e22f7f2fa7b63c376fa38c8af3..183ffc8e62cadc4b6b78c339d7a8ec0c4febf481 100644 --- a/drivers/net/wireless/ath5k/ath5k.h +++ b/drivers/net/wireless/ath5k/ath5k.h @@ -507,11 +507,15 @@ enum ath5k_tx_queue_id { #define AR5K_TXQ_FLAG_TXEOLINT_ENABLE 0x0004 /* Enable TXEOL interrupt -not used- */ #define AR5K_TXQ_FLAG_TXDESCINT_ENABLE 0x0008 /* Enable TXDESC interrupt -not used- */ #define AR5K_TXQ_FLAG_TXURNINT_ENABLE 0x0010 /* Enable TXURN interrupt */ -#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0020 /* Disable random post-backoff */ -#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0040 /* Enable ready time expiry policy (?)*/ -#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0080 /* Enable backoff while bursting */ -#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x0100 /* Disable backoff while bursting */ -#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x0200 /* Enable hw compression -not implemented-*/ +#define AR5K_TXQ_FLAG_CBRORNINT_ENABLE 0x0020 /* Enable CBRORN interrupt */ +#define AR5K_TXQ_FLAG_CBRURNINT_ENABLE 0x0040 /* Enable CBRURN interrupt */ +#define AR5K_TXQ_FLAG_QTRIGINT_ENABLE 0x0080 /* Enable QTRIG interrupt */ +#define AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE 0x0100 /* Enable TXNOFRM interrupt */ +#define AR5K_TXQ_FLAG_BACKOFF_DISABLE 0x0200 /* Disable random post-backoff */ +#define AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE 0x0300 /* Enable ready time expiry policy (?)*/ +#define AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE 0x0800 /* Enable backoff while bursting */ +#define AR5K_TXQ_FLAG_POST_FR_BKOFF_DIS 0x1000 /* Disable backoff while bursting */ +#define AR5K_TXQ_FLAG_COMPRESSION_ENABLE 0x2000 /* Enable hw compression -not implemented-*/ /* * A struct to hold tx queue's parameters @@ -817,13 +821,6 @@ struct ath5k_athchan_2ghz { return (false); \ } while (0) -enum ath5k_ant_setting { - AR5K_ANT_VARIABLE = 0, /* variable by programming */ - AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ - AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ - AR5K_ANT_MAX = 3, -}; - /* * Hardware interrupt abstraction */ @@ -853,7 +850,7 @@ enum ath5k_ant_setting { * checked. We should do this with ath5k_hw_update_mib_counters() but * it seems we should also then do some noise immunity work. * @AR5K_INT_RXPHY: RX PHY Error - * @AR5K_INT_RXKCM: ?? + * @AR5K_INT_RXKCM: RX Key cache miss * @AR5K_INT_SWBA: SoftWare Beacon Alert - indicates its time to send a * beacon that must be handled in software. The alternative is if you * have VEOL support, in that case you let the hardware deal with things. @@ -869,7 +866,7 @@ enum ath5k_ant_setting { * @AR5K_INT_FATAL: Fatal errors were encountered, typically caused by DMA * errors. These types of errors we can enable seem to be of type * AR5K_SIMR2_MCABT, AR5K_SIMR2_SSERR and AR5K_SIMR2_DPERR. - * @AR5K_INT_GLOBAL: Seems to be used to clear and set the IER + * @AR5K_INT_GLOBAL: Used to clear and set the IER * @AR5K_INT_NOCARD: signals the card has been removed * @AR5K_INT_COMMON: common interrupts shared amogst MACs with the same * bit value @@ -881,36 +878,61 @@ enum ath5k_ant_setting { * MACs. */ enum ath5k_int { - AR5K_INT_RX = 0x00000001, /* Not common */ + AR5K_INT_RXOK = 0x00000001, AR5K_INT_RXDESC = 0x00000002, + AR5K_INT_RXERR = 0x00000004, AR5K_INT_RXNOFRM = 0x00000008, AR5K_INT_RXEOL = 0x00000010, AR5K_INT_RXORN = 0x00000020, - AR5K_INT_TX = 0x00000040, /* Not common */ + AR5K_INT_TXOK = 0x00000040, AR5K_INT_TXDESC = 0x00000080, + AR5K_INT_TXERR = 0x00000100, + AR5K_INT_TXNOFRM = 0x00000200, + AR5K_INT_TXEOL = 0x00000400, AR5K_INT_TXURN = 0x00000800, AR5K_INT_MIB = 0x00001000, + AR5K_INT_SWI = 0x00002000, AR5K_INT_RXPHY = 0x00004000, AR5K_INT_RXKCM = 0x00008000, AR5K_INT_SWBA = 0x00010000, + AR5K_INT_BRSSI = 0x00020000, AR5K_INT_BMISS = 0x00040000, - AR5K_INT_BNR = 0x00100000, /* Not common */ - AR5K_INT_GPIO = 0x01000000, - AR5K_INT_FATAL = 0x40000000, /* Not common */ - AR5K_INT_GLOBAL = 0x80000000, - - AR5K_INT_COMMON = AR5K_INT_RXNOFRM - | AR5K_INT_RXDESC - | AR5K_INT_RXEOL - | AR5K_INT_RXORN - | AR5K_INT_TXURN - | AR5K_INT_TXDESC - | AR5K_INT_MIB - | AR5K_INT_RXPHY - | AR5K_INT_RXKCM - | AR5K_INT_SWBA - | AR5K_INT_BMISS - | AR5K_INT_GPIO, + AR5K_INT_FATAL = 0x00080000, /* Non common */ + AR5K_INT_BNR = 0x00100000, /* Non common */ + AR5K_INT_TIM = 0x00200000, /* Non common */ + AR5K_INT_DTIM = 0x00400000, /* Non common */ + AR5K_INT_DTIM_SYNC = 0x00800000, /* Non common */ + AR5K_INT_GPIO = 0x01000000, + AR5K_INT_BCN_TIMEOUT = 0x02000000, /* Non common */ + AR5K_INT_CAB_TIMEOUT = 0x04000000, /* Non common */ + AR5K_INT_RX_DOPPLER = 0x08000000, /* Non common */ + AR5K_INT_QCBRORN = 0x10000000, /* Non common */ + AR5K_INT_QCBRURN = 0x20000000, /* Non common */ + AR5K_INT_QTRIG = 0x40000000, /* Non common */ + AR5K_INT_GLOBAL = 0x80000000, + + AR5K_INT_COMMON = AR5K_INT_RXOK + | AR5K_INT_RXDESC + | AR5K_INT_RXERR + | AR5K_INT_RXNOFRM + | AR5K_INT_RXEOL + | AR5K_INT_RXORN + | AR5K_INT_TXOK + | AR5K_INT_TXDESC + | AR5K_INT_TXERR + | AR5K_INT_TXNOFRM + | AR5K_INT_TXEOL + | AR5K_INT_TXURN + | AR5K_INT_MIB + | AR5K_INT_SWI + | AR5K_INT_RXPHY + | AR5K_INT_RXKCM + | AR5K_INT_SWBA + | AR5K_INT_BRSSI + | AR5K_INT_BMISS + | AR5K_INT_GPIO + | AR5K_INT_GLOBAL, + AR5K_INT_NOCARD = 0xffffffff }; @@ -1030,6 +1052,7 @@ struct ath5k_hw { bool ah_calibration; bool ah_running; bool ah_single_chip; + bool ah_combined_mic; enum ath5k_rfgain ah_rf_gain; u32 ah_mac_srev; @@ -1064,10 +1087,11 @@ struct ath5k_hw { u8 ah_sta_id[ETH_ALEN]; - /* Current BSSID we are trying to assoc to / creating. + /* Current BSSID we are trying to assoc to / create. * This is passed by mac80211 on config_interface() and cached here for * use in resets */ u8 ah_bssid[ETH_ALEN]; + u8 ah_bssid_mask[ETH_ALEN]; u32 ah_gpio[AR5K_MAX_GPIO]; int ah_gpio_npins; @@ -1081,6 +1105,11 @@ struct ath5k_hw { u32 ah_txq_imr_txurn; u32 ah_txq_imr_txdesc; u32 ah_txq_imr_txeol; + u32 ah_txq_imr_cbrorn; + u32 ah_txq_imr_cbrurn; + u32 ah_txq_imr_qtrig; + u32 ah_txq_imr_nofrm; + u32 ah_txq_isr; u32 *ah_rf_banks; size_t ah_rf_banks_size; struct ath5k_gain ah_gain; @@ -1321,4 +1350,9 @@ static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits) return retval; } +static inline int ath5k_pad_size(int hdrlen) +{ + return (hdrlen < 24) ? 0 : hdrlen & 3; +} + #endif diff --git a/drivers/net/wireless/ath5k/attach.c b/drivers/net/wireless/ath5k/attach.c index 51d569883cdd787a7a9b3de3f567f4e415aa1ea1..dea378f767310818a289667b7b24441beab89713 100644 --- a/drivers/net/wireless/ath5k/attach.c +++ b/drivers/net/wireless/ath5k/attach.c @@ -106,7 +106,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) { struct ath5k_hw *ah; struct pci_dev *pdev = sc->pdev; - u8 mac[ETH_ALEN]; + u8 mac[ETH_ALEN] = {}; int ret; u32 srev; @@ -317,15 +317,15 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version) goto err_free; } - /* Set MAC address */ - ret = ath5k_eeprom_read_mac(ah, mac); - if (ret) { - ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", - sc->pdev->device); - goto err_free; + if (srev >= AR5K_SREV_AR2414) { + ah->ah_combined_mic = true; + AR5K_REG_ENABLE_BITS(ah, AR5K_MISC_MODE, + AR5K_MISC_MODE_COMBINED_MIC); } + /* MAC address is cleared until add_interface */ ath5k_hw_set_lladdr(ah, mac); + /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */ memset(ah->ah_bssid, 0xff, ETH_ALEN); ath5k_hw_set_associd(ah, ah->ah_bssid, 0); diff --git a/drivers/net/wireless/ath5k/base.c b/drivers/net/wireless/ath5k/base.c index 2d14255eb103d60096256eee89c78bbfe68f8550..4af2607deec09ad9582e2aa488723b461daf8416 100644 --- a/drivers/net/wireless/ath5k/base.c +++ b/drivers/net/wireless/ath5k/base.c @@ -60,6 +60,9 @@ #include "debug.h" static int ath5k_calinterval = 10; /* Calibrate PHY every 10 secs (TODO: Fixme) */ +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /******************\ @@ -197,7 +200,7 @@ static int ath5k_pci_resume(struct pci_dev *pdev); #endif /* CONFIG_PM */ static struct pci_driver ath5k_pci_driver = { - .name = "ath5k_pci", + .name = KBUILD_MODNAME, .id_table = ath5k_pci_id_table, .probe = ath5k_pci_probe, .remove = __devexit_p(ath5k_pci_remove), @@ -219,8 +222,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); static void ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); -static int ath5k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf); +static int ath5k_config(struct ieee80211_hw *hw, u32 changed); static int ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); @@ -238,7 +240,7 @@ static int ath5k_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats); static u64 ath5k_get_tsf(struct ieee80211_hw *hw); static void ath5k_reset_tsf(struct ieee80211_hw *hw); -static int ath5k_beacon_update(struct ieee80211_hw *hw, +static int ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb); static void ath5k_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, @@ -548,8 +550,8 @@ ath5k_pci_probe(struct pci_dev *pdev, /* set up multi-rate retry capabilities */ if (sc->ah->ah_version == AR5K_AR5212) { - hw->max_altrates = 3; - hw->max_altrate_tries = 11; + hw->max_rates = 4; + hw->max_rate_tries = 11; } /* Finish private driver data initialization */ @@ -711,7 +713,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) { struct ath5k_softc *sc = hw->priv; struct ath5k_hw *ah = sc->ah; - u8 mac[ETH_ALEN]; + u8 mac[ETH_ALEN] = {}; int ret; ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device); @@ -781,7 +783,13 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw) tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc); setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc); - ath5k_hw_get_lladdr(ah, mac); + ret = ath5k_eeprom_read_mac(ah, mac); + if (ret) { + ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n", + sc->pdev->device); + goto err_queues; + } + SET_IEEE80211_PERM_ADDR(hw, mac); /* All MAC address bits matter for ACKs */ memset(sc->bssidmask, 0xff, ETH_ALEN); @@ -1188,7 +1196,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL, (sc->power_level * 2), ieee80211_get_tx_rate(sc->hw, info)->hw_value, - info->control.retry_limit, keyidx, 0, flags, 0, 0); + info->control.rates[0].count, keyidx, 0, flags, 0, 0); if (ret) goto err_unmap; @@ -1200,7 +1208,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf) break; mrr_rate[i] = rate->hw_value; - mrr_tries[i] = info->control.retries[i].limit; + mrr_tries[i] = info->control.rates[i + 1].count; } ah->ah_setup_mrr_tx_desc(ah, ds, @@ -1660,7 +1668,7 @@ ath5k_tasklet_rx(unsigned long data) struct ath5k_desc *ds; int ret; int hdrlen; - int pad; + int padsize; spin_lock(&sc->rxbuflock); if (list_empty(&sc->rxbuf)) { @@ -1745,16 +1753,19 @@ accept: skb_put(skb, rs.rs_datalen); - /* - * the hardware adds a padding to 4 byte boundaries between - * the header and the payload data if the header length is - * not multiples of 4 - remove it - */ + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - hdrlen % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); - if (hdrlen & 3) { - pad = hdrlen % 4; - memmove(skb->data + pad, skb->data, hdrlen); - skb_pull(skb, pad); + padsize = ath5k_pad_size(hdrlen); + if (padsize) { + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); } /* @@ -1785,7 +1796,17 @@ accept: rxs.noise = sc->ah->ah_noise_floor; rxs.signal = rxs.noise + rs.rs_rssi; - rxs.qual = rs.rs_rssi * 100 / 64; + + /* An rssi of 35 indicates you should be able use + * 54 Mbps reliably. A more elaborate scheme can be used + * here but it requires a map of SNR/throughput for each + * possible mode used */ + rxs.qual = rs.rs_rssi * 100 / 35; + + /* rssi can be more than 35 though, anything above that + * should be considered at 100% */ + if (rxs.qual > 100) + rxs.qual = 100; rxs.antenna = rs.rs_antenna; rxs.rate_idx = ath5k_hw_to_driver_rix(sc, rs.rs_rate); @@ -1846,30 +1867,26 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq) pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE); - memset(&info->status, 0, sizeof(info->status)); - info->tx_rate_idx = ath5k_hw_to_driver_rix(sc, - ts.ts_rate[ts.ts_final_idx]); - info->status.retry_count = ts.ts_longretry; - + ieee80211_tx_info_clear_status(info); for (i = 0; i < 4; i++) { - struct ieee80211_tx_altrate *r = - &info->status.retries[i]; + struct ieee80211_tx_rate *r = + &info->status.rates[i]; if (ts.ts_rate[i]) { - r->rate_idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); - r->limit = ts.ts_retry[i]; + r->idx = ath5k_hw_to_driver_rix(sc, ts.ts_rate[i]); + r->count = ts.ts_retry[i]; } else { - r->rate_idx = -1; - r->limit = 0; + r->idx = -1; + r->count = 0; } } - info->status.excessive_retries = 0; + /* count the successful attempt as well */ + info->status.rates[ts.ts_final_idx].count++; + if (unlikely(ts.ts_status)) { sc->ll_stats.dot11ACKFailureCount++; - if (ts.ts_status & AR5K_TXERR_XRETRY) - info->status.excessive_retries = 1; - else if (ts.ts_status & AR5K_TXERR_FILT) + if (ts.ts_status & AR5K_TXERR_FILT) info->flags |= IEEE80211_TX_STAT_TX_FILTERED; } else { info->flags |= IEEE80211_TX_STAT_ACK; @@ -2143,8 +2160,6 @@ ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf) * * In IBSS mode we use a self-linked tx descriptor if possible. We enable SWBA * interrupts to detect TSF updates only. - * - * AP mode is missing. */ static void ath5k_beacon_config(struct ath5k_softc *sc) @@ -2157,7 +2172,9 @@ ath5k_beacon_config(struct ath5k_softc *sc) if (sc->opmode == NL80211_IFTYPE_STATION) { sc->imask |= AR5K_INT_BMISS; - } else if (sc->opmode == NL80211_IFTYPE_ADHOC) { + } else if (sc->opmode == NL80211_IFTYPE_ADHOC || + sc->opmode == NL80211_IFTYPE_MESH_POINT || + sc->opmode == NL80211_IFTYPE_AP) { /* * In IBSS mode we use a self-linked tx descriptor and let the * hardware send the beacons automatically. We have to load it @@ -2169,13 +2186,15 @@ ath5k_beacon_config(struct ath5k_softc *sc) sc->imask |= AR5K_INT_SWBA; - if (ath5k_hw_hasveol(ah)) { - spin_lock(&sc->block); - ath5k_beacon_send(sc); - spin_unlock(&sc->block); - } + if (sc->opmode == NL80211_IFTYPE_ADHOC) { + if (ath5k_hw_hasveol(ah)) { + spin_lock(&sc->block); + ath5k_beacon_send(sc); + spin_unlock(&sc->block); + } + } else + ath5k_beacon_update_timers(sc, -1); } - /* TODO else AP */ ath5k_hw_set_imr(ah, sc->imask); } @@ -2215,9 +2234,9 @@ ath5k_init(struct ath5k_softc *sc, bool is_resume) */ sc->curchan = sc->hw->conf.channel; sc->curband = &sc->sbands[sc->curchan->band]; - sc->imask = AR5K_INT_RX | AR5K_INT_TX | AR5K_INT_RXEOL | - AR5K_INT_RXORN | AR5K_INT_FATAL | AR5K_INT_GLOBAL | - AR5K_INT_MIB; + sc->imask = AR5K_INT_RXOK | AR5K_INT_RXERR | AR5K_INT_RXEOL | + AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL | + AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB; ret = ath5k_reset(sc, false, false); if (ret) goto done; @@ -2409,9 +2428,10 @@ ath5k_intr(int irq, void *dev_id) /* bump tx trigger level */ ath5k_hw_update_tx_triglevel(ah, true); } - if (status & AR5K_INT_RX) + if (status & (AR5K_INT_RXOK | AR5K_INT_RXERR)) tasklet_schedule(&sc->rxtq); - if (status & AR5K_INT_TX) + if (status & (AR5K_INT_TXOK | AR5K_INT_TXDESC + | AR5K_INT_TXERR | AR5K_INT_TXEOL)) tasklet_schedule(&sc->txtq); if (status & AR5K_INT_BMISS) { } @@ -2527,8 +2547,7 @@ ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led, led->led_dev.brightness_set = ath5k_led_brightness_set; err = led_classdev_register(&sc->pdev->dev, &led->led_dev); - if (err) - { + if (err) { ATH5K_WARN(sc, "could not register LED %s\n", name); led->sc = NULL; } @@ -2607,7 +2626,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) struct ath5k_buf *bf; unsigned long flags; int hdrlen; - int pad; + int padsize; ath5k_debug_dump_skb(sc, skb, "TX ", 1); @@ -2619,15 +2638,16 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * if this is not the case we add the padding after the header */ hdrlen = ieee80211_get_hdrlen_from_skb(skb); - if (hdrlen & 3) { - pad = hdrlen % 4; - if (skb_headroom(skb) < pad) { + padsize = ath5k_pad_size(hdrlen); + if (padsize) { + + if (skb_headroom(skb) < padsize) { ATH5K_ERR(sc, "tx hdrlen not %%4: %d not enough" - " headroom to pad %d\n", hdrlen, pad); + " headroom to pad %d\n", hdrlen, padsize); return -1; } - skb_push(skb, pad); - memmove(skb->data, skb->data+pad, hdrlen); + skb_push(skb, padsize); + memmove(skb->data, skb->data+padsize, hdrlen); } spin_lock_irqsave(&sc->txbuflock, flags); @@ -2746,8 +2766,10 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, sc->vif = conf->vif; switch (conf->type) { + case NL80211_IFTYPE_AP: case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: case NL80211_IFTYPE_MONITOR: sc->opmode = conf->type; break; @@ -2759,6 +2781,7 @@ static int ath5k_add_interface(struct ieee80211_hw *hw, /* Set to a reasonable value. Note that this will * be set to mac80211's value at ath5k_config(). */ sc->bintval = 1000; + ath5k_hw_set_lladdr(sc->ah, conf->mac_addr); ret = 0; end: @@ -2771,11 +2794,13 @@ ath5k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ath5k_softc *sc = hw->priv; + u8 mac[ETH_ALEN] = {}; mutex_lock(&sc->lock); if (sc->vif != conf->vif) goto end; + ath5k_hw_set_lladdr(sc->ah, mac); sc->vif = NULL; end: mutex_unlock(&sc->lock); @@ -2785,10 +2810,10 @@ end: * TODO: Phy disable/diversity etc */ static int -ath5k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +ath5k_config(struct ieee80211_hw *hw, u32 changed) { struct ath5k_softc *sc = hw->priv; + struct ieee80211_conf *conf = &hw->conf; sc->bintval = conf->beacon_int; sc->power_level = conf->power_level; @@ -2809,7 +2834,7 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ret = -EIO; goto unlock; } - if (conf->bssid) { + if (conf->changed & IEEE80211_IFCC_BSSID && conf->bssid) { /* Cache for later use during resets */ memcpy(ah->ah_bssid, conf->bssid, ETH_ALEN); /* XXX: assoc id is set to 0 for now, mac80211 doesn't have @@ -2817,18 +2842,17 @@ ath5k_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, ath5k_hw_set_associd(ah, ah->ah_bssid, 0); mmiowb(); } - if (conf->changed & IEEE80211_IFCC_BEACON && - vif->type == NL80211_IFTYPE_ADHOC) { + (vif->type == NL80211_IFTYPE_ADHOC || + vif->type == NL80211_IFTYPE_MESH_POINT || + vif->type == NL80211_IFTYPE_AP)) { struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) { ret = -ENOMEM; goto unlock; } - /* call old handler for now */ - ath5k_beacon_update(hw, beacon); + ath5k_beacon_update(sc, beacon); } - mutex_unlock(&sc->lock); return ath5k_reset_wake(sc); @@ -2888,9 +2912,9 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, if (*new_flags & FIF_PROMISC_IN_BSS) { rfilt |= AR5K_RX_FILTER_PROM; __set_bit(ATH_STAT_PROMISC, sc->status); - } - else + } else { __clear_bit(ATH_STAT_PROMISC, sc->status); + } } /* Note, AR5K_RX_FILTER_MCAST is already enabled */ @@ -2948,12 +2972,15 @@ static void ath5k_configure_filter(struct ieee80211_hw *hw, test_bit(ATH_STAT_PROMISC, sc->status)) rfilt |= AR5K_RX_FILTER_PROM; if ((sc->opmode == NL80211_IFTYPE_STATION && sc->assoc) || - sc->opmode == NL80211_IFTYPE_ADHOC) { + sc->opmode == NL80211_IFTYPE_ADHOC || + sc->opmode == NL80211_IFTYPE_AP) rfilt |= AR5K_RX_FILTER_BEACON; - } + if (sc->opmode == NL80211_IFTYPE_MESH_POINT) + rfilt |= AR5K_RX_FILTER_CONTROL | AR5K_RX_FILTER_BEACON | + AR5K_RX_FILTER_PROBEREQ | AR5K_RX_FILTER_PROM; /* Set filters */ - ath5k_hw_set_rx_filter(ah,rfilt); + ath5k_hw_set_rx_filter(ah, rfilt); /* Set multicast bits */ ath5k_hw_set_mcast_filter(ah, mfilt[0], mfilt[1]); @@ -2970,12 +2997,13 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ath5k_softc *sc = hw->priv; int ret = 0; - switch(key->alg) { + if (modparam_nohwcrypt) + return -EOPNOTSUPP; + + switch (key->alg) { case ALG_WEP: - /* XXX: fix hardware encryption, its not working. For now - * allow software encryption */ - /* break; */ case ALG_TKIP: + break; case ALG_CCMP: return -EOPNOTSUPP; default: @@ -2994,6 +3022,8 @@ ath5k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } __set_bit(key->keyidx, sc->keymap); key->hw_key_idx = key->keyidx; + key->flags |= (IEEE80211_KEY_FLAG_GENERATE_IV | + IEEE80211_KEY_FLAG_GENERATE_MMIC); break; case DISABLE_KEY: ath5k_hw_reset_key(sc->ah, key->keyidx); @@ -3060,19 +3090,13 @@ ath5k_reset_tsf(struct ieee80211_hw *hw) } static int -ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) +ath5k_beacon_update(struct ath5k_softc *sc, struct sk_buff *skb) { - struct ath5k_softc *sc = hw->priv; unsigned long flags; int ret; ath5k_debug_dump_skb(sc, skb, "BC ", 1); - if (sc->opmode != NL80211_IFTYPE_ADHOC) { - ret = -EIO; - goto end; - } - spin_lock_irqsave(&sc->block, flags); ath5k_txbuf_free(sc, sc->bbuf); sc->bbuf->skb = skb; @@ -3085,7 +3109,6 @@ ath5k_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) mmiowb(); } -end: return ret; } static void diff --git a/drivers/net/wireless/ath5k/desc.c b/drivers/net/wireless/ath5k/desc.c index 5e362a7a362007aec0c8bf6800de1d97a587166d..b40a9287a39a8a3be2fd8888c2f5dd8fde484511 100644 --- a/drivers/net/wireless/ath5k/desc.c +++ b/drivers/net/wireless/ath5k/desc.c @@ -71,7 +71,7 @@ ath5k_hw_setup_2word_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc, /* Verify and set frame length */ /* remove padding we might have added before */ - frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN; if (frame_len & ~AR5K_2W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; @@ -202,7 +202,7 @@ static int ath5k_hw_setup_4word_tx_desc(struct ath5k_hw *ah, /* Verify and set frame length */ /* remove padding we might have added before */ - frame_len = pkt_len - (hdr_len & 3) + FCS_LEN; + frame_len = pkt_len - ath5k_pad_size(hdr_len) + FCS_LEN; if (frame_len & ~AR5K_4W_TX_DESC_CTL0_FRAME_LEN) return -EINVAL; diff --git a/drivers/net/wireless/ath5k/dma.c b/drivers/net/wireless/ath5k/dma.c index 7adceb2c7fab50c33d4769b04364ec6655b4ad3e..7e2b1a67e5da3c505cddea78fde4406ab80254fd 100644 --- a/drivers/net/wireless/ath5k/dma.c +++ b/drivers/net/wireless/ath5k/dma.c @@ -472,9 +472,6 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah) * * NOTE: We use read-and-clear register, so after this function is called ISR * is zeroed. - * - * XXX: Why filter interrupts in sw with interrupt_mask ? No benefit at all - * plus it can be misleading (one might thing that we save interrupts this way) */ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) { @@ -494,11 +491,16 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) } } else { /* - * Read interrupt status from the Read-And-Clear - * shadow register. + * Read interrupt status from Interrupt + * Status Register shadow copy (Read And Clear) + * * Note: PISR/SISR Not available on 5210 */ data = ath5k_hw_reg_read(ah, AR5K_RAC_PISR); + if (unlikely(data == AR5K_INT_NOCARD)) { + *interrupt_mask = data; + return -ENODEV; + } } /* @@ -506,17 +508,9 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) */ *interrupt_mask = (data & AR5K_INT_COMMON) & ah->ah_imr; - if (unlikely(data == AR5K_INT_NOCARD)) - return -ENODEV; - - if (data & (AR5K_ISR_RXOK | AR5K_ISR_RXERR)) - *interrupt_mask |= AR5K_INT_RX; - - if (data & (AR5K_ISR_TXOK | AR5K_ISR_TXERR - | AR5K_ISR_TXDESC | AR5K_ISR_TXEOL)) - *interrupt_mask |= AR5K_INT_TX; - if (ah->ah_version != AR5K_AR5210) { + u32 sisr2 = ath5k_hw_reg_read(ah, AR5K_RAC_SISR2); + /*HIU = Host Interface Unit (PCI etc)*/ if (unlikely(data & (AR5K_ISR_HIUERR))) *interrupt_mask |= AR5K_INT_FATAL; @@ -524,24 +518,93 @@ int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask) /*Beacon Not Ready*/ if (unlikely(data & (AR5K_ISR_BNR))) *interrupt_mask |= AR5K_INT_BNR; - } - /* - * XXX: BMISS interrupts may occur after association. - * I found this on 5210 code but it needs testing. If this is - * true we should disable them before assoc and re-enable them - * after a successfull assoc + some jiffies. - */ -#if 0 - interrupt_mask &= ~AR5K_INT_BMISS; -#endif + if (unlikely(sisr2 & (AR5K_SISR2_SSERR | + AR5K_SISR2_DPERR | + AR5K_SISR2_MCABT))) + *interrupt_mask |= AR5K_INT_FATAL; + + if (data & AR5K_ISR_TIM) + *interrupt_mask |= AR5K_INT_TIM; + + if (data & AR5K_ISR_BCNMISC) { + if (sisr2 & AR5K_SISR2_TIM) + *interrupt_mask |= AR5K_INT_TIM; + if (sisr2 & AR5K_SISR2_DTIM) + *interrupt_mask |= AR5K_INT_DTIM; + if (sisr2 & AR5K_SISR2_DTIM_SYNC) + *interrupt_mask |= AR5K_INT_DTIM_SYNC; + if (sisr2 & AR5K_SISR2_BCN_TIMEOUT) + *interrupt_mask |= AR5K_INT_BCN_TIMEOUT; + if (sisr2 & AR5K_SISR2_CAB_TIMEOUT) + *interrupt_mask |= AR5K_INT_CAB_TIMEOUT; + } + + if (data & AR5K_ISR_RXDOPPLER) + *interrupt_mask |= AR5K_INT_RX_DOPPLER; + if (data & AR5K_ISR_QCBRORN) { + *interrupt_mask |= AR5K_INT_QCBRORN; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), + AR5K_SISR3_QCBRORN); + } + if (data & AR5K_ISR_QCBRURN) { + *interrupt_mask |= AR5K_INT_QCBRURN; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR3), + AR5K_SISR3_QCBRURN); + } + if (data & AR5K_ISR_QTRIG) { + *interrupt_mask |= AR5K_INT_QTRIG; + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR4), + AR5K_SISR4_QTRIG); + } + + if (data & AR5K_ISR_TXOK) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), + AR5K_SISR0_QCU_TXOK); + + if (data & AR5K_ISR_TXDESC) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR0), + AR5K_SISR0_QCU_TXDESC); + + if (data & AR5K_ISR_TXERR) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), + AR5K_SISR1_QCU_TXERR); + + if (data & AR5K_ISR_TXEOL) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR1), + AR5K_SISR1_QCU_TXEOL); + + if (data & AR5K_ISR_TXURN) + ah->ah_txq_isr |= AR5K_REG_MS( + ath5k_hw_reg_read(ah, AR5K_RAC_SISR2), + AR5K_SISR2_QCU_TXURN); + } else { + if (unlikely(data & (AR5K_ISR_SSERR | AR5K_ISR_MCABT + | AR5K_ISR_HIUERR | AR5K_ISR_DPERR))) + *interrupt_mask |= AR5K_INT_FATAL; + + /* + * XXX: BMISS interrupts may occur after association. + * I found this on 5210 code but it needs testing. If this is + * true we should disable them before assoc and re-enable them + * after a successfull assoc + some jiffies. + interrupt_mask &= ~AR5K_INT_BMISS; + */ + } /* * In case we didn't handle anything, * print the register value. */ if (unlikely(*interrupt_mask == 0 && net_ratelimit())) - ATH5K_PRINTF("0x%08x\n", data); + ATH5K_PRINTF("ISR: 0x%08x IMR: 0x%08x\n", data, ah->ah_imr); return 0; } @@ -560,14 +623,17 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) { enum ath5k_int old_mask, int_mask; + old_mask = ah->ah_imr; + /* * Disable card interrupts to prevent any race conditions - * (they will be re-enabled afterwards). + * (they will be re-enabled afterwards if AR5K_INT GLOBAL + * is set again on the new mask). */ - ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); - ath5k_hw_reg_read(ah, AR5K_IER); - - old_mask = ah->ah_imr; + if (old_mask & AR5K_INT_GLOBAL) { + ath5k_hw_reg_write(ah, AR5K_IER_DISABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); + } /* * Add additional, chipset-dependent interrupt mask flags @@ -575,30 +641,64 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask) */ int_mask = new_mask & AR5K_INT_COMMON; - if (new_mask & AR5K_INT_RX) - int_mask |= AR5K_IMR_RXOK | AR5K_IMR_RXERR | AR5K_IMR_RXORN | - AR5K_IMR_RXDESC; - - if (new_mask & AR5K_INT_TX) - int_mask |= AR5K_IMR_TXOK | AR5K_IMR_TXERR | AR5K_IMR_TXDESC | - AR5K_IMR_TXURN; - if (ah->ah_version != AR5K_AR5210) { + /* Preserve per queue TXURN interrupt mask */ + u32 simr2 = ath5k_hw_reg_read(ah, AR5K_SIMR2) + & AR5K_SIMR2_QCU_TXURN; + if (new_mask & AR5K_INT_FATAL) { int_mask |= AR5K_IMR_HIUERR; - AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_MCABT | - AR5K_SIMR2_SSERR | AR5K_SIMR2_DPERR); + simr2 |= (AR5K_SIMR2_MCABT | AR5K_SIMR2_SSERR + | AR5K_SIMR2_DPERR); } + + /*Beacon Not Ready*/ + if (new_mask & AR5K_INT_BNR) + int_mask |= AR5K_INT_BNR; + + if (new_mask & AR5K_INT_TIM) + int_mask |= AR5K_IMR_TIM; + + if (new_mask & AR5K_INT_TIM) + simr2 |= AR5K_SISR2_TIM; + if (new_mask & AR5K_INT_DTIM) + simr2 |= AR5K_SISR2_DTIM; + if (new_mask & AR5K_INT_DTIM_SYNC) + simr2 |= AR5K_SISR2_DTIM_SYNC; + if (new_mask & AR5K_INT_BCN_TIMEOUT) + simr2 |= AR5K_SISR2_BCN_TIMEOUT; + if (new_mask & AR5K_INT_CAB_TIMEOUT) + simr2 |= AR5K_SISR2_CAB_TIMEOUT; + + if (new_mask & AR5K_INT_RX_DOPPLER) + int_mask |= AR5K_IMR_RXDOPPLER; + + /* Note: Per queue interrupt masks + * are set via reset_tx_queue (qcu.c) */ + ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); + ath5k_hw_reg_write(ah, simr2, AR5K_SIMR2); + + } else { + if (new_mask & AR5K_INT_FATAL) + int_mask |= (AR5K_IMR_SSERR | AR5K_IMR_MCABT + | AR5K_IMR_HIUERR | AR5K_IMR_DPERR); + + ath5k_hw_reg_write(ah, int_mask, AR5K_IMR); } - ath5k_hw_reg_write(ah, int_mask, AR5K_PIMR); + /* If RXNOFRM interrupt is masked disable it + * by setting AR5K_RXNOFRM to zero */ + if (!(new_mask & AR5K_INT_RXNOFRM)) + ath5k_hw_reg_write(ah, 0, AR5K_RXNOFRM); /* Store new interrupt mask */ ah->ah_imr = new_mask; - /* ..re-enable interrupts */ - ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); - ath5k_hw_reg_read(ah, AR5K_IER); + /* ..re-enable interrupts if AR5K_INT_GLOBAL is set */ + if (new_mask & AR5K_INT_GLOBAL) { + ath5k_hw_reg_write(ah, AR5K_IER_ENABLE, AR5K_IER); + ath5k_hw_reg_read(ah, AR5K_IER); + } return old_mask; } diff --git a/drivers/net/wireless/ath5k/eeprom.c b/drivers/net/wireless/ath5k/eeprom.c index a883839b6a9f2a2c7249e6f490658fe07f21368d..1cb7edfae625cca6076f45d6b11afa8463ae47cb 100644 --- a/drivers/net/wireless/ath5k/eeprom.c +++ b/drivers/net/wireless/ath5k/eeprom.c @@ -1,6 +1,7 @@ /* * Copyright (c) 2004-2008 Reyk Floeter * Copyright (c) 2006-2008 Nick Kossifidis + * Copyright (c) 2008 Felix Fietkau * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -63,8 +64,8 @@ static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data) /* * Translate binary channel representation in EEPROM to frequency */ -static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, - unsigned int mode) +static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin, + unsigned int mode) { u16 val; @@ -72,13 +73,13 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, return bin; if (mode == AR5K_EEPROM_MODE_11A) { - if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) + if (ee->ee_version > AR5K_EEPROM_VERSION_3_2) val = (5 * bin) + 4800; else val = bin > 62 ? (10 * 62) + (5 * (bin - 62)) + 5100 : (bin * 10) + 5100; } else { - if (ah->ah_ee_version > AR5K_EEPROM_VERSION_3_2) + if (ee->ee_version > AR5K_EEPROM_VERSION_3_2) val = bin + 2300; else val = bin + 2400; @@ -87,6 +88,71 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_hw *ah, u16 bin, return val; } +/* + * Initialize eeprom & capabilities structs + */ +static int +ath5k_eeprom_init_header(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + int ret; + u16 val; + + /* Initial TX thermal adjustment values */ + ee->ee_tx_clip = 4; + ee->ee_pwd_84 = ee->ee_pwd_90 = 1; + ee->ee_gain_select = 1; + + /* + * Read values from EEPROM and store them in the capability structure + */ + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); + + /* Return if we have an old EEPROM */ + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) + return 0; + +#ifdef notyet + /* + * Validate the checksum of the EEPROM date. There are some + * devices with invalid EEPROMs. + */ + for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { + AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); + cksum ^= val; + } + if (cksum != AR5K_EEPROM_INFO_CKSUM) { + ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); + return -EIO; + } +#endif + + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), + ee_ant_gain); + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); + AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); + } + + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { + AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); + ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; + ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; + + AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); + ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; + ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; + } + + return 0; +} + + /* * Read antenna infos from eeprom */ @@ -100,7 +166,7 @@ static int ath5k_eeprom_read_ants(struct ath5k_hw *ah, u32 *offset, AR5K_EEPROM_READ(o++, val); ee->ee_switch_settling[mode] = (val >> 8) & 0x7f; - ee->ee_ant_tx_rx[mode] = (val >> 2) & 0x3f; + ee->ee_atn_tx_rx[mode] = (val >> 2) & 0x3f; ee->ee_ant_control[mode][i] = (val << 4) & 0x3f; AR5K_EEPROM_READ(o++, val); @@ -157,6 +223,30 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, u16 val; int ret; + ee->ee_n_piers[mode] = 0; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); + switch(mode) { + case AR5K_EEPROM_MODE_11A: + ee->ee_ob[mode][3] = (val >> 5) & 0x7; + ee->ee_db[mode][3] = (val >> 2) & 0x7; + ee->ee_ob[mode][2] = (val << 1) & 0x7; + + AR5K_EEPROM_READ(o++, val); + ee->ee_ob[mode][2] |= (val >> 15) & 0x1; + ee->ee_db[mode][2] = (val >> 12) & 0x7; + ee->ee_ob[mode][1] = (val >> 9) & 0x7; + ee->ee_db[mode][1] = (val >> 6) & 0x7; + ee->ee_ob[mode][0] = (val >> 3) & 0x7; + ee->ee_db[mode][0] = val & 0x7; + break; + case AR5K_EEPROM_MODE_11G: + case AR5K_EEPROM_MODE_11B: + ee->ee_ob[mode][1] = (val >> 4) & 0x7; + ee->ee_db[mode][1] = val & 0x7; + break; + } + AR5K_EEPROM_READ(o++, val); ee->ee_tx_end2xlna_enable[mode] = (val >> 8) & 0xff; ee->ee_thr_62[mode] = val & 0xff; @@ -209,8 +299,11 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, AR5K_EEPROM_READ(o++, val); ee->ee_i_gain[mode] |= (val << 3) & 0x38; - if (mode == AR5K_EEPROM_MODE_11G) + if (mode == AR5K_EEPROM_MODE_11G) { ee->ee_cck_ofdm_power_delta = (val >> 3) & 0xff; + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6) + ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; + } } if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0 && @@ -219,10 +312,77 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, ee->ee_q_cal[mode] = (val >> 3) & 0x1f; } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_6 && - mode == AR5K_EEPROM_MODE_11G) - ee->ee_scaled_cck_delta = (val >> 11) & 0x1f; + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_0) + goto done; + + switch(mode) { + case AR5K_EEPROM_MODE_11A: + if (ah->ah_ee_version < AR5K_EEPROM_VERSION_4_1) + break; + + AR5K_EEPROM_READ(o++, val); + ee->ee_margin_tx_rx[mode] = val & 0x3f; + break; + case AR5K_EEPROM_MODE_11B: + AR5K_EEPROM_READ(o++, val); + + ee->ee_pwr_cal_b[0].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_b[0].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + ee->ee_pwr_cal_b[1].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + if (ee->ee_pwr_cal_b[1].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pwr_cal_b[2].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_b[2].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + break; + case AR5K_EEPROM_MODE_11G: + AR5K_EEPROM_READ(o++, val); + + ee->ee_pwr_cal_g[0].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_g[0].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + ee->ee_pwr_cal_g[1].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + if (ee->ee_pwr_cal_g[1].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + + AR5K_EEPROM_READ(o++, val); + ee->ee_turbo_max_power[mode] = val & 0x7f; + ee->ee_xr_power[mode] = (val >> 7) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_pwr_cal_g[2].freq = + ath5k_eeprom_bin2freq(ee, val & 0xff, mode); + if (ee->ee_pwr_cal_g[2].freq != AR5K_EEPROM_CHANNEL_DIS) + ee->ee_n_piers[mode]++; + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) + ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + + AR5K_EEPROM_READ(o++, val); + ee->ee_i_cal[mode] = (val >> 8) & 0x3f; + ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { + AR5K_EEPROM_READ(o++, val); + ee->ee_cck_ofdm_gain_delta = val & 0xff; + } + break; + } + +done: /* return new offset */ *offset = o; @@ -230,204 +390,944 @@ static int ath5k_eeprom_read_modes(struct ath5k_hw *ah, u32 *offset, } /* - * Initialize eeprom & capabilities structs + * Read turbo mode information on newer EEPROM versions */ -int ath5k_eeprom_init(struct ath5k_hw *ah) +static int +ath5k_eeprom_read_turbo_modes(struct ath5k_hw *ah, + u32 *offset, unsigned int mode) { struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; - unsigned int mode, i; - int ret; - u32 offset; + u32 o = *offset; u16 val; + int ret; - /* Initial TX thermal adjustment values */ - ee->ee_tx_clip = 4; - ee->ee_pwd_84 = ee->ee_pwd_90 = 1; - ee->ee_gain_select = 1; + if (ee->ee_version < AR5K_EEPROM_VERSION_5_0) + return 0; - /* - * Read values from EEPROM and store them in the capability structure - */ - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MAGIC, ee_magic); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_PROTECT, ee_protect); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_REG_DOMAIN, ee_regdomain); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_VERSION, ee_version); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_HDR, ee_header); + switch (mode){ + case AR5K_EEPROM_MODE_11A: + ee->ee_switch_settling_turbo[mode] = (val >> 6) & 0x7f; - /* Return if we have an old EEPROM */ - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_0) - return 0; + ee->ee_atn_tx_rx_turbo[mode] = (val >> 13) & 0x7; + AR5K_EEPROM_READ(o++, val); + ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x7) << 3; + ee->ee_margin_tx_rx_turbo[mode] = (val >> 3) & 0x3f; + + ee->ee_adc_desired_size_turbo[mode] = (val >> 9) & 0x7f; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size_turbo[mode] |= (val & 0x1) << 7; + ee->ee_pga_desired_size_turbo[mode] = (val >> 1) & 0xff; + + if (AR5K_EEPROM_EEMAP(ee->ee_misc0) >=2) + ee->ee_pd_gain_overlap = (val >> 9) & 0xf; + break; + case AR5K_EEPROM_MODE_11G: + ee->ee_switch_settling_turbo[mode] = (val >> 8) & 0x7f; + + ee->ee_atn_tx_rx_turbo[mode] = (val >> 15) & 0x7; + AR5K_EEPROM_READ(o++, val); + ee->ee_atn_tx_rx_turbo[mode] |= (val & 0x1f) << 1; + ee->ee_margin_tx_rx_turbo[mode] = (val >> 5) & 0x3f; + + ee->ee_adc_desired_size_turbo[mode] = (val >> 11) & 0x7f; + AR5K_EEPROM_READ(o++, val); + ee->ee_adc_desired_size_turbo[mode] |= (val & 0x7) << 5; + ee->ee_pga_desired_size_turbo[mode] = (val >> 3) & 0xff; + break; + } + + /* return new offset */ + *offset = o; + + return 0; +} + + +static int +ath5k_eeprom_init_modes(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + u32 mode_offset[3]; + unsigned int mode; + u32 offset; + int ret; -#ifdef notyet /* - * Validate the checksum of the EEPROM date. There are some - * devices with invalid EEPROMs. + * Get values for all modes */ - for (cksum = 0, offset = 0; offset < AR5K_EEPROM_INFO_MAX; offset++) { - AR5K_EEPROM_READ(AR5K_EEPROM_INFO(offset), val); - cksum ^= val; + mode_offset[AR5K_EEPROM_MODE_11A] = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); + mode_offset[AR5K_EEPROM_MODE_11B] = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); + mode_offset[AR5K_EEPROM_MODE_11G] = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); + + ee->ee_turbo_max_power[AR5K_EEPROM_MODE_11A] = + AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); + + for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { + offset = mode_offset[mode]; + + ret = ath5k_eeprom_read_ants(ah, &offset, mode); + if (ret) + return ret; + + ret = ath5k_eeprom_read_modes(ah, &offset, mode); + if (ret) + return ret; + + ret = ath5k_eeprom_read_turbo_modes(ah, &offset, mode); + if (ret) + return ret; } - if (cksum != AR5K_EEPROM_INFO_CKSUM) { - ATH5K_ERR(ah->ah_sc, "Invalid EEPROM checksum 0x%04x\n", cksum); - return -EIO; + + /* override for older eeprom versions for better performance */ + if (ah->ah_ee_version <= AR5K_EEPROM_VERSION_3_2) { + ee->ee_thr_62[AR5K_EEPROM_MODE_11A] = 15; + ee->ee_thr_62[AR5K_EEPROM_MODE_11B] = 28; + ee->ee_thr_62[AR5K_EEPROM_MODE_11G] = 28; } -#endif - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_ANT_GAIN(ah->ah_ee_version), - ee_ant_gain); + return 0; +} - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC0, ee_misc0); - AR5K_EEPROM_READ_HDR(AR5K_EEPROM_MISC1, ee_misc1); - } +static inline void +ath5k_get_pcdac_intercepts(struct ath5k_hw *ah, u8 min, u8 max, u8 *vp) +{ + const static u16 intercepts3[] = + { 0, 5, 10, 20, 30, 50, 70, 85, 90, 95, 100 }; + const static u16 intercepts3_2[] = + { 0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 }; + const u16 *ip; + int i; + + if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_3_2) + ip = intercepts3_2; + else + ip = intercepts3; - if (ah->ah_ee_version < AR5K_EEPROM_VERSION_3_3) { - AR5K_EEPROM_READ(AR5K_EEPROM_OBDB0_2GHZ, val); - ee->ee_ob[AR5K_EEPROM_MODE_11B][0] = val & 0x7; - ee->ee_db[AR5K_EEPROM_MODE_11B][0] = (val >> 3) & 0x7; + for (i = 0; i < ARRAY_SIZE(intercepts3); i++) + *vp++ = (ip[i] * max + (100 - ip[i]) * min) / 100; +} - AR5K_EEPROM_READ(AR5K_EEPROM_OBDB1_2GHZ, val); - ee->ee_ob[AR5K_EEPROM_MODE_11G][0] = val & 0x7; - ee->ee_db[AR5K_EEPROM_MODE_11G][0] = (val >> 3) & 0x7; +static inline int +ath5k_eeprom_read_freq_list(struct ath5k_hw *ah, int *offset, int max, + struct ath5k_chan_pcal_info *pc, u8 *count) +{ + int o = *offset; + int i = 0; + u8 f1, f2; + int ret; + u16 val; + + while(i < max) { + AR5K_EEPROM_READ(o++, val); + + f1 = (val >> 8) & 0xff; + f2 = val & 0xff; + + if (f1) + pc[i++].freq = f1; + + if (f2) + pc[i++].freq = f2; + + if (!f1 || !f2) + break; } + *offset = o; + *count = i; - /* - * Get conformance test limit values - */ - offset = AR5K_EEPROM_CTL(ah->ah_ee_version); - ee->ee_ctls = AR5K_EEPROM_N_CTLS(ah->ah_ee_version); + return 0; +} + +static int +ath5k_eeprom_init_11a_pcal_freq(struct ath5k_hw *ah, int offset) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal = ee->ee_pwr_cal_a; + int i, ret; + u16 val; + u8 mask; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { + ath5k_eeprom_read_freq_list(ah, &offset, + AR5K_EEPROM_N_5GHZ_CHAN, pcal, + &ee->ee_n_piers[AR5K_EEPROM_MODE_11A]); + } else { + mask = AR5K_EEPROM_FREQ_M(ah->ah_ee_version); - for (i = 0; i < ee->ee_ctls; i++) { AR5K_EEPROM_READ(offset++, val); - ee->ee_ctl[i] = (val >> 8) & 0xff; - ee->ee_ctl[i + 1] = val & 0xff; + pcal[0].freq = (val >> 9) & mask; + pcal[1].freq = (val >> 2) & mask; + pcal[2].freq = (val << 5) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[2].freq |= (val >> 11) & 0x1f; + pcal[3].freq = (val >> 4) & mask; + pcal[4].freq = (val << 3) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[4].freq |= (val >> 13) & 0x7; + pcal[5].freq = (val >> 6) & mask; + pcal[6].freq = (val << 1) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[6].freq |= (val >> 15) & 0x1; + pcal[7].freq = (val >> 8) & mask; + pcal[8].freq = (val >> 1) & mask; + pcal[9].freq = (val << 6) & mask; + + AR5K_EEPROM_READ(offset++, val); + pcal[9].freq |= (val >> 10) & 0x3f; + ee->ee_n_piers[AR5K_EEPROM_MODE_11A] = 10; } - /* - * Get values for 802.11a (5GHz) - */ - mode = AR5K_EEPROM_MODE_11A; + for(i = 0; i < AR5K_EEPROM_N_5GHZ_CHAN; i += 1) { + pcal[i].freq = ath5k_eeprom_bin2freq(ee, + pcal[i].freq, AR5K_EEPROM_MODE_11A); + } - ee->ee_turbo_max_power[mode] = - AR5K_EEPROM_HDR_T_5GHZ_DBM(ee->ee_header); + return 0; +} - offset = AR5K_EEPROM_MODES_11A(ah->ah_ee_version); +static inline int +ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal; + int i; + + switch(mode) { + case AR5K_EEPROM_MODE_11B: + pcal = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + pcal = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; + ath5k_eeprom_read_freq_list(ah, &offset, + AR5K_EEPROM_N_2GHZ_CHAN_2413, pcal, + &ee->ee_n_piers[mode]); + for(i = 0; i < AR5K_EEPROM_N_2GHZ_CHAN_2413; i += 1) { + pcal[i].freq = ath5k_eeprom_bin2freq(ee, + pcal[i].freq, mode); + } - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][3] = (val >> 5) & 0x7; - ee->ee_db[mode][3] = (val >> 2) & 0x7; - ee->ee_ob[mode][2] = (val << 1) & 0x7; - - AR5K_EEPROM_READ(offset++, val); - ee->ee_ob[mode][2] |= (val >> 15) & 0x1; - ee->ee_db[mode][2] = (val >> 12) & 0x7; - ee->ee_ob[mode][1] = (val >> 9) & 0x7; - ee->ee_db[mode][1] = (val >> 6) & 0x7; - ee->ee_ob[mode][0] = (val >> 3) & 0x7; - ee->ee_db[mode][0] = val & 0x7; - - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; + return 0; +} - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) { - AR5K_EEPROM_READ(offset++, val); - ee->ee_margin_tx_rx[mode] = val & 0x3f; + +static int +ath5k_eeprom_read_pcal_info_5111(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info *pcal; + int offset, ret; + int i, j; + u16 val; + + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + switch(mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + + ret = ath5k_eeprom_init_11a_pcal_freq(ah, + offset + AR5K_EEPROM_GROUP1_OFFSET); + if (ret < 0) + return ret; + + offset += AR5K_EEPROM_GROUP2_OFFSET; + pcal = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header) && + !AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + pcal = ee->ee_pwr_cal_b; + offset += AR5K_EEPROM_GROUP3_OFFSET; + + /* fixed piers */ + pcal[0].freq = 2412; + pcal[1].freq = 2447; + pcal[2].freq = 2484; + ee->ee_n_piers[mode] = 3; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + pcal = ee->ee_pwr_cal_g; + offset += AR5K_EEPROM_GROUP4_OFFSET; + + /* fixed piers */ + pcal[0].freq = 2312; + pcal[1].freq = 2412; + pcal[2].freq = 2484; + ee->ee_n_piers[mode] = 3; + break; + default: + return -EINVAL; } - /* - * Get values for 802.11b (2.4GHz) - */ - mode = AR5K_EEPROM_MODE_11B; - offset = AR5K_EEPROM_MODES_11B(ah->ah_ee_version); + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + struct ath5k_chan_pcal_info_rf5111 *cdata = + &pcal[i].rf5111_info; - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; + AR5K_EEPROM_READ(offset++, val); + cdata->pcdac_max = ((val >> 10) & AR5K_EEPROM_PCDAC_M); + cdata->pcdac_min = ((val >> 4) & AR5K_EEPROM_PCDAC_M); + cdata->pwr[0] = ((val << 2) & AR5K_EEPROM_POWER_M); - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][1] = (val >> 4) & 0x7; - ee->ee_db[mode][1] = val & 0x7; + AR5K_EEPROM_READ(offset++, val); + cdata->pwr[0] |= ((val >> 14) & 0x3); + cdata->pwr[1] = ((val >> 8) & AR5K_EEPROM_POWER_M); + cdata->pwr[2] = ((val >> 2) & AR5K_EEPROM_POWER_M); + cdata->pwr[3] = ((val << 4) & AR5K_EEPROM_POWER_M); - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; + AR5K_EEPROM_READ(offset++, val); + cdata->pwr[3] |= ((val >> 12) & 0xf); + cdata->pwr[4] = ((val >> 6) & AR5K_EEPROM_POWER_M); + cdata->pwr[5] = (val & AR5K_EEPROM_POWER_M); - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][0] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - ee->ee_cal_pier[mode][1] = - ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); + cdata->pwr[6] = ((val >> 10) & AR5K_EEPROM_POWER_M); + cdata->pwr[7] = ((val >> 4) & AR5K_EEPROM_POWER_M); + cdata->pwr[8] = ((val << 2) & AR5K_EEPROM_POWER_M); AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][2] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + cdata->pwr[8] |= ((val >> 14) & 0x3); + cdata->pwr[9] = ((val >> 8) & AR5K_EEPROM_POWER_M); + cdata->pwr[10] = ((val >> 2) & AR5K_EEPROM_POWER_M); + + ath5k_get_pcdac_intercepts(ah, cdata->pcdac_min, + cdata->pcdac_max, cdata->pcdac); + + for (j = 0; j < AR5K_EEPROM_N_PCDAC; j++) { + cdata->pwr[j] = (u16) + (AR5K_EEPROM_POWER_STEP * cdata->pwr[j]); + } } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + return 0; +} - /* - * Get values for 802.11g (2.4GHz) - */ - mode = AR5K_EEPROM_MODE_11G; - offset = AR5K_EEPROM_MODES_11G(ah->ah_ee_version); +static int +ath5k_eeprom_read_pcal_info_5112(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info_rf5112 *chan_pcal_info; + struct ath5k_chan_pcal_info *gen_chan_info; + u32 offset; + unsigned int i, c; + u16 val; + int ret; - ret = ath5k_eeprom_read_ants(ah, &offset, mode); - if (ret) - return ret; + switch (mode) { + case AR5K_EEPROM_MODE_11A: + /* + * Read 5GHz EEPROM channels + */ + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + ath5k_eeprom_init_11a_pcal_freq(ah, offset); + + offset += AR5K_EEPROM_GROUP2_OFFSET; + gen_chan_info = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += AR5K_EEPROM_GROUP3_OFFSET; + + /* NB: frequency piers parsed during mode init */ + gen_chan_info = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + offset = AR5K_EEPROM_GROUPS_START(ee->ee_version); + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += AR5K_EEPROM_GROUP4_OFFSET; + else if (AR5K_EEPROM_HDR_11B(ee->ee_header)) + offset += AR5K_EEPROM_GROUP2_OFFSET; + + /* NB: frequency piers parsed during mode init */ + gen_chan_info = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } - AR5K_EEPROM_READ(offset++, val); - ee->ee_adc_desired_size[mode] = (s8)((val >> 8) & 0xff); - ee->ee_ob[mode][1] = (val >> 4) & 0x7; - ee->ee_db[mode][1] = val & 0x7; + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + chan_pcal_info = &gen_chan_info[i].rf5112_info; - ret = ath5k_eeprom_read_modes(ah, &offset, mode); - if (ret) - return ret; + /* Power values in dBm * 4 + * for the lower xpd gain curve + * (0 dBm -> higher output power) */ + for (c = 0; c < AR5K_EEPROM_N_XPD0_POINTS; c++) { + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr_x0[c] = (val & 0xff); + chan_pcal_info->pwr_x0[++c] = ((val >> 8) & 0xff); + } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) { + /* PCDAC steps + * corresponding to the above power + * measurements */ AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][0] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); - ee->ee_cal_pier[mode][1] = - ath5k_eeprom_bin2freq(ah, (val >> 8) & 0xff, mode); + chan_pcal_info->pcdac_x0[1] = (val & 0x1f); + chan_pcal_info->pcdac_x0[2] = ((val >> 5) & 0x1f); + chan_pcal_info->pcdac_x0[3] = ((val >> 10) & 0x1f); + /* Power values in dBm * 4 + * for the higher xpd gain curve + * (18 dBm -> lower output power) */ AR5K_EEPROM_READ(offset++, val); - ee->ee_turbo_max_power[mode] = val & 0x7f; - ee->ee_xr_power[mode] = (val >> 7) & 0x3f; + chan_pcal_info->pwr_x3[0] = (val & 0xff); + chan_pcal_info->pwr_x3[1] = ((val >> 8) & 0xff); AR5K_EEPROM_READ(offset++, val); - ee->ee_cal_pier[mode][2] = - ath5k_eeprom_bin2freq(ah, val & 0xff, mode); + chan_pcal_info->pwr_x3[2] = (val & 0xff); + + /* PCDAC steps + * corresponding to the above power + * measurements (static) */ + chan_pcal_info->pcdac_x3[0] = 20; + chan_pcal_info->pcdac_x3[1] = 35; + chan_pcal_info->pcdac_x3[2] = 63; + + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_3) { + chan_pcal_info->pcdac_x0[0] = ((val >> 8) & 0xff); + + /* Last xpd0 power level is also channel maximum */ + gen_chan_info[i].max_pwr = chan_pcal_info->pwr_x0[3]; + } else { + chan_pcal_info->pcdac_x0[0] = 1; + gen_chan_info[i].max_pwr = ((val >> 8) & 0xff); + } - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_1) - ee->ee_margin_tx_rx[mode] = (val >> 8) & 0x3f; + /* Recreate pcdac_x0 table for this channel using pcdac steps */ + chan_pcal_info->pcdac_x0[1] += chan_pcal_info->pcdac_x0[0]; + chan_pcal_info->pcdac_x0[2] += chan_pcal_info->pcdac_x0[1]; + chan_pcal_info->pcdac_x0[3] += chan_pcal_info->pcdac_x0[2]; + } + + return 0; +} + +static inline unsigned int +ath5k_pdgains_size_2413(struct ath5k_eeprom_info *ee, unsigned int mode) +{ + static const unsigned int pdgains_size[] = { 4, 6, 9, 12 }; + unsigned int sz; + + sz = pdgains_size[ee->ee_pd_gains[mode] - 1]; + sz *= ee->ee_n_piers[mode]; + + return sz; +} + +static unsigned int +ath5k_cal_data_offset_2413(struct ath5k_eeprom_info *ee, int mode) +{ + u32 offset = AR5K_EEPROM_CAL_DATA_START(ee->ee_misc4); + + switch(mode) { + case AR5K_EEPROM_MODE_11G: + if (AR5K_EEPROM_HDR_11B(ee->ee_header)) + offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11B) + 2; + /* fall through */ + case AR5K_EEPROM_MODE_11B: + if (AR5K_EEPROM_HDR_11A(ee->ee_header)) + offset += ath5k_pdgains_size_2413(ee, AR5K_EEPROM_MODE_11A) + 5; + /* fall through */ + case AR5K_EEPROM_MODE_11A: + break; + default: + break; + } + + return offset; +} + +static int +ath5k_eeprom_read_pcal_info_2413(struct ath5k_hw *ah, int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_chan_pcal_info_rf2413 *chan_pcal_info; + struct ath5k_chan_pcal_info *gen_chan_info; + unsigned int i, c; + u32 offset; + int ret; + u16 val; + u8 pd_gains = 0; + + if (ee->ee_x_gain[mode] & 0x1) pd_gains++; + if ((ee->ee_x_gain[mode] >> 1) & 0x1) pd_gains++; + if ((ee->ee_x_gain[mode] >> 2) & 0x1) pd_gains++; + if ((ee->ee_x_gain[mode] >> 3) & 0x1) pd_gains++; + ee->ee_pd_gains[mode] = pd_gains; + + offset = ath5k_cal_data_offset_2413(ee, mode); + switch (mode) { + case AR5K_EEPROM_MODE_11A: + if (!AR5K_EEPROM_HDR_11A(ee->ee_header)) + return 0; + + ath5k_eeprom_init_11a_pcal_freq(ah, offset); + offset += AR5K_EEPROM_N_5GHZ_CHAN / 2; + gen_chan_info = ee->ee_pwr_cal_a; + break; + case AR5K_EEPROM_MODE_11B: + if (!AR5K_EEPROM_HDR_11B(ee->ee_header)) + return 0; + ath5k_eeprom_init_11bg_2413(ah, mode, offset); + offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; + gen_chan_info = ee->ee_pwr_cal_b; + break; + case AR5K_EEPROM_MODE_11G: + if (!AR5K_EEPROM_HDR_11G(ee->ee_header)) + return 0; + + ath5k_eeprom_init_11bg_2413(ah, mode, offset); + offset += AR5K_EEPROM_N_2GHZ_CHAN_2413 / 2; + gen_chan_info = ee->ee_pwr_cal_g; + break; + default: + return -EINVAL; + } + + if (pd_gains == 0) + return 0; + + for (i = 0; i < ee->ee_n_piers[mode]; i++) { + chan_pcal_info = &gen_chan_info[i].rf2413_info; + + /* + * Read pwr_i, pddac_i and the first + * 2 pd points (pwr, pddac) + */ AR5K_EEPROM_READ(offset++, val); - ee->ee_i_cal[mode] = (val >> 8) & 0x3f; - ee->ee_q_cal[mode] = (val >> 3) & 0x1f; + chan_pcal_info->pwr_i[0] = val & 0x1f; + chan_pcal_info->pddac_i[0] = (val >> 5) & 0x7f; + chan_pcal_info->pwr[0][0] = + (val >> 12) & 0xf; - if (ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_2) { + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[0][0] = val & 0x3f; + chan_pcal_info->pwr[0][1] = (val >> 6) & 0xf; + chan_pcal_info->pddac[0][1] = + (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[0][2] = val & 0xf; + chan_pcal_info->pddac[0][2] = + (val >> 4) & 0x3f; + + chan_pcal_info->pwr[0][3] = 0; + chan_pcal_info->pddac[0][3] = 0; + + if (pd_gains > 1) { + /* + * Pd gain 0 is not the last pd gain + * so it only has 2 pd points. + * Continue wih pd gain 1. + */ + chan_pcal_info->pwr_i[1] = (val >> 10) & 0x1f; + + chan_pcal_info->pddac_i[1] = (val >> 15) & 0x1; AR5K_EEPROM_READ(offset++, val); - ee->ee_cck_ofdm_gain_delta = val & 0xff; + chan_pcal_info->pddac_i[1] |= (val & 0x3F) << 1; + + chan_pcal_info->pwr[1][0] = (val >> 6) & 0xf; + chan_pcal_info->pddac[1][0] = + (val >> 10) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[1][1] = val & 0xf; + chan_pcal_info->pddac[1][1] = + (val >> 4) & 0x3f; + chan_pcal_info->pwr[1][2] = + (val >> 10) & 0xf; + + chan_pcal_info->pddac[1][2] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[1][2] |= + (val & 0xF) << 2; + + chan_pcal_info->pwr[1][3] = 0; + chan_pcal_info->pddac[1][3] = 0; + } else if (pd_gains == 1) { + /* + * Pd gain 0 is the last one so + * read the extra point. + */ + chan_pcal_info->pwr[0][3] = + (val >> 10) & 0xf; + + chan_pcal_info->pddac[0][3] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[0][3] |= + (val & 0xF) << 2; + } + + /* + * Proceed with the other pd_gains + * as above. + */ + if (pd_gains > 2) { + chan_pcal_info->pwr_i[2] = (val >> 4) & 0x1f; + chan_pcal_info->pddac_i[2] = (val >> 9) & 0x7f; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[2][0] = + (val >> 0) & 0xf; + chan_pcal_info->pddac[2][0] = + (val >> 4) & 0x3f; + chan_pcal_info->pwr[2][1] = + (val >> 10) & 0xf; + + chan_pcal_info->pddac[2][1] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[2][1] |= + (val & 0xF) << 2; + + chan_pcal_info->pwr[2][2] = + (val >> 4) & 0xf; + chan_pcal_info->pddac[2][2] = + (val >> 8) & 0x3f; + + chan_pcal_info->pwr[2][3] = 0; + chan_pcal_info->pddac[2][3] = 0; + } else if (pd_gains == 2) { + chan_pcal_info->pwr[1][3] = + (val >> 4) & 0xf; + chan_pcal_info->pddac[1][3] = + (val >> 8) & 0x3f; + } + + if (pd_gains > 3) { + chan_pcal_info->pwr_i[3] = (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr_i[3] |= ((val >> 0) & 0x7) << 2; + + chan_pcal_info->pddac_i[3] = (val >> 3) & 0x7f; + chan_pcal_info->pwr[3][0] = + (val >> 10) & 0xf; + chan_pcal_info->pddac[3][0] = + (val >> 14) & 0x3; + + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[3][0] |= + (val & 0xF) << 2; + chan_pcal_info->pwr[3][1] = + (val >> 4) & 0xf; + chan_pcal_info->pddac[3][1] = + (val >> 8) & 0x3f; + + chan_pcal_info->pwr[3][2] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[3][2] |= + ((val >> 0) & 0x3) << 2; + + chan_pcal_info->pddac[3][2] = + (val >> 2) & 0x3f; + chan_pcal_info->pwr[3][3] = + (val >> 8) & 0xf; + + chan_pcal_info->pddac[3][3] = + (val >> 12) & 0xF; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pddac[3][3] |= + ((val >> 0) & 0x3) << 4; + } else if (pd_gains == 3) { + chan_pcal_info->pwr[2][3] = + (val >> 14) & 0x3; + AR5K_EEPROM_READ(offset++, val); + chan_pcal_info->pwr[2][3] |= + ((val >> 0) & 0x3) << 2; + + chan_pcal_info->pddac[2][3] = + (val >> 2) & 0x3f; + } + + for (c = 0; c < pd_gains; c++) { + /* Recreate pwr table for this channel using pwr steps */ + chan_pcal_info->pwr[c][0] += chan_pcal_info->pwr_i[c] * 2; + chan_pcal_info->pwr[c][1] += chan_pcal_info->pwr[c][0]; + chan_pcal_info->pwr[c][2] += chan_pcal_info->pwr[c][1]; + chan_pcal_info->pwr[c][3] += chan_pcal_info->pwr[c][2]; + if (chan_pcal_info->pwr[c][3] == chan_pcal_info->pwr[c][2]) + chan_pcal_info->pwr[c][3] = 0; + + /* Recreate pddac table for this channel using pddac steps */ + chan_pcal_info->pddac[c][0] += chan_pcal_info->pddac_i[c]; + chan_pcal_info->pddac[c][1] += chan_pcal_info->pddac[c][0]; + chan_pcal_info->pddac[c][2] += chan_pcal_info->pddac[c][1]; + chan_pcal_info->pddac[c][3] += chan_pcal_info->pddac[c][2]; + if (chan_pcal_info->pddac[c][3] == chan_pcal_info->pddac[c][2]) + chan_pcal_info->pddac[c][3] = 0; } } - /* - * Read 5GHz EEPROM channels - */ + return 0; +} + +/* + * Read per rate target power (this is the maximum tx power + * supported by the card). This info is used when setting + * tx power, no matter the channel. + * + * This also works for v5 EEPROMs. + */ +static int ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_rate_pcal_info *rate_pcal_info; + u16 *rate_target_pwr_num; + u32 offset; + u16 val; + int ret, i; + + offset = AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1); + rate_target_pwr_num = &ee->ee_rate_target_pwr_num[mode]; + switch (mode) { + case AR5K_EEPROM_MODE_11A: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11A(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_a; + ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_5GHZ_CHAN; + break; + case AR5K_EEPROM_MODE_11B: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11B(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_b; + ee->ee_rate_target_pwr_num[mode] = 2; /* 3rd is g mode's 1st */ + break; + case AR5K_EEPROM_MODE_11G: + offset += AR5K_EEPROM_TARGET_PWR_OFF_11G(ee->ee_version); + rate_pcal_info = ee->ee_rate_tpwr_g; + ee->ee_rate_target_pwr_num[mode] = AR5K_EEPROM_N_2GHZ_CHAN; + break; + default: + return -EINVAL; + } + + /* Different freq mask for older eeproms (<= v3.2) */ + if (ee->ee_version <= AR5K_EEPROM_VERSION_3_2) { + for (i = 0; i < (*rate_target_pwr_num); i++) { + AR5K_EEPROM_READ(offset++, val); + rate_pcal_info[i].freq = + ath5k_eeprom_bin2freq(ee, (val >> 9) & 0x7f, mode); + + rate_pcal_info[i].target_power_6to24 = ((val >> 3) & 0x3f); + rate_pcal_info[i].target_power_36 = (val << 3) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + + if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || + val == 0) { + (*rate_target_pwr_num) = i; + break; + } + + rate_pcal_info[i].target_power_36 |= ((val >> 13) & 0x7); + rate_pcal_info[i].target_power_48 = ((val >> 7) & 0x3f); + rate_pcal_info[i].target_power_54 = ((val >> 1) & 0x3f); + } + } else { + for (i = 0; i < (*rate_target_pwr_num); i++) { + AR5K_EEPROM_READ(offset++, val); + rate_pcal_info[i].freq = + ath5k_eeprom_bin2freq(ee, (val >> 8) & 0xff, mode); + + rate_pcal_info[i].target_power_6to24 = ((val >> 2) & 0x3f); + rate_pcal_info[i].target_power_36 = (val << 4) & 0x3f; + + AR5K_EEPROM_READ(offset++, val); + + if (rate_pcal_info[i].freq == AR5K_EEPROM_CHANNEL_DIS || + val == 0) { + (*rate_target_pwr_num) = i; + break; + } + + rate_pcal_info[i].target_power_36 |= (val >> 12) & 0xf; + rate_pcal_info[i].target_power_48 = ((val >> 6) & 0x3f); + rate_pcal_info[i].target_power_54 = (val & 0x3f); + } + } + + return 0; +} + +static int +ath5k_eeprom_read_pcal_info(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + int (*read_pcal)(struct ath5k_hw *hw, int mode); + int mode; + int err; + + if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_4_0) && + (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 1)) + read_pcal = ath5k_eeprom_read_pcal_info_5112; + else if ((ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0) && + (AR5K_EEPROM_EEMAP(ee->ee_misc0) == 2)) + read_pcal = ath5k_eeprom_read_pcal_info_2413; + else + read_pcal = ath5k_eeprom_read_pcal_info_5111; + + for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++) { + err = read_pcal(ah, mode); + if (err) + return err; + + err = ath5k_eeprom_read_target_rate_pwr_info(ah, mode); + if (err < 0) + return err; + } + + return 0; +} + +/* Read conformance test limits */ +static int +ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah) +{ + struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom; + struct ath5k_edge_power *rep; + unsigned int fmask, pmask; + unsigned int ctl_mode; + int ret, i, j; + u32 offset; + u16 val; + + pmask = AR5K_EEPROM_POWER_M; + fmask = AR5K_EEPROM_FREQ_M(ee->ee_version); + offset = AR5K_EEPROM_CTL(ee->ee_version); + ee->ee_ctls = AR5K_EEPROM_N_CTLS(ee->ee_version); + for (i = 0; i < ee->ee_ctls; i += 2) { + AR5K_EEPROM_READ(offset++, val); + ee->ee_ctl[i] = (val >> 8) & 0xff; + ee->ee_ctl[i + 1] = val & 0xff; + } + + offset = AR5K_EEPROM_GROUP8_OFFSET; + if (ee->ee_version >= AR5K_EEPROM_VERSION_4_0) + offset += AR5K_EEPROM_TARGET_PWRSTART(ee->ee_misc1) - + AR5K_EEPROM_GROUP5_OFFSET; + else + offset += AR5K_EEPROM_GROUPS_START(ee->ee_version); + + rep = ee->ee_ctl_pwr; + for(i = 0; i < ee->ee_ctls; i++) { + switch(ee->ee_ctl[i] & AR5K_CTL_MODE_M) { + case AR5K_CTL_11A: + case AR5K_CTL_TURBO: + ctl_mode = AR5K_EEPROM_MODE_11A; + break; + default: + ctl_mode = AR5K_EEPROM_MODE_11G; + break; + } + if (ee->ee_ctl[i] == 0) { + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) + offset += 8; + else + offset += 7; + rep += AR5K_EEPROM_N_EDGES; + continue; + } + if (ee->ee_version >= AR5K_EEPROM_VERSION_3_3) { + for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { + AR5K_EEPROM_READ(offset++, val); + rep[j].freq = (val >> 8) & fmask; + rep[j + 1].freq = val & fmask; + } + for (j = 0; j < AR5K_EEPROM_N_EDGES; j += 2) { + AR5K_EEPROM_READ(offset++, val); + rep[j].edge = (val >> 8) & pmask; + rep[j].flag = (val >> 14) & 1; + rep[j + 1].edge = val & pmask; + rep[j + 1].flag = (val >> 6) & 1; + } + } else { + AR5K_EEPROM_READ(offset++, val); + rep[0].freq = (val >> 9) & fmask; + rep[1].freq = (val >> 2) & fmask; + rep[2].freq = (val << 5) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[2].freq |= (val >> 11) & 0x1f; + rep[3].freq = (val >> 4) & fmask; + rep[4].freq = (val << 3) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[4].freq |= (val >> 13) & 0x7; + rep[5].freq = (val >> 6) & fmask; + rep[6].freq = (val << 1) & fmask; + + AR5K_EEPROM_READ(offset++, val); + rep[6].freq |= (val >> 15) & 0x1; + rep[7].freq = (val >> 8) & fmask; + + rep[0].edge = (val >> 2) & pmask; + rep[1].edge = (val << 4) & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[1].edge |= (val >> 12) & 0xf; + rep[2].edge = (val >> 6) & pmask; + rep[3].edge = val & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[4].edge = (val >> 10) & pmask; + rep[5].edge = (val >> 4) & pmask; + rep[6].edge = (val << 2) & pmask; + + AR5K_EEPROM_READ(offset++, val); + rep[6].edge |= (val >> 14) & 0x3; + rep[7].edge = (val >> 8) & pmask; + } + for (j = 0; j < AR5K_EEPROM_N_EDGES; j++) { + rep[j].freq = ath5k_eeprom_bin2freq(ee, + rep[j].freq, ctl_mode); + } + rep += AR5K_EEPROM_N_EDGES; + } return 0; } + +/* + * Initialize eeprom power tables + */ +int +ath5k_eeprom_init(struct ath5k_hw *ah) +{ + int err; + + err = ath5k_eeprom_init_header(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_init_modes(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_read_pcal_info(ah); + if (err < 0) + return err; + + err = ath5k_eeprom_read_ctl_info(ah); + if (err < 0) + return err; + + return 0; +} /* * Read the MAC address from eeprom */ diff --git a/drivers/net/wireless/ath5k/eeprom.h b/drivers/net/wireless/ath5k/eeprom.h index a468ecfbb18aa38c433937f8312766d23ca2096c..09eb7d0176a4e93dad5b9691bb03e7fa2025a757 100644 --- a/drivers/net/wireless/ath5k/eeprom.h +++ b/drivers/net/wireless/ath5k/eeprom.h @@ -25,24 +25,8 @@ #define AR5K_EEPROM_MAGIC_5211 0x0000145b /* 5211 */ #define AR5K_EEPROM_MAGIC_5210 0x0000145a /* 5210 */ -#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ -#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */ -#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */ -#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */ -#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008 -#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */ -#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020 -#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */ -#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080 -#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */ -#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200 -#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */ -#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800 -#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */ -#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 -#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ -#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 #define AR5K_EEPROM_REG_DOMAIN 0x00bf /* EEPROM regdom */ +#define AR5K_EEPROM_CHECKSUM 0x00c0 /* EEPROM checksum */ #define AR5K_EEPROM_INFO_BASE 0x00c0 /* EEPROM header */ #define AR5K_EEPROM_INFO_MAX (0x400 - AR5K_EEPROM_INFO_BASE) #define AR5K_EEPROM_INFO_CKSUM 0xffff @@ -53,15 +37,19 @@ #define AR5K_EEPROM_VERSION_3_1 0x3001 /* ob/db values for 2Ghz (ar5211_rfregs) */ #define AR5K_EEPROM_VERSION_3_2 0x3002 /* different frequency representation (eeprom_bin2freq) */ #define AR5K_EEPROM_VERSION_3_3 0x3003 /* offsets changed, has 32 CTLs (see below) and ee_false_detect (eeprom_read_modes) */ -#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain ee_cck_ofdm_power_delta (eeprom_read_modes) */ -#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc*, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */ +#define AR5K_EEPROM_VERSION_3_4 0x3004 /* has ee_i_gain, ee_cck_ofdm_power_delta (eeprom_read_modes) */ +#define AR5K_EEPROM_VERSION_4_0 0x4000 /* has ee_misc, ee_cal_pier, ee_turbo_max_power and ee_xr_power (eeprom_init) */ #define AR5K_EEPROM_VERSION_4_1 0x4001 /* has ee_margin_tx_rx (eeprom_init) */ #define AR5K_EEPROM_VERSION_4_2 0x4002 /* has ee_cck_ofdm_gain_delta (eeprom_init) */ -#define AR5K_EEPROM_VERSION_4_3 0x4003 +#define AR5K_EEPROM_VERSION_4_3 0x4003 /* power calibration changes */ #define AR5K_EEPROM_VERSION_4_4 0x4004 #define AR5K_EEPROM_VERSION_4_5 0x4005 #define AR5K_EEPROM_VERSION_4_6 0x4006 /* has ee_scaled_cck_delta */ -#define AR5K_EEPROM_VERSION_4_7 0x4007 +#define AR5K_EEPROM_VERSION_4_7 0x3007 /* 4007 ? */ +#define AR5K_EEPROM_VERSION_4_9 0x4009 /* EAR futureproofing */ +#define AR5K_EEPROM_VERSION_5_0 0x5000 /* Has 2413 PDADC calibration etc */ +#define AR5K_EEPROM_VERSION_5_1 0x5001 /* Has capability values */ +#define AR5K_EEPROM_VERSION_5_3 0x5003 /* Has spur mitigation tables */ #define AR5K_EEPROM_MODE_11A 0 #define AR5K_EEPROM_MODE_11B 1 @@ -74,8 +62,8 @@ #define AR5K_EEPROM_HDR_T_2GHZ_DIS(_v) (((_v) >> 3) & 0x1) /* Disable turbo for 2Ghz (?) */ #define AR5K_EEPROM_HDR_T_5GHZ_DBM(_v) (((_v) >> 4) & 0x7f) /* Max turbo power for a/XR mode (eeprom_init) */ #define AR5K_EEPROM_HDR_DEVICE(_v) (((_v) >> 11) & 0x7) -#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz (?) */ #define AR5K_EEPROM_HDR_RFKILL(_v) (((_v) >> 14) & 0x1) /* Device has RFKill support */ +#define AR5K_EEPROM_HDR_T_5GHZ_DIS(_v) (((_v) >> 15) & 0x1) /* Disable turbo for 5Ghz */ #define AR5K_EEPROM_RFKILL_GPIO_SEL 0x0000001c #define AR5K_EEPROM_RFKILL_GPIO_SEL_S 2 @@ -87,27 +75,95 @@ (((_v) >= AR5K_EEPROM_VERSION_3_3) ? _v3_3 : _v3_0) #define AR5K_EEPROM_ANT_GAIN(_v) AR5K_EEPROM_OFF(_v, 0x00c4, 0x00c3) -#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((int8_t)(((_v) >> 8) & 0xff)) -#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((int8_t)((_v) & 0xff)) +#define AR5K_EEPROM_ANT_GAIN_5GHZ(_v) ((s8)(((_v) >> 8) & 0xff)) +#define AR5K_EEPROM_ANT_GAIN_2GHZ(_v) ((s8)((_v) & 0xff)) + +/* Misc values available since EEPROM 4.0 */ +#define AR5K_EEPROM_MISC0 AR5K_EEPROM_INFO(4) +#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HDR_XR2_DIS(_v) (((_v) >> 12) & 0x1) +#define AR5K_EEPROM_HDR_XR5_DIS(_v) (((_v) >> 13) & 0x1) +#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) + +#define AR5K_EEPROM_MISC1 AR5K_EEPROM_INFO(5) +#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) +#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) +#define AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(_v) (((_v) >> 15) & 0x1) + +#define AR5K_EEPROM_MISC2 AR5K_EEPROM_INFO(6) +#define AR5K_EEPROM_EEP_FILE_VERSION(_v) (((_v) >> 8) & 0xff) +#define AR5K_EEPROM_EAR_FILE_VERSION(_v) ((_v) & 0xff) + +#define AR5K_EEPROM_MISC3 AR5K_EEPROM_INFO(7) +#define AR5K_EEPROM_ART_BUILD_NUM(_v) (((_v) >> 10) & 0x3f) +#define AR5K_EEPROM_EAR_FILE_ID(_v) ((_v) & 0xff) + +#define AR5K_EEPROM_MISC4 AR5K_EEPROM_INFO(8) +#define AR5K_EEPROM_CAL_DATA_START(_v) (((_v) >> 4) & 0xfff) +#define AR5K_EEPROM_MASK_R0(_v) (((_v) >> 2) & 0x3) +#define AR5K_EEPROM_MASK_R1(_v) ((_v) & 0x3) + +#define AR5K_EEPROM_MISC5 AR5K_EEPROM_INFO(9) +#define AR5K_EEPROM_COMP_DIS(_v) ((_v) & 0x1) +#define AR5K_EEPROM_AES_DIS(_v) (((_v) >> 1) & 0x1) +#define AR5K_EEPROM_FF_DIS(_v) (((_v) >> 2) & 0x1) +#define AR5K_EEPROM_BURST_DIS(_v) (((_v) >> 3) & 0x1) +#define AR5K_EEPROM_MAX_QCU(_v) (((_v) >> 4) & 0xf) +#define AR5K_EEPROM_HEAVY_CLIP_EN(_v) (((_v) >> 8) & 0x1) +#define AR5K_EEPROM_KEY_CACHE_SIZE(_v) (((_v) >> 12) & 0xf) + +#define AR5K_EEPROM_MISC6 AR5K_EEPROM_INFO(10) +#define AR5K_EEPROM_TX_CHAIN_DIS ((_v) & 0x8) +#define AR5K_EEPROM_RX_CHAIN_DIS (((_v) >> 3) & 0x8) +#define AR5K_EEPROM_FCC_MID_EN (((_v) >> 6) & 0x1) +#define AR5K_EEPROM_JAP_U1EVEN_EN (((_v) >> 7) & 0x1) +#define AR5K_EEPROM_JAP_U2_EN (((_v) >> 8) & 0x1) +#define AR5K_EEPROM_JAP_U1ODD_EN (((_v) >> 9) & 0x1) +#define AR5K_EEPROM_JAP_11A_NEW_EN (((_v) >> 10) & 0x1) /* calibration settings */ #define AR5K_EEPROM_MODES_11A(_v) AR5K_EEPROM_OFF(_v, 0x00c5, 0x00d4) #define AR5K_EEPROM_MODES_11B(_v) AR5K_EEPROM_OFF(_v, 0x00d0, 0x00f2) #define AR5K_EEPROM_MODES_11G(_v) AR5K_EEPROM_OFF(_v, 0x00da, 0x010d) #define AR5K_EEPROM_CTL(_v) AR5K_EEPROM_OFF(_v, 0x00e4, 0x0128) /* Conformance test limits */ +#define AR5K_EEPROM_GROUPS_START(_v) AR5K_EEPROM_OFF(_v, 0x0100, 0x0150) /* Start of Groups */ +#define AR5K_EEPROM_GROUP1_OFFSET 0x0 +#define AR5K_EEPROM_GROUP2_OFFSET 0x5 +#define AR5K_EEPROM_GROUP3_OFFSET 0x37 +#define AR5K_EEPROM_GROUP4_OFFSET 0x46 +#define AR5K_EEPROM_GROUP5_OFFSET 0x55 +#define AR5K_EEPROM_GROUP6_OFFSET 0x65 +#define AR5K_EEPROM_GROUP7_OFFSET 0x69 +#define AR5K_EEPROM_GROUP8_OFFSET 0x6f + +#define AR5K_EEPROM_TARGET_PWR_OFF_11A(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP5_OFFSET, 0x0000) +#define AR5K_EEPROM_TARGET_PWR_OFF_11B(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP6_OFFSET, 0x0010) +#define AR5K_EEPROM_TARGET_PWR_OFF_11G(_v) AR5K_EEPROM_OFF(_v, AR5K_EEPROM_GROUPS_START(_v) + \ + AR5K_EEPROM_GROUP7_OFFSET, 0x0014) /* [3.1 - 3.3] */ #define AR5K_EEPROM_OBDB0_2GHZ 0x00ec #define AR5K_EEPROM_OBDB1_2GHZ 0x00ed -/* Misc values available since EEPROM 4.0 */ -#define AR5K_EEPROM_MISC0 0x00c4 -#define AR5K_EEPROM_EARSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_EEMAP(_v) (((_v) >> 14) & 0x3) -#define AR5K_EEPROM_MISC1 0x00c5 -#define AR5K_EEPROM_TARGET_PWRSTART(_v) ((_v) & 0xfff) -#define AR5K_EEPROM_HAS32KHZCRYSTAL(_v) (((_v) >> 14) & 0x1) - +#define AR5K_EEPROM_PROTECT 0x003f /* EEPROM protect status */ +#define AR5K_EEPROM_PROTECT_RD_0_31 0x0001 /* Read protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_WR_0_31 0x0002 /* Write protection bit for offsets 0x0 - 0x1f */ +#define AR5K_EEPROM_PROTECT_RD_32_63 0x0004 /* 0x20 - 0x3f */ +#define AR5K_EEPROM_PROTECT_WR_32_63 0x0008 +#define AR5K_EEPROM_PROTECT_RD_64_127 0x0010 /* 0x40 - 0x7f */ +#define AR5K_EEPROM_PROTECT_WR_64_127 0x0020 +#define AR5K_EEPROM_PROTECT_RD_128_191 0x0040 /* 0x80 - 0xbf (regdom) */ +#define AR5K_EEPROM_PROTECT_WR_128_191 0x0080 +#define AR5K_EEPROM_PROTECT_RD_192_207 0x0100 /* 0xc0 - 0xcf */ +#define AR5K_EEPROM_PROTECT_WR_192_207 0x0200 +#define AR5K_EEPROM_PROTECT_RD_208_223 0x0400 /* 0xd0 - 0xdf */ +#define AR5K_EEPROM_PROTECT_WR_208_223 0x0800 +#define AR5K_EEPROM_PROTECT_RD_224_239 0x1000 /* 0xe0 - 0xef */ +#define AR5K_EEPROM_PROTECT_WR_224_239 0x2000 +#define AR5K_EEPROM_PROTECT_RD_240_255 0x4000 /* 0xf0 - 0xff */ +#define AR5K_EEPROM_PROTECT_WR_240_255 0x8000 /* Some EEPROM defines */ #define AR5K_EEPROM_EEP_SCALE 100 @@ -115,8 +171,11 @@ #define AR5K_EEPROM_N_MODES 3 #define AR5K_EEPROM_N_5GHZ_CHAN 10 #define AR5K_EEPROM_N_2GHZ_CHAN 3 +#define AR5K_EEPROM_N_2GHZ_CHAN_2413 4 #define AR5K_EEPROM_MAX_CHAN 10 +#define AR5K_EEPROM_N_PWR_POINTS_5111 11 #define AR5K_EEPROM_N_PCDAC 11 +#define AR5K_EEPROM_N_PHASE_CAL 5 #define AR5K_EEPROM_N_TEST_FREQ 8 #define AR5K_EEPROM_N_EDGES 8 #define AR5K_EEPROM_N_INTERCEPTS 11 @@ -136,6 +195,8 @@ #define AR5K_EEPROM_N_XPD_PER_CHANNEL 4 #define AR5K_EEPROM_N_XPD0_POINTS 4 #define AR5K_EEPROM_N_XPD3_POINTS 3 +#define AR5K_EEPROM_N_PD_GAINS 4 +#define AR5K_EEPROM_N_PD_POINTS 5 #define AR5K_EEPROM_N_INTERCEPT_10_2GHZ 35 #define AR5K_EEPROM_N_INTERCEPT_10_5GHZ 55 #define AR5K_EEPROM_POWER_M 0x3f @@ -158,8 +219,99 @@ #define AR5K_EEPROM_READ_HDR(_o, _v) \ AR5K_EEPROM_READ(_o, ah->ah_capabilities.cap_eeprom._v); \ -/* Struct to hold EEPROM calibration data */ +enum ath5k_ant_setting { + AR5K_ANT_VARIABLE = 0, /* variable by programming */ + AR5K_ANT_FIXED_A = 1, /* fixed to 11a frequencies */ + AR5K_ANT_FIXED_B = 2, /* fixed to 11b frequencies */ + AR5K_ANT_MAX = 3, +}; + +enum ath5k_ctl_mode { + AR5K_CTL_11A = 0, + AR5K_CTL_11B = 1, + AR5K_CTL_11G = 2, + AR5K_CTL_TURBO = 3, + AR5K_CTL_108G = 4, + AR5K_CTL_2GHT20 = 5, + AR5K_CTL_5GHT20 = 6, + AR5K_CTL_2GHT40 = 7, + AR5K_CTL_5GHT40 = 8, + AR5K_CTL_MODE_M = 15, +}; + +/* Per channel calibration data, used for power table setup */ +struct ath5k_chan_pcal_info_rf5111 { + /* Power levels in half dbm units + * for one power curve. */ + u8 pwr[AR5K_EEPROM_N_PWR_POINTS_5111]; + /* PCDAC table steps + * for the above values */ + u8 pcdac[AR5K_EEPROM_N_PWR_POINTS_5111]; + /* Starting PCDAC step */ + u8 pcdac_min; + /* Final PCDAC step */ + u8 pcdac_max; +}; + +struct ath5k_chan_pcal_info_rf5112 { + /* Power levels in quarter dBm units + * for lower (0) and higher (3) + * level curves */ + s8 pwr_x0[AR5K_EEPROM_N_XPD0_POINTS]; + s8 pwr_x3[AR5K_EEPROM_N_XPD3_POINTS]; + /* PCDAC table steps + * for the above values */ + u8 pcdac_x0[AR5K_EEPROM_N_XPD0_POINTS]; + u8 pcdac_x3[AR5K_EEPROM_N_XPD3_POINTS]; +}; + +struct ath5k_chan_pcal_info_rf2413 { + /* Starting pwr/pddac values */ + s8 pwr_i[AR5K_EEPROM_N_PD_GAINS]; + u8 pddac_i[AR5K_EEPROM_N_PD_GAINS]; + /* (pwr,pddac) points */ + s8 pwr[AR5K_EEPROM_N_PD_GAINS] + [AR5K_EEPROM_N_PD_POINTS]; + u8 pddac[AR5K_EEPROM_N_PD_GAINS] + [AR5K_EEPROM_N_PD_POINTS]; +}; + +struct ath5k_chan_pcal_info { + /* Frequency */ + u16 freq; + /* Max available power */ + s8 max_pwr; + union { + struct ath5k_chan_pcal_info_rf5111 rf5111_info; + struct ath5k_chan_pcal_info_rf5112 rf5112_info; + struct ath5k_chan_pcal_info_rf2413 rf2413_info; + }; +}; + +/* Per rate calibration data for each mode, used for power table setup */ +struct ath5k_rate_pcal_info { + u16 freq; /* Frequency */ + /* Power level for 6-24Mbit/s rates */ + u16 target_power_6to24; + /* Power level for 36Mbit rate */ + u16 target_power_36; + /* Power level for 48Mbit rate */ + u16 target_power_48; + /* Power level for 54Mbit rate */ + u16 target_power_54; +}; + +/* Power edges for conformance test limits */ +struct ath5k_edge_power { + u16 freq; + u16 edge; /* in half dBm */ + bool flag; +}; + +/* EEPROM calibration data */ struct ath5k_eeprom_info { + + /* Header information */ u16 ee_magic; u16 ee_protect; u16 ee_regdomain; @@ -168,6 +320,11 @@ struct ath5k_eeprom_info { u16 ee_ant_gain; u16 ee_misc0; u16 ee_misc1; + u16 ee_misc2; + u16 ee_misc3; + u16 ee_misc4; + u16 ee_misc5; + u16 ee_misc6; u16 ee_cck_ofdm_gain_delta; u16 ee_cck_ofdm_power_delta; u16 ee_scaled_cck_delta; @@ -185,7 +342,7 @@ struct ath5k_eeprom_info { u16 ee_turbo_max_power[AR5K_EEPROM_N_MODES]; u16 ee_xr_power[AR5K_EEPROM_N_MODES]; u16 ee_switch_settling[AR5K_EEPROM_N_MODES]; - u16 ee_ant_tx_rx[AR5K_EEPROM_N_MODES]; + u16 ee_atn_tx_rx[AR5K_EEPROM_N_MODES]; u16 ee_ant_control[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_PCDAC]; u16 ee_ob[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; u16 ee_db[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_OBDB]; @@ -198,18 +355,40 @@ struct ath5k_eeprom_info { u16 ee_x_gain[AR5K_EEPROM_N_MODES]; u16 ee_i_gain[AR5K_EEPROM_N_MODES]; u16 ee_margin_tx_rx[AR5K_EEPROM_N_MODES]; + u16 ee_switch_settling_turbo[AR5K_EEPROM_N_MODES]; + u16 ee_margin_tx_rx_turbo[AR5K_EEPROM_N_MODES]; + u16 ee_atn_tx_rx_turbo[AR5K_EEPROM_N_MODES]; - /* Unused */ + /* Power calibration data */ u16 ee_false_detect[AR5K_EEPROM_N_MODES]; - u16 ee_cal_pier[AR5K_EEPROM_N_MODES][AR5K_EEPROM_N_2GHZ_CHAN]; - u16 ee_channel[AR5K_EEPROM_N_MODES][AR5K_EEPROM_MAX_CHAN]; /*empty*/ + + /* Number of pd gain curves per mode (RF2413) */ + u8 ee_pd_gains[AR5K_EEPROM_N_MODES]; + + u8 ee_n_piers[AR5K_EEPROM_N_MODES]; + struct ath5k_chan_pcal_info ee_pwr_cal_a[AR5K_EEPROM_N_5GHZ_CHAN]; + struct ath5k_chan_pcal_info ee_pwr_cal_b[AR5K_EEPROM_N_2GHZ_CHAN]; + struct ath5k_chan_pcal_info ee_pwr_cal_g[AR5K_EEPROM_N_2GHZ_CHAN]; + + /* Per rate target power levels */ + u16 ee_rate_target_pwr_num[AR5K_EEPROM_N_MODES]; + struct ath5k_rate_pcal_info ee_rate_tpwr_a[AR5K_EEPROM_N_5GHZ_CHAN]; + struct ath5k_rate_pcal_info ee_rate_tpwr_b[AR5K_EEPROM_N_2GHZ_CHAN]; + struct ath5k_rate_pcal_info ee_rate_tpwr_g[AR5K_EEPROM_N_2GHZ_CHAN]; /* Conformance test limits (Unused) */ u16 ee_ctls; u16 ee_ctl[AR5K_EEPROM_MAX_CTLS]; + struct ath5k_edge_power ee_ctl_pwr[AR5K_EEPROM_N_EDGES * AR5K_EEPROM_MAX_CTLS]; /* Noise Floor Calibration settings */ s16 ee_noise_floor_thr[AR5K_EEPROM_N_MODES]; s8 ee_adc_desired_size[AR5K_EEPROM_N_MODES]; s8 ee_pga_desired_size[AR5K_EEPROM_N_MODES]; + s8 ee_adc_desired_size_turbo[AR5K_EEPROM_N_MODES]; + s8 ee_pga_desired_size_turbo[AR5K_EEPROM_N_MODES]; + s8 ee_pd_gain_overlap; + + u32 ee_antenna[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX]; }; + diff --git a/drivers/net/wireless/ath5k/initvals.c b/drivers/net/wireless/ath5k/initvals.c index ceaa6c475c0615bb786cf52bb7c0f1838ee557c9..450bd6e945ff152d76d411b7380b38fb84f4baa7 100644 --- a/drivers/net/wireless/ath5k/initvals.c +++ b/drivers/net/wireless/ath5k/initvals.c @@ -1681,7 +1681,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) */ /* For AR5212 and combatible */ - if (ah->ah_version == AR5K_AR5212){ + if (ah->ah_version == AR5K_AR5212) { /* First set of mode-specific settings */ ath5k_hw_ini_mode_registers(ah, @@ -1695,7 +1695,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) ar5212_ini, change_channel); /* Second set of mode-specific settings */ - if (ah->ah_radio == AR5K_RF5111){ + if (ah->ah_radio == AR5K_RF5111) { ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5212_rf5111_ini_mode_end), @@ -1706,7 +1706,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) ARRAY_SIZE(rf5111_ini_bbgain), rf5111_ini_bbgain, change_channel); - } else if (ah->ah_radio == AR5K_RF5112){ + } else if (ah->ah_radio == AR5K_RF5112) { ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(ar5212_rf5112_ini_mode_end), @@ -1716,7 +1716,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel) ARRAY_SIZE(rf5112_ini_bbgain), rf5112_ini_bbgain, change_channel); - } else if (ah->ah_radio == AR5K_RF5413){ + } else if (ah->ah_radio == AR5K_RF5413) { ath5k_hw_ini_mode_registers(ah, ARRAY_SIZE(rf5413_ini_mode_end), diff --git a/drivers/net/wireless/ath5k/pcu.c b/drivers/net/wireless/ath5k/pcu.c index a47df9a24aa126783497eeb296edad22aa150d0e..0cac05c6a9ce8dda1b1c50a5da26db3c187b9ecb 100644 --- a/drivers/net/wireless/ath5k/pcu.c +++ b/drivers/net/wireless/ath5k/pcu.c @@ -46,34 +46,45 @@ int ath5k_hw_set_opmode(struct ath5k_hw *ah) { u32 pcu_reg, beacon_reg, low_id, high_id; - pcu_reg = 0; + + /* Preserve rest settings */ + pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; + pcu_reg &= ~(AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_AP + | AR5K_STA_ID1_KEYSRCH_MODE + | (ah->ah_version == AR5K_AR5210 ? + (AR5K_STA_ID1_PWR_SV | AR5K_STA_ID1_NO_PSPOLL) : 0)); + beacon_reg = 0; ATH5K_TRACE(ah->ah_sc); switch (ah->ah_op_mode) { case NL80211_IFTYPE_ADHOC: - pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_DESC_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_NO_PSPOLL : 0); + pcu_reg |= AR5K_STA_ID1_ADHOC | AR5K_STA_ID1_KEYSRCH_MODE; beacon_reg |= AR5K_BCR_ADHOC; + if (ah->ah_version == AR5K_AR5210) + pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; + else + AR5K_REG_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC); break; case NL80211_IFTYPE_AP: case NL80211_IFTYPE_MESH_POINT: - pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_RTS_DEF_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? - AR5K_STA_ID1_NO_PSPOLL : 0); + pcu_reg |= AR5K_STA_ID1_AP | AR5K_STA_ID1_KEYSRCH_MODE; beacon_reg |= AR5K_BCR_AP; + if (ah->ah_version == AR5K_AR5210) + pcu_reg |= AR5K_STA_ID1_NO_PSPOLL; + else + AR5K_REG_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_ADHOC); break; case NL80211_IFTYPE_STATION: - pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? + pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE + | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_PWR_SV : 0); case NL80211_IFTYPE_MONITOR: - pcu_reg |= AR5K_STA_ID1_DEFAULT_ANTENNA | - (ah->ah_version == AR5K_AR5210 ? + pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE + | (ah->ah_version == AR5K_AR5210 ? AR5K_STA_ID1_NO_PSPOLL : 0); break; @@ -130,6 +141,8 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah, ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_RXCLR); ath5k_hw_reg_write(ah, 0, AR5K_PROFCNT_CYCLE); } + + /* TODO: Handle ANI stats */ } /** @@ -258,16 +271,19 @@ void ath5k_hw_get_lladdr(struct ath5k_hw *ah, u8 *mac) int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac) { u32 low_id, high_id; + u32 pcu_reg; ATH5K_TRACE(ah->ah_sc); /* Set new station ID */ memcpy(ah->ah_sta_id, mac, ETH_ALEN); + pcu_reg = ath5k_hw_reg_read(ah, AR5K_STA_ID1) & 0xffff0000; + low_id = AR5K_LOW_ID(mac); high_id = AR5K_HIGH_ID(mac); ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0); - ath5k_hw_reg_write(ah, high_id, AR5K_STA_ID1); + ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1); return 0; } @@ -290,8 +306,10 @@ void ath5k_hw_set_associd(struct ath5k_hw *ah, const u8 *bssid, u16 assoc_id) * Set simple BSSID mask on 5212 */ if (ah->ah_version == AR5K_AR5212) { - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM0); - ath5k_hw_reg_write(ah, 0xffffffff, AR5K_BSS_IDM1); + ath5k_hw_reg_write(ah, AR5K_LOW_ID(ah->ah_bssid_mask), + AR5K_BSS_IDM0); + ath5k_hw_reg_write(ah, AR5K_HIGH_ID(ah->ah_bssid_mask), + AR5K_BSS_IDM1); } /* @@ -415,6 +433,9 @@ int ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask) u32 low_id, high_id; ATH5K_TRACE(ah->ah_sc); + /* Cache bssid mask so that we can restore it + * on reset */ + memcpy(ah->ah_bssid_mask, mask, ETH_ALEN); if (ah->ah_version == AR5K_AR5212) { low_id = AR5K_LOW_ID(mask); high_id = AR5K_HIGH_ID(mask); @@ -576,7 +597,7 @@ void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter) filter |= AR5K_RX_FILTER_PROM; } - /*Zero length DMA*/ + /*Zero length DMA (phy error reporting) */ if (data) AR5K_REG_ENABLE_BITS(ah, AR5K_RXCFG, AR5K_RXCFG_ZLFDMA); else @@ -661,7 +682,12 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) * Set the additional timers by mode */ switch (ah->ah_op_mode) { + case NL80211_IFTYPE_MONITOR: case NL80211_IFTYPE_STATION: + /* In STA mode timer1 is used as next wakeup + * timer and timer2 as next CFP duration start + * timer. Both in 1/8TUs. */ + /* TODO: PCF handling */ if (ah->ah_version == AR5K_AR5210) { timer1 = 0xffffffff; timer2 = 0xffffffff; @@ -669,27 +695,60 @@ void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval) timer1 = 0x0000ffff; timer2 = 0x0007ffff; } + /* Mark associated AP as PCF incapable for now */ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PCF); break; - + case NL80211_IFTYPE_ADHOC: + AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG, AR5K_TXCFG_ADHOC_BCN_ATIM); default: + /* On non-STA modes timer1 is used as next DMA + * beacon alert (DBA) timer and timer2 as next + * software beacon alert. Both in 1/8TUs. */ timer1 = (next_beacon - AR5K_TUNE_DMA_BEACON_RESP) << 3; timer2 = (next_beacon - AR5K_TUNE_SW_BEACON_RESP) << 3; + break; } + /* Timer3 marks the end of our ATIM window + * a zero length window is not allowed because + * we 'll get no beacons */ timer3 = next_beacon + (ah->ah_atim_window ? ah->ah_atim_window : 1); /* * Set the beacon register and enable all timers. - * (next beacon, DMA beacon, software beacon, ATIM window time) */ - ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); + /* When in AP mode zero timer0 to start TSF */ + if (ah->ah_op_mode == NL80211_IFTYPE_AP) + ath5k_hw_reg_write(ah, 0, AR5K_TIMER0); + else + ath5k_hw_reg_write(ah, next_beacon, AR5K_TIMER0); ath5k_hw_reg_write(ah, timer1, AR5K_TIMER1); ath5k_hw_reg_write(ah, timer2, AR5K_TIMER2); ath5k_hw_reg_write(ah, timer3, AR5K_TIMER3); + /* Force a TSF reset if requested and enable beacons */ + if (interval & AR5K_BEACON_RESET_TSF) + ath5k_hw_reset_tsf(ah); + ath5k_hw_reg_write(ah, interval & (AR5K_BEACON_PERIOD | - AR5K_BEACON_RESET_TSF | AR5K_BEACON_ENABLE), - AR5K_BEACON); + AR5K_BEACON_ENABLE), + AR5K_BEACON); + + /* Flush any pending BMISS interrupts on ISR by + * performing a clear-on-write operation on PISR + * register for the BMISS bit (writing a bit on + * ISR togles a reset for that bit and leaves + * the rest bits intact) */ + if (ah->ah_version == AR5K_AR5210) + ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_ISR); + else + ath5k_hw_reg_write(ah, AR5K_ISR_BMISS, AR5K_PISR); + + /* TODO: Set enchanced sleep registers on AR5212 + * based on vif->bss_conf params, until then + * disable power save reporting.*/ + AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, AR5K_STA_ID1_PWR_SV); + } #if 0 @@ -899,14 +958,26 @@ int ath5k_hw_beaconq_finish(struct ath5k_hw *ah, unsigned long phys_addr) */ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) { - unsigned int i; + unsigned int i, type; + u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; ATH5K_TRACE(ah->ah_sc); AR5K_ASSERT_ENTRY(entry, AR5K_KEYTABLE_SIZE); + type = ath5k_hw_reg_read(ah, AR5K_KEYTABLE_TYPE(entry)); + for (i = 0; i < AR5K_KEYCACHE_SIZE; i++) ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_OFF(entry, i)); + /* Reset associated MIC entry if TKIP + * is enabled located at offset (entry + 64) */ + if (type == AR5K_KEYTABLE_TYPE_TKIP) { + AR5K_ASSERT_ENTRY(micentry, AR5K_KEYTABLE_SIZE); + for (i = 0; i < AR5K_KEYCACHE_SIZE / 2 ; i++) + ath5k_hw_reg_write(ah, 0, + AR5K_KEYTABLE_OFF(micentry, i)); + } + /* * Set NULL encryption on AR5212+ * @@ -916,10 +987,16 @@ int ath5k_hw_reset_key(struct ath5k_hw *ah, u16 entry) * Note2: Windows driver (ndiswrapper) sets this to * 0x00000714 instead of 0x00000007 */ - if (ah->ah_version > AR5K_AR5211) + if (ah->ah_version > AR5K_AR5211) { ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, AR5K_KEYTABLE_TYPE(entry)); + if (type == AR5K_KEYTABLE_TYPE_TKIP) { + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(micentry)); + } + } + return 0; } @@ -936,6 +1013,23 @@ int ath5k_hw_is_key_valid(struct ath5k_hw *ah, u16 entry) AR5K_KEYTABLE_VALID; } +static +int ath5k_keycache_type(const struct ieee80211_key_conf *key) +{ + switch (key->alg) { + case ALG_TKIP: + return AR5K_KEYTABLE_TYPE_TKIP; + case ALG_CCMP: + return AR5K_KEYTABLE_TYPE_CCM; + case ALG_WEP: + if (key->keylen == LEN_WEP40) + return AR5K_KEYTABLE_TYPE_40; + else if (key->keylen == LEN_WEP104) + return AR5K_KEYTABLE_TYPE_104; + } + return -EINVAL; +} + /* * Set a key entry on the table */ @@ -943,40 +1037,53 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, const struct ieee80211_key_conf *key, const u8 *mac) { unsigned int i; + int keylen; __le32 key_v[5] = {}; + __le32 key0 = 0, key1 = 0; + __le32 *rxmic, *txmic; u32 keytype; + u16 micentry = entry + AR5K_KEYTABLE_MIC_OFFSET; + bool is_tkip; + const u8 *key_ptr; ATH5K_TRACE(ah->ah_sc); - /* key->keylen comes in from mac80211 in bytes */ + is_tkip = (key->alg == ALG_TKIP); - if (key->keylen > AR5K_KEYTABLE_SIZE / 8) + /* + * key->keylen comes in from mac80211 in bytes. + * TKIP is 128 bit + 128 bit mic + */ + keylen = (is_tkip) ? (128 / 8) : key->keylen; + + if (entry > AR5K_KEYTABLE_SIZE || + (is_tkip && micentry > AR5K_KEYTABLE_SIZE)) return -EOPNOTSUPP; - switch (key->keylen) { - /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit */ - case 40 / 8: - memcpy(&key_v[0], key->key, 5); - keytype = AR5K_KEYTABLE_TYPE_40; - break; + if (unlikely(keylen > 16)) + return -EOPNOTSUPP; - /* WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit */ - case 104 / 8: - memcpy(&key_v[0], &key->key[0], 6); - memcpy(&key_v[2], &key->key[6], 6); - memcpy(&key_v[4], &key->key[12], 1); - keytype = AR5K_KEYTABLE_TYPE_104; - break; - /* WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit */ - case 128 / 8: - memcpy(&key_v[0], &key->key[0], 6); - memcpy(&key_v[2], &key->key[6], 6); - memcpy(&key_v[4], &key->key[12], 4); - keytype = AR5K_KEYTABLE_TYPE_128; - break; + keytype = ath5k_keycache_type(key); + if (keytype < 0) + return keytype; - default: - return -EINVAL; /* shouldn't happen */ + /* + * each key block is 6 bytes wide, written as pairs of + * alternating 32 and 16 bit le values. + */ + key_ptr = key->key; + for (i = 0; keylen >= 6; keylen -= 6) { + memcpy(&key_v[i], key_ptr, 6); + i += 2; + key_ptr += 6; + } + if (keylen) + memcpy(&key_v[i], key_ptr, keylen); + + /* intentionally corrupt key until mic is installed */ + if (is_tkip) { + key0 = key_v[0] = ~key_v[0]; + key1 = key_v[1] = ~key_v[1]; } for (i = 0; i < ARRAY_SIZE(key_v); i++) @@ -985,6 +1092,40 @@ int ath5k_hw_set_key(struct ath5k_hw *ah, u16 entry, ath5k_hw_reg_write(ah, keytype, AR5K_KEYTABLE_TYPE(entry)); + if (is_tkip) { + /* Install rx/tx MIC */ + rxmic = (__le32 *) &key->key[16]; + txmic = (__le32 *) &key->key[24]; + + if (ah->ah_combined_mic) { + key_v[0] = rxmic[0]; + key_v[1] = cpu_to_le32(le32_to_cpu(txmic[0]) >> 16); + key_v[2] = rxmic[1]; + key_v[3] = cpu_to_le32(le32_to_cpu(txmic[0]) & 0xffff); + key_v[4] = txmic[1]; + } else { + key_v[0] = rxmic[0]; + key_v[1] = 0; + key_v[2] = rxmic[1]; + key_v[3] = 0; + key_v[4] = 0; + } + for (i = 0; i < ARRAY_SIZE(key_v); i++) + ath5k_hw_reg_write(ah, le32_to_cpu(key_v[i]), + AR5K_KEYTABLE_OFF(micentry, i)); + + ath5k_hw_reg_write(ah, AR5K_KEYTABLE_TYPE_NULL, + AR5K_KEYTABLE_TYPE(micentry)); + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC0(micentry)); + ath5k_hw_reg_write(ah, 0, AR5K_KEYTABLE_MAC1(micentry)); + + /* restore first 2 words of key */ + ath5k_hw_reg_write(ah, le32_to_cpu(~key0), + AR5K_KEYTABLE_OFF(entry, 0)); + ath5k_hw_reg_write(ah, le32_to_cpu(~key1), + AR5K_KEYTABLE_OFF(entry, 1)); + } + return ath5k_hw_set_key_lladdr(ah, entry, mac); } diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index e43f6563e61a08ab6cbfcaaff1d455c6eb56e8f7..7ba18e09463b2ab981712bbfa87766e1a26a7caa 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c @@ -1412,7 +1412,8 @@ static int ath5k_hw_rf5112_rfregs(struct ath5k_hw *ah, rf_ini = rfregs_2112a; rf_size = ARRAY_SIZE(rfregs_5112a); if (mode < 2) { - ATH5K_ERR(ah->ah_sc,"invalid channel mode: %i\n",mode); + ATH5K_ERR(ah->ah_sc, "invalid channel mode: %i\n", + mode); return -EINVAL; } mode = mode - 2; /*no a/turboa modes for 2112*/ @@ -1708,7 +1709,7 @@ enum ath5k_rfgain ath5k_hw_get_rf_gain(struct ath5k_hw *ah) if (ah->ah_radio >= AR5K_RF5112) { ath5k_hw_rfregs_gainf_corr(ah); ah->ah_gain.g_current = - ah->ah_gain.g_current>=ah->ah_gain.g_f_corr ? + ah->ah_gain.g_current >= ah->ah_gain.g_f_corr ? (ah->ah_gain.g_current-ah->ah_gain.g_f_corr) : 0; } @@ -2195,9 +2196,7 @@ static int ath5k_hw_rf5110_calibrate(struct ath5k_hw *ah, return ret; } - ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - if (ret) - return ret; + ath5k_hw_noise_floor_calibration(ah, channel->center_freq); /* * Re-enable RX/TX and beacons diff --git a/drivers/net/wireless/ath5k/qcu.c b/drivers/net/wireless/ath5k/qcu.c index 01bf09176d23b79a993ed5daf4b33b30a22a9cc6..1b7bc50ea8eb212b68fdd51f96283de34998e693 100644 --- a/drivers/net/wireless/ath5k/qcu.c +++ b/drivers/net/wireless/ath5k/qcu.c @@ -432,13 +432,30 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) if (tq->tqi_flags & AR5K_TXQ_FLAG_TXEOLINT_ENABLE) AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txeol, queue); + if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRORNINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrorn, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_CBRURNINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_cbrurn, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_QTRIGINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_qtrig, queue); + + if (tq->tqi_flags & AR5K_TXQ_FLAG_TXNOFRMINT_ENABLE) + AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_nofrm, queue); /* Update secondary interrupt mask registers */ + + /* Filter out inactive queues */ ah->ah_txq_imr_txok &= ah->ah_txq_status; ah->ah_txq_imr_txerr &= ah->ah_txq_status; ah->ah_txq_imr_txurn &= ah->ah_txq_status; ah->ah_txq_imr_txdesc &= ah->ah_txq_status; ah->ah_txq_imr_txeol &= ah->ah_txq_status; + ah->ah_txq_imr_cbrorn &= ah->ah_txq_status; + ah->ah_txq_imr_cbrurn &= ah->ah_txq_status; + ah->ah_txq_imr_qtrig &= ah->ah_txq_status; + ah->ah_txq_imr_nofrm &= ah->ah_txq_status; ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txok, AR5K_SIMR0_QCU_TXOK) | @@ -448,8 +465,24 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue) AR5K_SIMR1_QCU_TXERR) | AR5K_REG_SM(ah->ah_txq_imr_txeol, AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1); - ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txurn, - AR5K_SIMR2_QCU_TXURN), AR5K_SIMR2); + /* Update simr2 but don't overwrite rest simr2 settings */ + AR5K_REG_DISABLE_BITS(ah, AR5K_SIMR2, AR5K_SIMR2_QCU_TXURN); + AR5K_REG_ENABLE_BITS(ah, AR5K_SIMR2, + AR5K_REG_SM(ah->ah_txq_imr_txurn, + AR5K_SIMR2_QCU_TXURN)); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_cbrorn, + AR5K_SIMR3_QCBRORN) | + AR5K_REG_SM(ah->ah_txq_imr_cbrurn, + AR5K_SIMR3_QCBRURN), AR5K_SIMR3); + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_qtrig, + AR5K_SIMR4_QTRIG), AR5K_SIMR4); + /* Set TXNOFRM_QCU for the queues with TXNOFRM enabled */ + ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_nofrm, + AR5K_TXNOFRM_QCU), AR5K_TXNOFRM); + /* No queue has TXNOFRM enabled, disable the interrupt + * by setting AR5K_TXNOFRM to zero */ + if (ah->ah_txq_imr_nofrm == 0) + ath5k_hw_reg_write(ah, 0, AR5K_TXNOFRM); } return 0; diff --git a/drivers/net/wireless/ath5k/reg.h b/drivers/net/wireless/ath5k/reg.h index e557fe178bbf9401af6c7846118d0a7f46a16c84..91aaeaf881995c583747feae712254a21e667872 100644 --- a/drivers/net/wireless/ath5k/reg.h +++ b/drivers/net/wireless/ath5k/reg.h @@ -234,6 +234,7 @@ #define AR5K_TXNOFRM 0x004c #define AR5K_TXNOFRM_M 0x000003ff #define AR5K_TXNOFRM_QCU 0x000ffc00 +#define AR5K_TXNOFRM_QCU_S 10 /* * Receive frame gap timeout register @@ -350,7 +351,7 @@ #define AR5K_SISR3 0x0090 /* Register Address [5211+] */ #define AR5K_SISR3_QCBRORN 0x000003ff /* Mask for QCBRORN */ -#define AR5K_SISR3_QCBORN_S 0 +#define AR5K_SISR3_QCBRORN_S 0 #define AR5K_SISR3_QCBRURN 0x03ff0000 /* Mask for QCBRURN */ #define AR5K_SISR3_QCBRURN_S 16 @@ -1113,14 +1114,16 @@ #define AR5K_PCU_MAX 0x8fff /* - * First station id register (MAC address in lower 32 bits) + * First station id register (Lower 32 bits of MAC address) */ -#define AR5K_STA_ID0 0x8000 +#define AR5K_STA_ID0 0x8000 +#define AR5K_STA_ID0_ARRD_L32 0xffffffff /* - * Second station id register (MAC address in upper 16 bits) + * Second station id register (Upper 16 bits of MAC address + PCU settings) */ #define AR5K_STA_ID1 0x8004 /* Register Address */ +#define AR5K_STA_ID1_ADDR_U16 0x0000ffff /* Upper 16 bits of MAC addres */ #define AR5K_STA_ID1_AP 0x00010000 /* Set AP mode */ #define AR5K_STA_ID1_ADHOC 0x00020000 /* Set Ad-Hoc mode */ #define AR5K_STA_ID1_PWR_SV 0x00040000 /* Power save reporting */ @@ -1726,6 +1729,7 @@ #define AR5K_MISC_MODE 0x8120 /* Register Address */ #define AR5K_MISC_MODE_FBSSID_MATCH 0x00000001 /* Force BSSID match */ #define AR5K_MISC_MODE_ACKSIFS_MEM 0x00000002 /* ACK SIFS memory (?) */ +#define AR5K_MISC_MODE_COMBINED_MIC 0x00000004 /* use rx/tx MIC key */ /* more bits */ /* @@ -1810,6 +1814,10 @@ #define AR5K_KEYTABLE_MAC1(_n) AR5K_KEYTABLE_OFF(_n, 7) #define AR5K_KEYTABLE_VALID 0x00008000 +/* If key type is TKIP and MIC is enabled + * MIC key goes in offset entry + 64 */ +#define AR5K_KEYTABLE_MIC_OFFSET 64 + /* WEP 40-bit = 40-bit entered key + 24 bit IV = 64-bit * WEP 104-bit = 104-bit entered key + 24-bit IV = 128-bit * WEP 128-bit = 128-bit entered key + 24 bit IV = 152-bit diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index 1b6d45b6772db39c269752e1b5bbef4e328d6389..dc2d7d8bdb7aceda7a27d52571b1047f65e86a3e 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c @@ -674,7 +674,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, (ee->ee_switch_settling[ee_mode] << 7) & 0x3f80, 0xffffc07f); AR5K_REG_MASKED_BITS(ah, AR5K_PHY_GAIN, - (ee->ee_ant_tx_rx[ee_mode] << 12) & 0x3f000, + (ee->ee_atn_tx_rx[ee_mode] << 12) & 0x3f000, 0xfffc0fff); AR5K_REG_MASKED_BITS(ah, AR5K_PHY_DESIRED_SIZE, (ee->ee_adc_desired_size[ee_mode] & 0x00ff) | @@ -842,9 +842,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, * * XXX: Find an interval that's OK for all cards... */ - ret = ath5k_hw_noise_floor_calibration(ah, channel->center_freq); - if (ret) - return ret; + ath5k_hw_noise_floor_calibration(ah, channel->center_freq); /* * Reset queues and start beacon timers at the end of the reset routine @@ -864,8 +862,7 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, /* Pre-enable interrupts on 5211/5212*/ if (ah->ah_version != AR5K_AR5210) - ath5k_hw_set_imr(ah, AR5K_INT_RX | AR5K_INT_TX | - AR5K_INT_FATAL); + ath5k_hw_set_imr(ah, ah->ah_imr); /* * Set RF kill flags if supported by the device (read from the EEPROM) diff --git a/drivers/net/wireless/ath9k/Kconfig b/drivers/net/wireless/ath9k/Kconfig index 80a69243041346c043de298c75664eb06e0c0afa..c43bd321f97fb6abfbbbce9bca13f37bfd1f5552 100644 --- a/drivers/net/wireless/ath9k/Kconfig +++ b/drivers/net/wireless/ath9k/Kconfig @@ -9,3 +9,14 @@ config ATH9K Atheros IEEE 802.11n AR5008 and AR9001 family of chipsets. If you choose to build a module, it'll be called ath9k. + +config ATH9K_DEBUG + bool "Atheros ath9k debugging" + depends on ATH9K + ---help--- + Say Y, if you need ath9k to display debug messages. + Pass the debug mask as a module parameter: + + modprobe ath9k debug=0x00002000 + + Look in ath9k/core.h for possible debug masks diff --git a/drivers/net/wireless/ath9k/Makefile b/drivers/net/wireless/ath9k/Makefile index a6411517e5f849f79c9e49180783ca11264ba4e5..1209d14613ac49cbdabf8e10fd17cf4257e2b440 100644 --- a/drivers/net/wireless/ath9k/Makefile +++ b/drivers/net/wireless/ath9k/Makefile @@ -1,11 +1,16 @@ ath9k-y += hw.o \ + eeprom.o \ + mac.o \ + calib.o \ + ani.o \ phy.o \ regd.o \ beacon.o \ main.o \ recv.o \ xmit.o \ - rc.o \ - core.o + rc.o + +ath9k-$(CONFIG_ATH9K_DEBUG) += debug.o obj-$(CONFIG_ATH9K) += ath9k.o diff --git a/drivers/net/wireless/ath9k/ani.c b/drivers/net/wireless/ath9k/ani.c new file mode 100644 index 0000000000000000000000000000000000000000..251e2d9a7a4a6d20e772325f6d7449a757f91984 --- /dev/null +++ b/drivers/net/wireless/ath9k/ani.c @@ -0,0 +1,852 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { + if (ahp->ah_ani[i].c.channel == chan->channel) + return i; + if (ahp->ah_ani[i].c.channel == 0) { + ahp->ah_ani[i].c.channel = chan->channel; + ahp->ah_ani[i].c.channelFlags = chan->channelFlags; + return i; + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "No more channel states left. Using channel 0\n"); + + return 0; +} + +static bool ath9k_hw_ani_control(struct ath_hal *ah, + enum ath9k_ani_cmd cmd, int param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState = ahp->ah_curani; + + switch (cmd & ahp->ah_ani_function) { + case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ + u32 level = param; + + if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned)ARRAY_SIZE(ahp->ah_totalSizeDesired)); + return false; + } + + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_TOT_DES, + ahp->ah_totalSizeDesired[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_LOW, + ahp->ah_coarseLow[level]); + REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, + AR_PHY_AGC_CTL1_COARSE_HIGH, + ahp->ah_coarseHigh[level]); + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRPWR, + ahp->ah_firpwr[level]); + + if (level > aniState->noiseImmunityLevel) + ahp->ah_stats.ast_ani_niup++; + else if (level < aniState->noiseImmunityLevel) + ahp->ah_stats.ast_ani_nidown++; + aniState->noiseImmunityLevel = level; + break; + } + case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ + const int m1ThreshLow[] = { 127, 50 }; + const int m2ThreshLow[] = { 127, 40 }; + const int m1Thresh[] = { 127, 0x4d }; + const int m2Thresh[] = { 127, 0x40 }; + const int m2CountThr[] = { 31, 16 }; + const int m2CountThrLow[] = { 63, 48 }; + u32 on = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M1_THRESH_LOW, + m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2_THRESH_LOW, + m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M1_THRESH, + m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2_THRESH, + m2Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR, + AR_PHY_SFCORR_M2COUNT_THR, + m2CountThr[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, + m2CountThrLow[on]); + + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH_LOW, + m1ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH_LOW, + m2ThreshLow[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M1_THRESH, + m1Thresh[on]); + REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, + AR_PHY_SFCORR_EXT_M2_THRESH, + m2Thresh[on]); + + if (on) + REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + else + REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, + AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); + + if (!on != aniState->ofdmWeakSigDetectOff) { + if (on) + ahp->ah_stats.ast_ani_ofdmon++; + else + ahp->ah_stats.ast_ani_ofdmoff++; + aniState->ofdmWeakSigDetectOff = !on; + } + break; + } + case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ + const int weakSigThrCck[] = { 8, 6 }; + u32 high = param ? 1 : 0; + + REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, + AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, + weakSigThrCck[high]); + if (high != aniState->cckWeakSigThreshold) { + if (high) + ahp->ah_stats.ast_ani_cckhigh++; + else + ahp->ah_stats.ast_ani_ccklow++; + aniState->cckWeakSigThreshold = high; + } + break; + } + case ATH9K_ANI_FIRSTEP_LEVEL:{ + const int firstep[] = { 0, 4, 8 }; + u32 level = param; + + if (level >= ARRAY_SIZE(firstep)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) ARRAY_SIZE(firstep)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, + AR_PHY_FIND_SIG_FIRSTEP, + firstep[level]); + if (level > aniState->firstepLevel) + ahp->ah_stats.ast_ani_stepup++; + else if (level < aniState->firstepLevel) + ahp->ah_stats.ast_ani_stepdown++; + aniState->firstepLevel = level; + break; + } + case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ + const int cycpwrThr1[] = + { 2, 4, 6, 8, 10, 12, 14, 16 }; + u32 level = param; + + if (level >= ARRAY_SIZE(cycpwrThr1)) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "level out of range (%u > %u)\n", + level, + (unsigned) + ARRAY_SIZE(cycpwrThr1)); + return false; + } + REG_RMW_FIELD(ah, AR_PHY_TIMING5, + AR_PHY_TIMING5_CYCPWR_THR1, + cycpwrThr1[level]); + if (level > aniState->spurImmunityLevel) + ahp->ah_stats.ast_ani_spurup++; + else if (level < aniState->spurImmunityLevel) + ahp->ah_stats.ast_ani_spurdown++; + aniState->spurImmunityLevel = level; + break; + } + case ATH9K_ANI_PRESENT: + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "invalid cmd %u\n", cmd); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "ANI parameters:\n"); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "noiseImmunityLevel=%d, spurImmunityLevel=%d, " + "ofdmWeakSigDetectOff=%d\n", + aniState->noiseImmunityLevel, aniState->spurImmunityLevel, + !aniState->ofdmWeakSigDetectOff); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "cckWeakSigThreshold=%d, " + "firstepLevel=%d, listenTime=%d\n", + aniState->cckWeakSigThreshold, aniState->firstepLevel, + aniState->listenTime); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", + aniState->cycleCount, aniState->ofdmPhyErrCount, + aniState->cckPhyErrCount); + + return true; +} + +static void ath9k_hw_update_mibstats(struct ath_hal *ah, + struct ath9k_mib_stats *stats) +{ + stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); + stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); + stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); + stats->rts_good += REG_READ(ah, AR_RTS_OK); + stats->beacons += REG_READ(ah, AR_BEACON_CNT); +} + +static void ath9k_ani_restart(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + + if (!DO_ANI(ah)) + return; + + aniState = ahp->ah_curani; + + aniState->listenTime = 0; + if (ahp->ah_hasHwPhyCounters) { + if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { + aniState->ofdmPhyErrBase = 0; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "OFDM Trigger is too high for hw counters\n"); + } else { + aniState->ofdmPhyErrBase = + AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; + } + if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { + aniState->cckPhyErrBase = 0; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "CCK Trigger is too high for hw counters\n"); + } else { + aniState->cckPhyErrBase = + AR_PHY_COUNTMAX - aniState->cckTrigHigh; + } + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Writing ofdmbase=%u cckbase=%u\n", + aniState->ofdmPhyErrBase, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + } + aniState->ofdmPhyErrCount = 0; + aniState->cckPhyErrCount = 0; +} + +static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *chan = ah->ah_curchan; + struct ar5416AniState *aniState; + enum wireless_mode mode; + int32_t rssi; + + if (!DO_ANI(ah)) + return; + + aniState = ahp->ah_curani; + + if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1)) { + return; + } + } + + if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel + 1)) { + return; + } + } + + if (ah->ah_opmode == NL80211_IFTYPE_AP) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } + return; + } + rssi = BEACON_RSSI(ahp); + if (rssi > aniState->rssiThrHigh) { + if (!aniState->ofdmWeakSigDetectOff) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + false)) { + ath9k_hw_ani_control(ah, + ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); + return; + } + } + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + return; + } + } else if (rssi > aniState->rssiThrLow) { + if (aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + true); + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + return; + } else { + mode = ath9k_hw_chan2wmode(ah, chan); + if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { + if (!aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + false); + if (aniState->firstepLevel > 0) + ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, 0); + return; + } + } +} + +static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *chan = ah->ah_curchan; + struct ar5416AniState *aniState; + enum wireless_mode mode; + int32_t rssi; + + if (!DO_ANI(ah)) + return; + + aniState = ahp->ah_curani; + if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel + 1)) { + return; + } + } + if (ah->ah_opmode == NL80211_IFTYPE_AP) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } + return; + } + rssi = BEACON_RSSI(ahp); + if (rssi > aniState->rssiThrLow) { + if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel + 1); + } else { + mode = ath9k_hw_chan2wmode(ah, chan); + if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { + if (aniState->firstepLevel > 0) + ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, 0); + } + } +} + +static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + int32_t rssi; + + aniState = ahp->ah_curani; + + if (ah->ah_opmode == NL80211_IFTYPE_AP) { + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1)) + return; + } + } else { + rssi = BEACON_RSSI(ahp); + if (rssi > aniState->rssiThrHigh) { + /* XXX: Handle me */ + } else if (rssi > aniState->rssiThrLow) { + if (aniState->ofdmWeakSigDetectOff) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + true) == true) + return; + } + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1) == true) + return; + } + } else { + if (aniState->firstepLevel > 0) { + if (ath9k_hw_ani_control(ah, + ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel - 1) == true) + return; + } + } + } + + if (aniState->spurImmunityLevel > 0) { + if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel - 1)) + return; + } + + if (aniState->noiseImmunityLevel > 0) { + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel - 1); + return; + } +} + +static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + u32 txFrameCount, rxFrameCount, cycleCount; + int32_t listenTime; + + txFrameCount = REG_READ(ah, AR_TFCNT); + rxFrameCount = REG_READ(ah, AR_RFCNT); + cycleCount = REG_READ(ah, AR_CCCNT); + + aniState = ahp->ah_curani; + if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { + + listenTime = 0; + ahp->ah_stats.ast_ani_lzero++; + } else { + int32_t ccdelta = cycleCount - aniState->cycleCount; + int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; + int32_t tfdelta = txFrameCount - aniState->txFrameCount; + listenTime = (ccdelta - rfdelta - tfdelta) / 44000; + } + aniState->cycleCount = cycleCount; + aniState->txFrameCount = txFrameCount; + aniState->rxFrameCount = rxFrameCount; + + return listenTime; +} + +void ath9k_ani_reset(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + struct ath9k_channel *chan = ah->ah_curchan; + int index; + + if (!DO_ANI(ah)) + return; + + index = ath9k_hw_get_ani_channel_idx(ah, chan); + aniState = &ahp->ah_ani[index]; + ahp->ah_curani = aniState; + + if (DO_ANI(ah) && ah->ah_opmode != NL80211_IFTYPE_STATION + && ah->ah_opmode != NL80211_IFTYPE_ADHOC) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Reset ANI state opmode %u\n", ah->ah_opmode); + ahp->ah_stats.ast_ani_reset++; + + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + !ATH9K_ANI_USE_OFDM_WEAK_SIG); + ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, + ATH9K_ANI_CCK_WEAK_SIG_THR); + + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | + ATH9K_RX_FILTER_PHYERR); + + if (ah->ah_opmode == NL80211_IFTYPE_AP) { + ahp->ah_curani->ofdmTrigHigh = + ah->ah_config.ofdm_trig_high; + ahp->ah_curani->ofdmTrigLow = + ah->ah_config.ofdm_trig_low; + ahp->ah_curani->cckTrigHigh = + ah->ah_config.cck_trig_high; + ahp->ah_curani->cckTrigLow = + ah->ah_config.cck_trig_low; + } + ath9k_ani_restart(ah); + return; + } + + if (aniState->noiseImmunityLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, + aniState->noiseImmunityLevel); + if (aniState->spurImmunityLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, + aniState->spurImmunityLevel); + if (aniState->ofdmWeakSigDetectOff) + ath9k_hw_ani_control(ah, ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, + !aniState->ofdmWeakSigDetectOff); + if (aniState->cckWeakSigThreshold) + ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, + aniState->cckWeakSigThreshold); + if (aniState->firstepLevel != 0) + ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, + aniState->firstepLevel); + if (ahp->ah_hasHwPhyCounters) { + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) & + ~ATH9K_RX_FILTER_PHYERR); + ath9k_ani_restart(ah); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); + + } else { + ath9k_ani_restart(ah); + ath9k_hw_setrxfilter(ah, ath9k_hw_getrxfilter(ah) | + ATH9K_RX_FILTER_PHYERR); + } +} + +void ath9k_hw_ani_monitor(struct ath_hal *ah, + const struct ath9k_node_stats *stats, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416AniState *aniState; + int32_t listenTime; + + aniState = ahp->ah_curani; + ahp->ah_stats.ast_nodestats = *stats; + + listenTime = ath9k_hw_ani_get_listen_time(ah); + if (listenTime < 0) { + ahp->ah_stats.ast_ani_lneg++; + ath9k_ani_restart(ah); + return; + } + + aniState->listenTime += listenTime; + + if (ahp->ah_hasHwPhyCounters) { + u32 phyCnt1, phyCnt2; + u32 ofdmPhyErrCnt, cckPhyErrCnt; + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + + phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); + phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); + + if (phyCnt1 < aniState->ofdmPhyErrBase || + phyCnt2 < aniState->cckPhyErrBase) { + if (phyCnt1 < aniState->ofdmPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "phyCnt1 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt1, + aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_1, + aniState->ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, + AR_PHY_ERR_OFDM_TIMING); + } + if (phyCnt2 < aniState->cckPhyErrBase) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "phyCnt2 0x%x, resetting " + "counter value to 0x%x\n", + phyCnt2, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, + aniState->cckPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, + AR_PHY_ERR_CCK_TIMING); + } + return; + } + + ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ahp->ah_stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + + cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + ahp->ah_stats.ast_ani_cckerrs += + cckPhyErrCnt - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = cckPhyErrCnt; + } + + if (!DO_ANI(ah)) + return; + + if (aniState->listenTime > 5 * ahp->ah_aniPeriod) { + if (aniState->ofdmPhyErrCount <= aniState->listenTime * + aniState->ofdmTrigLow / 1000 && + aniState->cckPhyErrCount <= aniState->listenTime * + aniState->cckTrigLow / 1000) + ath9k_hw_ani_lower_immunity(ah); + ath9k_ani_restart(ah); + } else if (aniState->listenTime > ahp->ah_aniPeriod) { + if (aniState->ofdmPhyErrCount > aniState->listenTime * + aniState->ofdmTrigHigh / 1000) { + ath9k_hw_ani_ofdm_err_trigger(ah); + ath9k_ani_restart(ah); + } else if (aniState->cckPhyErrCount > + aniState->listenTime * aniState->cckTrigHigh / + 1000) { + ath9k_hw_ani_cck_err_trigger(ah); + ath9k_ani_restart(ah); + } + } +} + +bool ath9k_hw_phycounters(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ahp->ah_hasHwPhyCounters ? true : false; +} + +void ath9k_enable_mib_counters(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable MIB counters\n"); + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + + REG_WRITE(ah, AR_FILT_OFDM, 0); + REG_WRITE(ah, AR_FILT_CCK, 0); + REG_WRITE(ah, AR_MIBC, + ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) + & 0x0f); + REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); + REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); +} + +void ath9k_hw_disable_mib_counters(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n"); + + REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); + + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + + REG_WRITE(ah, AR_FILT_OFDM, 0); + REG_WRITE(ah, AR_FILT_CCK, 0); +} + +u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, + u32 *rxc_pcnt, + u32 *rxf_pcnt, + u32 *txf_pcnt) +{ + static u32 cycles, rx_clear, rx_frame, tx_frame; + u32 good = 1; + + u32 rc = REG_READ(ah, AR_RCCNT); + u32 rf = REG_READ(ah, AR_RFCNT); + u32 tf = REG_READ(ah, AR_TFCNT); + u32 cc = REG_READ(ah, AR_CCCNT); + + if (cycles == 0 || cycles > cc) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "cycle counter wrap. ExtBusy = 0\n"); + good = 0; + } else { + u32 cc_d = cc - cycles; + u32 rc_d = rc - rx_clear; + u32 rf_d = rf - rx_frame; + u32 tf_d = tf - tx_frame; + + if (cc_d != 0) { + *rxc_pcnt = rc_d * 100 / cc_d; + *rxf_pcnt = rf_d * 100 / cc_d; + *txf_pcnt = tf_d * 100 / cc_d; + } else { + good = 0; + } + } + + cycles = cc; + rx_frame = rf; + rx_clear = rc; + tx_frame = tf; + + return good; +} + +/* + * Process a MIB interrupt. We may potentially be invoked because + * any of the MIB counters overflow/trigger so don't assume we're + * here because a PHY error counter triggered. + */ +void ath9k_hw_procmibevent(struct ath_hal *ah, + const struct ath9k_node_stats *stats) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 phyCnt1, phyCnt2; + + /* Reset these counters regardless */ + REG_WRITE(ah, AR_FILT_OFDM, 0); + REG_WRITE(ah, AR_FILT_CCK, 0); + if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) + REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); + + /* Clear the mib counters and save them in the stats */ + ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); + ahp->ah_stats.ast_nodestats = *stats; + + if (!DO_ANI(ah)) + return; + + /* NB: these are not reset-on-read */ + phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); + phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); + if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || + ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { + struct ar5416AniState *aniState = ahp->ah_curani; + u32 ofdmPhyErrCnt, cckPhyErrCnt; + + /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ + ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; + ahp->ah_stats.ast_ani_ofdmerrs += + ofdmPhyErrCnt - aniState->ofdmPhyErrCount; + aniState->ofdmPhyErrCount = ofdmPhyErrCnt; + + cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; + ahp->ah_stats.ast_ani_cckerrs += + cckPhyErrCnt - aniState->cckPhyErrCount; + aniState->cckPhyErrCount = cckPhyErrCnt; + + /* + * NB: figure out which counter triggered. If both + * trigger we'll only deal with one as the processing + * clobbers the error counter so the trigger threshold + * check will never be true. + */ + if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) + ath9k_hw_ani_ofdm_err_trigger(ah); + if (aniState->cckPhyErrCount > aniState->cckTrigHigh) + ath9k_hw_ani_cck_err_trigger(ah); + /* NB: always restart to insure the h/w counters are reset */ + ath9k_ani_restart(ah); + } +} + +void ath9k_hw_ani_setup(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; + const int coarseHigh[] = { -14, -14, -14, -14, -12 }; + const int coarseLow[] = { -64, -64, -64, -64, -70 }; + const int firpwr[] = { -78, -78, -78, -78, -80 }; + + for (i = 0; i < 5; i++) { + ahp->ah_totalSizeDesired[i] = totalSizeDesired[i]; + ahp->ah_coarseHigh[i] = coarseHigh[i]; + ahp->ah_coarseLow[i] = coarseLow[i]; + ahp->ah_firpwr[i] = firpwr[i]; + } +} + +void ath9k_hw_ani_attach(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Attach ANI\n"); + + ahp->ah_hasHwPhyCounters = 1; + + memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani)); + for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { + ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; + ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; + ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; + ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; + ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; + ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; + ahp->ah_ani[i].ofdmWeakSigDetectOff = + !ATH9K_ANI_USE_OFDM_WEAK_SIG; + ahp->ah_ani[i].cckWeakSigThreshold = + ATH9K_ANI_CCK_WEAK_SIG_THR; + ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; + ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; + if (ahp->ah_hasHwPhyCounters) { + ahp->ah_ani[i].ofdmPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; + ahp->ah_ani[i].cckPhyErrBase = + AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; + } + } + if (ahp->ah_hasHwPhyCounters) { + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Setting OfdmErrBase = 0x%08x\n", + ahp->ah_ani[0].ofdmPhyErrBase); + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", + ahp->ah_ani[0].cckPhyErrBase); + + REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase); + REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase); + ath9k_enable_mib_counters(ah); + } + ahp->ah_aniPeriod = ATH9K_ANI_PERIOD; + if (ah->ah_config.enable_ani) + ahp->ah_procPhyErr |= HAL_PROCESS_ANI; +} + +void ath9k_hw_ani_detach(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detach ANI\n"); + + if (ahp->ah_hasHwPhyCounters) { + ath9k_hw_disable_mib_counters(ah); + REG_WRITE(ah, AR_PHY_ERR_1, 0); + REG_WRITE(ah, AR_PHY_ERR_2, 0); + } +} diff --git a/drivers/net/wireless/ath9k/ath9k.h b/drivers/net/wireless/ath9k/ath9k.h index accace5f7efb9d809e962c4a32d2120e57182d60..d2781350295348f850c7b0501044a904c8a3ce65 100644 --- a/drivers/net/wireless/ath9k/ath9k.h +++ b/drivers/net/wireless/ath9k/ath9k.h @@ -26,6 +26,7 @@ #define AR9160_DEVID_PCI 0x0027 #define AR9280_DEVID_PCI 0x0029 #define AR9280_DEVID_PCIE 0x002a +#define AR9285_DEVID_PCIE 0x002b #define AR5416_AR9100_DEVID 0x000b @@ -138,6 +139,19 @@ struct ath_desc { #define ATH9K_TXDESC_NOACK 0x0002 #define ATH9K_TXDESC_RTSENA 0x0004 #define ATH9K_TXDESC_CTSENA 0x0008 +/* ATH9K_TXDESC_INTREQ forces a tx interrupt to be generated for + * the descriptor its marked on. We take a tx interrupt to reap + * descriptors when the h/w hits an EOL condition or + * when the descriptor is specifically marked to generate + * an interrupt with this flag. Descriptors should be + * marked periodically to insure timely replenishing of the + * supply needed for sending frames. Defering interrupts + * reduces system load and potentially allows more concurrent + * work to be done but if done to aggressively can cause + * senders to backup. When the hardware queue is left too + * large rate control information may also be too out of + * date. An Alternative for this is TX interrupt mitigation + * but this needs more testing. */ #define ATH9K_TXDESC_INTREQ 0x0010 #define ATH9K_TXDESC_VEOL 0x0020 #define ATH9K_TXDESC_EXT_ONLY 0x0040 @@ -388,22 +402,6 @@ enum ath9k_int { ATH9K_INT_NOCARD = 0xffffffff }; -struct ath9k_rate_table { - int rateCount; - u8 rateCodeToIndex[256]; - struct { - u8 valid; - u8 phy; - u32 rateKbps; - u8 rateCode; - u8 shortPreamble; - u8 dot11Rate; - u8 controlRate; - u16 lpAckDuration; - u16 spAckDuration; - } info[32]; -}; - #define ATH9K_RATESERIES_RTS_CTS 0x0001 #define ATH9K_RATESERIES_2040 0x0002 #define ATH9K_RATESERIES_HALFGI 0x0004 @@ -479,12 +477,10 @@ struct ath9k_channel { (((_c)->channelFlags & CHANNEL_A_HT20) == CHANNEL_A_HT20) || \ (((_c)->channelFlags & CHANNEL_A_HT40PLUS) == CHANNEL_A_HT40PLUS) || \ (((_c)->channelFlags & CHANNEL_A_HT40MINUS) == CHANNEL_A_HT40MINUS)) -#define IS_CHAN_B(_c) (((_c)->channelFlags & CHANNEL_B) == CHANNEL_B) #define IS_CHAN_G(_c) ((((_c)->channelFlags & (CHANNEL_G)) == CHANNEL_G) || \ (((_c)->channelFlags & CHANNEL_G_HT20) == CHANNEL_G_HT20) || \ (((_c)->channelFlags & CHANNEL_G_HT40PLUS) == CHANNEL_G_HT40PLUS) || \ (((_c)->channelFlags & CHANNEL_G_HT40MINUS) == CHANNEL_G_HT40MINUS)) -#define IS_CHAN_CCK(_c) (((_c)->channelFlags & CHANNEL_CCK) != 0) #define IS_CHAN_OFDM(_c) (((_c)->channelFlags & CHANNEL_OFDM) != 0) #define IS_CHAN_5GHZ(_c) (((_c)->channelFlags & CHANNEL_5GHZ) != 0) #define IS_CHAN_2GHZ(_c) (((_c)->channelFlags & CHANNEL_2GHZ) != 0) @@ -493,6 +489,7 @@ struct ath9k_channel { #define IS_CHAN_QUARTER_RATE(_c) (((_c)->channelFlags & CHANNEL_QUARTER) != 0) /* These macros check chanmode and not channelFlags */ +#define IS_CHAN_B(_c) ((_c)->chanmode == CHANNEL_B) #define IS_CHAN_HT20(_c) (((_c)->chanmode == CHANNEL_A_HT20) || \ ((_c)->chanmode == CHANNEL_G_HT20)) #define IS_CHAN_HT40(_c) (((_c)->chanmode == CHANNEL_A_HT40PLUS) || \ @@ -651,13 +648,6 @@ enum ath9k_ant_setting { ATH9K_ANT_FIXED_B }; -enum ath9k_opmode { - ATH9K_M_STA = 1, - ATH9K_M_IBSS = 0, - ATH9K_M_HOSTAP = 6, - ATH9K_M_MONITOR = 8 -}; - #define ATH9K_SLOT_TIME_6 6 #define ATH9K_SLOT_TIME_9 9 #define ATH9K_SLOT_TIME_20 20 @@ -689,13 +679,19 @@ enum ath9k_ani_cmd { ATH9K_ANI_ALL = 0xff }; -enum phytype { - PHY_DS, - PHY_FH, - PHY_OFDM, - PHY_HT, +enum { + WLAN_RC_PHY_OFDM, + WLAN_RC_PHY_CCK, + WLAN_RC_PHY_HT_20_SS, + WLAN_RC_PHY_HT_20_DS, + WLAN_RC_PHY_HT_40_SS, + WLAN_RC_PHY_HT_40_DS, + WLAN_RC_PHY_HT_20_SS_HGI, + WLAN_RC_PHY_HT_20_DS_HGI, + WLAN_RC_PHY_HT_40_SS_HGI, + WLAN_RC_PHY_HT_40_DS_HGI, + WLAN_RC_PHY_MAX }; -#define PHY_CCK PHY_DS enum ath9k_tp_scale { ATH9K_TP_SCALE_MAX = 0, @@ -778,7 +774,8 @@ struct ath_hal { void __iomem *ah_sh; struct ath_softc *ah_sc; - enum ath9k_opmode ah_opmode; + + enum nl80211_iftype ah_opmode; struct ath9k_ops_config ah_config; struct ath9k_hw_capabilities ah_caps; @@ -815,195 +812,246 @@ struct chan_centers { u16 ext_center; }; -int ath_hal_getcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 *result); -const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah, - u32 mode); -void ath9k_hw_detach(struct ath_hal *ah); -struct ath_hal *ath9k_hw_attach(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *error); -bool ath9k_regd_init_channels(struct ath_hal *ah, - u32 maxchans, u32 *nchans, - u8 *regclassids, - u32 maxregids, u32 *nregids, - u16 cc, - bool enableOutdoor, - bool enableExtendedChannels); +struct ath_rate_table; + +/* Helpers */ + +enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, + const struct ath9k_channel *chan); +bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val); +u32 ath9k_hw_reverse_bits(u32 val, u32 n); +bool ath9k_get_channel_edges(struct ath_hal *ah, + u16 flags, u16 *low, + u16 *high); +u16 ath9k_hw_computetxtime(struct ath_hal *ah, + struct ath_rate_table *rates, + u32 frameLen, u16 rateix, + bool shortPreamble); u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags); -enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, - enum ath9k_int ints); -bool ath9k_hw_reset(struct ath_hal *ah, - struct ath9k_channel *chan, +void ath9k_hw_get_channel_centers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct chan_centers *centers); + +/* Attach, Detach */ + +const char *ath9k_hw_probe(u16 vendorid, u16 devid); +void ath9k_hw_detach(struct ath_hal *ah); +struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, + void __iomem *mem, int *error); +void ath9k_hw_rfdetach(struct ath_hal *ah); + + +/* HW Reset */ + +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, enum ath9k_ht_extprotspacing extprotspacing, - bool bChannelChange, - int *status); -bool ath9k_hw_phy_disable(struct ath_hal *ah); -void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, - bool *isCalDone); -void ath9k_hw_ani_monitor(struct ath_hal *ah, - const struct ath9k_node_stats *stats, - struct ath9k_channel *chan); -bool ath9k_hw_calibrate(struct ath_hal *ah, - struct ath9k_channel *chan, - u8 rxchainmask, - bool longcal, - bool *isCalDone); -s16 ath9k_hw_getchan_noise(struct ath_hal *ah, - struct ath9k_channel *chan); -void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, - u16 assocId); -void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits); -void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, - u16 assocId); -bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q); -void ath9k_hw_reset_tsf(struct ath_hal *ah); -bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry); -bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, - const u8 *mac); -bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, - u16 entry, - const struct ath9k_keyval *k, - const u8 *mac, - int xorKey); -bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, - u32 setting); -void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore); -bool ath9k_hw_intrpend(struct ath_hal *ah); -bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked); -bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, - bool bIncTrigLevel); -void ath9k_hw_procmibevent(struct ath_hal *ah, - const struct ath9k_node_stats *stats); -bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set); -void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode); -bool ath9k_hw_phycounters(struct ath_hal *ah); + bool bChannelChange, int *status); + +/* Key Cache Management */ + bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry); -bool ath9k_hw_getcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 *result); -bool ath9k_hw_setcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 setting, - int *status); -u32 ath9k_hw_getdefantenna(struct ath_hal *ah); -void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac); -void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask); -bool ath9k_hw_setbssidmask(struct ath_hal *ah, - const u8 *mask); +bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac); +bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, + const struct ath9k_keyval *k, + const u8 *mac, int xorKey); +bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry); + +/* Power Management */ + bool ath9k_hw_setpower(struct ath_hal *ah, enum ath9k_power_mode mode); -enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah); -u64 ath9k_hw_gettsf64(struct ath_hal *ah); +void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore); + +/* Beacon timers */ + +void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period); +void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, + const struct ath9k_beacon_state *bs); +/* HW Capabilities */ + +bool ath9k_hw_fill_cap_info(struct ath_hal *ah); +bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 *result); +bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 setting, int *status); + +/* GPIO / RFKILL / Antennae */ + +void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio); +u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio); +void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type); +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val); +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +void ath9k_enable_rfkill(struct ath_hal *ah); +#endif +int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg); u32 ath9k_hw_getdefantenna(struct ath_hal *ah); -bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us); +void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna); bool ath9k_hw_setantennaswitch(struct ath_hal *ah, enum ath9k_ant_setting settings, struct ath9k_channel *chan, u8 *tx_chainmask, u8 *rx_chainmask, u8 *antenna_cfgd); -void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna); -int ath9k_hw_select_antconfig(struct ath_hal *ah, - u32 cfg); -bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, - u32 txdp); + +/* General Operation */ + +u32 ath9k_hw_getrxfilter(struct ath_hal *ah); +void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits); +bool ath9k_hw_phy_disable(struct ath_hal *ah); +bool ath9k_hw_disable(struct ath_hal *ah); +bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit); +void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac); +bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac); +void ath9k_hw_setopmode(struct ath_hal *ah); +void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1); +void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask); +bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask); +void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId); +u64 ath9k_hw_gettsf64(struct ath_hal *ah); +void ath9k_hw_reset_tsf(struct ath_hal *ah); +bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting); +bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us); +void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode); + +/* Regulatory */ + +bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah); +struct ath9k_channel* ath9k_regd_check_channel(struct ath_hal *ah, + const struct ath9k_channel *c); +u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan); +u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah, + struct ath9k_channel *chan); +bool ath9k_regd_init_channels(struct ath_hal *ah, + u32 maxchans, u32 *nchans, u8 *regclassids, + u32 maxregids, u32 *nregids, u16 cc, + bool enableOutdoor, bool enableExtendedChannels); + +/* ANI */ + +void ath9k_ani_reset(struct ath_hal *ah); +void ath9k_hw_ani_monitor(struct ath_hal *ah, + const struct ath9k_node_stats *stats, + struct ath9k_channel *chan); +bool ath9k_hw_phycounters(struct ath_hal *ah); +void ath9k_enable_mib_counters(struct ath_hal *ah); +void ath9k_hw_disable_mib_counters(struct ath_hal *ah); +u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, + u32 *rxc_pcnt, + u32 *rxf_pcnt, + u32 *txf_pcnt); +void ath9k_hw_procmibevent(struct ath_hal *ah, + const struct ath9k_node_stats *stats); +void ath9k_hw_ani_setup(struct ath_hal *ah); +void ath9k_hw_ani_attach(struct ath_hal *ah); +void ath9k_hw_ani_detach(struct ath_hal *ah); + +/* Calibration */ + +void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, + bool *isCalDone); +void ath9k_hw_start_nfcal(struct ath_hal *ah); +void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan); +int16_t ath9k_hw_getnf(struct ath_hal *ah, + struct ath9k_channel *chan); +void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah); +s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan); +bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal, + bool *isCalDone); +bool ath9k_hw_init_cal(struct ath_hal *ah, + struct ath9k_channel *chan); + + +/* EEPROM */ + +int ath9k_hw_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit); +void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan); +bool ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u8 AntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit); +bool ath9k_hw_set_power_cal_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset); +bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, + struct ath9k_channel *chan); +int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config); +u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band); +u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz); +int ath9k_hw_eeprom_attach(struct ath_hal *ah); + +/* Interrupt Handling */ + +bool ath9k_hw_intrpend(struct ath_hal *ah); +bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked); +enum ath9k_int ath9k_hw_intrget(struct ath_hal *ah); +enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints); + +/* MAC (PCU/QCU) */ + +u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q); +bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp); bool ath9k_hw_txstart(struct ath_hal *ah, u32 q); -u16 ath9k_hw_computetxtime(struct ath_hal *ah, - const struct ath9k_rate_table *rates, - u32 frameLen, u16 rateix, - bool shortPreamble); +u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q); +bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel); +bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q); +bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 segLen, bool firstSeg, + bool lastSeg, const struct ath_desc *ds0); +void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds); +int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds); +void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pktLen, enum ath9k_pkt_type type, u32 txPower, + u32 keyIx, enum ath9k_key_type keyType, u32 flags); void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, struct ath_desc *lastds, u32 durUpdateEn, u32 rtsctsRate, u32 rtsctsDuration, struct ath9k_11n_rate_series series[], u32 nseries, u32 flags); -void ath9k_hw_set11n_burstduration(struct ath_hal *ah, - struct ath_desc *ds, +void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, + u32 aggrLen); +void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, + u32 numDelims); +void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds); +void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds); +void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, u32 burstDuration); -void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds); -u32 ath9k_hw_reverse_bits(u32 val, u32 n); -bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q); -u32 ath9k_regd_get_ctl(struct ath_hal *ah, struct ath9k_channel *chan); -u32 ath9k_regd_get_antenna_allowed(struct ath_hal *ah, - struct ath9k_channel *chan); -u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags); -bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, - struct ath9k_tx_queue_info *qinfo); +void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, + u32 vmf); +void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs); bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, const struct ath9k_tx_queue_info *qinfo); -struct ath9k_channel *ath9k_regd_check_channel(struct ath_hal *ah, - const struct ath9k_channel *c); -void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pktLen, enum ath9k_pkt_type type, - u32 txPower, u32 keyIx, - enum ath9k_key_type keyType, u32 flags); -bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 segLen, bool firstSeg, - bool lastSeg, - const struct ath_desc *ds0); -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, - u32 *rxc_pcnt, - u32 *rxf_pcnt, - u32 *txf_pcnt); -void ath9k_hw_dmaRegDump(struct ath_hal *ah); -void ath9k_hw_beaconinit(struct ath_hal *ah, - u32 next_beacon, u32 beacon_period); -void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, - const struct ath9k_beacon_state *bs); +bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, + struct ath9k_tx_queue_info *qinfo); +int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, + const struct ath9k_tx_queue_info *qinfo); +bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q); +bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q); +int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pa, struct ath_desc *nds, u64 tsf); bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, u32 size, u32 flags); +bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set); void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp); void ath9k_hw_rxena(struct ath_hal *ah); -void ath9k_hw_setopmode(struct ath_hal *ah); -bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac); -void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, - u32 filter1); -u32 ath9k_hw_getrxfilter(struct ath_hal *ah); void ath9k_hw_startpcureceive(struct ath_hal *ah); void ath9k_hw_stoppcurecv(struct ath_hal *ah); bool ath9k_hw_stopdmarecv(struct ath_hal *ah); -int ath9k_hw_rxprocdesc(struct ath_hal *ah, - struct ath_desc *ds, u32 pa, - struct ath_desc *nds, u64 tsf); -u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q); -int ath9k_hw_txprocdesc(struct ath_hal *ah, - struct ath_desc *ds); -void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, - u32 numDelims); -void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, - u32 aggrLen); -void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds); -bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q); -void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs); -void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds); -void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, - struct ath_desc *ds, u32 vmf); -bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit); -bool ath9k_regd_is_public_safety_sku(struct ath_hal *ah); -int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, - const struct ath9k_tx_queue_info *qinfo); -u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q); -const char *ath9k_hw_probe(u16 vendorid, u16 devid); -bool ath9k_hw_disable(struct ath_hal *ah); -void ath9k_hw_rfdetach(struct ath_hal *ah); -void ath9k_hw_get_channel_centers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct chan_centers *centers); -bool ath9k_get_channel_edges(struct ath_hal *ah, - u16 flags, u16 *low, - u16 *high); -void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, - u32 ah_signal_type); -void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 value); -u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio); -void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio); + #endif diff --git a/drivers/net/wireless/ath9k/beacon.c b/drivers/net/wireless/ath9k/beacon.c index 4dd1c1bda0fb80958b16066d882d86c7219a3b3e..3ab0b43aaf93f79c6b8af3859f7cf0ea9990e3db 100644 --- a/drivers/net/wireless/ath9k/beacon.c +++ b/drivers/net/wireless/ath9k/beacon.c @@ -14,13 +14,9 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ - /* Implementation of beacon processing. */ - #include "core.h" /* - * Configure parameters for the beacon queue - * * This function will modify certain transmit queue properties depending on * the operating mode of the station (AP or AdHoc). Parameters are AIFS * settings and channel width min/max @@ -30,33 +26,38 @@ static int ath_beaconq_config(struct ath_softc *sc) struct ath_hal *ah = sc->sc_ah; struct ath9k_tx_queue_info qi; - ath9k_hw_get_txq_props(ah, sc->sc_bhalq, &qi); - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + ath9k_hw_get_txq_props(ah, sc->beacon.beaconq, &qi); + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { /* Always burst out beacon and CAB traffic. */ qi.tqi_aifs = 1; qi.tqi_cwmin = 0; qi.tqi_cwmax = 0; } else { /* Adhoc mode; important thing is to use 2x cwmin. */ - qi.tqi_aifs = sc->sc_beacon_qi.tqi_aifs; - qi.tqi_cwmin = 2*sc->sc_beacon_qi.tqi_cwmin; - qi.tqi_cwmax = sc->sc_beacon_qi.tqi_cwmax; + qi.tqi_aifs = sc->beacon.beacon_qi.tqi_aifs; + qi.tqi_cwmin = 2*sc->beacon.beacon_qi.tqi_cwmin; + qi.tqi_cwmax = sc->beacon.beacon_qi.tqi_cwmax; } - if (!ath9k_hw_set_txq_props(ah, sc->sc_bhalq, &qi)) { + if (!ath9k_hw_set_txq_props(ah, sc->beacon.beaconq, &qi)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to update h/w beacon queue parameters\n", - __func__); + "unable to update h/w beacon queue parameters\n"); return 0; } else { - ath9k_hw_resettxqueue(ah, sc->sc_bhalq); /* push to h/w */ + ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); /* push to h/w */ return 1; } } +static void ath_bstuck_process(struct ath_softc *sc) +{ + DPRINTF(sc, ATH_DBG_BEACON, + "stuck beacon; resetting (bmiss count %u)\n", + sc->beacon.bmisscnt); + ath_reset(sc, false); +} + /* - * Setup the beacon frame for transmit. - * * Associates the beacon frame buffer with a transmit descriptor. Will set * up all required antenna switch parameters, rate codes, and channel flags. * Beacons are always sent out at the lowest rate, and are not retried. @@ -68,21 +69,20 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_hal *ah = sc->sc_ah; struct ath_desc *ds; struct ath9k_11n_rate_series series[4]; - const struct ath9k_rate_table *rt; + struct ath_rate_table *rt; int flags, antenna; u8 rix, rate; int ctsrate = 0; int ctsduration = 0; - DPRINTF(sc, ATH_DBG_BEACON, "%s: m %p len %u\n", - __func__, skb, skb->len); + DPRINTF(sc, ATH_DBG_BEACON, "m %p len %u\n", skb, skb->len); /* setup descriptors */ ds = bf->bf_desc; flags = ATH9K_TXDESC_NOACK; - if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { ds->ds_link = bf->bf_daddr; /* self-linked */ flags |= ATH9K_TXDESC_VEOL; @@ -96,7 +96,7 @@ static void ath_beacon_setup(struct ath_softc *sc, * SWBA's * XXX assumes two antenna */ - antenna = ((sc->ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1); + antenna = ((sc->beacon.ast_be_xmit / sc->sc_nbcnvaps) & 1 ? 2 : 1); } ds->ds_data = bf->bf_buf_addr; @@ -106,15 +106,15 @@ static void ath_beacon_setup(struct ath_softc *sc, * XXX everything at min xmit rate */ rix = 0; - rt = sc->sc_currates; - rate = rt->info[rix].rateCode; + rt = sc->cur_rate_table; + rate = rt->info[rix].ratecode; if (sc->sc_flags & SC_OP_PREAMBLE_SHORT) - rate |= rt->info[rix].shortPreamble; + rate |= rt->info[rix].short_preamble; ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN, /* frame length */ ATH9K_PKT_TYPE_BEACON, /* Atheros packet type */ - avp->av_btxctl.txpower, /* txpower XXX */ + MAX_RATE_POWER, /* FIXME */ ATH9K_TXKEYIX_INVALID, /* no encryption */ ATH9K_KEY_TYPE_CLEAR, /* no encryption */ flags /* no ack, @@ -138,31 +138,26 @@ static void ath_beacon_setup(struct ath_softc *sc, ctsrate, ctsduration, series, 4, 0); } -/* - * Generate beacon frame and queue cab data for a vap. - * - * Updates the contents of the beacon frame. It is assumed that the buffer for - * the beacon frame has been allocated in the ATH object, and simply needs to - * be filled for this cycle. Also, any CAB (crap after beacon?) traffic will - * be added to the beacon frame at this point. -*/ +/* Generate beacon frame and queue cab data for a vap */ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) { struct ath_buf *bf; struct ath_vap *avp; struct sk_buff *skb; struct ath_txq *cabq; + struct ieee80211_vif *vif; struct ieee80211_tx_info *info; int cabq_depth; - avp = sc->sc_vaps[if_id]; - ASSERT(avp); + vif = sc->sc_vaps[if_id]; + ASSERT(vif); - cabq = sc->sc_cabq; + avp = (void *)vif->drv_priv; + cabq = sc->beacon.cabq; if (avp->av_bcbuf == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n", - __func__, avp, avp->av_bcbuf); + DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n", + avp, avp->av_bcbuf); return NULL; } @@ -172,9 +167,10 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) pci_unmap_single(sc->pdev, bf->bf_dmacontext, skb->len, PCI_DMA_TODEVICE); + dev_kfree_skb_any(skb); } - skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); + skb = ieee80211_beacon_get(sc->hw, vif); bf->bf_mpdu = skb; if (skb == NULL) return NULL; @@ -186,17 +182,24 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) * TX frames) */ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - sc->seq_no += 0x10; + sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } bf->bf_buf_addr = bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on beaconing\n"); + return NULL; + } - skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); + skb = ieee80211_get_buffered_bc(sc->hw, vif); /* * if the CABQ traffic from previous DTIM is pending and the current @@ -219,7 +222,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) if (sc->sc_nvaps > 1) { ath_tx_draintxq(sc, cabq, false); DPRINTF(sc, ATH_DBG_BEACON, - "%s: flush previous cabq traffic\n", __func__); + "flush previous cabq traffic\n"); } } @@ -232,7 +235,7 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) */ while (skb) { ath_tx_cabq(sc, skb); - skb = ieee80211_get_buffered_bc(sc->hw, avp->av_if_data); + skb = ieee80211_get_buffered_bc(sc->hw, vif); } return bf; @@ -244,17 +247,20 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id) */ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) { + struct ieee80211_vif *vif; struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; struct ath_vap *avp; struct sk_buff *skb; - avp = sc->sc_vaps[if_id]; - ASSERT(avp); + vif = sc->sc_vaps[if_id]; + ASSERT(vif); + + avp = (void *)vif->drv_priv; if (avp->av_bcbuf == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "%s: avp=%p av_bcbuf=%p\n", - __func__, avp, avp != NULL ? avp->av_bcbuf : NULL); + DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n", + avp, avp != NULL ? avp->av_bcbuf : NULL); return; } bf = avp->av_bcbuf; @@ -264,20 +270,12 @@ static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id) ath_beacon_setup(sc, avp, bf); /* NB: caller is known to have already stopped tx dma */ - ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bf->bf_daddr); - ath9k_hw_txstart(ah, sc->sc_bhalq); - DPRINTF(sc, ATH_DBG_BEACON, "%s: TXDP%u = %llx (%p)\n", __func__, - sc->sc_bhalq, ito64(bf->bf_daddr), bf->bf_desc); + ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bf->bf_daddr); + ath9k_hw_txstart(ah, sc->beacon.beaconq); + DPRINTF(sc, ATH_DBG_BEACON, "TXDP%u = %llx (%p)\n", + sc->beacon.beaconq, ito64(bf->bf_daddr), bf->bf_desc); } -/* - * Setup a h/w transmit queue for beacons. - * - * This function allocates an information structure (struct ath9k_txq_info) - * on the stack, sets some specific parameters (zero out channel width - * min/max, and enable aifs). The info structure does not need to be - * persistant. -*/ int ath_beaconq_setup(struct ath_hal *ah) { struct ath9k_tx_queue_info qi; @@ -290,35 +288,29 @@ int ath_beaconq_setup(struct ath_hal *ah) return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi); } - -/* - * Allocate and setup an initial beacon frame. - * - * Allocate a beacon state variable for a specific VAP instance created on - * the ATH interface. This routine also calculates the beacon "slot" for - * staggared beacons in the mBSSID case. -*/ int ath_beacon_alloc(struct ath_softc *sc, int if_id) { + struct ieee80211_vif *vif; struct ath_vap *avp; struct ieee80211_hdr *hdr; struct ath_buf *bf; struct sk_buff *skb; __le64 tstamp; - avp = sc->sc_vaps[if_id]; - ASSERT(avp); + vif = sc->sc_vaps[if_id]; + ASSERT(vif); + + avp = (void *)vif->drv_priv; /* Allocate a beacon descriptor if we haven't done so. */ if (!avp->av_bcbuf) { /* Allocate beacon state for hostap/ibss. We know * a buffer is available. */ - - avp->av_bcbuf = list_first_entry(&sc->sc_bbuf, + avp->av_bcbuf = list_first_entry(&sc->beacon.bbuf, struct ath_buf, list); list_del(&avp->av_bcbuf->list); - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || !(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) { int slot; /* @@ -327,13 +319,13 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) */ avp->av_bslot = 0; for (slot = 0; slot < ATH_BCBUF; slot++) - if (sc->sc_bslot[slot] == ATH_IF_ID_ANY) { + if (sc->beacon.bslot[slot] == ATH_IF_ID_ANY) { /* * XXX hack, space out slots to better * deal with misses */ if (slot+1 < ATH_BCBUF && - sc->sc_bslot[slot+1] == + sc->beacon.bslot[slot+1] == ATH_IF_ID_ANY) { avp->av_bslot = slot+1; break; @@ -341,8 +333,8 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) avp->av_bslot = slot; /* NB: keep looking for a double slot */ } - BUG_ON(sc->sc_bslot[avp->av_bslot] != ATH_IF_ID_ANY); - sc->sc_bslot[avp->av_bslot] = if_id; + BUG_ON(sc->beacon.bslot[avp->av_bslot] != ATH_IF_ID_ANY); + sc->beacon.bslot[avp->av_bslot] = if_id; sc->sc_nbcnvaps++; } } @@ -363,15 +355,14 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) * FIXME: Fill avp->av_btxctl.txpower and * avp->av_btxctl.shortPreamble */ - skb = ieee80211_beacon_get(sc->hw, avp->av_if_data); + skb = ieee80211_beacon_get(sc->hw, vif); if (skb == NULL) { - DPRINTF(sc, ATH_DBG_BEACON, "%s: cannot get skb\n", - __func__); + DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n"); return -ENOMEM; } tstamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp; - sc->bc_tstamp = le64_to_cpu(tstamp); + sc->beacon.bc_tstamp = le64_to_cpu(tstamp); /* * Calculate a TSF adjustment factor required for @@ -402,36 +393,36 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id) val = cpu_to_le64(tsfadjust << 10); /* TU->TSF */ DPRINTF(sc, ATH_DBG_BEACON, - "%s: %s beacons, bslot %d intval %u tsfadjust %llu\n", - __func__, "stagger", + "stagger beacons, bslot %d intval %u tsfadjust %llu\n", avp->av_bslot, intval, (unsigned long long)tsfadjust); hdr = (struct ieee80211_hdr *)skb->data; memcpy(&hdr[1], &val, sizeof(val)); } + bf->bf_mpdu = skb; bf->bf_buf_addr = bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); - bf->bf_mpdu = skb; + if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on beacon alloc\n"); + return -ENOMEM; + } return 0; } -/* - * Reclaim beacon resources and return buffer to the pool. - * - * Checks the VAP to put the beacon frame buffer back to the ATH object - * queue, and de-allocates any skbs that were sent as CAB traffic. -*/ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) { if (avp->av_bcbuf != NULL) { struct ath_buf *bf; if (avp->av_bslot != -1) { - sc->sc_bslot[avp->av_bslot] = ATH_IF_ID_ANY; + sc->beacon.bslot[avp->av_bslot] = ATH_IF_ID_ANY; sc->sc_nbcnvaps--; } @@ -444,19 +435,12 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp) dev_kfree_skb_any(skb); bf->bf_mpdu = NULL; } - list_add_tail(&bf->list, &sc->sc_bbuf); + list_add_tail(&bf->list, &sc->beacon.bbuf); avp->av_bcbuf = NULL; } } -/* - * Tasklet for Sending Beacons - * - * Transmit one or more beacon frames at SWBA. Dynamic updates to the frame - * contents are done as needed and the slot time is also adjusted based on - * current state. -*/ void ath9k_beacon_tasklet(unsigned long data) { struct ath_softc *sc = (struct ath_softc *)data; @@ -473,9 +457,7 @@ void ath9k_beacon_tasklet(unsigned long data) if (sc->sc_flags & SC_OP_NO_RESET) { show_cycles = ath9k_hw_GetMibCycleCountsPct(ah, - &rx_clear, - &rx_frame, - &tx_frame); + &rx_clear, &rx_frame, &tx_frame); } /* @@ -487,67 +469,65 @@ void ath9k_beacon_tasklet(unsigned long data) * * FIXME: Clean up this mess !! */ - if (ath9k_hw_numtxpending(ah, sc->sc_bhalq) != 0) { - sc->sc_bmisscount++; + if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) { + sc->beacon.bmisscnt++; /* XXX: doth needs the chanchange IE countdown decremented. * We should consider adding a mac80211 call to indicate * a beacon miss so appropriate action could be taken * (in that layer). */ - if (sc->sc_bmisscount < BSTUCK_THRESH) { + if (sc->beacon.bmisscnt < BSTUCK_THRESH) { if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, - "%s: missed %u consecutive beacons\n", - __func__, sc->sc_bmisscount); + "missed %u consecutive beacons\n", + sc->beacon.bmisscnt); if (show_cycles) { /* * Display cycle counter stats from HW * to aide in debug of stickiness. */ DPRINTF(sc, ATH_DBG_BEACON, - "%s: busy times: rx_clear=%d, " + "busy times: rx_clear=%d, " "rx_frame=%d, tx_frame=%d\n", - __func__, rx_clear, rx_frame, + rx_clear, rx_frame, tx_frame); } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: unable to obtain " - "busy times\n", __func__); + "unable to obtain " + "busy times\n"); } } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: missed %u consecutive beacons\n", - __func__, sc->sc_bmisscount); + "missed %u consecutive beacons\n", + sc->beacon.bmisscnt); } - } else if (sc->sc_bmisscount >= BSTUCK_THRESH) { + } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) { if (sc->sc_flags & SC_OP_NO_RESET) { - if (sc->sc_bmisscount == BSTUCK_THRESH) { + if (sc->beacon.bmisscnt == BSTUCK_THRESH) { DPRINTF(sc, ATH_DBG_BEACON, - "%s: beacon is officially " - "stuck\n", __func__); - ath9k_hw_dmaRegDump(ah); + "beacon is officially " + "stuck\n"); } } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: beacon is officially stuck\n", - __func__); + "beacon is officially stuck\n"); ath_bstuck_process(sc); } } return; } - if (sc->sc_bmisscount != 0) { + if (sc->beacon.bmisscnt != 0) { if (sc->sc_flags & SC_OP_NO_RESET) { DPRINTF(sc, ATH_DBG_BEACON, - "%s: resume beacon xmit after %u misses\n", - __func__, sc->sc_bmisscount); + "resume beacon xmit after %u misses\n", + sc->beacon.bmisscnt); } else { DPRINTF(sc, ATH_DBG_BEACON, - "%s: resume beacon xmit after %u misses\n", - __func__, sc->sc_bmisscount); + "resume beacon xmit after %u misses\n", + sc->beacon.bmisscnt); } - sc->sc_bmisscount = 0; + sc->beacon.bmisscnt = 0; } /* @@ -562,11 +542,11 @@ void ath9k_beacon_tasklet(unsigned long data) tsf = ath9k_hw_gettsf64(ah); tsftu = TSF_TO_TU(tsf>>32, tsf); slot = ((tsftu % intval) * ATH_BCBUF) / intval; - if_id = sc->sc_bslot[(slot + 1) % ATH_BCBUF]; + if_id = sc->beacon.bslot[(slot + 1) % ATH_BCBUF]; DPRINTF(sc, ATH_DBG_BEACON, - "%s: slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", - __func__, slot, (unsigned long long)tsf, tsftu, + "slot %d [tsf %llu tsftu %u intval %u] if_id %d\n", + slot, (unsigned long long)tsf, tsftu, intval, if_id); bfaddr = 0; @@ -594,47 +574,33 @@ void ath9k_beacon_tasklet(unsigned long data) * set to ATH_BCBUF so this check is a noop. */ /* XXX locking */ - if (sc->sc_updateslot == UPDATE) { - sc->sc_updateslot = COMMIT; /* commit next beacon */ - sc->sc_slotupdate = slot; - } else if (sc->sc_updateslot == COMMIT && sc->sc_slotupdate == slot) - ath_setslottime(sc); /* commit change to hardware */ - + if (sc->beacon.updateslot == UPDATE) { + sc->beacon.updateslot = COMMIT; /* commit next beacon */ + sc->beacon.slotupdate = slot; + } else if (sc->beacon.updateslot == COMMIT && sc->beacon.slotupdate == slot) { + ath9k_hw_setslottime(sc->sc_ah, sc->beacon.slottime); + sc->beacon.updateslot = OK; + } if (bfaddr != 0) { /* * Stop any current dma and put the new frame(s) on the queue. * This should never fail since we check above that no frames * are still pending on the queue. */ - if (!ath9k_hw_stoptxdma(ah, sc->sc_bhalq)) { + if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: beacon queue %u did not stop?\n", - __func__, sc->sc_bhalq); + "beacon queue %u did not stop?\n", sc->beacon.beaconq); /* NB: the HAL still stops DMA, so proceed */ } /* NB: cabq traffic should already be queued and primed */ - ath9k_hw_puttxbuf(ah, sc->sc_bhalq, bfaddr); - ath9k_hw_txstart(ah, sc->sc_bhalq); + ath9k_hw_puttxbuf(ah, sc->beacon.beaconq, bfaddr); + ath9k_hw_txstart(ah, sc->beacon.beaconq); - sc->ast_be_xmit += bc; /* XXX per-vap? */ + sc->beacon.ast_be_xmit += bc; /* XXX per-vap? */ } } -/* - * Tasklet for Beacon Stuck processing - * - * Processing for Beacon Stuck. - * Basically resets the chip. -*/ -void ath_bstuck_process(struct ath_softc *sc) -{ - DPRINTF(sc, ATH_DBG_BEACON, - "%s: stuck beacon; resetting (bmiss count %u)\n", - __func__, sc->sc_bmisscount); - ath_reset(sc, false); -} - /* * Configure the beacon and sleep timers. * @@ -652,15 +618,21 @@ void ath_bstuck_process(struct ath_softc *sc) */ void ath_beacon_config(struct ath_softc *sc, int if_id) { + struct ieee80211_vif *vif; struct ath_hal *ah = sc->sc_ah; struct ath_beacon_config conf; - enum ath9k_opmode av_opmode; + struct ath_vap *avp; + enum nl80211_iftype opmode; u32 nexttbtt, intval; - if (if_id != ATH_IF_ID_ANY) - av_opmode = sc->sc_vaps[if_id]->av_opmode; - else - av_opmode = sc->sc_ah->ah_opmode; + if (if_id != ATH_IF_ID_ANY) { + vif = sc->sc_vaps[if_id]; + ASSERT(vif); + avp = (void *)vif->drv_priv; + opmode = avp->av_opmode; + } else { + opmode = sc->sc_ah->ah_opmode; + } memset(&conf, 0, sizeof(struct ath_beacon_config)); @@ -672,10 +644,10 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval; /* extract tstamp from last beacon and convert to TU */ - nexttbtt = TSF_TO_TU(sc->bc_tstamp >> 32, sc->bc_tstamp); + nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp); /* XXX conditionalize multi-bss support? */ - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { /* * For multi-bss ap support beacons are either staggered * evenly over N slots or burst together. For the former @@ -694,11 +666,11 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) else if (intval) /* NB: can be 0 for monitor mode */ nexttbtt = roundup(nexttbtt, intval); - DPRINTF(sc, ATH_DBG_BEACON, "%s: nexttbtt %u intval %u (%u)\n", - __func__, nexttbtt, intval, conf.beacon_interval); + DPRINTF(sc, ATH_DBG_BEACON, "nexttbtt %u intval %u (%u)\n", + nexttbtt, intval, conf.beacon_interval); - /* Check for ATH9K_M_HOSTAP and sc_nostabeacons for WDS client */ - if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { + /* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */ + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) { struct ath9k_beacon_state bs; u64 tsf; u32 tsftu; @@ -782,7 +754,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) bs.bs_sleepduration = bs.bs_dtimperiod; DPRINTF(sc, ATH_DBG_BEACON, - "%s: tsf %llu " + "tsf %llu " "tsf:tu %u " "intval %u " "nexttbtt %u " @@ -794,7 +766,6 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) "maxdur %u " "next %u " "timoffset %u\n", - __func__, (unsigned long long)tsf, tsftu, bs.bs_intval, bs.bs_nexttbtt, @@ -818,7 +789,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) ath9k_hw_set_interrupts(ah, 0); if (nexttbtt == intval) intval |= ATH9K_BEACON_RESET_TSF; - if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { /* * Pull nexttbtt forward to reflect the current * TSF @@ -834,8 +805,8 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) } #undef FUDGE DPRINTF(sc, ATH_DBG_BEACON, - "%s: IBSS nexttbtt %u intval %u (%u)\n", - __func__, nexttbtt, + "IBSS nexttbtt %u intval %u (%u)\n", + nexttbtt, intval & ~ATH9K_BEACON_RESET_TSF, conf.beacon_interval); @@ -850,7 +821,7 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) if (!(ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) sc->sc_imask |= ATH9K_INT_SWBA; ath_beaconq_config(sc); - } else if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) { + } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { /* * In AP mode we enable the beacon timers and * SWBA interrupts to prepare beacon frames. @@ -860,20 +831,18 @@ void ath_beacon_config(struct ath_softc *sc, int if_id) ath_beaconq_config(sc); } ath9k_hw_beaconinit(ah, nexttbtt, intval); - sc->sc_bmisscount = 0; + sc->beacon.bmisscnt = 0; ath9k_hw_set_interrupts(ah, sc->sc_imask); /* * When using a self-linked beacon descriptor in * ibss mode load it once here. */ - if (sc->sc_ah->ah_opmode == ATH9K_M_IBSS && + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC && (ah->ah_caps.hw_caps & ATH9K_HW_CAP_VEOL)) ath_beacon_start_adhoc(sc, 0); } } -/* Function to collect beacon rssi data and resync beacon if necessary */ - void ath_beacon_sync(struct ath_softc *sc, int if_id) { /* diff --git a/drivers/net/wireless/ath9k/calib.c b/drivers/net/wireless/ath9k/calib.c new file mode 100644 index 0000000000000000000000000000000000000000..3c7454fc51bdf0f24f1c70475352c85443236818 --- /dev/null +++ b/drivers/net/wireless/ath9k/calib.c @@ -0,0 +1,1021 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; + +/* We can tune this as we go by monitoring really low values */ +#define ATH9K_NF_TOO_LOW -60 + +/* AR5416 may return very high value (like -31 dBm), in those cases the nf + * is incorrect and we should use the static NF value. Later we can try to + * find out why they are reporting these values */ + +static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) +{ + if (nf > ATH9K_NF_TOO_LOW) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "noise floor value detected (%d) is " + "lower than what we think is a " + "reasonable value (%d)\n", + nf, ATH9K_NF_TOO_LOW); + return false; + } + return true; +} + +static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) +{ + int16_t nfval; + int16_t sort[ATH9K_NF_CAL_HIST_MAX]; + int i, j; + + for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) + sort[i] = nfCalBuffer[i]; + + for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { + for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { + if (sort[j] > sort[j - 1]) { + nfval = sort[j]; + sort[j] = sort[j - 1]; + sort[j - 1] = nfval; + } + } + } + nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; + + return nfval; +} + +static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, + int16_t *nfarray) +{ + int i; + + for (i = 0; i < NUM_NF_READINGS; i++) { + h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; + + if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) + h[i].currIndex = 0; + + if (h[i].invalidNFcount > 0) { + if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE || + nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { + h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; + } else { + h[i].invalidNFcount--; + h[i].privNF = nfarray[i]; + } + } else { + h[i].privNF = + ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); + } + } + return; +} + +static void ath9k_hw_do_getnf(struct ath_hal *ah, + int16_t nfarray[NUM_NF_READINGS]) +{ + int16_t nf; + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 0] is %d\n", nf); + nfarray[0] = nf; + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), + AR9280_PHY_CH1_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), + AR_PHY_CH1_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 1] is %d\n", nf); + nfarray[1] = nf; + + if (!AR_SREV_9280(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), + AR_PHY_CH2_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ctl] [chain 2] is %d\n", nf); + nfarray[2] = nf; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), + AR9280_PHY_EXT_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), + AR_PHY_EXT_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 0] is %d\n", nf); + nfarray[3] = nf; + + if (AR_SREV_9280_10_OR_LATER(ah)) + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), + AR9280_PHY_CH1_EXT_MINCCA_PWR); + else + nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), + AR_PHY_CH1_EXT_MINCCA_PWR); + + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 1] is %d\n", nf); + nfarray[4] = nf; + + if (!AR_SREV_9280(ah)) { + nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), + AR_PHY_CH2_EXT_MINCCA_PWR); + if (nf & 0x100) + nf = 0 - ((nf ^ 0x1ff) + 1); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF calibrated [ext] [chain 2] is %d\n", nf); + nfarray[5] = nf; + } +} + +static bool getNoiseFloorThresh(struct ath_hal *ah, + const struct ath9k_channel *chan, + int16_t *nft) +{ + switch (chan->chanmode) { + case CHANNEL_A: + case CHANNEL_A_HT20: + case CHANNEL_A_HT40PLUS: + case CHANNEL_A_HT40MINUS: + *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_5); + break; + case CHANNEL_B: + case CHANNEL_G: + case CHANNEL_G_HT20: + case CHANNEL_G_HT40PLUS: + case CHANNEL_G_HT40MINUS: + *nft = (int8_t)ath9k_hw_get_eeprom(ah, EEP_NFTHRESH_2); + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "invalid channel flags 0x%x\n", chan->channelFlags); + return false; + } + + return true; +} + +static void ath9k_hw_setup_calibration(struct ath_hal *ah, + struct hal_cal_list *currCal) +{ + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, + currCal->calData->calCountMax); + + switch (currCal->calData->calType) { + case IQ_MISMATCH_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting IQ Mismatch Calibration\n"); + break; + case ADC_GAIN_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting ADC Gain Calibration\n"); + break; + case ADC_DC_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting ADC DC Calibration\n"); + break; + case ADC_DC_INIT_CAL: + REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "starting Init ADC DC Calibration\n"); + break; + } + + REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_DO_CAL); +} + +static void ath9k_hw_reset_calibration(struct ath_hal *ah, + struct hal_cal_list *currCal) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + ath9k_hw_setup_calibration(ah, currCal); + + currCal->calState = CAL_RUNNING; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_Meas0.sign[i] = 0; + ahp->ah_Meas1.sign[i] = 0; + ahp->ah_Meas2.sign[i] = 0; + ahp->ah_Meas3.sign[i] = 0; + } + + ahp->ah_CalSamples = 0; +} + +static void ath9k_hw_per_calibration(struct ath_hal *ah, + struct ath9k_channel *ichan, + u8 rxchainmask, + struct hal_cal_list *currCal, + bool *isCalDone) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + *isCalDone = false; + + if (currCal->calState == CAL_RUNNING) { + if (!(REG_READ(ah, AR_PHY_TIMING_CTRL4(0)) & + AR_PHY_TIMING_CTRL4_DO_CAL)) { + + currCal->calData->calCollect(ah); + ahp->ah_CalSamples++; + + if (ahp->ah_CalSamples >= currCal->calData->calNumSamples) { + int i, numChains = 0; + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (rxchainmask & (1 << i)) + numChains++; + } + + currCal->calData->calPostProc(ah, numChains); + ichan->CalValid |= currCal->calData->calType; + currCal->calState = CAL_DONE; + *isCalDone = true; + } else { + ath9k_hw_setup_calibration(ah, currCal); + } + } + } else if (!(ichan->CalValid & currCal->calData->calType)) { + ath9k_hw_reset_calibration(ah, currCal); + } +} + +static bool ath9k_hw_iscal_supported(struct ath_hal *ah, + struct ath9k_channel *chan, + enum hal_cal_types calType) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + bool retval = false; + + switch (calType & ahp->ah_suppCals) { + case IQ_MISMATCH_CAL: + if (!IS_CHAN_B(chan)) + retval = true; + break; + case ADC_GAIN_CAL: + case ADC_DC_CAL: + if (!IS_CHAN_B(chan) + && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) + retval = true; + break; + } + + return retval; +} + +static void ath9k_hw_iqcal_collect(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_totalPowerMeasI[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ahp->ah_totalPowerMeasQ[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ahp->ah_totalIqCorrMeas[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", + ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i], + ahp->ah_totalPowerMeasQ[i], + ahp->ah_totalIqCorrMeas[i]); + } +} + +static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_totalAdcIOddPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ahp->ah_totalAdcIEvenPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ahp->ah_totalAdcQOddPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ahp->ah_totalAdcQEvenPhase[i] += + REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ahp->ah_CalSamples, i, + ahp->ah_totalAdcIOddPhase[i], + ahp->ah_totalAdcIEvenPhase[i], + ahp->ah_totalAdcQOddPhase[i], + ahp->ah_totalAdcQEvenPhase[i]); + } +} + +static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + int i; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + ahp->ah_totalAdcDcOffsetIOddPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); + ahp->ah_totalAdcDcOffsetIEvenPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); + ahp->ah_totalAdcDcOffsetQOddPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); + ahp->ah_totalAdcDcOffsetQEvenPhase[i] += + (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " + "oddq=0x%08x; evenq=0x%08x;\n", + ahp->ah_CalSamples, i, + ahp->ah_totalAdcDcOffsetIOddPhase[i], + ahp->ah_totalAdcDcOffsetIEvenPhase[i], + ahp->ah_totalAdcDcOffsetQOddPhase[i], + ahp->ah_totalAdcDcOffsetQEvenPhase[i]); + } +} + +static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 powerMeasQ, powerMeasI, iqCorrMeas; + u32 qCoffDenom, iCoffDenom; + int32_t qCoff, iCoff; + int iqCorrNeg, i; + + for (i = 0; i < numChains; i++) { + powerMeasI = ahp->ah_totalPowerMeasI[i]; + powerMeasQ = ahp->ah_totalPowerMeasQ[i]; + iqCorrMeas = ahp->ah_totalIqCorrMeas[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting IQ Cal and Correction for Chain %d\n", + i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Orignal: Chn %diq_corr_meas = 0x%08x\n", + i, ahp->ah_totalIqCorrMeas[i]); + + iqCorrNeg = 0; + + if (iqCorrMeas > 0x80000000) { + iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; + iqCorrNeg = 1; + } + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", + iqCorrNeg); + + iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; + qCoffDenom = powerMeasQ / 64; + + if (powerMeasQ != 0) { + iCoff = iqCorrMeas / iCoffDenom; + qCoff = powerMeasI / qCoffDenom - 64; + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d iCoff = 0x%08x\n", i, iCoff); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d qCoff = 0x%08x\n", i, qCoff); + + iCoff = iCoff & 0x3f; + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "New: Chn %d iCoff = 0x%08x\n", i, iCoff); + if (iqCorrNeg == 0x0) + iCoff = 0x40 - iCoff; + + if (qCoff > 15) + qCoff = 15; + else if (qCoff <= -16) + qCoff = 16; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", + i, iCoff, qCoff); + + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, + iCoff); + REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, + qCoff); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "IQ Cal and Correction done for Chain %d\n", + i); + } + } + + REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), + AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); +} + +static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, qEvenMeasOffset; + u32 qGainMismatch, iGainMismatch, val, i; + + for (i = 0; i < numChains; i++) { + iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i]; + iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i]; + qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i]; + qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting ADC Gain Cal for Chain %d\n", i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = 0x%08x\n", i, + iOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = 0x%08x\n", i, + iEvenMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = 0x%08x\n", i, + qOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = 0x%08x\n", i, + qEvenMeasOffset); + + if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { + iGainMismatch = + ((iEvenMeasOffset * 32) / + iOddMeasOffset) & 0x3f; + qGainMismatch = + ((qOddMeasOffset * 32) / + qEvenMeasOffset) & 0x3f; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_i = 0x%08x\n", i, + iGainMismatch); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d gain_mismatch_q = 0x%08x\n", i, + qGainMismatch); + + val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xfffff000; + val |= (qGainMismatch) | (iGainMismatch << 6); + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "ADC Gain Cal done for Chain %d\n", i); + } + } + + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | + AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); +} + +static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 iOddMeasOffset, iEvenMeasOffset, val, i; + int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; + const struct hal_percal_data *calData = + ahp->ah_cal_list_curr->calData; + u32 numSamples = + (1 << (calData->calCountMax + 5)) * calData->calNumSamples; + + for (i = 0; i < numChains; i++) { + iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i]; + iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i]; + qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i]; + qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i]; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Starting ADC DC Offset Cal for Chain %d\n", i); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_i = %d\n", i, + iOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_i = %d\n", i, + iEvenMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_odd_q = %d\n", i, + qOddMeasOffset); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d pwr_meas_even_q = %d\n", i, + qEvenMeasOffset); + + iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / + numSamples) & 0x1ff; + qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / + numSamples) & 0x1ff; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, + iDcMismatch); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, + qDcMismatch); + + val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); + val &= 0xc0000fff; + val |= (qDcMismatch << 12) | (iDcMismatch << 21); + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "ADC DC Offset Cal done for Chain %d\n", i); + } + + REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), + REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | + AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); +} + +void ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, + bool *isCalDone) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *ichan = + ath9k_regd_check_channel(ah, chan); + struct hal_cal_list *currCal = ahp->ah_cal_list_curr; + + *isCalDone = true; + + if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) + return; + + if (currCal == NULL) + return; + + if (ichan == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); + return; + } + + + if (currCal->calState != CAL_DONE) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Calibration state incorrect, %d\n", + currCal->calState); + return; + } + + + if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType)) + return; + + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "Resetting Cal %d state for channel %u/0x%x\n", + currCal->calData->calType, chan->channel, + chan->channelFlags); + + ichan->CalValid &= ~currCal->calData->calType; + currCal->calState = CAL_WAITING; + + *isCalDone = false; +} + +void ath9k_hw_start_nfcal(struct ath_hal *ah) +{ + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_ENABLE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); +} + +void ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) +{ + struct ath9k_nfcal_hist *h; + int i, j; + int32_t val; + const u32 ar5416_cca_regs[6] = { + AR_PHY_CCA, + AR_PHY_CH1_CCA, + AR_PHY_CH2_CCA, + AR_PHY_EXT_CCA, + AR_PHY_CH1_EXT_CCA, + AR_PHY_CH2_EXT_CCA + }; + u8 chainmask; + + if (AR_SREV_9280(ah)) + chainmask = 0x1B; + else + chainmask = 0x3F; + +#ifdef ATH_NF_PER_CHAN + h = chan->nfCalHist; +#else + h = ah->nfCalHist; +#endif + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (h[i].privNF) << 1) & 0x1ff); + REG_WRITE(ah, ar5416_cca_regs[i], val); + } + } + + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_ENABLE_NF); + REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, + AR_PHY_AGC_CONTROL_NO_UPDATE_NF); + REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); + + for (j = 0; j < 1000; j++) { + if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & + AR_PHY_AGC_CONTROL_NF) == 0) + break; + udelay(10); + } + + for (i = 0; i < NUM_NF_READINGS; i++) { + if (chainmask & (1 << i)) { + val = REG_READ(ah, ar5416_cca_regs[i]); + val &= 0xFFFFFE00; + val |= (((u32) (-50) << 1) & 0x1ff); + REG_WRITE(ah, ar5416_cca_regs[i], val); + } + } +} + +int16_t ath9k_hw_getnf(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + int16_t nf, nfThresh; + int16_t nfarray[NUM_NF_READINGS] = { 0 }; + struct ath9k_nfcal_hist *h; + u8 chainmask; + + if (AR_SREV_9280(ah)) + chainmask = 0x1B; + else + chainmask = 0x3F; + + chan->channelFlags &= (~CHANNEL_CW_INT); + if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "NF did not complete in calibration window\n"); + nf = 0; + chan->rawNoiseFloor = nf; + return chan->rawNoiseFloor; + } else { + ath9k_hw_do_getnf(ah, nfarray); + nf = nfarray[0]; + if (getNoiseFloorThresh(ah, chan, &nfThresh) + && nf > nfThresh) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "noise floor failed detected; " + "detected %d, threshold %d\n", + nf, nfThresh); + chan->channelFlags |= CHANNEL_CW_INT; + } + } + +#ifdef ATH_NF_PER_CHAN + h = chan->nfCalHist; +#else + h = ah->nfCalHist; +#endif + + ath9k_hw_update_nfcal_hist_buffer(h, nfarray); + chan->rawNoiseFloor = h[0].privNF; + + return chan->rawNoiseFloor; +} + +void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah) +{ + int i, j; + + for (i = 0; i < NUM_NF_READINGS; i++) { + ah->nfCalHist[i].currIndex = 0; + ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; + ah->nfCalHist[i].invalidNFcount = + AR_PHY_CCA_FILTERWINDOW_LENGTH; + for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { + ah->nfCalHist[i].nfCalBuffer[j] = + AR_PHY_CCA_MAX_GOOD_VALUE; + } + } + return; +} + +s16 ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) +{ + struct ath9k_channel *ichan; + s16 nf; + + ichan = ath9k_regd_check_channel(ah, chan); + if (ichan == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); + return ATH_DEFAULT_NOISE_FLOOR; + } + if (ichan->rawNoiseFloor == 0) { + enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); + nf = NOISE_FLOOR[mode]; + } else + nf = ichan->rawNoiseFloor; + + if (!ath9k_hw_nf_in_range(ah, nf)) + nf = ATH_DEFAULT_NOISE_FLOOR; + + return nf; +} + +bool ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, + u8 rxchainmask, bool longcal, + bool *isCalDone) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct hal_cal_list *currCal = ahp->ah_cal_list_curr; + struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); + + *isCalDone = true; + + if (ichan == NULL) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); + return false; + } + + if (currCal && + (currCal->calState == CAL_RUNNING || + currCal->calState == CAL_WAITING)) { + ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal, + isCalDone); + if (*isCalDone) { + ahp->ah_cal_list_curr = currCal = currCal->calNext; + + if (currCal->calState == CAL_WAITING) { + *isCalDone = false; + ath9k_hw_reset_calibration(ah, currCal); + } + } + } + + if (longcal) { + ath9k_hw_getnf(ah, ichan); + ath9k_hw_loadnf(ah, ah->ah_curchan); + ath9k_hw_start_nfcal(ah); + + if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { + chan->channelFlags |= CHANNEL_CW_INT; + ichan->channelFlags &= ~CHANNEL_CW_INT; + } + } + + return true; +} + +static inline void ath9k_hw_9285_pa_cal(struct ath_hal *ah) +{ + + u32 regVal; + int i, offset, offs_6_1, offs_0; + u32 ccomp_org, reg_field; + u32 regList[][2] = { + { 0x786c, 0 }, + { 0x7854, 0 }, + { 0x7820, 0 }, + { 0x7824, 0 }, + { 0x7868, 0 }, + { 0x783c, 0 }, + { 0x7838, 0 }, + }; + + if (AR_SREV_9285_11(ah)) { + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); + udelay(10); + } + + for (i = 0; i < ARRAY_SIZE(regList); i++) + regList[i][1] = REG_READ(ah, regList[i][0]); + + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1)); + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal |= (0x1 << 27); + REG_WRITE(ah, 0x9808, regVal); + + REG_RMW_FIELD(ah, AR9285_AN_TOP3, AR9285_AN_TOP3_PWDDAC, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDRXTXBB1, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDV2I, 1); + REG_RMW_FIELD(ah, AR9285_AN_RXTXBB1, AR9285_AN_RXTXBB1_PDDACIF, 1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G2, AR9285_AN_RF2G2_OFFCAL, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PWDDB, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_ENPACAL, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV1, 1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPADRV2, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G1, AR9285_AN_RF2G1_PDPAOUT, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G8, AR9285_AN_RF2G8_PADRVGN2TAB0, 7); + REG_RMW_FIELD(ah, AR9285_AN_RF2G7, AR9285_AN_RF2G7_PADRVGN2TAB0, 0); + ccomp_org = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_CCOMP); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, 7); + + REG_WRITE(ah, AR9285_AN_TOP2, 0xca0358a0); + udelay(30); + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, 0); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 0); + + for (i = 6; i > 0; i--) { + regVal = REG_READ(ah, 0x7834); + regVal |= (1 << (19 + i)); + REG_WRITE(ah, 0x7834, regVal); + udelay(1); + regVal = REG_READ(ah, 0x7834); + regVal &= (~(0x1 << (19 + i))); + reg_field = MS(REG_READ(ah, 0x7840), AR9285_AN_RXTXBB1_SPARE9); + regVal |= (reg_field << (19 + i)); + REG_WRITE(ah, 0x7834, regVal); + } + + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, 1); + udelay(1); + reg_field = MS(REG_READ(ah, AR9285_AN_RF2G9), AR9285_AN_RXTXBB1_SPARE9); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, reg_field); + offs_6_1 = MS(REG_READ(ah, AR9285_AN_RF2G6), AR9285_AN_RF2G6_OFFS); + offs_0 = MS(REG_READ(ah, AR9285_AN_RF2G3), AR9285_AN_RF2G3_PDVCCOMP); + + offset = (offs_6_1<<1) | offs_0; + offset = offset - 0; + offs_6_1 = offset>>1; + offs_0 = offset & 1; + + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_OFFS, offs_6_1); + REG_RMW_FIELD(ah, AR9285_AN_RF2G3, AR9285_AN_RF2G3_PDVCCOMP, offs_0); + + regVal = REG_READ(ah, 0x7834); + regVal |= 0x1; + REG_WRITE(ah, 0x7834, regVal); + regVal = REG_READ(ah, 0x9808); + regVal &= (~(0x1 << 27)); + REG_WRITE(ah, 0x9808, regVal); + + for (i = 0; i < ARRAY_SIZE(regList); i++) + REG_WRITE(ah, regList[i][0], regList[i][1]); + + REG_RMW_FIELD(ah, AR9285_AN_RF2G6, AR9285_AN_RF2G6_CCOMP, ccomp_org); + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + +} + +bool ath9k_hw_init_cal(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_channel *ichan = ath9k_regd_check_channel(ah, chan); + + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_CAL); + + if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "offset calibration failed to complete in 1ms; " + "noisy environment?\n"); + return false; + } + + if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah)) + ath9k_hw_9285_pa_cal(ah); + + REG_WRITE(ah, AR_PHY_AGC_CONTROL, + REG_READ(ah, AR_PHY_AGC_CONTROL) | + AR_PHY_AGC_CONTROL_NF); + + ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL; + + if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { + if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) { + INIT_CAL(&ahp->ah_adcGainCalData); + INSERT_CAL(ahp, &ahp->ah_adcGainCalData); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "enabling ADC Gain Calibration.\n"); + } + if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) { + INIT_CAL(&ahp->ah_adcDcCalData); + INSERT_CAL(ahp, &ahp->ah_adcDcCalData); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "enabling ADC DC Calibration.\n"); + } + if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) { + INIT_CAL(&ahp->ah_iqCalData); + INSERT_CAL(ahp, &ahp->ah_iqCalData); + DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, + "enabling IQ Calibration.\n"); + } + + ahp->ah_cal_list_curr = ahp->ah_cal_list; + + if (ahp->ah_cal_list_curr) + ath9k_hw_reset_calibration(ah, ahp->ah_cal_list_curr); + } + + ichan->CalValid = 0; + + return true; +} + +const struct hal_percal_data iq_cal_multi_sample = { + IQ_MISMATCH_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_iqcal_collect, + ath9k_hw_iqcalibrate +}; +const struct hal_percal_data iq_cal_single_sample = { + IQ_MISMATCH_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_iqcal_collect, + ath9k_hw_iqcalibrate +}; +const struct hal_percal_data adc_gain_cal_multi_sample = { + ADC_GAIN_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_adc_gaincal_collect, + ath9k_hw_adc_gaincal_calibrate +}; +const struct hal_percal_data adc_gain_cal_single_sample = { + ADC_GAIN_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_adc_gaincal_collect, + ath9k_hw_adc_gaincal_calibrate +}; +const struct hal_percal_data adc_dc_cal_multi_sample = { + ADC_DC_CAL, + MAX_CAL_SAMPLES, + PER_MIN_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; +const struct hal_percal_data adc_dc_cal_single_sample = { + ADC_DC_CAL, + MIN_CAL_SAMPLES, + PER_MAX_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; +const struct hal_percal_data adc_init_dc_cal = { + ADC_DC_INIT_CAL, + MIN_CAL_SAMPLES, + INIT_LOG_COUNT, + ath9k_hw_adc_dccal_collect, + ath9k_hw_adc_dccal_calibrate +}; diff --git a/drivers/net/wireless/ath9k/core.c b/drivers/net/wireless/ath9k/core.c deleted file mode 100644 index c5033f6f42acd3c6ddf4cf7d00835adf9c9b665e..0000000000000000000000000000000000000000 --- a/drivers/net/wireless/ath9k/core.c +++ /dev/null @@ -1,1886 +0,0 @@ -/* - * Copyright (c) 2008, Atheros Communications Inc. - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - - /* Implementation of the main "ATH" layer. */ - -#include "core.h" -#include "regd.h" - -static int ath_outdoor; /* enable outdoor use */ - -static u32 ath_chainmask_sel_up_rssi_thres = - ATH_CHAINMASK_SEL_UP_RSSI_THRES; -static u32 ath_chainmask_sel_down_rssi_thres = - ATH_CHAINMASK_SEL_DOWN_RSSI_THRES; -static u32 ath_chainmask_sel_period = - ATH_CHAINMASK_SEL_TIMEOUT; - -/* return bus cachesize in 4B word units */ - -static void bus_read_cachesize(struct ath_softc *sc, int *csz) -{ - u8 u8tmp; - - pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp); - *csz = (int)u8tmp; - - /* - * This check was put in to avoid "unplesant" consequences if - * the bootrom has not fully initialized all PCI devices. - * Sometimes the cache line size register is not set - */ - - if (*csz == 0) - *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ -} - -/* - * Set current operating mode - * - * This function initializes and fills the rate table in the ATH object based - * on the operating mode. -*/ -static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) -{ - const struct ath9k_rate_table *rt; - int i; - - memset(sc->sc_rixmap, 0xff, sizeof(sc->sc_rixmap)); - rt = ath9k_hw_getratetable(sc->sc_ah, mode); - BUG_ON(!rt); - - for (i = 0; i < rt->rateCount; i++) - sc->sc_rixmap[rt->info[i].rateCode] = (u8) i; - - memset(sc->sc_hwmap, 0, sizeof(sc->sc_hwmap)); - for (i = 0; i < 256; i++) { - u8 ix = rt->rateCodeToIndex[i]; - - if (ix == 0xff) - continue; - - sc->sc_hwmap[i].ieeerate = - rt->info[ix].dot11Rate & IEEE80211_RATE_VAL; - sc->sc_hwmap[i].rateKbps = rt->info[ix].rateKbps; - - if (rt->info[ix].shortPreamble || - rt->info[ix].phy == PHY_OFDM) { - /* XXX: Handle this */ - } - - /* NB: this uses the last entry if the rate isn't found */ - /* XXX beware of overlow */ - } - sc->sc_currates = rt; - sc->sc_curmode = mode; - /* - * All protection frames are transmited at 2Mb/s for - * 11g, otherwise at 1Mb/s. - * XXX select protection rate index from rate table. - */ - sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0); -} - -/* - * Set up rate table (legacy rates) - */ -static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) -{ - struct ath_hal *ah = sc->sc_ah; - const struct ath9k_rate_table *rt = NULL; - struct ieee80211_supported_band *sband; - struct ieee80211_rate *rate; - int i, maxrates; - - switch (band) { - case IEEE80211_BAND_2GHZ: - rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11G); - break; - case IEEE80211_BAND_5GHZ: - rt = ath9k_hw_getratetable(ah, ATH9K_MODE_11A); - break; - default: - break; - } - - if (rt == NULL) - return; - - sband = &sc->sbands[band]; - rate = sc->rates[band]; - - if (rt->rateCount > ATH_RATE_MAX) - maxrates = ATH_RATE_MAX; - else - maxrates = rt->rateCount; - - for (i = 0; i < maxrates; i++) { - rate[i].bitrate = rt->info[i].rateKbps / 100; - rate[i].hw_value = rt->info[i].rateCode; - sband->n_bitrates++; - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Rate: %2dMbps, ratecode: %2d\n", - __func__, - rate[i].bitrate / 10, - rate[i].hw_value); - } -} - -/* - * Set up channel list - */ -static int ath_setup_channels(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - int nchan, i, a = 0, b = 0; - u8 regclassids[ATH_REGCLASSIDS_MAX]; - u32 nregclass = 0; - struct ieee80211_supported_band *band_2ghz; - struct ieee80211_supported_band *band_5ghz; - struct ieee80211_channel *chan_2ghz; - struct ieee80211_channel *chan_5ghz; - struct ath9k_channel *c; - - /* Fill in ah->ah_channels */ - if (!ath9k_regd_init_channels(ah, - ATH_CHAN_MAX, - (u32 *)&nchan, - regclassids, - ATH_REGCLASSIDS_MAX, - &nregclass, - CTRY_DEFAULT, - false, - 1)) { - u32 rd = ah->ah_currentRD; - - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to collect channel list; " - "regdomain likely %u country code %u\n", - __func__, rd, CTRY_DEFAULT); - return -EINVAL; - } - - band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ]; - band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ]; - chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ]; - chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ]; - - for (i = 0; i < nchan; i++) { - c = &ah->ah_channels[i]; - if (IS_CHAN_2GHZ(c)) { - chan_2ghz[a].band = IEEE80211_BAND_2GHZ; - chan_2ghz[a].center_freq = c->channel; - chan_2ghz[a].max_power = c->maxTxPower; - - if (c->privFlags & CHANNEL_DISALLOW_ADHOC) - chan_2ghz[a].flags |= - IEEE80211_CHAN_NO_IBSS; - if (c->channelFlags & CHANNEL_PASSIVE) - chan_2ghz[a].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; - - band_2ghz->n_channels = ++a; - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: 2MHz channel: %d, " - "channelFlags: 0x%x\n", - __func__, - c->channel, - c->channelFlags); - } else if (IS_CHAN_5GHZ(c)) { - chan_5ghz[b].band = IEEE80211_BAND_5GHZ; - chan_5ghz[b].center_freq = c->channel; - chan_5ghz[b].max_power = c->maxTxPower; - - if (c->privFlags & CHANNEL_DISALLOW_ADHOC) - chan_5ghz[b].flags |= - IEEE80211_CHAN_NO_IBSS; - if (c->channelFlags & CHANNEL_PASSIVE) - chan_5ghz[b].flags |= - IEEE80211_CHAN_PASSIVE_SCAN; - - band_5ghz->n_channels = ++b; - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: 5MHz channel: %d, " - "channelFlags: 0x%x\n", - __func__, - c->channel, - c->channelFlags); - } - } - - return 0; -} - -/* - * Determine mode from channel flags - * - * This routine will provide the enumerated WIRELESSS_MODE value based - * on the settings of the channel flags. If no valid set of flags - * exist, the lowest mode (11b) is selected. -*/ - -static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) -{ - if (chan->chanmode == CHANNEL_A) - return ATH9K_MODE_11A; - else if (chan->chanmode == CHANNEL_G) - return ATH9K_MODE_11G; - else if (chan->chanmode == CHANNEL_B) - return ATH9K_MODE_11B; - else if (chan->chanmode == CHANNEL_A_HT20) - return ATH9K_MODE_11NA_HT20; - else if (chan->chanmode == CHANNEL_G_HT20) - return ATH9K_MODE_11NG_HT20; - else if (chan->chanmode == CHANNEL_A_HT40PLUS) - return ATH9K_MODE_11NA_HT40PLUS; - else if (chan->chanmode == CHANNEL_A_HT40MINUS) - return ATH9K_MODE_11NA_HT40MINUS; - else if (chan->chanmode == CHANNEL_G_HT40PLUS) - return ATH9K_MODE_11NG_HT40PLUS; - else if (chan->chanmode == CHANNEL_G_HT40MINUS) - return ATH9K_MODE_11NG_HT40MINUS; - - WARN_ON(1); /* should not get here */ - - return ATH9K_MODE_11B; -} - -/* - * Stop the device, grabbing the top-level lock to protect - * against concurrent entry through ath_init (which can happen - * if another thread does a system call and the thread doing the - * stop is preempted). - */ - -static int ath_stop(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: invalid %ld\n", - __func__, sc->sc_flags & SC_OP_INVALID); - - /* - * Shutdown the hardware and driver: - * stop output from above - * turn off timers - * disable interrupts - * clear transmit machinery - * clear receive machinery - * turn off the radio - * reclaim beacon resources - * - * Note that some of this work is not possible if the - * hardware is gone (invalid). - */ - - ath_draintxq(sc, false); - if (!(sc->sc_flags & SC_OP_INVALID)) { - ath_stoprecv(sc); - ath9k_hw_phy_disable(ah); - } else - sc->sc_rxlink = NULL; - - return 0; -} - -/* - * Set the current channel - * - * Set/change channels. If the channel is really being changed, it's done - * by reseting the chip. To accomplish this we must first cleanup any pending - * DMA, then restart stuff after a la ath_init. -*/ -int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) -{ - struct ath_hal *ah = sc->sc_ah; - bool fastcc = true, stopped; - - if (sc->sc_flags & SC_OP_INVALID) /* the device is invalid or removed */ - return -EIO; - - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: %u (%u MHz) -> %u (%u MHz), cflags:%x\n", - __func__, - ath9k_hw_mhz2ieee(ah, sc->sc_ah->ah_curchan->channel, - sc->sc_ah->ah_curchan->channelFlags), - sc->sc_ah->ah_curchan->channel, - ath9k_hw_mhz2ieee(ah, hchan->channel, hchan->channelFlags), - hchan->channel, hchan->channelFlags); - - if (hchan->channel != sc->sc_ah->ah_curchan->channel || - hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || - (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || - (sc->sc_flags & SC_OP_FULL_RESET)) { - int status; - /* - * This is only performed if the channel settings have - * actually changed. - * - * To switch channels clear any pending DMA operations; - * wait long enough for the RX fifo to drain, reset the - * hardware at the new frequency, and then re-enable - * the relevant bits of the h/w. - */ - ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, false); /* clear pending tx frames */ - stopped = ath_stoprecv(sc); /* turn off frame recv */ - - /* XXX: do not flush receive queue here. We don't want - * to flush data frames already in queue because of - * changing channel. */ - - if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) - fastcc = false; - - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, hchan, - sc->sc_ht_info.tx_chan_width, - sc->sc_tx_chainmask, - sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, - fastcc, &status)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset channel %u (%uMhz) " - "flags 0x%x hal status %u\n", __func__, - ath9k_hw_mhz2ieee(ah, hchan->channel, - hchan->channelFlags), - hchan->channel, hchan->channelFlags, status); - spin_unlock_bh(&sc->sc_resetlock); - return -EIO; - } - spin_unlock_bh(&sc->sc_resetlock); - - sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; - sc->sc_flags &= ~SC_OP_FULL_RESET; - - /* Re-enable rx framework */ - if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to restart recv logic\n", __func__); - return -EIO; - } - /* - * Change channels and update the h/w rate map - * if we're switching; e.g. 11a to 11b/g. - */ - ath_setcurmode(sc, ath_chan2mode(hchan)); - - ath_update_txpow(sc); /* update tx power state */ - /* - * Re-enable interrupts. - */ - ath9k_hw_set_interrupts(ah, sc->sc_imask); - } - return 0; -} - -/**********************/ -/* Chainmask Handling */ -/**********************/ - -static void ath_chainmask_sel_timertimeout(unsigned long data) -{ - struct ath_chainmask_sel *cm = (struct ath_chainmask_sel *)data; - cm->switch_allowed = 1; -} - -/* Start chainmask select timer */ -static void ath_chainmask_sel_timerstart(struct ath_chainmask_sel *cm) -{ - cm->switch_allowed = 0; - mod_timer(&cm->timer, ath_chainmask_sel_period); -} - -/* Stop chainmask select timer */ -static void ath_chainmask_sel_timerstop(struct ath_chainmask_sel *cm) -{ - cm->switch_allowed = 0; - del_timer_sync(&cm->timer); -} - -static void ath_chainmask_sel_init(struct ath_softc *sc, struct ath_node *an) -{ - struct ath_chainmask_sel *cm = &an->an_chainmask_sel; - - memset(cm, 0, sizeof(struct ath_chainmask_sel)); - - cm->cur_tx_mask = sc->sc_tx_chainmask; - cm->cur_rx_mask = sc->sc_rx_chainmask; - cm->tx_avgrssi = ATH_RSSI_DUMMY_MARKER; - setup_timer(&cm->timer, - ath_chainmask_sel_timertimeout, (unsigned long) cm); -} - -int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an) -{ - struct ath_chainmask_sel *cm = &an->an_chainmask_sel; - - /* - * Disable auto-swtiching in one of the following if conditions. - * sc_chainmask_auto_sel is used for internal global auto-switching - * enabled/disabled setting - */ - if (sc->sc_ah->ah_caps.tx_chainmask != ATH_CHAINMASK_SEL_3X3) { - cm->cur_tx_mask = sc->sc_tx_chainmask; - return cm->cur_tx_mask; - } - - if (cm->tx_avgrssi == ATH_RSSI_DUMMY_MARKER) - return cm->cur_tx_mask; - - if (cm->switch_allowed) { - /* Switch down from tx 3 to tx 2. */ - if (cm->cur_tx_mask == ATH_CHAINMASK_SEL_3X3 && - ATH_RSSI_OUT(cm->tx_avgrssi) >= - ath_chainmask_sel_down_rssi_thres) { - cm->cur_tx_mask = sc->sc_tx_chainmask; - - /* Don't let another switch happen until - * this timer expires */ - ath_chainmask_sel_timerstart(cm); - } - /* Switch up from tx 2 to 3. */ - else if (cm->cur_tx_mask == sc->sc_tx_chainmask && - ATH_RSSI_OUT(cm->tx_avgrssi) <= - ath_chainmask_sel_up_rssi_thres) { - cm->cur_tx_mask = ATH_CHAINMASK_SEL_3X3; - - /* Don't let another switch happen - * until this timer expires */ - ath_chainmask_sel_timerstart(cm); - } - } - - return cm->cur_tx_mask; -} - -/* - * Update tx/rx chainmask. For legacy association, - * hard code chainmask to 1x1, for 11n association, use - * the chainmask configuration. - */ - -void ath_update_chainmask(struct ath_softc *sc, int is_ht) -{ - sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; - if (is_ht) { - sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask; - sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask; - } else { - sc->sc_tx_chainmask = 1; - sc->sc_rx_chainmask = 1; - } - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: tx chmask: %d, rx chmask: %d\n", - __func__, sc->sc_tx_chainmask, sc->sc_rx_chainmask); -} - -/*******/ -/* ANI */ -/*******/ - -/* - * This routine performs the periodic noise floor calibration function - * that is used to adjust and optimize the chip performance. This - * takes environmental changes (location, temperature) into account. - * When the task is complete, it reschedules itself depending on the - * appropriate interval that was calculated. - */ - -static void ath_ani_calibrate(unsigned long data) -{ - struct ath_softc *sc; - struct ath_hal *ah; - bool longcal = false; - bool shortcal = false; - bool aniflag = false; - unsigned int timestamp = jiffies_to_msecs(jiffies); - u32 cal_interval; - - sc = (struct ath_softc *)data; - ah = sc->sc_ah; - - /* - * don't calibrate when we're scanning. - * we are most likely not on our home channel. - */ - if (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC) - return; - - /* Long calibration runs independently of short calibration. */ - if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { - longcal = true; - DPRINTF(sc, ATH_DBG_ANI, "%s: longcal @%lu\n", - __func__, jiffies); - sc->sc_ani.sc_longcal_timer = timestamp; - } - - /* Short calibration applies only while sc_caldone is false */ - if (!sc->sc_ani.sc_caldone) { - if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= - ATH_SHORT_CALINTERVAL) { - shortcal = true; - DPRINTF(sc, ATH_DBG_ANI, "%s: shortcal @%lu\n", - __func__, jiffies); - sc->sc_ani.sc_shortcal_timer = timestamp; - sc->sc_ani.sc_resetcal_timer = timestamp; - } - } else { - if ((timestamp - sc->sc_ani.sc_resetcal_timer) >= - ATH_RESTART_CALINTERVAL) { - ath9k_hw_reset_calvalid(ah, ah->ah_curchan, - &sc->sc_ani.sc_caldone); - if (sc->sc_ani.sc_caldone) - sc->sc_ani.sc_resetcal_timer = timestamp; - } - } - - /* Verify whether we must check ANI */ - if ((timestamp - sc->sc_ani.sc_checkani_timer) >= - ATH_ANI_POLLINTERVAL) { - aniflag = true; - sc->sc_ani.sc_checkani_timer = timestamp; - } - - /* Skip all processing if there's nothing to do. */ - if (longcal || shortcal || aniflag) { - /* Call ANI routine if necessary */ - if (aniflag) - ath9k_hw_ani_monitor(ah, &sc->sc_halstats, - ah->ah_curchan); - - /* Perform calibration if necessary */ - if (longcal || shortcal) { - bool iscaldone = false; - - if (ath9k_hw_calibrate(ah, ah->ah_curchan, - sc->sc_rx_chainmask, longcal, - &iscaldone)) { - if (longcal) - sc->sc_ani.sc_noise_floor = - ath9k_hw_getchan_noise(ah, - ah->ah_curchan); - - DPRINTF(sc, ATH_DBG_ANI, - "%s: calibrate chan %u/%x nf: %d\n", - __func__, - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags, - sc->sc_ani.sc_noise_floor); - } else { - DPRINTF(sc, ATH_DBG_ANY, - "%s: calibrate chan %u/%x failed\n", - __func__, - ah->ah_curchan->channel, - ah->ah_curchan->channelFlags); - } - sc->sc_ani.sc_caldone = iscaldone; - } - } - - /* - * Set timer interval based on previous results. - * The interval must be the shortest necessary to satisfy ANI, - * short calibration and long calibration. - */ - - cal_interval = ATH_ANI_POLLINTERVAL; - if (!sc->sc_ani.sc_caldone) - cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); - - mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); -} - -/******************/ -/* VAP management */ -/******************/ - -int ath_vap_attach(struct ath_softc *sc, - int if_id, - struct ieee80211_vif *if_data, - enum ath9k_opmode opmode) -{ - struct ath_vap *avp; - - if (if_id >= ATH_BCBUF || sc->sc_vaps[if_id] != NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Invalid interface id = %u\n", __func__, if_id); - return -EINVAL; - } - - switch (opmode) { - case ATH9K_M_STA: - case ATH9K_M_IBSS: - case ATH9K_M_MONITOR: - break; - case ATH9K_M_HOSTAP: - /* XXX not right, beacon buffer is allocated on RUN trans */ - if (list_empty(&sc->sc_bbuf)) - return -ENOMEM; - break; - default: - return -EINVAL; - } - - /* create ath_vap */ - avp = kmalloc(sizeof(struct ath_vap), GFP_KERNEL); - if (avp == NULL) - return -ENOMEM; - - memset(avp, 0, sizeof(struct ath_vap)); - avp->av_if_data = if_data; - /* Set the VAP opmode */ - avp->av_opmode = opmode; - avp->av_bslot = -1; - - if (opmode == ATH9K_M_HOSTAP) - ath9k_hw_set_tsfadjust(sc->sc_ah, 1); - - sc->sc_vaps[if_id] = avp; - sc->sc_nvaps++; - /* Set the device opmode */ - sc->sc_ah->ah_opmode = opmode; - - /* default VAP configuration */ - avp->av_config.av_fixed_rateset = IEEE80211_FIXED_RATE_NONE; - avp->av_config.av_fixed_retryset = 0x03030303; - - return 0; -} - -int ath_vap_detach(struct ath_softc *sc, int if_id) -{ - struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp; - - avp = sc->sc_vaps[if_id]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: invalid interface id %u\n", - __func__, if_id); - return -EINVAL; - } - - /* - * Quiesce the hardware while we remove the vap. In - * particular we need to reclaim all references to the - * vap state by any frames pending on the tx queues. - * - * XXX can we do this w/o affecting other vap's? - */ - ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, false); /* stop xmit side */ - ath_stoprecv(sc); /* stop recv side */ - ath_flushrecv(sc); /* flush recv queue */ - - kfree(avp); - sc->sc_vaps[if_id] = NULL; - sc->sc_nvaps--; - - return 0; -} - -int ath_vap_config(struct ath_softc *sc, - int if_id, struct ath_vap_config *if_config) -{ - struct ath_vap *avp; - - if (if_id >= ATH_BCBUF) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Invalid interface id = %u\n", __func__, if_id); - return -EINVAL; - } - - avp = sc->sc_vaps[if_id]; - ASSERT(avp != NULL); - - if (avp) - memcpy(&avp->av_config, if_config, sizeof(avp->av_config)); - - return 0; -} - -/********/ -/* Core */ -/********/ - -int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan) -{ - struct ath_hal *ah = sc->sc_ah; - int status; - int error = 0; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: mode %d\n", - __func__, sc->sc_ah->ah_opmode); - - /* - * Stop anything previously setup. This is safe - * whether this is the first time through or not. - */ - ath_stop(sc); - - /* Initialize chanmask selection */ - sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; - sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; - - /* Reset SERDES registers */ - ath9k_hw_configpcipowersave(ah, 0); - - /* - * The basic interface to setting the hardware in a good - * state is ``reset''. On return the hardware is known to - * be powered up and with interrupts disabled. This must - * be followed by initialization of the appropriate bits - * and then setup of the interrupt mask. - */ - - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, initial_chan, - sc->sc_ht_info.tx_chan_width, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset hardware; hal status %u " - "(freq %u flags 0x%x)\n", __func__, status, - initial_chan->channel, initial_chan->channelFlags); - error = -EIO; - spin_unlock_bh(&sc->sc_resetlock); - goto done; - } - spin_unlock_bh(&sc->sc_resetlock); - /* - * This is needed only to setup initial state - * but it's best done after a reset. - */ - ath_update_txpow(sc); - - /* - * Setup the hardware after reset: - * The receive engine is set going. - * Frame transmit is handled entirely - * in the frame output path; there's nothing to do - * here except setup the interrupt mask. - */ - if (ath_startrecv(sc) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to start recv logic\n", __func__); - error = -EIO; - goto done; - } - /* Setup our intr mask. */ - sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX - | ATH9K_INT_RXEOL | ATH9K_INT_RXORN - | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; - - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT) - sc->sc_imask |= ATH9K_INT_GTT; - - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - sc->sc_imask |= ATH9K_INT_CST; - - /* - * Enable MIB interrupts when there are hardware phy counters. - * Note we only do this (at the moment) for station mode. - */ - if (ath9k_hw_phycounters(ah) && - ((sc->sc_ah->ah_opmode == ATH9K_M_STA) || - (sc->sc_ah->ah_opmode == ATH9K_M_IBSS))) - sc->sc_imask |= ATH9K_INT_MIB; - /* - * Some hardware processes the TIM IE and fires an - * interrupt when the TIM bit is set. For hardware - * that does, if not overridden by configuration, - * enable the TIM interrupt when operating as station. - */ - if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && - (sc->sc_ah->ah_opmode == ATH9K_M_STA) && - !sc->sc_config.swBeaconProcess) - sc->sc_imask |= ATH9K_INT_TIM; - /* - * Don't enable interrupts here as we've not yet built our - * vap and node data structures, which will be needed as soon - * as we start receiving. - */ - ath_setcurmode(sc, ath_chan2mode(initial_chan)); - - /* XXX: we must make sure h/w is ready and clear invalid flag - * before turning on interrupt. */ - sc->sc_flags &= ~SC_OP_INVALID; -done: - return error; -} - -int ath_reset(struct ath_softc *sc, bool retry_tx) -{ - struct ath_hal *ah = sc->sc_ah; - int status; - int error = 0; - - ath9k_hw_set_interrupts(ah, 0); /* disable interrupts */ - ath_draintxq(sc, retry_tx); /* stop xmit */ - ath_stoprecv(sc); /* stop recv */ - ath_flushrecv(sc); /* flush recv queue */ - - /* Reset chip */ - spin_lock_bh(&sc->sc_resetlock); - if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, - sc->sc_tx_chainmask, sc->sc_rx_chainmask, - sc->sc_ht_extprotspacing, false, &status)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset hardware; hal status %u\n", - __func__, status); - error = -EIO; - } - spin_unlock_bh(&sc->sc_resetlock); - - if (ath_startrecv(sc) != 0) /* restart recv */ - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to start recv logic\n", __func__); - - /* - * We may be doing a reset in response to a request - * that changes the channel so update any state that - * might change as a result. - */ - ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); - - ath_update_txpow(sc); - - if (sc->sc_flags & SC_OP_BEACONS) - ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ - - ath9k_hw_set_interrupts(ah, sc->sc_imask); - - /* Restart the txq */ - if (retry_tx) { - int i; - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { - if (ATH_TXQ_SETUP(sc, i)) { - spin_lock_bh(&sc->sc_txq[i].axq_lock); - ath_txq_schedule(sc, &sc->sc_txq[i]); - spin_unlock_bh(&sc->sc_txq[i].axq_lock); - } - } - } - - return error; -} - -int ath_suspend(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - - /* No I/O if device has been surprise removed */ - if (sc->sc_flags & SC_OP_INVALID) - return -EIO; - - /* Shut off the interrupt before setting sc->sc_invalid to '1' */ - ath9k_hw_set_interrupts(ah, 0); - - /* XXX: we must make sure h/w will not generate any interrupt - * before setting the invalid flag. */ - sc->sc_flags |= SC_OP_INVALID; - - /* disable HAL and put h/w to sleep */ - ath9k_hw_disable(sc->sc_ah); - - ath9k_hw_configpcipowersave(sc->sc_ah, 1); - - return 0; -} - -/* Interrupt handler. Most of the actual processing is deferred. - * It's the caller's responsibility to ensure the chip is awake. */ - -irqreturn_t ath_isr(int irq, void *dev) -{ - struct ath_softc *sc = dev; - struct ath_hal *ah = sc->sc_ah; - enum ath9k_int status; - bool sched = false; - - do { - if (sc->sc_flags & SC_OP_INVALID) { - /* - * The hardware is not ready/present, don't - * touch anything. Note this can happen early - * on if the IRQ is shared. - */ - return IRQ_NONE; - } - if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */ - return IRQ_NONE; - } - - /* - * Figure out the reason(s) for the interrupt. Note - * that the hal returns a pseudo-ISR that may include - * bits we haven't explicitly enabled so we mask the - * value to insure we only process bits we requested. - */ - ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ - - status &= sc->sc_imask; /* discard unasked-for bits */ - - /* - * If there are no status bits set, then this interrupt was not - * for me (should have been caught above). - */ - - if (!status) - return IRQ_NONE; - - sc->sc_intrstatus = status; - - if (status & ATH9K_INT_FATAL) { - /* need a chip reset */ - sched = true; - } else if (status & ATH9K_INT_RXORN) { - /* need a chip reset */ - sched = true; - } else { - if (status & ATH9K_INT_SWBA) { - /* schedule a tasklet for beacon handling */ - tasklet_schedule(&sc->bcon_tasklet); - } - if (status & ATH9K_INT_RXEOL) { - /* - * NB: the hardware should re-read the link when - * RXE bit is written, but it doesn't work - * at least on older hardware revs. - */ - sched = true; - } - - if (status & ATH9K_INT_TXURN) - /* bump tx trigger level */ - ath9k_hw_updatetxtriglevel(ah, true); - /* XXX: optimize this */ - if (status & ATH9K_INT_RX) - sched = true; - if (status & ATH9K_INT_TX) - sched = true; - if (status & ATH9K_INT_BMISS) - sched = true; - /* carrier sense timeout */ - if (status & ATH9K_INT_CST) - sched = true; - if (status & ATH9K_INT_MIB) { - /* - * Disable interrupts until we service the MIB - * interrupt; otherwise it will continue to - * fire. - */ - ath9k_hw_set_interrupts(ah, 0); - /* - * Let the hal handle the event. We assume - * it will clear whatever condition caused - * the interrupt. - */ - ath9k_hw_procmibevent(ah, &sc->sc_halstats); - ath9k_hw_set_interrupts(ah, sc->sc_imask); - } - if (status & ATH9K_INT_TIM_TIMER) { - if (!(ah->ah_caps.hw_caps & - ATH9K_HW_CAP_AUTOSLEEP)) { - /* Clear RxAbort bit so that we can - * receive frames */ - ath9k_hw_setrxabort(ah, 0); - sched = true; - } - } - } - } while (0); - - if (sched) { - /* turn off every interrupt except SWBA */ - ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA)); - tasklet_schedule(&sc->intr_tq); - } - - return IRQ_HANDLED; -} - -/* Deferred interrupt processing */ - -static void ath9k_tasklet(unsigned long data) -{ - struct ath_softc *sc = (struct ath_softc *)data; - u32 status = sc->sc_intrstatus; - - if (status & ATH9K_INT_FATAL) { - /* need a chip reset */ - ath_reset(sc, false); - return; - } else { - - if (status & - (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { - /* XXX: fill me in */ - /* - if (status & ATH9K_INT_RXORN) { - } - if (status & ATH9K_INT_RXEOL) { - } - */ - spin_lock_bh(&sc->sc_rxflushlock); - ath_rx_tasklet(sc, 0); - spin_unlock_bh(&sc->sc_rxflushlock); - } - /* XXX: optimize this */ - if (status & ATH9K_INT_TX) - ath_tx_tasklet(sc); - /* XXX: fill me in */ - /* - if (status & ATH9K_INT_BMISS) { - } - if (status & (ATH9K_INT_TIM | ATH9K_INT_DTIMSYNC)) { - if (status & ATH9K_INT_TIM) { - } - if (status & ATH9K_INT_DTIMSYNC) { - } - } - */ - } - - /* re-enable hardware interrupt */ - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); -} - -int ath_init(u16 devid, struct ath_softc *sc) -{ - struct ath_hal *ah = NULL; - int status; - int error = 0, i; - int csz = 0; - - /* XXX: hardware will not be ready until ath_open() being called */ - sc->sc_flags |= SC_OP_INVALID; - - sc->sc_debug = DBG_DEFAULT; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: devid 0x%x\n", __func__, devid); - - /* Initialize tasklet */ - tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); - tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, - (unsigned long)sc); - - /* - * Cache line size is used to size and align various - * structures used to communicate with the hardware. - */ - bus_read_cachesize(sc, &csz); - /* XXX assert csz is non-zero */ - sc->sc_cachelsz = csz << 2; /* convert to bytes */ - - spin_lock_init(&sc->sc_resetlock); - - ah = ath9k_hw_attach(devid, sc, sc->mem, &status); - if (ah == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to attach hardware; HAL status %u\n", - __func__, status); - error = -ENXIO; - goto bad; - } - sc->sc_ah = ah; - - /* Initializes the noise floor to a reasonable default value. - * Later on this will be updated during ANI processing. */ - sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; - - /* Get the hardware key cache size. */ - sc->sc_keymax = ah->ah_caps.keycache_size; - if (sc->sc_keymax > ATH_KEYMAX) { - DPRINTF(sc, ATH_DBG_KEYCACHE, - "%s: Warning, using only %u entries in %u key cache\n", - __func__, ATH_KEYMAX, sc->sc_keymax); - sc->sc_keymax = ATH_KEYMAX; - } - - /* - * Reset the key cache since some parts do not - * reset the contents on initial power up. - */ - for (i = 0; i < sc->sc_keymax; i++) - ath9k_hw_keyreset(ah, (u16) i); - /* - * Mark key cache slots associated with global keys - * as in use. If we knew TKIP was not to be used we - * could leave the +32, +64, and +32+64 slots free. - * XXX only for splitmic. - */ - for (i = 0; i < IEEE80211_WEP_NKID; i++) { - set_bit(i, sc->sc_keymap); - set_bit(i + 32, sc->sc_keymap); - set_bit(i + 64, sc->sc_keymap); - set_bit(i + 32 + 64, sc->sc_keymap); - } - /* - * Collect the channel list using the default country - * code and including outdoor channels. The 802.11 layer - * is resposible for filtering this list based on settings - * like the phy mode. - */ - error = ath_setup_channels(sc); - if (error) - goto bad; - - /* default to STA mode */ - sc->sc_ah->ah_opmode = ATH9K_M_MONITOR; - - /* Setup rate tables */ - - ath_setup_rates(sc, IEEE80211_BAND_2GHZ); - ath_setup_rates(sc, IEEE80211_BAND_5GHZ); - - /* NB: setup here so ath_rate_update is happy */ - ath_setcurmode(sc, ATH9K_MODE_11A); - - /* - * Allocate hardware transmit queues: one queue for - * beacon frames and one data queue for each QoS - * priority. Note that the hal handles reseting - * these queues at the needed time. - */ - sc->sc_bhalq = ath_beaconq_setup(ah); - if (sc->sc_bhalq == -1) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup a beacon xmit queue\n", __func__); - error = -EIO; - goto bad2; - } - sc->sc_cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); - if (sc->sc_cabq == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup CAB xmit queue\n", __func__); - error = -EIO; - goto bad2; - } - - sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME; - ath_cabq_update(sc); - - for (i = 0; i < ARRAY_SIZE(sc->sc_haltype2q); i++) - sc->sc_haltype2q[i] = -1; - - /* Setup data queues */ - /* NB: ensure BK queue is the lowest priority h/w queue */ - if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for BK traffic\n", - __func__); - error = -EIO; - goto bad2; - } - - if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for BE traffic\n", - __func__); - error = -EIO; - goto bad2; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for VI traffic\n", - __func__); - error = -EIO; - goto bad2; - } - if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to setup xmit queue for VO traffic\n", - __func__); - error = -EIO; - goto bad2; - } - - setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); - - sc->sc_rc = ath_rate_attach(ah); - if (sc->sc_rc == NULL) { - error = -EIO; - goto bad2; - } - - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL)) { - /* - * Whether we should enable h/w TKIP MIC. - * XXX: if we don't support WME TKIP MIC, then we wouldn't - * report WMM capable, so it's always safe to turn on - * TKIP MIC in this case. - */ - ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, - 0, 1, NULL); - } - - /* - * Check whether the separate key cache entries - * are required to handle both tx+rx MIC keys. - * With split mic keys the number of stations is limited - * to 27 otherwise 59. - */ - if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_TKIP, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, - ATH9K_CIPHER_MIC, NULL) - && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, - 0, NULL)) - sc->sc_splitmic = 1; - - /* turn on mcast key search if possible */ - if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) - (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, - 1, NULL); - - sc->sc_config.txpowlimit = ATH_TXPOWER_MAX; - sc->sc_config.txpowlimit_override = 0; - - /* 11n Capabilities */ - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { - sc->sc_flags |= SC_OP_TXAGGR; - sc->sc_flags |= SC_OP_RXAGGR; - } - - sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; - sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; - - ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); - sc->sc_defant = ath9k_hw_getdefantenna(ah); - - ath9k_hw_getmac(ah, sc->sc_myaddr); - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) { - ath9k_hw_getbssidmask(ah, sc->sc_bssidmask); - ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); - ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); - } - sc->sc_slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ - - /* initialize beacon slots */ - for (i = 0; i < ARRAY_SIZE(sc->sc_bslot); i++) - sc->sc_bslot[i] = ATH_IF_ID_ANY; - - /* save MISC configurations */ - sc->sc_config.swBeaconProcess = 1; - -#ifdef CONFIG_SLOW_ANT_DIV - /* range is 40 - 255, we use something in the middle */ - ath_slow_ant_div_init(&sc->sc_antdiv, sc, 0x127); -#endif - - return 0; -bad2: - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->sc_txq[i]); -bad: - if (ah) - ath9k_hw_detach(ah); - return error; -} - -void ath_deinit(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - int i; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s\n", __func__); - - tasklet_kill(&sc->intr_tq); - tasklet_kill(&sc->bcon_tasklet); - ath_stop(sc); - if (!(sc->sc_flags & SC_OP_INVALID)) - ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - ath_rate_detach(sc->sc_rc); - /* cleanup tx queues */ - for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) - if (ATH_TXQ_SETUP(sc, i)) - ath_tx_cleanupq(sc, &sc->sc_txq[i]); - ath9k_hw_detach(ah); -} - -/*******************/ -/* Node Management */ -/*******************/ - -struct ath_node *ath_node_attach(struct ath_softc *sc, u8 *addr, int if_id) -{ - struct ath_vap *avp; - struct ath_node *an; - DECLARE_MAC_BUF(mac); - - avp = sc->sc_vaps[if_id]; - ASSERT(avp != NULL); - - /* mac80211 sta_notify callback is from an IRQ context, so no sleep */ - an = kmalloc(sizeof(struct ath_node), GFP_ATOMIC); - if (an == NULL) - return NULL; - memset(an, 0, sizeof(*an)); - - an->an_sc = sc; - memcpy(an->an_addr, addr, ETH_ALEN); - atomic_set(&an->an_refcnt, 1); - - /* set up per-node tx/rx state */ - ath_tx_node_init(sc, an); - ath_rx_node_init(sc, an); - - ath_chainmask_sel_init(sc, an); - ath_chainmask_sel_timerstart(&an->an_chainmask_sel); - list_add(&an->list, &sc->node_list); - - return an; -} - -void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag) -{ - unsigned long flags; - - DECLARE_MAC_BUF(mac); - - ath_chainmask_sel_timerstop(&an->an_chainmask_sel); - an->an_flags |= ATH_NODE_CLEAN; - ath_tx_node_cleanup(sc, an, bh_flag); - ath_rx_node_cleanup(sc, an); - - ath_tx_node_free(sc, an); - ath_rx_node_free(sc, an); - - spin_lock_irqsave(&sc->node_lock, flags); - - list_del(&an->list); - - spin_unlock_irqrestore(&sc->node_lock, flags); - - kfree(an); -} - -/* Finds a node and increases the refcnt if found */ - -struct ath_node *ath_node_get(struct ath_softc *sc, u8 *addr) -{ - struct ath_node *an = NULL, *an_found = NULL; - - if (list_empty(&sc->node_list)) /* FIXME */ - goto out; - list_for_each_entry(an, &sc->node_list, list) { - if (!compare_ether_addr(an->an_addr, addr)) { - atomic_inc(&an->an_refcnt); - an_found = an; - break; - } - } -out: - return an_found; -} - -/* Decrements the refcnt and if it drops to zero, detach the node */ - -void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag) -{ - if (atomic_dec_and_test(&an->an_refcnt)) - ath_node_detach(sc, an, bh_flag); -} - -/* Finds a node, doesn't increment refcnt. Caller must hold sc->node_lock */ -struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr) -{ - struct ath_node *an = NULL, *an_found = NULL; - - if (list_empty(&sc->node_list)) - return NULL; - - list_for_each_entry(an, &sc->node_list, list) - if (!compare_ether_addr(an->an_addr, addr)) { - an_found = an; - break; - } - - return an_found; -} - -/* - * Set up New Node - * - * Setup driver-specific state for a newly associated node. This routine - * really only applies if compression or XR are enabled, there is no code - * covering any other cases. -*/ - -void ath_newassoc(struct ath_softc *sc, - struct ath_node *an, int isnew, int isuapsd) -{ - int tidno; - - /* if station reassociates, tear down the aggregation state. */ - if (!isnew) { - for (tidno = 0; tidno < WME_NUM_TID; tidno++) { - if (sc->sc_flags & SC_OP_TXAGGR) - ath_tx_aggr_teardown(sc, an, tidno); - if (sc->sc_flags & SC_OP_RXAGGR) - ath_rx_aggr_teardown(sc, an, tidno); - } - } - an->an_flags = 0; -} - -/**************/ -/* Encryption */ -/**************/ - -void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot) -{ - ath9k_hw_keyreset(sc->sc_ah, keyix); - if (freeslot) - clear_bit(keyix, sc->sc_keymap); -} - -int ath_keyset(struct ath_softc *sc, - u16 keyix, - struct ath9k_keyval *hk, - const u8 mac[ETH_ALEN]) -{ - bool status; - - status = ath9k_hw_set_keycache_entry(sc->sc_ah, - keyix, hk, mac, false); - - return status != false; -} - -/***********************/ -/* TX Power/Regulatory */ -/***********************/ - -/* - * Set Transmit power in HAL - * - * This routine makes the actual HAL calls to set the new transmit power - * limit. -*/ - -void ath_update_txpow(struct ath_softc *sc) -{ - struct ath_hal *ah = sc->sc_ah; - u32 txpow; - - if (sc->sc_curtxpow != sc->sc_config.txpowlimit) { - ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit); - /* read back in case value is clamped */ - ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); - sc->sc_curtxpow = txpow; - } -} - -/* Return the current country and domain information */ -void ath_get_currentCountry(struct ath_softc *sc, - struct ath9k_country_entry *ctry) -{ - ath9k_regd_get_current_country(sc->sc_ah, ctry); - - /* If HAL not specific yet, since it is band dependent, - * use the one we passed in. */ - if (ctry->countryCode == CTRY_DEFAULT) { - ctry->iso[0] = 0; - ctry->iso[1] = 0; - } else if (ctry->iso[0] && ctry->iso[1]) { - if (!ctry->iso[2]) { - if (ath_outdoor) - ctry->iso[2] = 'O'; - else - ctry->iso[2] = 'I'; - } - } -} - -/**************************/ -/* Slow Antenna Diversity */ -/**************************/ - -void ath_slow_ant_div_init(struct ath_antdiv *antdiv, - struct ath_softc *sc, - int32_t rssitrig) -{ - int trig; - - /* antdivf_rssitrig can range from 40 - 0xff */ - trig = (rssitrig > 0xff) ? 0xff : rssitrig; - trig = (rssitrig < 40) ? 40 : rssitrig; - - antdiv->antdiv_sc = sc; - antdiv->antdivf_rssitrig = trig; -} - -void ath_slow_ant_div_start(struct ath_antdiv *antdiv, - u8 num_antcfg, - const u8 *bssid) -{ - antdiv->antdiv_num_antcfg = - num_antcfg < ATH_ANT_DIV_MAX_CFG ? - num_antcfg : ATH_ANT_DIV_MAX_CFG; - antdiv->antdiv_state = ATH_ANT_DIV_IDLE; - antdiv->antdiv_curcfg = 0; - antdiv->antdiv_bestcfg = 0; - antdiv->antdiv_laststatetsf = 0; - - memcpy(antdiv->antdiv_bssid, bssid, sizeof(antdiv->antdiv_bssid)); - - antdiv->antdiv_start = 1; -} - -void ath_slow_ant_div_stop(struct ath_antdiv *antdiv) -{ - antdiv->antdiv_start = 0; -} - -static int32_t ath_find_max_val(int32_t *val, - u8 num_val, u8 *max_index) -{ - u32 MaxVal = *val++; - u32 cur_index = 0; - - *max_index = 0; - while (++cur_index < num_val) { - if (*val > MaxVal) { - MaxVal = *val; - *max_index = cur_index; - } - - val++; - } - - return MaxVal; -} - -void ath_slow_ant_div(struct ath_antdiv *antdiv, - struct ieee80211_hdr *hdr, - struct ath_rx_status *rx_stats) -{ - struct ath_softc *sc = antdiv->antdiv_sc; - struct ath_hal *ah = sc->sc_ah; - u64 curtsf = 0; - u8 bestcfg, curcfg = antdiv->antdiv_curcfg; - __le16 fc = hdr->frame_control; - - if (antdiv->antdiv_start && ieee80211_is_beacon(fc) - && !compare_ether_addr(hdr->addr3, antdiv->antdiv_bssid)) { - antdiv->antdiv_lastbrssi[curcfg] = rx_stats->rs_rssi; - antdiv->antdiv_lastbtsf[curcfg] = ath9k_hw_gettsf64(sc->sc_ah); - curtsf = antdiv->antdiv_lastbtsf[curcfg]; - } else { - return; - } - - switch (antdiv->antdiv_state) { - case ATH_ANT_DIV_IDLE: - if ((antdiv->antdiv_lastbrssi[curcfg] < - antdiv->antdivf_rssitrig) - && ((curtsf - antdiv->antdiv_laststatetsf) > - ATH_ANT_DIV_MIN_IDLE_US)) { - - curcfg++; - if (curcfg == antdiv->antdiv_num_antcfg) - curcfg = 0; - - if (!ath9k_hw_select_antconfig(ah, curcfg)) { - antdiv->antdiv_bestcfg = antdiv->antdiv_curcfg; - antdiv->antdiv_curcfg = curcfg; - antdiv->antdiv_laststatetsf = curtsf; - antdiv->antdiv_state = ATH_ANT_DIV_SCAN; - } - } - break; - - case ATH_ANT_DIV_SCAN: - if ((curtsf - antdiv->antdiv_laststatetsf) < - ATH_ANT_DIV_MIN_SCAN_US) - break; - - curcfg++; - if (curcfg == antdiv->antdiv_num_antcfg) - curcfg = 0; - - if (curcfg == antdiv->antdiv_bestcfg) { - ath_find_max_val(antdiv->antdiv_lastbrssi, - antdiv->antdiv_num_antcfg, &bestcfg); - if (!ath9k_hw_select_antconfig(ah, bestcfg)) { - antdiv->antdiv_bestcfg = bestcfg; - antdiv->antdiv_curcfg = bestcfg; - antdiv->antdiv_laststatetsf = curtsf; - antdiv->antdiv_state = ATH_ANT_DIV_IDLE; - } - } else { - if (!ath9k_hw_select_antconfig(ah, curcfg)) { - antdiv->antdiv_curcfg = curcfg; - antdiv->antdiv_laststatetsf = curtsf; - antdiv->antdiv_state = ATH_ANT_DIV_SCAN; - } - } - - break; - } -} - -/***********************/ -/* Descriptor Handling */ -/***********************/ - -/* - * Set up DMA descriptors - * - * This function will allocate both the DMA descriptor structure, and the - * buffers it contains. These are used to contain the descriptors used - * by the system. -*/ - -int ath_descdma_setup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head, - const char *name, - int nbuf, - int ndesc) -{ -#define DS2PHYS(_dd, _ds) \ - ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) -#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) -#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) - - struct ath_desc *ds; - struct ath_buf *bf; - int i, bsize, error; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA: %u buffers %u desc/buf\n", - __func__, name, nbuf, ndesc); - - /* ath_desc must be a multiple of DWORDs */ - if ((sizeof(struct ath_desc) % 4) != 0) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: ath_desc not DWORD aligned\n", - __func__); - ASSERT((sizeof(struct ath_desc) % 4) == 0); - error = -ENOMEM; - goto fail; - } - - dd->dd_name = name; - dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; - - /* - * Need additional DMA memory because we can't use - * descriptors that cross the 4K page boundary. Assume - * one skipped descriptor per 4K page. - */ - if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { - u32 ndesc_skipped = - ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); - u32 dma_len; - - while (ndesc_skipped) { - dma_len = ndesc_skipped * sizeof(struct ath_desc); - dd->dd_desc_len += dma_len; - - ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); - }; - } - - /* allocate descriptors */ - dd->dd_desc = pci_alloc_consistent(sc->pdev, - dd->dd_desc_len, - &dd->dd_desc_paddr); - if (dd->dd_desc == NULL) { - error = -ENOMEM; - goto fail; - } - ds = dd->dd_desc; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: %s DMA map: %p (%u) -> %llx (%u)\n", - __func__, dd->dd_name, ds, (u32) dd->dd_desc_len, - ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); - - /* allocate buffers */ - bsize = sizeof(struct ath_buf) * nbuf; - bf = kmalloc(bsize, GFP_KERNEL); - if (bf == NULL) { - error = -ENOMEM; - goto fail2; - } - memset(bf, 0, bsize); - dd->dd_bufptr = bf; - - INIT_LIST_HEAD(head); - for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - - if (!(sc->sc_ah->ah_caps.hw_caps & - ATH9K_HW_CAP_4KB_SPLITTRANS)) { - /* - * Skip descriptor addresses which can cause 4KB - * boundary crossing (addr + length) with a 32 dword - * descriptor fetch. - */ - while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { - ASSERT((caddr_t) bf->bf_desc < - ((caddr_t) dd->dd_desc + - dd->dd_desc_len)); - - ds += ndesc; - bf->bf_desc = ds; - bf->bf_daddr = DS2PHYS(dd, ds); - } - } - list_add_tail(&bf->list, head); - } - return 0; -fail2: - pci_free_consistent(sc->pdev, - dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); -fail: - memset(dd, 0, sizeof(*dd)); - return error; -#undef ATH_DESC_4KB_BOUND_CHECK -#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED -#undef DS2PHYS -} - -/* - * Cleanup DMA descriptors - * - * This function will free the DMA block that was allocated for the descriptor - * pool. Since this was allocated as one "chunk", it is freed in the same - * manner. -*/ - -void ath_descdma_cleanup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head) -{ - /* Free memory associated with descriptors */ - pci_free_consistent(sc->pdev, - dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); - - INIT_LIST_HEAD(head); - kfree(dd->dd_bufptr); - memset(dd, 0, sizeof(*dd)); -} - -/*************/ -/* Utilities */ -/*************/ - -int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) -{ - int qnum; - - switch (queue) { - case 0: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_VO]; - break; - case 1: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_VI]; - break; - case 2: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE]; - break; - case 3: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BK]; - break; - default: - qnum = sc->sc_haltype2q[ATH9K_WME_AC_BE]; - break; - } - - return qnum; -} - -int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) -{ - int qnum; - - switch (queue) { - case ATH9K_WME_AC_VO: - qnum = 0; - break; - case ATH9K_WME_AC_VI: - qnum = 1; - break; - case ATH9K_WME_AC_BE: - qnum = 2; - break; - case ATH9K_WME_AC_BK: - qnum = 3; - break; - default: - qnum = -1; - break; - } - - return qnum; -} - - -/* - * Expand time stamp to TSF - * - * Extend 15-bit time stamp from rx descriptor to - * a full 64-bit TSF using the current h/w TSF. -*/ - -u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) -{ - u64 tsf; - - tsf = ath9k_hw_gettsf64(sc->sc_ah); - if ((tsf & 0x7fff) < rstamp) - tsf -= 0x8000; - return (tsf & ~0x7fff) | rstamp; -} - -/* - * Set Default Antenna - * - * Call into the HAL to set the default antenna to use. Not really valid for - * MIMO technology. -*/ - -void ath_setdefantenna(void *context, u32 antenna) -{ - struct ath_softc *sc = (struct ath_softc *)context; - struct ath_hal *ah = sc->sc_ah; - - /* XXX block beacon interrupts */ - ath9k_hw_setantenna(ah, antenna); - sc->sc_defant = antenna; - sc->sc_rxotherant = 0; -} - -/* - * Set Slot Time - * - * This will wake up the chip if required, and set the slot time for the - * frame (maximum transmit time). Slot time is assumed to be already set - * in the ATH object member sc_slottime -*/ - -void ath_setslottime(struct ath_softc *sc) -{ - ath9k_hw_setslottime(sc->sc_ah, sc->sc_slottime); - sc->sc_updateslot = OK; -} diff --git a/drivers/net/wireless/ath9k/core.h b/drivers/net/wireless/ath9k/core.h index cb3e61e57c4d9a82218c6c7220fdef0f26fa3e77..4ca2aed236e090d081e6649f019cf81da86273c0 100644 --- a/drivers/net/wireless/ath9k/core.h +++ b/drivers/net/wireless/ath9k/core.h @@ -17,27 +17,8 @@ #ifndef CORE_H #define CORE_H -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include -#include -#include #include #include #include @@ -47,10 +28,6 @@ struct ath_node; -/******************/ -/* Utility macros */ -/******************/ - /* Macro to expand scalars to 64-bit objects */ #define ito64(x) (sizeof(x) == 8) ? \ @@ -84,94 +61,125 @@ struct ath_node; #define TSF_TO_TU(_h,_l) \ ((((u32)(_h)) << 22) | (((u32)(_l)) >> 10)) -#define ATH9K_BH_STATUS_INTACT 0 -#define ATH9K_BH_STATUS_CHANGE 1 - -#define ATH_TXQ_SETUP(sc, i) ((sc)->sc_txqsetup & (1<tx.txqsetup & (1<sc_debug & (_m)) \ - printk(_fmt , ##__VA_ARGS__); \ - } while (0) +#ifdef CONFIG_ATH9K_DEBUG + +/** + * struct ath_interrupt_stats - Contains statistics about interrupts + * @total: Total no. of interrupts generated so far + * @rxok: RX with no errors + * @rxeol: RX with no more RXDESC available + * @rxorn: RX FIFO overrun + * @txok: TX completed at the requested rate + * @txurn: TX FIFO underrun + * @mib: MIB regs reaching its threshold + * @rxphyerr: RX with phy errors + * @rx_keycache_miss: RX with key cache misses + * @swba: Software Beacon Alert + * @bmiss: Beacon Miss + * @bnr: Beacon Not Ready + * @cst: Carrier Sense TImeout + * @gtt: Global TX Timeout + * @tim: RX beacon TIM occurrence + * @cabend: RX End of CAB traffic + * @dtimsync: DTIM sync lossage + * @dtim: RX Beacon with DTIM + */ +struct ath_interrupt_stats { + u32 total; + u32 rxok; + u32 rxeol; + u32 rxorn; + u32 txok; + u32 txeol; + u32 txurn; + u32 mib; + u32 rxphyerr; + u32 rx_keycache_miss; + u32 swba; + u32 bmiss; + u32 bnr; + u32 cst; + u32 gtt; + u32 tim; + u32 cabend; + u32 dtimsync; + u32 dtim; +}; + +struct ath_stats { + struct ath_interrupt_stats istats; +}; + +struct ath9k_debug { + int debug_mask; + struct dentry *debugfs_root; + struct dentry *debugfs_phy; + struct dentry *debugfs_dma; + struct dentry *debugfs_interrupt; + struct ath_stats stats; +}; + +void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...); +int ath9k_init_debug(struct ath_softc *sc); +void ath9k_exit_debug(struct ath_softc *sc); +void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status); + +#else + +static inline void DPRINTF(struct ath_softc *sc, int dbg_mask, + const char *fmt, ...) +{ +} + +static inline int ath9k_init_debug(struct ath_softc *sc) +{ + return 0; +} -/***************************/ -/* Load-time Configuration */ -/***************************/ +static inline void ath9k_exit_debug(struct ath_softc *sc) +{ +} + +static inline void ath_debug_stat_interrupt(struct ath_softc *sc, + enum ath9k_int status) +{ +} + +#endif /* CONFIG_ATH9K_DEBUG */ -/* Per-instance load-time (note: NOT run-time) configurations - * for Atheros Device */ struct ath_config { u32 ath_aggr_prot; u16 txpowlimit; u16 txpowlimit_override; - u8 cabqReadytime; /* Cabq Readytime % */ - u8 swBeaconProcess; /* Process received beacons in SW (vs HW) */ -}; - -/***********************/ -/* Chainmask Selection */ -/***********************/ - -#define ATH_CHAINMASK_SEL_TIMEOUT 6000 -/* Default - Number of last RSSI values that is used for - * chainmask selection */ -#define ATH_CHAINMASK_SEL_RSSI_CNT 10 -/* Means use 3x3 chainmask instead of configured chainmask */ -#define ATH_CHAINMASK_SEL_3X3 7 -/* Default - Rssi threshold below which we have to switch to 3x3 */ -#define ATH_CHAINMASK_SEL_UP_RSSI_THRES 20 -/* Default - Rssi threshold above which we have to switch to - * user configured values */ -#define ATH_CHAINMASK_SEL_DOWN_RSSI_THRES 35 -/* Struct to store the chainmask select related info */ -struct ath_chainmask_sel { - struct timer_list timer; - int cur_tx_mask; /* user configured or 3x3 */ - int cur_rx_mask; /* user configured or 3x3 */ - int tx_avgrssi; - u8 switch_allowed:1, /* timer will set this */ - cm_sel_enabled : 1; + u8 cabqReadytime; + u8 swBeaconProcess; }; -int ath_chainmask_sel_logic(struct ath_softc *sc, struct ath_node *an); -void ath_update_chainmask(struct ath_softc *sc, int is_ht); - /*************************/ /* Descriptor Management */ /*************************/ @@ -200,15 +208,14 @@ enum buffer_type { }; struct ath_buf_state { - int bfs_nframes; /* # frames in aggregate */ - u16 bfs_al; /* length of aggregate */ - u16 bfs_frmlen; /* length of frame */ - int bfs_seqno; /* sequence number */ - int bfs_tidno; /* tid of this frame */ - int bfs_retries; /* current retries */ - struct ath_rc_series bfs_rcs[4]; /* rate series */ - u32 bf_type; /* BUF_* (enum buffer_type) */ - /* key type use to encrypt this frame */ + int bfs_nframes; /* # frames in aggregate */ + u16 bfs_al; /* length of aggregate */ + u16 bfs_frmlen; /* length of frame */ + int bfs_seqno; /* sequence number */ + int bfs_tidno; /* tid of this frame */ + int bfs_retries; /* current retries */ + u32 bf_type; /* BUF_* (enum buffer_type) */ + u32 bfs_keyix; enum ath9k_key_type bfs_keytype; }; @@ -219,6 +226,7 @@ struct ath_buf_state { #define bf_seqno bf_state.bfs_seqno #define bf_tidno bf_state.bfs_tidno #define bf_rcs bf_state.bfs_rcs +#define bf_keyix bf_state.bfs_keyix #define bf_keytype bf_state.bfs_keytype #define bf_isdata(bf) (bf->bf_state.bf_type & BUF_DATA) #define bf_isaggr(bf) (bf->bf_state.bf_type & BUF_AGGR) @@ -242,9 +250,7 @@ struct ath_buf { an aggregate) */ struct ath_buf *bf_lastfrm; /* last buf of this frame */ struct ath_buf *bf_next; /* next subframe in the aggregate */ - struct ath_buf *bf_rifslast; /* last buf for RIFS burst */ void *bf_mpdu; /* enclosing frame structure */ - void *bf_node; /* pointer to the node */ struct ath_desc *bf_desc; /* virtual addr of desc */ dma_addr_t bf_daddr; /* physical addr of desc */ dma_addr_t bf_buf_addr; /* physical addr of data buffer */ @@ -254,13 +260,6 @@ struct ath_buf { dma_addr_t bf_dmacontext; }; -/* - * reset the rx buffer. - * any new fields added to the athbuf and require - * reset need to be added to this macro. - * currently bf_status is the only one requires that - * requires reset. - */ #define ATH_RXBUF_RESET(_bf) ((_bf)->bf_status = 0) /* hw processing complete, desc processed by hal */ @@ -281,159 +280,81 @@ struct ath_descdma { dma_addr_t dd_dmacontext; }; -/* Abstraction of a received RX MPDU/MMPDU, or a RX fragment */ - -struct ath_rx_context { - struct ath_buf *ctx_rxbuf; /* associated ath_buf for rx */ -}; -#define ATH_RX_CONTEXT(skb) ((struct ath_rx_context *)skb->cb) - -int ath_descdma_setup(struct ath_softc *sc, - struct ath_descdma *dd, - struct list_head *head, - const char *name, - int nbuf, - int ndesc); -int ath_desc_alloc(struct ath_softc *sc); -void ath_desc_free(struct ath_softc *sc); -void ath_descdma_cleanup(struct ath_softc *sc, - struct ath_descdma *dd, +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head, const char *name, + int nbuf, int ndesc); +void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd, struct list_head *head); -/******/ -/* RX */ -/******/ - -#define ATH_MAX_ANTENNA 3 -#define ATH_RXBUF 512 -#define ATH_RX_TIMEOUT 40 /* 40 milliseconds */ -#define WME_NUM_TID 16 -#define IEEE80211_BAR_CTL_TID_M 0xF000 /* tid mask */ -#define IEEE80211_BAR_CTL_TID_S 12 /* tid shift */ - -enum ATH_RX_TYPE { - ATH_RX_NON_CONSUMED = 0, - ATH_RX_CONSUMED -}; - -/* per frame rx status block */ -struct ath_recv_status { - u64 tsf; /* mac tsf */ - int8_t rssi; /* RSSI (noise floor ajusted) */ - int8_t rssictl[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int8_t rssiextn[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int8_t abs_rssi; /* absolute RSSI */ - u8 rateieee; /* data rate received (IEEE rate code) */ - u8 ratecode; /* phy rate code */ - int rateKbps; /* data rate received (Kbps) */ - int antenna; /* rx antenna */ - int flags; /* status of associated skb */ -#define ATH_RX_FCS_ERROR 0x01 -#define ATH_RX_MIC_ERROR 0x02 -#define ATH_RX_DECRYPT_ERROR 0x04 -#define ATH_RX_RSSI_VALID 0x08 -/* if any of ctl,extn chainrssis are valid */ -#define ATH_RX_CHAIN_RSSI_VALID 0x10 -/* if extn chain rssis are valid */ -#define ATH_RX_RSSI_EXTN_VALID 0x20 -/* set if 40Mhz, clear if 20Mhz */ -#define ATH_RX_40MHZ 0x40 -/* set if short GI, clear if full GI */ -#define ATH_RX_SHORT_GI 0x80 -}; - -struct ath_rxbuf { - struct sk_buff *rx_wbuf; - unsigned long rx_time; /* system time when received */ - struct ath_recv_status rx_status; /* cached rx status */ -}; - -/* Per-TID aggregate receiver state for a node */ -struct ath_arx_tid { - struct ath_node *an; - struct ath_rxbuf *rxbuf; /* re-ordering buffer */ - struct timer_list timer; - spinlock_t tidlock; - int baw_head; /* seq_next at head */ - int baw_tail; /* tail of block-ack window */ - int seq_reset; /* need to reset start sequence */ - int addba_exchangecomplete; - u16 seq_next; /* next expected sequence */ - u16 baw_size; /* block-ack window size */ -}; - -/* Per-node receiver aggregate state */ -struct ath_arx { - struct ath_arx_tid tid[WME_NUM_TID]; -}; - -int ath_startrecv(struct ath_softc *sc); -bool ath_stoprecv(struct ath_softc *sc); -void ath_flushrecv(struct ath_softc *sc); -u32 ath_calcrxfilter(struct ath_softc *sc); -void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an); -void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an); -void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an); -void ath_handle_rx_intr(struct ath_softc *sc); -int ath_rx_init(struct ath_softc *sc, int nbufs); -void ath_rx_cleanup(struct ath_softc *sc); -int ath_rx_tasklet(struct ath_softc *sc, int flush); -int ath_rx_input(struct ath_softc *sc, - struct ath_node *node, - int is_ampdu, - struct sk_buff *skb, - struct ath_recv_status *rx_status, - enum ATH_RX_TYPE *status); -int _ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix); -int ath_rx_subframe(struct ath_node *an, struct sk_buff *skb, - struct ath_recv_status *status); - -/******/ -/* TX */ -/******/ +/***********/ +/* RX / TX */ +/***********/ +#define ATH_MAX_ANTENNA 3 +#define ATH_RXBUF 512 +#define WME_NUM_TID 16 #define ATH_TXBUF 512 -/* max number of transmit attempts (tries) */ #define ATH_TXMAXTRY 13 -/* max number of 11n transmit attempts (tries) */ #define ATH_11N_TXMAXTRY 10 -/* max number of tries for management and control frames */ #define ATH_MGT_TXMAXTRY 4 #define WME_BA_BMP_SIZE 64 #define WME_MAX_BA WME_BA_BMP_SIZE #define ATH_TID_MAX_BUFS (2 * WME_MAX_BA) + #define TID_TO_WME_AC(_tid) \ ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \ (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \ (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \ WME_AC_VO) +#define WME_AC_BE 0 +#define WME_AC_BK 1 +#define WME_AC_VI 2 +#define WME_AC_VO 3 +#define WME_NUM_AC 4 + +#define ADDBA_EXCHANGE_ATTEMPTS 10 +#define ATH_AGGR_DELIM_SZ 4 +#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ +/* number of delimiters for encryption padding */ +#define ATH_AGGR_ENCRYPTDELIM 10 +/* minimum h/w qdepth to be sustained to maximize aggregation */ +#define ATH_AGGR_MIN_QDEPTH 2 +#define ATH_AMPDU_SUBFRAME_DEFAULT 32 +#define IEEE80211_SEQ_SEQ_SHIFT 4 +#define IEEE80211_SEQ_MAX 4096 +#define IEEE80211_MIN_AMPDU_BUF 0x8 +#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 + +/* return whether a bit at index _n in bitmap _bm is set + * _sz is the size of the bitmap */ +#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \ + ((_bm)[(_n) >> 5] & (1 << ((_n) & 31)))) + +/* return block-ack bitmap index given sequence and starting sequence */ +#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) + +/* returns delimiter padding required given the packet length */ +#define ATH_AGGR_GET_NDELIM(_len) \ + (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ + (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) + +#define BAW_WITHIN(_start, _bawsz, _seqno) \ + ((((_seqno) - (_start)) & 4095) < (_bawsz)) -/* Wireless Multimedia Extension Defines */ -#define WME_AC_BE 0 /* best effort */ -#define WME_AC_BK 1 /* background */ -#define WME_AC_VI 2 /* video */ -#define WME_AC_VO 3 /* voice */ -#define WME_NUM_AC 4 +#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) +#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) +#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) +#define ATH_AN_2_TID(_an, _tidno) (&(_an)->tid[(_tidno)]) -enum ATH_SM_PWRSAV{ - ATH_SM_ENABLE, - ATH_SM_PWRSAV_STATIC, - ATH_SM_PWRSAV_DYNAMIC, +enum ATH_AGGR_STATUS { + ATH_AGGR_DONE, + ATH_AGGR_BAW_CLOSED, + ATH_AGGR_LIMITED, + ATH_AGGR_SHORTPKT, + ATH_AGGR_8K_LIMITED, }; -/* - * Data transmit queue state. One of these exists for each - * hardware transmit queue. Packets sent to us from above - * are assigned to queues based on their priority. Not all - * devices support a complete set of hardware transmit queues. - * For those devices the array sc_ac2q will map multiple - * priorities to fewer hardware queues (typically all to one - * hardware queue). - */ struct ath_txq { u32 axq_qnum; /* hardware q number */ u32 *axq_link; /* link ptr in last TX desc */ @@ -443,10 +364,6 @@ struct ath_txq { u32 axq_depth; /* queue depth */ u8 axq_aggr_depth; /* aggregates queued */ u32 axq_totalqueued; /* total ever queued */ - - /* count to determine if descriptor should generate int on this txq. */ - u32 axq_intrcnt; - bool stopped; /* Is mac80211 queue stopped ? */ struct ath_buf *axq_linkbuf; /* virtual addr of last buffer*/ @@ -460,6 +377,10 @@ struct ath_txq { struct list_head axq_acq; }; +#define AGGR_CLEANUP BIT(1) +#define AGGR_ADDBA_COMPLETE BIT(2) +#define AGGR_ADDBA_PROGRESS BIT(3) + /* per TID aggregate tx state for a destination */ struct ath_atx_tid { struct list_head list; /* round-robin tid entry */ @@ -475,9 +396,7 @@ struct ath_atx_tid { int baw_tail; /* next unused tx buffer slot */ int sched; int paused; - int cleanup_inprogress; - u32 addba_exchangecomplete:1; - int32_t addba_exchangeinprogress; + u8 state; int addba_exchangeattempts; }; @@ -490,32 +409,10 @@ struct ath_atx_ac { struct list_head tid_q; /* queue of TIDs with buffers */ }; -/* per dest tx state */ -struct ath_atx { - struct ath_atx_tid tid[WME_NUM_TID]; - struct ath_atx_ac ac[WME_NUM_AC]; -}; - /* per-frame tx control block */ struct ath_tx_control { - struct ath_node *an; + struct ath_txq *txq; int if_id; - int qnum; - u32 ht:1; - u32 ps:1; - u32 use_minrate:1; - enum ath9k_pkt_type atype; - enum ath9k_key_type keytype; - u32 flags; - u16 seqno; - u16 tidno; - u16 txpower; - u16 frmlen; - u32 keyix; - int min_rate; - int mcast_rate; - struct ath_softc *dev; - dma_addr_t dmacontext; }; /* per frame tx status block */ @@ -528,21 +425,63 @@ struct ath_xmit_status { #define ATH_TX_BAR 0x04 }; +/* All RSSI values are noise floor adjusted */ struct ath_tx_stat { - int rssi; /* RSSI (noise floor ajusted) */ - int rssictl[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int rssiextn[ATH_MAX_ANTENNA]; /* RSSI (noise floor ajusted) */ - int rateieee; /* data rate xmitted (IEEE rate code) */ - int rateKbps; /* data rate xmitted (Kbps) */ - int ratecode; /* phy rate code */ - int flags; /* validity flags */ -/* if any of ctl,extn chain rssis are valid */ -#define ATH_TX_CHAIN_RSSI_VALID 0x01 -/* if extn chain rssis are valid */ -#define ATH_TX_RSSI_EXTN_VALID 0x02 + int rssi; + int rssictl[ATH_MAX_ANTENNA]; + int rssiextn[ATH_MAX_ANTENNA]; + int rateieee; + int rateKbps; + int ratecode; + int flags; u32 airtime; /* time on air per final tx rate */ }; +struct aggr_rifs_param { + int param_max_frames; + int param_max_len; + int param_rl; + int param_al; + struct ath_rc_series *param_rcs; +}; + +struct ath_node { + struct ath_softc *an_sc; + struct ath_atx_tid tid[WME_NUM_TID]; + struct ath_atx_ac ac[WME_NUM_AC]; + u16 maxampdu; + u8 mpdudensity; +}; + +struct ath_tx { + u16 seq_no; + u32 txqsetup; + int hwq_map[ATH9K_WME_AC_VO+1]; + spinlock_t txbuflock; + struct list_head txbuf; + struct ath_txq txq[ATH9K_NUM_TX_QUEUES]; + struct ath_descdma txdma; +}; + +struct ath_rx { + u8 defant; + u8 rxotherant; + u32 *rxlink; + int bufsize; + unsigned int rxfilter; + spinlock_t rxflushlock; + spinlock_t rxbuflock; + struct list_head rxbuf; + struct ath_descdma rxdma; +}; + +int ath_startrecv(struct ath_softc *sc); +bool ath_stoprecv(struct ath_softc *sc); +void ath_flushrecv(struct ath_softc *sc); +u32 ath_calcrxfilter(struct ath_softc *sc); +int ath_rx_init(struct ath_softc *sc, int nbufs); +void ath_rx_cleanup(struct ath_softc *sc); +int ath_rx_tasklet(struct ath_softc *sc, int flush); struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype); void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_setup(struct ath_softc *sc, int haltype); @@ -550,139 +489,51 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx); void ath_tx_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx); void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an); -void ath_tx_node_cleanup(struct ath_softc *sc, - struct ath_node *an, bool bh_flag); +void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an); void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an); void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq); int ath_tx_init(struct ath_softc *sc, int nbufs); int ath_tx_cleanup(struct ath_softc *sc); int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype); +struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb); int ath_txq_update(struct ath_softc *sc, int qnum, struct ath9k_tx_queue_info *q); -int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb); +int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, + struct ath_tx_control *txctl); void ath_tx_tasklet(struct ath_softc *sc); u32 ath_txq_depth(struct ath_softc *sc, int qnum); u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum); -void ath_notify_txq_status(struct ath_softc *sc, u16 queue_depth); -void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_xmit_status *tx_status, struct ath_node *an); void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb); +void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid); +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno); +void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tidno); +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn); +int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid); -/**********************/ -/* Node / Aggregation */ -/**********************/ - -/* indicates the node is clened up */ -#define ATH_NODE_CLEAN 0x1 -/* indicates the node is 80211 power save */ -#define ATH_NODE_PWRSAVE 0x2 - -#define ADDBA_EXCHANGE_ATTEMPTS 10 -#define ATH_AGGR_DELIM_SZ 4 /* delimiter size */ -#define ATH_AGGR_MINPLEN 256 /* in bytes, minimum packet length */ -/* number of delimiters for encryption padding */ -#define ATH_AGGR_ENCRYPTDELIM 10 -/* minimum h/w qdepth to be sustained to maximize aggregation */ -#define ATH_AGGR_MIN_QDEPTH 2 -#define ATH_AMPDU_SUBFRAME_DEFAULT 32 -#define IEEE80211_SEQ_SEQ_SHIFT 4 -#define IEEE80211_SEQ_MAX 4096 -#define IEEE80211_MIN_AMPDU_BUF 0x8 - -/* return whether a bit at index _n in bitmap _bm is set - * _sz is the size of the bitmap */ -#define ATH_BA_ISSET(_bm, _n) (((_n) < (WME_BA_BMP_SIZE)) && \ - ((_bm)[(_n) >> 5] & (1 << ((_n) & 31)))) - -/* return block-ack bitmap index given sequence and starting sequence */ -#define ATH_BA_INDEX(_st, _seq) (((_seq) - (_st)) & (IEEE80211_SEQ_MAX - 1)) - -/* returns delimiter padding required given the packet length */ -#define ATH_AGGR_GET_NDELIM(_len) \ - (((((_len) + ATH_AGGR_DELIM_SZ) < ATH_AGGR_MINPLEN) ? \ - (ATH_AGGR_MINPLEN - (_len) - ATH_AGGR_DELIM_SZ) : 0) >> 2) - -#define BAW_WITHIN(_start, _bawsz, _seqno) \ - ((((_seqno) - (_start)) & 4095) < (_bawsz)) - -#define ATH_DS_BA_SEQ(_ds) ((_ds)->ds_us.tx.ts_seqnum) -#define ATH_DS_BA_BITMAP(_ds) (&(_ds)->ds_us.tx.ba_low) -#define ATH_DS_TX_BA(_ds) ((_ds)->ds_us.tx.ts_flags & ATH9K_TX_BA) -#define ATH_AN_2_TID(_an, _tidno) (&(_an)->an_aggr.tx.tid[(_tidno)]) - -enum ATH_AGGR_STATUS { - ATH_AGGR_DONE, - ATH_AGGR_BAW_CLOSED, - ATH_AGGR_LIMITED, - ATH_AGGR_SHORTPKT, - ATH_AGGR_8K_LIMITED, -}; - -enum ATH_AGGR_CHECK { - AGGR_NOT_REQUIRED, - AGGR_REQUIRED, - AGGR_CLEANUP_PROGRESS, - AGGR_EXCHANGE_PROGRESS, - AGGR_EXCHANGE_DONE -}; +/********/ +/* VAPs */ +/********/ -struct aggr_rifs_param { - int param_max_frames; - int param_max_len; - int param_rl; - int param_al; - struct ath_rc_series *param_rcs; -}; +/* + * Define the scheme that we select MAC address for multiple + * BSS on the same radio. The very first VAP will just use the MAC + * address from the EEPROM. For the next 3 VAPs, we set the + * U/L bit (bit 1) in MAC address, and use the next two bits as the + * index of the VAP. + */ -/* Per-node aggregation state */ -struct ath_node_aggr { - struct ath_atx tx; /* node transmit state */ - struct ath_arx rx; /* node receive state */ -}; +#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \ + ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02)) -/* driver-specific node state */ -struct ath_node { - struct list_head list; - struct ath_softc *an_sc; - atomic_t an_refcnt; - struct ath_chainmask_sel an_chainmask_sel; - struct ath_node_aggr an_aggr; - u8 an_smmode; /* SM Power save mode */ - u8 an_flags; - u8 an_addr[ETH_ALEN]; +struct ath_vap { + int av_bslot; + enum nl80211_iftype av_opmode; + struct ath_buf *av_bcbuf; + struct ath_tx_control av_btxctl; }; -void ath_tx_resume_tid(struct ath_softc *sc, - struct ath_atx_tid *tid); -enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, - struct ath_node *an, u8 tidno); -void ath_tx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tidno); -void ath_rx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tidno); -int ath_rx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn); -int ath_rx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid); -int ath_tx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn); -int ath_tx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid); -void ath_newassoc(struct ath_softc *sc, - struct ath_node *node, int isnew, int isuapsd); -struct ath_node *ath_node_attach(struct ath_softc *sc, - u8 addr[ETH_ALEN], int if_id); -void ath_node_detach(struct ath_softc *sc, struct ath_node *an, bool bh_flag); -struct ath_node *ath_node_get(struct ath_softc *sc, u8 addr[ETH_ALEN]); -void ath_node_put(struct ath_softc *sc, struct ath_node *an, bool bh_flag); -struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr); - /*******************/ /* Beacon Handling */ /*******************/ @@ -693,12 +544,11 @@ struct ath_node *ath_node_find(struct ath_softc *sc, u8 *addr); * number of beacon intervals, the game's up. */ #define BSTUCK_THRESH (9 * ATH_BCBUF) -#define ATH_BCBUF 4 /* number of beacon buffers */ -#define ATH_DEFAULT_BINTVAL 100 /* default beacon interval in TU */ +#define ATH_BCBUF 1 +#define ATH_DEFAULT_BINTVAL 100 /* TU */ #define ATH_DEFAULT_BMISS_LIMIT 10 #define IEEE80211_MS_TO_TU(x) (((x) * 1000) / 1024) -/* beacon configuration */ struct ath_beacon_config { u16 beacon_interval; u16 listen_interval; @@ -712,93 +562,32 @@ struct ath_beacon_config { } u; /* last received beacon/probe response timestamp of this BSS. */ }; +struct ath_beacon { + enum { + OK, /* no change needed */ + UPDATE, /* update pending */ + COMMIT /* beacon sent, commit change */ + } updateslot; /* slot time update fsm */ + + u32 beaconq; + u32 bmisscnt; + u32 ast_be_xmit; + u64 bc_tstamp; + int bslot[ATH_BCBUF]; + int slottime; + int slotupdate; + struct ath9k_tx_queue_info beacon_qi; + struct ath_descdma bdma; + struct ath_txq *cabq; + struct list_head bbuf; +}; + void ath9k_beacon_tasklet(unsigned long data); void ath_beacon_config(struct ath_softc *sc, int if_id); int ath_beaconq_setup(struct ath_hal *ah); int ath_beacon_alloc(struct ath_softc *sc, int if_id); -void ath_bstuck_process(struct ath_softc *sc); void ath_beacon_return(struct ath_softc *sc, struct ath_vap *avp); void ath_beacon_sync(struct ath_softc *sc, int if_id); -void ath_get_beaconconfig(struct ath_softc *sc, - int if_id, - struct ath_beacon_config *conf); -/********/ -/* VAPs */ -/********/ - -/* - * Define the scheme that we select MAC address for multiple - * BSS on the same radio. The very first VAP will just use the MAC - * address from the EEPROM. For the next 3 VAPs, we set the - * U/L bit (bit 1) in MAC address, and use the next two bits as the - * index of the VAP. - */ - -#define ATH_SET_VAP_BSSID_MASK(bssid_mask) \ - ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02)) - -/* VAP configuration (from protocol layer) */ -struct ath_vap_config { - u32 av_fixed_rateset; - u32 av_fixed_retryset; -}; - -/* driver-specific vap state */ -struct ath_vap { - struct ieee80211_vif *av_if_data; - enum ath9k_opmode av_opmode; /* VAP operational mode */ - struct ath_buf *av_bcbuf; /* beacon buffer */ - struct ath_tx_control av_btxctl; /* txctl information for beacon */ - int av_bslot; /* beacon slot index */ - struct ath_vap_config av_config;/* vap configuration parameters*/ - struct ath_rate_node *rc_node; -}; - -int ath_vap_attach(struct ath_softc *sc, - int if_id, - struct ieee80211_vif *if_data, - enum ath9k_opmode opmode); -int ath_vap_detach(struct ath_softc *sc, int if_id); -int ath_vap_config(struct ath_softc *sc, - int if_id, struct ath_vap_config *if_config); - -/*********************/ -/* Antenna diversity */ -/*********************/ - -#define ATH_ANT_DIV_MAX_CFG 2 -#define ATH_ANT_DIV_MIN_IDLE_US 1000000 /* us */ -#define ATH_ANT_DIV_MIN_SCAN_US 50000 /* us */ - -enum ATH_ANT_DIV_STATE{ - ATH_ANT_DIV_IDLE, - ATH_ANT_DIV_SCAN, /* evaluating antenna */ -}; - -struct ath_antdiv { - struct ath_softc *antdiv_sc; - u8 antdiv_start; - enum ATH_ANT_DIV_STATE antdiv_state; - u8 antdiv_num_antcfg; - u8 antdiv_curcfg; - u8 antdiv_bestcfg; - int32_t antdivf_rssitrig; - int32_t antdiv_lastbrssi[ATH_ANT_DIV_MAX_CFG]; - u64 antdiv_lastbtsf[ATH_ANT_DIV_MAX_CFG]; - u64 antdiv_laststatetsf; - u8 antdiv_bssid[ETH_ALEN]; -}; - -void ath_slow_ant_div_init(struct ath_antdiv *antdiv, - struct ath_softc *sc, int32_t rssitrig); -void ath_slow_ant_div_start(struct ath_antdiv *antdiv, - u8 num_antcfg, - const u8 *bssid); -void ath_slow_ant_div_stop(struct ath_antdiv *antdiv); -void ath_slow_ant_div(struct ath_antdiv *antdiv, - struct ieee80211_hdr *wh, - struct ath_rx_status *rx_stats); -void ath_setdefantenna(void *sc, u32 antenna); /*******/ /* ANI */ @@ -863,7 +652,7 @@ struct ath_rfkill { #define DEFAULT_CACHELINE 32 #define ATH_DEFAULT_NOISE_FLOOR -95 #define ATH_REGCLASSIDS_MAX 10 -#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ +#define ATH_CABQ_READY_TIME 80 /* % of beacon interval */ #define ATH_MAX_SW_RETRIES 10 #define ATH_CHAN_MAX 255 #define IEEE80211_WEP_NKID 4 /* number of key ids */ @@ -876,34 +665,12 @@ struct ath_rfkill { * Different parts have different size key caches. We handle * up to ATH_KEYMAX entries (could dynamically allocate state). */ -#define ATH_KEYMAX 128 /* max key cache size we handle */ +#define ATH_KEYMAX 128 /* max key cache size we handle */ #define ATH_IF_ID_ANY 0xff #define ATH_TXPOWER_MAX 100 /* .5 dBm units */ - -#define RSSI_LPF_THRESHOLD -20 -#define ATH_RSSI_EP_MULTIPLIER (1<<7) /* pow2 to optimize out * and / */ -#define ATH_RATE_DUMMY_MARKER 0 -#define ATH_RSSI_LPF_LEN 10 -#define ATH_RSSI_DUMMY_MARKER 0x127 - -#define ATH_EP_MUL(x, mul) ((x) * (mul)) -#define ATH_EP_RND(x, mul) \ - ((((x)%(mul)) >= ((mul)/2)) ? ((x) + ((mul) - 1)) / (mul) : (x)/(mul)) -#define ATH_RSSI_OUT(x) \ - (((x) != ATH_RSSI_DUMMY_MARKER) ? \ - (ATH_EP_RND((x), ATH_RSSI_EP_MULTIPLIER)) : ATH_RSSI_DUMMY_MARKER) -#define ATH_RSSI_IN(x) \ - (ATH_EP_MUL((x), ATH_RSSI_EP_MULTIPLIER)) -#define ATH_LPF_RSSI(x, y, len) \ - ((x != ATH_RSSI_DUMMY_MARKER) ? \ - (((x) * ((len) - 1) + (y)) / (len)) : (y)) -#define ATH_RSSI_LPF(x, y) do { \ - if ((y) >= RSSI_LPF_THRESHOLD) \ - x = ATH_LPF_RSSI((x), \ - ATH_RSSI_IN((y)), ATH_RSSI_LPF_LEN); \ - } while (0) - +#define ATH_RSSI_DUMMY_MARKER 0x127 +#define ATH_RATE_DUMMY_MARKER 0 enum PROT_MODE { PROT_M_NONE = 0, @@ -911,19 +678,6 @@ enum PROT_MODE { PROT_M_CTSONLY }; -enum RATE_TYPE { - NORMAL_RATE = 0, - HALF_RATE, - QUARTER_RATE -}; - -struct ath_ht_info { - enum ath9k_ht_macmode tx_chan_width; - u16 maxampdu; - u8 mpdudensity; - u8 ext_chan_offset; -}; - #define SC_OP_INVALID BIT(0) #define SC_OP_BEACONS BIT(1) #define SC_OP_RXAGGR BIT(2) @@ -944,141 +698,57 @@ struct ath_softc { struct pci_dev *pdev; struct tasklet_struct intr_tq; struct tasklet_struct bcon_tasklet; - struct ath_config sc_config; struct ath_hal *sc_ah; - struct ath_rate_softc *sc_rc; void __iomem *mem; + spinlock_t sc_resetlock; + struct mutex mutex; u8 sc_curbssid[ETH_ALEN]; u8 sc_myaddr[ETH_ALEN]; u8 sc_bssidmask[ETH_ALEN]; - - int sc_debug; u32 sc_intrstatus; u32 sc_flags; /* SC_OP_* */ - unsigned int rx_filter; u16 sc_curtxpow; u16 sc_curaid; u16 sc_cachelsz; - int sc_slotupdate; /* slot to next advance fsm */ - int sc_slottime; - int sc_bslot[ATH_BCBUF]; + u8 sc_nbcnvaps; + u16 sc_nvaps; u8 sc_tx_chainmask; u8 sc_rx_chainmask; + u32 sc_keymax; + DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); + u8 sc_splitmic; + u8 sc_protrix; enum ath9k_int sc_imask; - enum wireless_mode sc_curmode; /* current phy mode */ enum PROT_MODE sc_protmode; - - u8 sc_nbcnvaps; /* # of vaps sending beacons */ - u16 sc_nvaps; /* # of active virtual ap's */ - struct ath_vap *sc_vaps[ATH_BCBUF]; - - u8 sc_mcastantenna; - u8 sc_defant; /* current default antenna */ - u8 sc_rxotherant; /* rx's on non-default antenna */ - - struct ath9k_node_stats sc_halstats; /* station-mode rssi stats */ - struct list_head node_list; - struct ath_ht_info sc_ht_info; enum ath9k_ht_extprotspacing sc_ht_extprotspacing; + enum ath9k_ht_macmode tx_chan_width; -#ifdef CONFIG_SLOW_ANT_DIV - struct ath_antdiv sc_antdiv; -#endif - enum { - OK, /* no change needed */ - UPDATE, /* update pending */ - COMMIT /* beacon sent, commit change */ - } sc_updateslot; /* slot time update fsm */ - - /* Crypto */ - u32 sc_keymax; /* size of key cache */ - DECLARE_BITMAP(sc_keymap, ATH_KEYMAX); /* key use bit map */ - u8 sc_splitmic; /* split TKIP MIC keys */ - - /* RX */ - struct list_head sc_rxbuf; - struct ath_descdma sc_rxdma; - int sc_rxbufsize; /* rx size based on mtu */ - u32 *sc_rxlink; /* link ptr in last RX desc */ - - /* TX */ - struct list_head sc_txbuf; - struct ath_txq sc_txq[ATH9K_NUM_TX_QUEUES]; - struct ath_descdma sc_txdma; - u32 sc_txqsetup; - u32 sc_txintrperiod; /* tx interrupt batching */ - int sc_haltype2q[ATH9K_WME_AC_VO+1]; /* HAL WME AC -> h/w qnum */ - u16 seq_no; /* TX sequence number */ - - /* Beacon */ - struct ath9k_tx_queue_info sc_beacon_qi; - struct ath_descdma sc_bdma; - struct ath_txq *sc_cabq; - struct list_head sc_bbuf; - u32 sc_bhalq; - u32 sc_bmisscount; - u32 ast_be_xmit; /* beacons transmitted */ - u64 bc_tstamp; - - /* Rate */ + struct ath_config sc_config; + struct ath_rx rx; + struct ath_tx tx; + struct ath_beacon beacon; + struct ieee80211_vif *sc_vaps[ATH_BCBUF]; struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX]; - const struct ath9k_rate_table *sc_currates; - u8 sc_rixmap[256]; /* IEEE to h/w rate table ix */ - u8 sc_protrix; /* protection rate index */ - struct { - u32 rateKbps; /* transfer rate in kbs */ - u8 ieeerate; /* IEEE rate */ - } sc_hwmap[256]; /* h/w rate ix mappings */ - - /* Channel, Band */ + struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX]; + struct ath_rate_table *cur_rate_table; struct ieee80211_channel channels[IEEE80211_NUM_BANDS][ATH_CHAN_MAX]; struct ieee80211_supported_band sbands[IEEE80211_NUM_BANDS]; - - /* Locks */ - spinlock_t sc_rxflushlock; - spinlock_t sc_rxbuflock; - spinlock_t sc_txbuflock; - spinlock_t sc_resetlock; - spinlock_t node_lock; - - /* LEDs */ struct ath_led radio_led; struct ath_led assoc_led; struct ath_led tx_led; struct ath_led rx_led; - - /* Rfkill */ struct ath_rfkill rf_kill; - - /* ANI */ struct ath_ani sc_ani; + struct ath9k_node_stats sc_halstats; +#ifdef CONFIG_ATH9K_DEBUG + struct ath9k_debug sc_debug; +#endif }; -int ath_init(u16 devid, struct ath_softc *sc); -void ath_deinit(struct ath_softc *sc); -int ath_open(struct ath_softc *sc, struct ath9k_channel *initial_chan); -int ath_suspend(struct ath_softc *sc); -irqreturn_t ath_isr(int irq, void *dev); int ath_reset(struct ath_softc *sc, bool retry_tx); -int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan); - -/*********************/ -/* Utility Functions */ -/*********************/ - -void ath_key_reset(struct ath_softc *sc, u16 keyix, int freeslot); -int ath_keyset(struct ath_softc *sc, - u16 keyix, - struct ath9k_keyval *hk, - const u8 mac[ETH_ALEN]); int ath_get_hal_qnum(u16 queue, struct ath_softc *sc); int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc); -void ath_setslottime(struct ath_softc *sc); -void ath_update_txpow(struct ath_softc *sc); int ath_cabq_update(struct ath_softc *); -void ath_get_currentCountry(struct ath_softc *sc, - struct ath9k_country_entry *ctry); -u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp); #endif /* CORE_H */ diff --git a/drivers/net/wireless/ath9k/debug.c b/drivers/net/wireless/ath9k/debug.c new file mode 100644 index 0000000000000000000000000000000000000000..a80ed576830f0238f07ac003a8c8c579d52c86cc --- /dev/null +++ b/drivers/net/wireless/ath9k/debug.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "reg.h" +#include "hw.h" + +static unsigned int ath9k_debug = DBG_DEFAULT; +module_param_named(debug, ath9k_debug, uint, 0); + +void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...) +{ + if (!sc) + return; + + if (sc->sc_debug.debug_mask & dbg_mask) { + va_list args; + + va_start(args, fmt); + printk(KERN_DEBUG "ath9k: "); + vprintk(fmt, args); + va_end(args); + } +} + +static int ath9k_debugfs_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t read_file_dma(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + struct ath_hal *ah = sc->sc_ah; + char buf[1024]; + unsigned int len = 0; + u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; + int i, qcuOffset = 0, dcuOffset = 0; + u32 *qcuBase = &val[0], *dcuBase = &val[4]; + + REG_WRITE(ah, AR_MACMISC, + ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | + (AR_MACMISC_MISC_OBS_BUS_1 << + AR_MACMISC_MISC_OBS_BUS_MSB_S))); + + len += snprintf(buf + len, sizeof(buf) - len, + "Raw DMA Debug values:\n"); + + for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { + if (i % 4 == 0) + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + + val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); + len += snprintf(buf + len, sizeof(buf) - len, "%d: %08x ", + i, val[i]); + } + + len += snprintf(buf + len, sizeof(buf) - len, "\n\n"); + len += snprintf(buf + len, sizeof(buf) - len, + "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); + + for (i = 0; i < ATH9K_NUM_QUEUES; i++, qcuOffset += 4, dcuOffset += 5) { + if (i == 8) { + qcuOffset = 0; + qcuBase++; + } + + if (i == 6) { + dcuOffset = 0; + dcuBase++; + } + + len += snprintf(buf + len, sizeof(buf) - len, + "%2d %2x %1x %2x %2x\n", + i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, + (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + 3), + val[2] & (0x7 << (i * 3)) >> (i * 3), + (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); + } + + len += snprintf(buf + len, sizeof(buf) - len, "\n"); + + len += snprintf(buf + len, sizeof(buf) - len, + "qcu_stitch state: %2x qcu_fetch state: %2x\n", + (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); + len += snprintf(buf + len, sizeof(buf) - len, + "qcu_complete state: %2x dcu_complete state: %2x\n", + (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); + len += snprintf(buf + len, sizeof(buf) - len, + "dcu_arb state: %2x dcu_fp state: %2x\n", + (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); + len += snprintf(buf + len, sizeof(buf) - len, + "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", + (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); + len += snprintf(buf + len, sizeof(buf) - len, + "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", + (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); + len += snprintf(buf + len, sizeof(buf) - len, + "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", + (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); + + len += snprintf(buf + len, sizeof(buf) - len, "pcu observe: 0x%x \n", + REG_READ(ah, AR_OBS_BUS_1)); + len += snprintf(buf + len, sizeof(buf) - len, + "AR_CR: 0x%x \n", REG_READ(ah, AR_CR)); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_dma = { + .read = read_file_dma, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + + +void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status) +{ + if (status) + sc->sc_debug.stats.istats.total++; + if (status & ATH9K_INT_RX) + sc->sc_debug.stats.istats.rxok++; + if (status & ATH9K_INT_RXEOL) + sc->sc_debug.stats.istats.rxeol++; + if (status & ATH9K_INT_RXORN) + sc->sc_debug.stats.istats.rxorn++; + if (status & ATH9K_INT_TX) + sc->sc_debug.stats.istats.txok++; + if (status & ATH9K_INT_TXURN) + sc->sc_debug.stats.istats.txurn++; + if (status & ATH9K_INT_MIB) + sc->sc_debug.stats.istats.mib++; + if (status & ATH9K_INT_RXPHY) + sc->sc_debug.stats.istats.rxphyerr++; + if (status & ATH9K_INT_RXKCM) + sc->sc_debug.stats.istats.rx_keycache_miss++; + if (status & ATH9K_INT_SWBA) + sc->sc_debug.stats.istats.swba++; + if (status & ATH9K_INT_BMISS) + sc->sc_debug.stats.istats.bmiss++; + if (status & ATH9K_INT_BNR) + sc->sc_debug.stats.istats.bnr++; + if (status & ATH9K_INT_CST) + sc->sc_debug.stats.istats.cst++; + if (status & ATH9K_INT_GTT) + sc->sc_debug.stats.istats.gtt++; + if (status & ATH9K_INT_TIM) + sc->sc_debug.stats.istats.tim++; + if (status & ATH9K_INT_CABEND) + sc->sc_debug.stats.istats.cabend++; + if (status & ATH9K_INT_DTIMSYNC) + sc->sc_debug.stats.istats.dtimsync++; + if (status & ATH9K_INT_DTIM) + sc->sc_debug.stats.istats.dtim++; +} + +static ssize_t read_file_interrupt(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct ath_softc *sc = file->private_data; + char buf[512]; + unsigned int len = 0; + + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RX", sc->sc_debug.stats.istats.rxok); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXEOL", sc->sc_debug.stats.istats.rxeol); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXORN", sc->sc_debug.stats.istats.rxorn); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TX", sc->sc_debug.stats.istats.txok); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TXURN", sc->sc_debug.stats.istats.txurn); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "MIB", sc->sc_debug.stats.istats.mib); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXPHY", sc->sc_debug.stats.istats.rxphyerr); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "RXKCM", sc->sc_debug.stats.istats.rx_keycache_miss); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "SWBA", sc->sc_debug.stats.istats.swba); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "BMISS", sc->sc_debug.stats.istats.bmiss); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "BNR", sc->sc_debug.stats.istats.bnr); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "CST", sc->sc_debug.stats.istats.cst); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "GTT", sc->sc_debug.stats.istats.gtt); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TIM", sc->sc_debug.stats.istats.tim); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "CABEND", sc->sc_debug.stats.istats.cabend); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "DTIMSYNC", sc->sc_debug.stats.istats.dtimsync); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "DTIM", sc->sc_debug.stats.istats.dtim); + len += snprintf(buf + len, sizeof(buf) - len, + "%8s: %10u\n", "TOTAL", sc->sc_debug.stats.istats.total); + + return simple_read_from_buffer(user_buf, count, ppos, buf, len); +} + +static const struct file_operations fops_interrupt = { + .read = read_file_interrupt, + .open = ath9k_debugfs_open, + .owner = THIS_MODULE +}; + +int ath9k_init_debug(struct ath_softc *sc) +{ + sc->sc_debug.debug_mask = ath9k_debug; + + sc->sc_debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL); + if (!sc->sc_debug.debugfs_root) + goto err; + + sc->sc_debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy), + sc->sc_debug.debugfs_root); + if (!sc->sc_debug.debugfs_phy) + goto err; + + sc->sc_debug.debugfs_dma = debugfs_create_file("dma", S_IRUGO, + sc->sc_debug.debugfs_phy, sc, &fops_dma); + if (!sc->sc_debug.debugfs_dma) + goto err; + + sc->sc_debug.debugfs_interrupt = debugfs_create_file("interrupt", + S_IRUGO, + sc->sc_debug.debugfs_phy, + sc, &fops_interrupt); + if (!sc->sc_debug.debugfs_interrupt) + goto err; + + return 0; +err: + ath9k_exit_debug(sc); + return -ENOMEM; +} + +void ath9k_exit_debug(struct ath_softc *sc) +{ + debugfs_remove(sc->sc_debug.debugfs_interrupt); + debugfs_remove(sc->sc_debug.debugfs_dma); + debugfs_remove(sc->sc_debug.debugfs_phy); + debugfs_remove(sc->sc_debug.debugfs_root); +} diff --git a/drivers/net/wireless/ath9k/eeprom.c b/drivers/net/wireless/ath9k/eeprom.c new file mode 100644 index 0000000000000000000000000000000000000000..acd6c5374d44c1cca46ecaca40009f9051ec11cf --- /dev/null +++ b/drivers/net/wireless/ath9k/eeprom.c @@ -0,0 +1,2824 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah, + u32 reg, u32 mask, + u32 shift, u32 val) +{ + u32 regVal; + + regVal = REG_READ(ah, reg) & ~mask; + regVal |= (val << shift) & mask; + + REG_WRITE(ah, reg, regVal); + + if (ah->ah_config.analog_shiftreg) + udelay(100); + + return; +} + +static inline u16 ath9k_hw_fbin2freq(u8 fbin, bool is2GHz) +{ + + if (fbin == AR5416_BCHAN_UNUSED) + return fbin; + + return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); +} + +static inline int16_t ath9k_hw_interpolate(u16 target, + u16 srcLeft, u16 srcRight, + int16_t targetLeft, + int16_t targetRight) +{ + int16_t rv; + + if (srcRight == srcLeft) { + rv = targetLeft; + } else { + rv = (int16_t) (((target - srcLeft) * targetRight + + (srcRight - target) * targetLeft) / + (srcRight - srcLeft)); + } + return rv; +} + +static inline bool ath9k_hw_get_lower_upper_index(u8 target, u8 *pList, + u16 listSize, u16 *indexL, + u16 *indexR) +{ + u16 i; + + if (target <= pList[0]) { + *indexL = *indexR = 0; + return true; + } + if (target >= pList[listSize - 1]) { + *indexL = *indexR = (u16) (listSize - 1); + return true; + } + + for (i = 0; i < listSize - 1; i++) { + if (pList[i] == target) { + *indexL = *indexR = i; + return true; + } + if (target < pList[i + 1]) { + *indexL = i; + *indexR = (u16) (i + 1); + return false; + } + } + return false; +} + +static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, u16 *data) +{ + (void)REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + + if (!ath9k_hw_wait(ah, + AR_EEPROM_STATUS_DATA, + AR_EEPROM_STATUS_DATA_BUSY | + AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) { + return false; + } + + *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), + AR_EEPROM_STATUS_DATA_VAL); + + return true; +} + +static int ath9k_hw_flash_map(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX); + + if (!ahp->ah_cal_mem) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "cannot remap eeprom region \n"); + return -EIO; + } + + return 0; +} + +static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, u16 *data) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + *data = ioread16(ahp->ah_cal_mem + off); + + return true; +} + +static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, u32 off, u16 *data) +{ + if (ath9k_hw_use_flash(ah)) + return ath9k_hw_flash_read(ah, off, data); + else + return ath9k_hw_eeprom_read(ah, off, data); +} + +static bool ath9k_hw_fill_4k_eeprom(struct ath_hal *ah) +{ +#define SIZE_EEPROM_4K (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + u16 *eep_data; + int addr, eep_start_loc = 0; + + eep_start_loc = 64; + + if (!ath9k_hw_use_flash(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading from EEPROM, not flash\n"); + } + + eep_data = (u16 *)eep; + + for (addr = 0; addr < SIZE_EEPROM_4K; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + eep_start_loc, eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region \n"); + return false; + } + eep_data++; + } + return true; +#undef SIZE_EEPROM_4K +} + +static bool ath9k_hw_fill_def_eeprom(struct ath_hal *ah) +{ +#define SIZE_EEPROM_DEF (sizeof(struct ar5416_eeprom_def) / sizeof(u16)) + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + u16 *eep_data; + int addr, ar5416_eep_start_loc = 0x100; + + eep_data = (u16 *)eep; + + for (addr = 0; addr < SIZE_EEPROM_DEF; addr++) { + if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, + eep_data)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Unable to read eeprom region\n"); + return false; + } + eep_data++; + } + return true; +#undef SIZE_EEPROM_DEF +} + +static bool (*ath9k_fill_eeprom[]) (struct ath_hal *) = { + ath9k_hw_fill_def_eeprom, + ath9k_hw_fill_4k_eeprom +}; + +static inline bool ath9k_hw_fill_eeprom(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_fill_eeprom[ahp->ah_eep_map](ah); +} + +static int ath9k_hw_check_def_eeprom(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = + (struct ar5416_eeprom_def *) &ahp->ah_eeprom.def; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr, size; + + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, + &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading Magic # failed\n"); + return false; + } + + if (!ath9k_hw_use_flash(ah)) { + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + size = sizeof(struct ar5416_eeprom_def); + need_swap = true; + eepdata = (u16 *) (&ahp->ah_eeprom); + + for (addr = 0; addr < size / sizeof(u16); addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "0x%04X ", *eepdata); + + if (((addr + 1) % 6) == 0) + DPRINTF(ah->ah_sc, + ATH_DBG_EEPROM, "\n"); + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ahp->ah_eeprom.def.baseEepHeader.length); + else + el = ahp->ah_eeprom.def.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_def)) + el = sizeof(struct ar5416_eeprom_def) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ahp->ah_eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer, j; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing \n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { + struct modal_eep_header *pModal = + &eep->modalHeader[j]; + integer = swab32(pModal->antCtrlCommon); + pModal->antCtrlCommon = integer; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = swab32(pModal->antCtrlChain[i]); + pModal->antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(pModal->spurChans[i].spurChan); + pModal->spurChans[i].spurChan = word; + } + } + } + + if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER || + ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ar5416_get_eep_ver(ahp)); + return -EINVAL; + } + + return 0; +} + +static int ath9k_hw_check_4k_eeprom(struct ath_hal *ah) +{ +#define EEPROM_4K_SIZE (sizeof(struct ar5416_eeprom_4k) / sizeof(u16)) + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = + (struct ar5416_eeprom_4k *) &ahp->ah_eeprom.map4k; + u16 *eepdata, temp, magic, magic2; + u32 sum = 0, el; + bool need_swap = false; + int i, addr; + + + if (!ath9k_hw_use_flash(ah)) { + + if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, + &magic)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Reading Magic # failed\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Read Magic = 0x%04X\n", magic); + + if (magic != AR5416_EEPROM_MAGIC) { + magic2 = swab16(magic); + + if (magic2 == AR5416_EEPROM_MAGIC) { + need_swap = true; + eepdata = (u16 *) (&ahp->ah_eeprom); + + for (addr = 0; addr < EEPROM_4K_SIZE; addr++) { + temp = swab16(*eepdata); + *eepdata = temp; + eepdata++; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "0x%04X ", *eepdata); + + if (((addr + 1) % 6) == 0) + DPRINTF(ah->ah_sc, + ATH_DBG_EEPROM, "\n"); + } + } else { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Invalid EEPROM Magic. " + "endianness mismatch.\n"); + return -EINVAL; + } + } + } + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", + need_swap ? "True" : "False"); + + if (need_swap) + el = swab16(ahp->ah_eeprom.map4k.baseEepHeader.length); + else + el = ahp->ah_eeprom.map4k.baseEepHeader.length; + + if (el > sizeof(struct ar5416_eeprom_def)) + el = sizeof(struct ar5416_eeprom_4k) / sizeof(u16); + else + el = el / sizeof(u16); + + eepdata = (u16 *)(&ahp->ah_eeprom); + + for (i = 0; i < el; i++) + sum ^= *eepdata++; + + if (need_swap) { + u32 integer; + u16 word; + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Endianness is not native.. Changing \n"); + + word = swab16(eep->baseEepHeader.length); + eep->baseEepHeader.length = word; + + word = swab16(eep->baseEepHeader.checksum); + eep->baseEepHeader.checksum = word; + + word = swab16(eep->baseEepHeader.version); + eep->baseEepHeader.version = word; + + word = swab16(eep->baseEepHeader.regDmn[0]); + eep->baseEepHeader.regDmn[0] = word; + + word = swab16(eep->baseEepHeader.regDmn[1]); + eep->baseEepHeader.regDmn[1] = word; + + word = swab16(eep->baseEepHeader.rfSilent); + eep->baseEepHeader.rfSilent = word; + + word = swab16(eep->baseEepHeader.blueToothOptions); + eep->baseEepHeader.blueToothOptions = word; + + word = swab16(eep->baseEepHeader.deviceCap); + eep->baseEepHeader.deviceCap = word; + + integer = swab32(eep->modalHeader.antCtrlCommon); + eep->modalHeader.antCtrlCommon = integer; + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + integer = swab32(eep->modalHeader.antCtrlChain[i]); + eep->modalHeader.antCtrlChain[i] = integer; + } + + for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { + word = swab16(eep->modalHeader.spurChans[i].spurChan); + eep->modalHeader.spurChans[i].spurChan = word; + } + } + + if (sum != 0xffff || ar5416_get_eep4k_ver(ahp) != AR5416_EEP_VER || + ar5416_get_eep4k_rev(ahp) < AR5416_EEP_NO_BACK_VER) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "Bad EEPROM checksum 0x%x or revision 0x%04x\n", + sum, ar5416_get_eep4k_ver(ahp)); + return -EINVAL; + } + + return 0; +#undef EEPROM_4K_SIZE +} + +static int (*ath9k_check_eeprom[]) (struct ath_hal *) = { + ath9k_hw_check_def_eeprom, + ath9k_hw_check_4k_eeprom +}; + +static inline int ath9k_hw_check_eeprom(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_check_eeprom[ahp->ah_eep_map](ah); +} + +static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, u8 pwrMax, u8 *pPwrList, + u8 *pVpdList, u16 numIntercepts, + u8 *pRetVpdList) +{ + u16 i, k; + u8 currPwr = pwrMin; + u16 idxL = 0, idxR = 0; + + for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { + ath9k_hw_get_lower_upper_index(currPwr, pPwrList, + numIntercepts, &(idxL), + &(idxR)); + if (idxR < 1) + idxR = 1; + if (idxL == numIntercepts - 1) + idxL = (u16) (numIntercepts - 2); + if (pPwrList[idxL] == pPwrList[idxR]) + k = pVpdList[idxL]; + else + k = (u16)(((currPwr - pPwrList[idxL]) * pVpdList[idxR] + + (pPwrList[idxR] - currPwr) * pVpdList[idxL]) / + (pPwrList[idxR] - pPwrList[idxL])); + pRetVpdList[i] = (u8) k; + currPwr += 2; + } + + return true; +} + +static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq_4k *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ +#define TMP_VAL_VPD_TABLE \ + ((vpdTableI[i][sizeCurrVpdTable - 1] + (ss - maxIndex + 1) * vpdStep)); + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_EEP4K_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_EEP4K_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; +#define PD_GAIN_BOUNDARY_DEFAULT 58; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index( + (u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), bChans, numPiers, + &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_EEP4K_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_EEP4K_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_EEP4K_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) + pPDADCValues[k++] = vpdTableI[i][ss++]; + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t) TMP_VAL_VPD_TABLE; + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_EEP4K_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = PD_GAIN_BOUNDARY_DEFAULT; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +#undef TMP_VAL_VPD_TABLE +} + +static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_data_per_freq *pRawDataSet, + u8 *bChans, u16 availPiers, + u16 tPdGainOverlap, int16_t *pMinCalPower, + u16 *pPdGainBoundaries, u8 *pPDADCValues, + u16 numXpdGains) +{ + int i, j, k; + int16_t ss; + u16 idxL = 0, idxR = 0, numPiers; + static u8 vpdTableL[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableR[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + static u8 vpdTableI[AR5416_NUM_PD_GAINS] + [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; + + u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; + u8 minPwrT4[AR5416_NUM_PD_GAINS]; + u8 maxPwrT4[AR5416_NUM_PD_GAINS]; + int16_t vpdStep; + int16_t tmpVal; + u16 sizeCurrVpdTable, maxIndex, tgtIndex; + bool match; + int16_t minDelta = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + for (numPiers = 0; numPiers < availPiers; numPiers++) { + if (bChans[numPiers] == AR5416_BCHAN_UNUSED) + break; + } + + match = ath9k_hw_get_lower_upper_index((u8)FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)), + bChans, numPiers, &idxL, &idxR); + + if (match) { + for (i = 0; i < numXpdGains; i++) { + minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; + maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pRawDataSet[idxL].pwrPdg[i], + pRawDataSet[idxL].vpdPdg[i], + AR5416_PD_GAIN_ICEPTS, + vpdTableI[i]); + } + } else { + for (i = 0; i < numXpdGains; i++) { + pVpdL = pRawDataSet[idxL].vpdPdg[i]; + pPwrL = pRawDataSet[idxL].pwrPdg[i]; + pVpdR = pRawDataSet[idxR].vpdPdg[i]; + pPwrR = pRawDataSet[idxR].pwrPdg[i]; + + minPwrT4[i] = max(pPwrL[0], pPwrR[0]); + + maxPwrT4[i] = + min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], + pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); + + + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrL, pVpdL, + AR5416_PD_GAIN_ICEPTS, + vpdTableL[i]); + ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], + pPwrR, pVpdR, + AR5416_PD_GAIN_ICEPTS, + vpdTableR[i]); + + for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { + vpdTableI[i][j] = + (u8)(ath9k_hw_interpolate((u16) + FREQ2FBIN(centers. + synth_center, + IS_CHAN_2GHZ + (chan)), + bChans[idxL], bChans[idxR], + vpdTableL[i][j], vpdTableR[i][j])); + } + } + } + + *pMinCalPower = (int16_t)(minPwrT4[0] / 2); + + k = 0; + + for (i = 0; i < numXpdGains; i++) { + if (i == (numXpdGains - 1)) + pPdGainBoundaries[i] = + (u16)(maxPwrT4[i] / 2); + else + pPdGainBoundaries[i] = + (u16)((maxPwrT4[i] + minPwrT4[i + 1]) / 4); + + pPdGainBoundaries[i] = + min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]); + + if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { + minDelta = pPdGainBoundaries[0] - 23; + pPdGainBoundaries[0] = 23; + } else { + minDelta = 0; + } + + if (i == 0) { + if (AR_SREV_9280_10_OR_LATER(ah)) + ss = (int16_t)(0 - (minPwrT4[i] / 2)); + else + ss = 0; + } else { + ss = (int16_t)((pPdGainBoundaries[i - 1] - + (minPwrT4[i] / 2)) - + tPdGainOverlap + 1 + minDelta); + } + vpdStep = (int16_t)(vpdTableI[i][1] - vpdTableI[i][0]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)(vpdTableI[i][0] + ss * vpdStep); + pPDADCValues[k++] = (u8)((tmpVal < 0) ? 0 : tmpVal); + ss++; + } + + sizeCurrVpdTable = (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); + tgtIndex = (u8)(pPdGainBoundaries[i] + tPdGainOverlap - + (minPwrT4[i] / 2)); + maxIndex = (tgtIndex < sizeCurrVpdTable) ? + tgtIndex : sizeCurrVpdTable; + + while ((ss < maxIndex) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { + pPDADCValues[k++] = vpdTableI[i][ss++]; + } + + vpdStep = (int16_t)(vpdTableI[i][sizeCurrVpdTable - 1] - + vpdTableI[i][sizeCurrVpdTable - 2]); + vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep); + + if (tgtIndex > maxIndex) { + while ((ss <= tgtIndex) && + (k < (AR5416_NUM_PDADC_VALUES - 1))) { + tmpVal = (int16_t)((vpdTableI[i][sizeCurrVpdTable - 1] + + (ss - maxIndex + 1) * vpdStep)); + pPDADCValues[k++] = (u8)((tmpVal > 255) ? + 255 : tmpVal); + ss++; + } + } + } + + while (i < AR5416_PD_GAINS_IN_MASK) { + pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; + i++; + } + + while (k < AR5416_NUM_PDADC_VALUES) { + pPDADCValues[k] = pPDADCValues[k - 1]; + k++; + } + + return; +} + +static void ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_target_power_leg *powInfo, + u16 numChannels, + struct cal_target_power_leg *pNewPower, + u16 numRates, bool isExtTarget) +{ + struct chan_centers centers; + u16 clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + u16 freq; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; + + if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && + (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) && + (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan)))) { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) + matchIndex = i - 1; + } + + if (matchIndex != -1) { + *pNewPower = powInfo[matchIndex]; + } else { + clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, + IS_CHAN_2GHZ(chan)); + chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, + IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = + (u8)ath9k_hw_interpolate(freq, clo, chi, + powInfo[lowIndex].tPow2x[i], + powInfo[lowIndex + 1].tPow2x[i]); + } + } +} + +static void ath9k_hw_get_target_powers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct cal_target_power_ht *powInfo, + u16 numChannels, + struct cal_target_power_ht *pNewPower, + u16 numRates, bool isHt40Target) +{ + struct chan_centers centers; + u16 clo, chi; + int i; + int matchIndex = -1, lowIndex = -1; + u16 freq; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = isHt40Target ? centers.synth_center : centers.ctl_center; + + if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { + matchIndex = 0; + } else { + for (i = 0; (i < numChannels) && + (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) { + matchIndex = i; + break; + } else + if ((freq < ath9k_hw_fbin2freq(powInfo[i].bChannel, + IS_CHAN_2GHZ(chan))) && + (freq > ath9k_hw_fbin2freq(powInfo[i - 1].bChannel, + IS_CHAN_2GHZ(chan)))) { + lowIndex = i - 1; + break; + } + } + if ((matchIndex == -1) && (lowIndex == -1)) + matchIndex = i - 1; + } + + if (matchIndex != -1) { + *pNewPower = powInfo[matchIndex]; + } else { + clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, + IS_CHAN_2GHZ(chan)); + chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, + IS_CHAN_2GHZ(chan)); + + for (i = 0; i < numRates; i++) { + pNewPower->tPow2x[i] = (u8)ath9k_hw_interpolate(freq, + clo, chi, + powInfo[lowIndex].tPow2x[i], + powInfo[lowIndex + 1].tPow2x[i]); + } + } +} + +static u16 ath9k_hw_get_max_edge_power(u16 freq, + struct cal_ctl_edges *pRdEdgesPower, + bool is2GHz, int num_band_edges) +{ + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + int i; + + for (i = 0; (i < num_band_edges) && + (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { + if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, is2GHz)) { + twiceMaxEdgePower = pRdEdgesPower[i].tPower; + break; + } else if ((i > 0) && + (freq < ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, + is2GHz))) { + if (ath9k_hw_fbin2freq(pRdEdgesPower[i - 1].bChannel, + is2GHz) < freq && + pRdEdgesPower[i - 1].flag) { + twiceMaxEdgePower = + pRdEdgesPower[i - 1].tPower; + } + break; + } + } + + return twiceMaxEdgePower; +} + +static bool ath9k_hw_set_def_power_cal_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; + struct cal_data_per_freq *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u32 reg32, regOffset, regChainOffset; + int16_t modalIdx; + + modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; + xpdMask = pEepData->modalHeader[modalIdx].xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader[modalIdx].pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + if (IS_CHAN_2GHZ(chan)) { + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + } else { + pCalBChans = pEepData->calFreqPier5G; + numPiers = AR5416_NUM_5G_CAL_PIERS; + } + + numXpdGain = 0; + + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_5416_V20_OR_LATER(ah) && + (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + if (IS_CHAN_2GHZ(chan)) + pRawDataset = pEepData->calPierData2G[i]; + else + pRawDataset = pEepData->calPierData5G[i]; + + ath9k_hw_get_def_gain_boundaries_pdadcs(ah, chan, + pRawDataset, pCalBChans, + numPiers, pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + + if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { + REG_WRITE(ah, + AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) + | SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC: Chain %d | PDADC %3d " + "Value %3d | PDADC %3d Value %3d | " + "PDADC %3d Value %3d | PDADC %3d " + "Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; + + return true; +} + +static bool ath9k_hw_set_4k_power_cal_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *pTxPowerIndexOffset) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; + struct cal_data_per_freq_4k *pRawDataset; + u8 *pCalBChans = NULL; + u16 pdGainOverlap_t2; + static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; + u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; + u16 numPiers, i, j; + int16_t tMinCalPower; + u16 numXpdGain, xpdMask; + u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; + u32 reg32, regOffset, regChainOffset; + + xpdMask = pEepData->modalHeader.xpdGain; + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + pdGainOverlap_t2 = + pEepData->modalHeader.pdGainOverlap; + } else { + pdGainOverlap_t2 = (u16)(MS(REG_READ(ah, AR_PHY_TPCRG5), + AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); + } + + pCalBChans = pEepData->calFreqPier2G; + numPiers = AR5416_NUM_2G_CAL_PIERS; + + numXpdGain = 0; + + for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { + if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { + if (numXpdGain >= AR5416_NUM_PD_GAINS) + break; + xpdGainValues[numXpdGain] = + (u16)(AR5416_PD_GAINS_IN_MASK - i); + numXpdGain++; + } + } + + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, + (numXpdGain - 1) & 0x3); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, + xpdGainValues[0]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, + xpdGainValues[1]); + REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, + xpdGainValues[2]); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_5416_V20_OR_LATER(ah) && + (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) && + (i != 0)) { + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + } else + regChainOffset = i * 0x1000; + + if (pEepData->baseEepHeader.txMask & (1 << i)) { + pRawDataset = pEepData->calPierData2G[i]; + + ath9k_hw_get_4k_gain_boundaries_pdadcs(ah, chan, + pRawDataset, pCalBChans, + numPiers, pdGainOverlap_t2, + &tMinCalPower, gainBoundaries, + pdadcValues, numXpdGain); + + if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { + REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset, + SM(pdGainOverlap_t2, + AR_PHY_TPCRG5_PD_GAIN_OVERLAP) + | SM(gainBoundaries[0], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) + | SM(gainBoundaries[1], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) + | SM(gainBoundaries[2], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) + | SM(gainBoundaries[3], + AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); + } + + regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset; + for (j = 0; j < 32; j++) { + reg32 = ((pdadcValues[4 * j + 0] & 0xFF) << 0) | + ((pdadcValues[4 * j + 1] & 0xFF) << 8) | + ((pdadcValues[4 * j + 2] & 0xFF) << 16)| + ((pdadcValues[4 * j + 3] & 0xFF) << 24); + REG_WRITE(ah, regOffset, reg32); + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC (%d,%4x): %4.4x %8.8x\n", + i, regChainOffset, regOffset, + reg32); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "PDADC: Chain %d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d | " + "PDADC %3d Value %3d |\n", + i, 4 * j, pdadcValues[4 * j], + 4 * j + 1, pdadcValues[4 * j + 1], + 4 * j + 2, pdadcValues[4 * j + 2], + 4 * j + 3, + pdadcValues[4 * j + 3]); + + regOffset += 4; + } + } + } + + *pTxPowerIndexOffset = 0; + + return true; +} + +static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ +#define REDUCE_SCALED_POWER_BY_TWO_CHAIN 6 /* 10*log10(2)*2 */ +#define REDUCE_SCALED_POWER_BY_THREE_CHAIN 10 /* 10*log10(3)*2 */ + + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11a[] = + { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ahp->ah_txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = max( + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[0], + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); + + twiceLargestAntenna = max((u8)twiceLargestAntenna, + pEepData->modalHeader + [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->ah_tpScale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + + switch (ar5416_get_ntxchains(tx_chainmask)) { + case 1: + break; + case 2: + scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN; + break; + case 3: + scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN; + break; + } + + scaledPower = max((u16)0, scaledPower); + + if (IS_CHAN_2GHZ(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - + SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } else { + numCtlModes = ARRAY_SIZE(ctlModesFor11a) - + SUB_NUM_CTL_MODES_AT_5G_40; + pCtlMode = ctlModesFor11a; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT20, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11a); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower5GHT40, + AR5416_NUM_5G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower5G, + AR5416_NUM_5G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ar5416_get_eep_ver(ahp) == 14 && ar5416_get_eep_rev(ahp) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " + "EXT_ADDITIVE %d\n", + ctlMode, numCtlModes, isHt40CtlMode, + (pCtlMode[ctlMode] & EXT_ADDITIVE)); + + for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; i++) { + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " + "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " + "chan %d\n", + i, cfgCtl, pCtlMode[ctlMode], + pEepData->ctlIndex[i], chan->channel); + + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains(tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), AR5416_NUM_BAND_EDGES); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " MATCH-EE_IDX %d: ch %d is2 %d " + "2xMinEdge %d chainmask %d chains %d\n", + i, freq, IS_CHAN_2GHZ(chan), + twiceMinEdgePower, tx_chainmask, + ar5416_get_ntxchains + (tx_chainmask)); + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = min(twiceMaxEdgePower, scaledPower); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " SEL-Min ctlMode %d pCtlMode %d " + "2xMaxEdge %d sP %d minCtlPwr %d\n", + ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, + scaledPower, minCtlPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11A: + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_5GHT20: + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11A_EXT: + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_5GHT40: + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = + targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = + targetPowerCck.tPow2x[2]; + ; + ratesArray[rate11s] = ratesArray[rate11l] = + targetPowerCck.tPow2x[3]; + ; + } + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + if (IS_CHAN_2GHZ(chan)) { + ratesArray[rateExtCck] = + targetPowerCckExt.tPow2x[0]; + } + } + return true; +} + +static bool ath9k_hw_set_4k_power_per_rate_table(struct ath_hal *ah, + struct ath9k_channel *chan, + int16_t *ratesArray, + u16 cfgCtl, + u16 AntennaReduction, + u16 twiceMaxRegulatoryPower, + u16 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; + u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + static const u16 tpScaleReductionTable[5] = + { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; + + int i; + int16_t twiceLargestAntenna; + struct cal_ctl_data_4k *rep; + struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { + 0, { 0, 0, 0, 0} + }; + struct cal_target_power_leg targetPowerOfdmExt = { + 0, { 0, 0, 0, 0} }, targetPowerCckExt = { + 0, { 0, 0, 0, 0 } + }; + struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { + 0, {0, 0, 0, 0} + }; + u16 scaledPower = 0, minCtlPower, maxRegAllowedPower; + u16 ctlModesFor11g[] = + { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, + CTL_2GHT40 + }; + u16 numCtlModes, *pCtlMode, ctlMode, freq; + struct chan_centers centers; + int tx_chainmask; + u16 twiceMinEdgePower; + + tx_chainmask = ahp->ah_txchainmask; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + twiceLargestAntenna = pEepData->modalHeader.antennaGainCh[0]; + + twiceLargestAntenna = (int16_t)min(AntennaReduction - + twiceLargestAntenna, 0); + + maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; + + if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { + maxRegAllowedPower -= + (tpScaleReductionTable[(ah->ah_tpScale)] * 2); + } + + scaledPower = min(powerLimit, maxRegAllowedPower); + scaledPower = max((u16)0, scaledPower); + + numCtlModes = ARRAY_SIZE(ctlModesFor11g) - SUB_NUM_CTL_MODES_AT_2G_40; + pCtlMode = ctlModesFor11g; + + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCck, 4, false); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdm, 4, false); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT20, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerHt20, 8, false); + + if (IS_CHAN_HT40(chan)) { + numCtlModes = ARRAY_SIZE(ctlModesFor11g); + ath9k_hw_get_target_powers(ah, chan, + pEepData->calTargetPower2GHT40, + AR5416_NUM_2G_40_TARGET_POWERS, + &targetPowerHt40, 8, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPowerCck, + AR5416_NUM_2G_CCK_TARGET_POWERS, + &targetPowerCckExt, 4, true); + ath9k_hw_get_legacy_target_powers(ah, chan, + pEepData->calTargetPower2G, + AR5416_NUM_2G_20_TARGET_POWERS, + &targetPowerOfdmExt, 4, true); + } + + for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { + bool isHt40CtlMode = (pCtlMode[ctlMode] == CTL_5GHT40) || + (pCtlMode[ctlMode] == CTL_2GHT40); + if (isHt40CtlMode) + freq = centers.synth_center; + else if (pCtlMode[ctlMode] & EXT_ADDITIVE) + freq = centers.ext_center; + else + freq = centers.ctl_center; + + if (ar5416_get_eep_ver(ahp) == 14 && + ar5416_get_eep_rev(ahp) <= 2) + twiceMaxEdgePower = AR5416_MAX_RATE_POWER; + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " + "EXT_ADDITIVE %d\n", + ctlMode, numCtlModes, isHt40CtlMode, + (pCtlMode[ctlMode] & EXT_ADDITIVE)); + + for (i = 0; (i < AR5416_NUM_CTLS) && + pEepData->ctlIndex[i]; i++) { + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " + "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " + "chan %d\n", + i, cfgCtl, pCtlMode[ctlMode], + pEepData->ctlIndex[i], chan->channel); + + if ((((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + pEepData->ctlIndex[i]) || + (((cfgCtl & ~CTL_MODE_M) | + (pCtlMode[ctlMode] & CTL_MODE_M)) == + ((pEepData->ctlIndex[i] & CTL_MODE_M) | + SD_NO_CTL))) { + rep = &(pEepData->ctlData[i]); + + twiceMinEdgePower = + ath9k_hw_get_max_edge_power(freq, + rep->ctlEdges[ar5416_get_ntxchains + (tx_chainmask) - 1], + IS_CHAN_2GHZ(chan), + AR5416_EEP4K_NUM_BAND_EDGES); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " MATCH-EE_IDX %d: ch %d is2 %d " + "2xMinEdge %d chainmask %d chains %d\n", + i, freq, IS_CHAN_2GHZ(chan), + twiceMinEdgePower, tx_chainmask, + ar5416_get_ntxchains + (tx_chainmask)); + if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { + twiceMaxEdgePower = + min(twiceMaxEdgePower, + twiceMinEdgePower); + } else { + twiceMaxEdgePower = twiceMinEdgePower; + break; + } + } + } + + minCtlPower = (u8)min(twiceMaxEdgePower, scaledPower); + + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + " SEL-Min ctlMode %d pCtlMode %d " + "2xMaxEdge %d sP %d minCtlPwr %d\n", + ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, + scaledPower, minCtlPower); + + switch (pCtlMode[ctlMode]) { + case CTL_11B: + for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); + i++) { + targetPowerCck.tPow2x[i] = + min((u16)targetPowerCck.tPow2x[i], + minCtlPower); + } + break; + case CTL_11G: + for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); + i++) { + targetPowerOfdm.tPow2x[i] = + min((u16)targetPowerOfdm.tPow2x[i], + minCtlPower); + } + break; + case CTL_2GHT20: + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); + i++) { + targetPowerHt20.tPow2x[i] = + min((u16)targetPowerHt20.tPow2x[i], + minCtlPower); + } + break; + case CTL_11B_EXT: + targetPowerCckExt.tPow2x[0] = min((u16) + targetPowerCckExt.tPow2x[0], + minCtlPower); + break; + case CTL_11G_EXT: + targetPowerOfdmExt.tPow2x[0] = min((u16) + targetPowerOfdmExt.tPow2x[0], + minCtlPower); + break; + case CTL_2GHT40: + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); + i++) { + targetPowerHt40.tPow2x[i] = + min((u16)targetPowerHt40.tPow2x[i], + minCtlPower); + } + break; + default: + break; + } + } + + ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = + ratesArray[rate18mb] = ratesArray[rate24mb] = + targetPowerOfdm.tPow2x[0]; + ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; + ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; + ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; + ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; + + for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) + ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; + + ratesArray[rate1l] = targetPowerCck.tPow2x[0]; + ratesArray[rate2s] = ratesArray[rate2l] = targetPowerCck.tPow2x[1]; + ratesArray[rate5_5s] = ratesArray[rate5_5l] = targetPowerCck.tPow2x[2]; + ratesArray[rate11s] = ratesArray[rate11l] = targetPowerCck.tPow2x[3]; + + if (IS_CHAN_HT40(chan)) { + for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { + ratesArray[rateHt40_0 + i] = + targetPowerHt40.tPow2x[i]; + } + ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; + ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; + ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; + ratesArray[rateExtCck] = targetPowerCckExt.tPow2x[0]; + } + return true; +} + +static int ath9k_hw_def_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *pEepData = &ahp->ah_eeprom.def; + struct modal_eep_header *pModal = + &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + if (!ath9k_hw_set_def_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set " + "tx power per rate table\n"); + return -EIO; + } + + if (!ath9k_hw_set_def_power_cal_table(ah, chan, &txPowerIndexOffset)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set power table\n"); + return -EIO; + } + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_SUB, + ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) + | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0)); + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->ah_maxPowerLevel = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->ah_maxPowerLevel = ratesArray[i]; + + return 0; +} + +static int ath9k_hw_4k_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *pEepData = &ahp->ah_eeprom.map4k; + struct modal_eep_4k_header *pModal = &pEepData->modalHeader; + int16_t ratesArray[Ar5416RateSize]; + int16_t txPowerIndexOffset = 0; + u8 ht40PowerIncForPdadc = 2; + int i; + + memset(ratesArray, 0, sizeof(ratesArray)); + + if ((pEepData->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; + } + + if (!ath9k_hw_set_4k_power_per_rate_table(ah, chan, + &ratesArray[0], cfgCtl, + twiceAntennaReduction, + twiceMaxRegulatoryPower, + powerLimit)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set " + "tx power per rate table\n"); + return -EIO; + } + + if (!ath9k_hw_set_4k_power_cal_table(ah, chan, &txPowerIndexOffset)) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "ath9k_hw_set_txpower: unable to set power table\n"); + return -EIO; + } + + for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { + ratesArray[i] = (int16_t)(txPowerIndexOffset + ratesArray[i]); + if (ratesArray[i] > AR5416_MAX_RATE_POWER) + ratesArray[i] = AR5416_MAX_RATE_POWER; + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + for (i = 0; i < Ar5416RateSize; i++) + ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, + ATH9K_POW_SM(ratesArray[rate18mb], 24) + | ATH9K_POW_SM(ratesArray[rate12mb], 16) + | ATH9K_POW_SM(ratesArray[rate9mb], 8) + | ATH9K_POW_SM(ratesArray[rate6mb], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, + ATH9K_POW_SM(ratesArray[rate54mb], 24) + | ATH9K_POW_SM(ratesArray[rate48mb], 16) + | ATH9K_POW_SM(ratesArray[rate36mb], 8) + | ATH9K_POW_SM(ratesArray[rate24mb], 0)); + + if (IS_CHAN_2GHZ(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, + ATH9K_POW_SM(ratesArray[rate2s], 24) + | ATH9K_POW_SM(ratesArray[rate2l], 16) + | ATH9K_POW_SM(ratesArray[rateXr], 8) + | ATH9K_POW_SM(ratesArray[rate1l], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, + ATH9K_POW_SM(ratesArray[rate11s], 24) + | ATH9K_POW_SM(ratesArray[rate11l], 16) + | ATH9K_POW_SM(ratesArray[rate5_5s], 8) + | ATH9K_POW_SM(ratesArray[rate5_5l], 0)); + } + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, + ATH9K_POW_SM(ratesArray[rateHt20_3], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_0], 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, + ATH9K_POW_SM(ratesArray[rateHt20_7], 24) + | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) + | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) + | ATH9K_POW_SM(ratesArray[rateHt20_4], 0)); + + if (IS_CHAN_HT40(chan)) { + REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, + ATH9K_POW_SM(ratesArray[rateHt40_3] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_2] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_1] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_0] + + ht40PowerIncForPdadc, 0)); + REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, + ATH9K_POW_SM(ratesArray[rateHt40_7] + + ht40PowerIncForPdadc, 24) + | ATH9K_POW_SM(ratesArray[rateHt40_6] + + ht40PowerIncForPdadc, 16) + | ATH9K_POW_SM(ratesArray[rateHt40_5] + + ht40PowerIncForPdadc, 8) + | ATH9K_POW_SM(ratesArray[rateHt40_4] + + ht40PowerIncForPdadc, 0)); + + REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, + ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) + | ATH9K_POW_SM(ratesArray[rateExtCck], 16) + | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) + | ATH9K_POW_SM(ratesArray[rateDupCck], 0)); + } + + i = rate6mb; + + if (IS_CHAN_HT40(chan)) + i = rateHt40_0; + else if (IS_CHAN_HT20(chan)) + i = rateHt20_0; + + if (AR_SREV_9280_10_OR_LATER(ah)) + ah->ah_maxPowerLevel = + ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; + else + ah->ah_maxPowerLevel = ratesArray[i]; + + return 0; +} + +static int (*ath9k_set_txpower[]) (struct ath_hal *, + struct ath9k_channel *, + u16, u8, u8, u8) = { + ath9k_hw_def_set_txpower, + ath9k_hw_4k_set_txpower +}; + +int ath9k_hw_set_txpower(struct ath_hal *ah, + struct ath9k_channel *chan, + u16 cfgCtl, + u8 twiceAntennaReduction, + u8 twiceMaxRegulatoryPower, + u8 powerLimit) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_set_txpower[ahp->ah_eep_map](ah, chan, cfgCtl, + twiceAntennaReduction, twiceMaxRegulatoryPower, + powerLimit); +} + +static void ath9k_hw_set_def_addac(struct ath_hal *ah, + struct ath9k_channel *chan) +{ +#define XPA_LVL_FREQ(cnt) (pModal->xpaBiasLvlFreq[cnt]) + struct modal_eep_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + u8 biaslevel; + + if (ah->ah_macVersion != AR_SREV_VERSION_9160) + return; + + if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + } else { + u16 resetFreqBin, freqBin, freqCount = 0; + struct chan_centers centers; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + + resetFreqBin = FREQ2FBIN(centers.synth_center, + IS_CHAN_2GHZ(chan)); + freqBin = XPA_LVL_FREQ(0) & 0xff; + biaslevel = (u8) (XPA_LVL_FREQ(0) >> 14); + + freqCount++; + + while (freqCount < 3) { + if (XPA_LVL_FREQ(freqCount) == 0x0) + break; + + freqBin = XPA_LVL_FREQ(freqCount) & 0xff; + if (resetFreqBin >= freqBin) + biaslevel = (u8)(XPA_LVL_FREQ(freqCount) >> 14); + else + break; + freqCount++; + } + } + + if (IS_CHAN_2GHZ(chan)) { + INI_RA(&ahp->ah_iniAddac, 7, 1) = (INI_RA(&ahp->ah_iniAddac, + 7, 1) & (~0x18)) | biaslevel << 3; + } else { + INI_RA(&ahp->ah_iniAddac, 6, 1) = (INI_RA(&ahp->ah_iniAddac, + 6, 1) & (~0xc0)) | biaslevel << 6; + } +#undef XPA_LVL_FREQ +} + +static void ath9k_hw_set_4k_addac(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + u8 biaslevel; + + if (ah->ah_macVersion != AR_SREV_VERSION_9160) + return; + + if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) + return; + + pModal = &eep->modalHeader; + + if (pModal->xpaBiasLvl != 0xff) { + biaslevel = pModal->xpaBiasLvl; + INI_RA(&ahp->ah_iniAddac, 7, 1) = + (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel << 3; + } +} + +static void (*ath9k_set_addac[]) (struct ath_hal *, struct ath9k_channel *) = { + ath9k_hw_set_def_addac, + ath9k_hw_set_4k_addac +}; + +void ath9k_hw_set_addac(struct ath_hal *ah, struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + ath9k_set_addac[ahp->ah_eep_map](ah, chan); +} + + + +/* XXX: Clean me up, make me more legible */ +static bool ath9k_hw_eeprom_set_def_board_values(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + int i, regChainOffset; + u8 txRxAttenLocal; + u16 ant_config; + + pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + + txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; + + ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config); + REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + + for (i = 0; i < AR5416_MAX_CHAINS; i++) { + if (AR_SREV_9280(ah)) { + if (i >= 2) + break; + } + + if (AR_SREV_5416_V20_OR_LATER(ah) && + (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) + && (i != 0)) + regChainOffset = (i == 1) ? 0x2000 : 0x1000; + else + regChainOffset = i * 0x1000; + + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[i]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, + AR_PHY_TIMING_CTRL4(0) + + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[i], + AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { + if ((eep->baseEepHeader.version & + AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[i]; + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, + pModal-> + bswMargin[i]); + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, + pModal-> + bswAtten[i]); + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal-> + xatten2Margin[i]); + REG_RMW_FIELD(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, + pModal-> + xatten2Db[i]); + } else { + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + (REG_READ(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) + | SM(pModal-> + bswMargin[i], + AR_PHY_GAIN_2GHZ_BSW_MARGIN)); + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + (REG_READ(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) + | SM(pModal->bswAtten[i], + AR_PHY_GAIN_2GHZ_BSW_ATTEN)); + } + } + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, + txRxAttenLocal); + REG_RMW_FIELD(ah, + AR_PHY_RXGAIN + + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, + pModal->rxTxMarginCh[i]); + } else { + REG_WRITE(ah, + AR_PHY_RXGAIN + regChainOffset, + (REG_READ(ah, + AR_PHY_RXGAIN + + regChainOffset) & + ~AR_PHY_RXGAIN_TXRX_ATTEN) | + SM(txRxAttenLocal, + AR_PHY_RXGAIN_TXRX_ATTEN)); + REG_WRITE(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset, + (REG_READ(ah, + AR_PHY_GAIN_2GHZ + + regChainOffset) & + ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | + SM(pModal->rxTxMarginCh[i], + AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); + } + } + } + + if (AR_SREV_9280_10_OR_LATER(ah)) { + if (IS_CHAN_2GHZ(chan)) { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_OB, + AR_AN_RF2G1_CH0_OB_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, + AR_AN_RF2G1_CH0_DB, + AR_AN_RF2G1_CH0_DB_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_OB, + AR_AN_RF2G1_CH1_OB_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, + AR_AN_RF2G1_CH1_DB, + AR_AN_RF2G1_CH1_DB_S, + pModal->db_ch1); + } else { + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_OB5, + AR_AN_RF5G1_CH0_OB5_S, + pModal->ob); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, + AR_AN_RF5G1_CH0_DB5, + AR_AN_RF5G1_CH0_DB5_S, + pModal->db); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_OB5, + AR_AN_RF5G1_CH1_OB5_S, + pModal->ob_ch1); + ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, + AR_AN_RF5G1_CH1_DB5, + AR_AN_RF5G1_CH1_DB5_S, + pModal->db_ch1); + } + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_XPABIAS_LVL, + AR_AN_TOP2_XPABIAS_LVL_S, + pModal->xpaBiasLvl); + ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, + AR_AN_TOP2_LOCALBIAS, + AR_AN_TOP2_LOCALBIAS_S, + pModal->local_bias); + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "ForceXPAon: %d\n", + pModal->force_xpaon); + REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, + pModal->force_xpaon); + } + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + if (!AR_SREV_9280_10_OR_LATER(ah)) + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, + AR_PHY_DESIRED_SZ_PGA, + pModal->pgaDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) + | SM(pModal->txEndToXpaOff, + AR_PHY_RF_CTL4_TX_END_XPAB_OFF) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAA_ON) + | SM(pModal->txFrameToXpaOn, + AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + if (AR_SREV_9280_10_OR_LATER(ah)) { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, + AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + } else { + REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, + AR_PHY_EXT_CCA_THRESH62, + pModal->thresh62); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, + AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } + + return true; +} + +static bool ath9k_hw_eeprom_set_4k_board_values(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct modal_eep_4k_header *pModal; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + int regChainOffset; + u8 txRxAttenLocal; + u16 ant_config = 0; + u8 ob[5], db1[5], db2[5]; + u8 ant_div_control1, ant_div_control2; + u32 regVal; + + + pModal = &eep->modalHeader; + + txRxAttenLocal = 23; + + ath9k_hw_get_eeprom_antenna_cfg(ah, chan, 0, &ant_config); + REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + + regChainOffset = 0; + REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, + pModal->antCtrlChain[0]); + + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, + (REG_READ(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset) & + ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | + AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | + SM(pModal->iqCalICh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | + SM(pModal->iqCalQCh[0], AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + txRxAttenLocal = pModal->txRxAttenCh[0]; + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, pModal->bswMargin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN1_DB, pModal->bswAtten[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, + pModal->xatten2Margin[0]); + REG_RMW_FIELD(ah, AR_PHY_GAIN_2GHZ + regChainOffset, + AR_PHY_GAIN_2GHZ_XATTEN2_DB, pModal->xatten2Db[0]); + } + + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_ATTEN, txRxAttenLocal); + REG_RMW_FIELD(ah, AR_PHY_RXGAIN + regChainOffset, + AR9280_PHY_RXGAIN_TXRX_MARGIN, pModal->rxTxMarginCh[0]); + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, (AR9285_AN_TOP4_DEFAULT | 0x14)); + + /* Initialize Ant Diversity settings from EEPROM */ + if (pModal->version == 3) { + ant_div_control1 = ((pModal->ob_234 >> 12) & 0xf); + ant_div_control2 = ((pModal->db1_234 >> 12) & 0xf); + regVal = REG_READ(ah, 0x99ac); + regVal &= (~(0x7f000000)); + regVal |= ((ant_div_control1 & 0x1) << 24); + regVal |= (((ant_div_control1 >> 1) & 0x1) << 29); + regVal |= (((ant_div_control1 >> 2) & 0x1) << 30); + regVal |= ((ant_div_control2 & 0x3) << 25); + regVal |= (((ant_div_control2 >> 2) & 0x3) << 27); + REG_WRITE(ah, 0x99ac, regVal); + regVal = REG_READ(ah, 0x99ac); + regVal = REG_READ(ah, 0xa208); + regVal &= (~(0x1 << 13)); + regVal |= (((ant_div_control1 >> 3) & 0x1) << 13); + REG_WRITE(ah, 0xa208, regVal); + regVal = REG_READ(ah, 0xa208); + } + + if (pModal->version >= 2) { + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = (pModal->ob_01 >> 4) & 0xf; + ob[2] = (pModal->ob_234 & 0xf); + ob[3] = ((pModal->ob_234 >> 4) & 0xf); + ob[4] = ((pModal->ob_234 >> 8) & 0xf); + + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = ((pModal->db1_01 >> 4) & 0xf); + db1[2] = (pModal->db1_234 & 0xf); + db1[3] = ((pModal->db1_234 >> 4) & 0xf); + db1[4] = ((pModal->db1_234 >> 8) & 0xf); + + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = ((pModal->db2_01 >> 4) & 0xf); + db2[2] = (pModal->db2_234 & 0xf); + db2[3] = ((pModal->db2_234 >> 4) & 0xf); + db2[4] = ((pModal->db2_234 >> 8) & 0xf); + + } else if (pModal->version == 1) { + + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "EEPROM Model version is set to 1 \n"); + ob[0] = (pModal->ob_01 & 0xf); + ob[1] = ob[2] = ob[3] = ob[4] = (pModal->ob_01 >> 4) & 0xf; + db1[0] = (pModal->db1_01 & 0xf); + db1[1] = db1[2] = db1[3] = + db1[4] = ((pModal->db1_01 >> 4) & 0xf); + db2[0] = (pModal->db2_01 & 0xf); + db2[1] = db2[2] = db2[3] = + db2[4] = ((pModal->db2_01 >> 4) & 0xf); + } else { + int i; + for (i = 0; i < 5; i++) { + ob[i] = pModal->ob_01; + db1[i] = pModal->db1_01; + db2[i] = pModal->db1_01; + } + } + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_0, AR9285_AN_RF2G3_OB_0_S, ob[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_1, AR9285_AN_RF2G3_OB_1_S, ob[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_2, AR9285_AN_RF2G3_OB_2_S, ob[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_3, AR9285_AN_RF2G3_OB_3_S, ob[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_OB_4, AR9285_AN_RF2G3_OB_4_S, ob[4]); + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_0, AR9285_AN_RF2G3_DB1_0_S, db1[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_1, AR9285_AN_RF2G3_DB1_1_S, db1[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G3, + AR9285_AN_RF2G3_DB1_2, AR9285_AN_RF2G3_DB1_2_S, db1[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_3, AR9285_AN_RF2G4_DB1_3_S, db1[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB1_4, AR9285_AN_RF2G4_DB1_4_S, db1[4]); + + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_0, AR9285_AN_RF2G4_DB2_0_S, db2[0]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_1, AR9285_AN_RF2G4_DB2_1_S, db2[1]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_2, AR9285_AN_RF2G4_DB2_2_S, db2[2]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_3, AR9285_AN_RF2G4_DB2_3_S, db2[3]); + ath9k_hw_analog_shift_rmw(ah, AR9285_AN_RF2G4, + AR9285_AN_RF2G4_DB2_4, AR9285_AN_RF2G4_DB2_4_S, db2[4]); + + + if (AR_SREV_9285_11(ah)) + REG_WRITE(ah, AR9285_AN_TOP4, AR9285_AN_TOP4_DEFAULT); + + REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, + pModal->switchSettling); + REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, + pModal->adcDesiredSize); + + REG_WRITE(ah, AR_PHY_RF_CTL4, + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) | + SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAB_OFF) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAA_ON) | + SM(pModal->txFrameToXpaOn, AR_PHY_RF_CTL4_FRAME_XPAB_ON)); + + REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, + pModal->txEndToRxOn); + REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, + pModal->thresh62); + REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, AR_PHY_EXT_CCA0_THRESH62, + pModal->thresh62); + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_2) { + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_DATA_START, + pModal->txFrameToDataStart); + REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, + pModal->txFrameToPaOn); + } + + if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= + AR5416_EEP_MINOR_VER_3) { + if (IS_CHAN_HT40(chan)) + REG_RMW_FIELD(ah, AR_PHY_SETTLING, + AR_PHY_SETTLING_SWITCH, + pModal->swSettleHt40); + } + + return true; +} + +static bool (*ath9k_eeprom_set_board_values[])(struct ath_hal *, + struct ath9k_channel *) = { + ath9k_hw_eeprom_set_def_board_values, + ath9k_hw_eeprom_set_4k_board_values +}; + +bool ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_eeprom_set_board_values[ahp->ah_eep_map](ah, chan); +} + +static int ath9k_hw_get_def_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + struct modal_eep_header *pModal = + &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + struct base_eep_header *pBase = &eep->baseEepHeader; + + switch (index) { + case 0: + *config = pModal->antCtrlCommon & 0xFFFF; + return 0; + case 1: + if (pBase->version >= 0x0E0D) { + if (pModal->useAnt1) { + *config = + ((pModal->antCtrlCommon & 0xFFFF0000) >> 16); + return 0; + } + } + break; + default: + break; + } + + return -EINVAL; +} + +static int ath9k_hw_get_4k_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + + switch (index) { + case 0: + *config = pModal->antCtrlCommon & 0xFFFF; + return 0; + default: + break; + } + + return -EINVAL; +} + +static int (*ath9k_get_eeprom_antenna_cfg[])(struct ath_hal *, + struct ath9k_channel *, + u8, u16 *) = { + ath9k_hw_get_def_eeprom_antenna_cfg, + ath9k_hw_get_4k_eeprom_antenna_cfg +}; + +int ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal *ah, + struct ath9k_channel *chan, + u8 index, u16 *config) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_get_eeprom_antenna_cfg[ahp->ah_eep_map](ah, chan, + index, config); +} + +static u8 ath9k_hw_get_4k_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) +{ + return 1; +} + +static u8 ath9k_hw_get_def_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + struct modal_eep_header *pModal = + &(eep->modalHeader[ATH9K_HAL_FREQ_BAND_2GHZ == freq_band]); + struct base_eep_header *pBase = &eep->baseEepHeader; + u8 num_ant_config; + + num_ant_config = 1; + + if (pBase->version >= 0x0E0D) + if (pModal->useAnt1) + num_ant_config += 1; + + return num_ant_config; +} + +static u8 (*ath9k_get_num_ant_config[])(struct ath_hal *, + enum ieee80211_band) = { + ath9k_hw_get_def_num_ant_config, + ath9k_hw_get_4k_num_ant_config +}; + +u8 ath9k_hw_get_num_ant_config(struct ath_hal *ah, + enum ieee80211_band freq_band) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_get_num_ant_config[ahp->ah_eep_map](ah, freq_band); +} + +u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, u16 i, bool is2GHz) +{ +#define EEP_MAP4K_SPURCHAN \ + (ahp->ah_eeprom.map4k.modalHeader.spurChans[i].spurChan) +#define EEP_DEF_SPURCHAN \ + (ahp->ah_eeprom.def.modalHeader[is2GHz].spurChans[i].spurChan) + struct ath_hal_5416 *ahp = AH5416(ah); + u16 spur_val = AR_NO_SPUR; + + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur idx %d is2Ghz. %d val %x\n", + i, is2GHz, ah->ah_config.spurchans[i][is2GHz]); + + switch (ah->ah_config.spurmode) { + case SPUR_DISABLE: + break; + case SPUR_ENABLE_IOCTL: + spur_val = ah->ah_config.spurchans[i][is2GHz]; + DPRINTF(ah->ah_sc, ATH_DBG_ANI, + "Getting spur val from new loc. %d\n", spur_val); + break; + case SPUR_ENABLE_EEPROM: + if (ahp->ah_eep_map == EEP_MAP_4KBITS) + spur_val = EEP_MAP4K_SPURCHAN; + else + spur_val = EEP_DEF_SPURCHAN; + break; + + } + + return spur_val; +#undef EEP_DEF_SPURCHAN +#undef EEP_MAP4K_SPURCHAN +} + +static u32 ath9k_hw_get_eeprom_4k(struct ath_hal *ah, + enum eeprom_param param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_4k *eep = &ahp->ah_eeprom.map4k; + struct modal_eep_4k_header *pModal = &eep->modalHeader; + struct base_eep_header_4k *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_2: + return pModal[1].noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_2: + return pModal->ob_01; + case EEP_DB_2: + return pModal->db1_01; + case EEP_MINOR_REV: + return pBase->version & AR5416_EEP_VER_MINOR_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + default: + return 0; + } +} + +static u32 ath9k_hw_get_eeprom_def(struct ath_hal *ah, + enum eeprom_param param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ar5416_eeprom_def *eep = &ahp->ah_eeprom.def; + struct modal_eep_header *pModal = eep->modalHeader; + struct base_eep_header *pBase = &eep->baseEepHeader; + + switch (param) { + case EEP_NFTHRESH_5: + return pModal[0].noiseFloorThreshCh[0]; + case EEP_NFTHRESH_2: + return pModal[1].noiseFloorThreshCh[0]; + case AR_EEPROM_MAC(0): + return pBase->macAddr[0] << 8 | pBase->macAddr[1]; + case AR_EEPROM_MAC(1): + return pBase->macAddr[2] << 8 | pBase->macAddr[3]; + case AR_EEPROM_MAC(2): + return pBase->macAddr[4] << 8 | pBase->macAddr[5]; + case EEP_REG_0: + return pBase->regDmn[0]; + case EEP_REG_1: + return pBase->regDmn[1]; + case EEP_OP_CAP: + return pBase->deviceCap; + case EEP_OP_MODE: + return pBase->opCapFlags; + case EEP_RF_SILENT: + return pBase->rfSilent; + case EEP_OB_5: + return pModal[0].ob; + case EEP_DB_5: + return pModal[0].db; + case EEP_OB_2: + return pModal[1].ob; + case EEP_DB_2: + return pModal[1].db; + case EEP_MINOR_REV: + return pBase->version & AR5416_EEP_VER_MINOR_MASK; + case EEP_TX_MASK: + return pBase->txMask; + case EEP_RX_MASK: + return pBase->rxMask; + case EEP_RXGAIN_TYPE: + return pBase->rxGainType; + case EEP_TXGAIN_TYPE: + return pBase->txGainType; + + default: + return 0; + } +} + +static u32 (*ath9k_get_eeprom[])(struct ath_hal *, enum eeprom_param) = { + ath9k_hw_get_eeprom_def, + ath9k_hw_get_eeprom_4k +}; + +u32 ath9k_hw_get_eeprom(struct ath_hal *ah, + enum eeprom_param param) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + return ath9k_get_eeprom[ahp->ah_eep_map](ah, param); +} + +int ath9k_hw_eeprom_attach(struct ath_hal *ah) +{ + int status; + struct ath_hal_5416 *ahp = AH5416(ah); + + if (ath9k_hw_use_flash(ah)) + ath9k_hw_flash_map(ah); + + if (AR_SREV_9285(ah)) + ahp->ah_eep_map = EEP_MAP_4KBITS; + else + ahp->ah_eep_map = EEP_MAP_DEFAULT; + + if (!ath9k_hw_fill_eeprom(ah)) + return -EIO; + + status = ath9k_hw_check_eeprom(ah); + + return status; +} diff --git a/drivers/net/wireless/ath9k/hw.c b/drivers/net/wireless/ath9k/hw.c index 98bc25c9b3cf4f5f5ddf3e22b92d0cbd12c60a3d..34474edefc97ee4ff472be082d15ebbcad7c9a20 100644 --- a/drivers/net/wireless/ath9k/hw.c +++ b/drivers/net/wireless/ath9k/hw.c @@ -23,195 +23,78 @@ #include "phy.h" #include "initvals.h" -static void ath9k_hw_iqcal_collect(struct ath_hal *ah); -static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains); -static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah); -static void ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, - u8 numChains); -static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah); -static void ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, - u8 numChains); - static const u8 CLOCK_RATE[] = { 40, 80, 22, 44, 88, 40 }; -static const int16_t NOISE_FLOOR[] = { -96, -93, -98, -96, -93, -96 }; - -static const struct hal_percal_data iq_cal_multi_sample = { - IQ_MISMATCH_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_iqcal_collect, - ath9k_hw_iqcalibrate -}; -static const struct hal_percal_data iq_cal_single_sample = { - IQ_MISMATCH_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_iqcal_collect, - ath9k_hw_iqcalibrate -}; -static const struct hal_percal_data adc_gain_cal_multi_sample = { - ADC_GAIN_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_adc_gaincal_collect, - ath9k_hw_adc_gaincal_calibrate -}; -static const struct hal_percal_data adc_gain_cal_single_sample = { - ADC_GAIN_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_adc_gaincal_collect, - ath9k_hw_adc_gaincal_calibrate -}; -static const struct hal_percal_data adc_dc_cal_multi_sample = { - ADC_DC_CAL, - MAX_CAL_SAMPLES, - PER_MIN_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; -static const struct hal_percal_data adc_dc_cal_single_sample = { - ADC_DC_CAL, - MIN_CAL_SAMPLES, - PER_MAX_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; -static const struct hal_percal_data adc_init_dc_cal = { - ADC_DC_INIT_CAL, - MIN_CAL_SAMPLES, - INIT_LOG_COUNT, - ath9k_hw_adc_dccal_collect, - ath9k_hw_adc_dccal_calibrate -}; - -static struct ath9k_rate_table ar5416_11a_table = { - 8, - {0}, - { - {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0}, - {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2}, - {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4} - }, -}; - -static struct ath9k_rate_table ar5416_11b_table = { - 4, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 1}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 1} - }, -}; - -static struct ath9k_rate_table ar5416_11g_table = { - 12, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3}, - - {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4}, - {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6}, - {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8} - }, -}; - -static struct ath9k_rate_table ar5416_11ng_table = { - 28, - {0}, - { - {true, PHY_CCK, 1000, 0x1b, 0x00, (0x80 | 2), 0}, - {true, PHY_CCK, 2000, 0x1a, 0x04, (0x80 | 4), 1}, - {true, PHY_CCK, 5500, 0x19, 0x04, (0x80 | 11), 2}, - {true, PHY_CCK, 11000, 0x18, 0x04, (0x80 | 22), 3}, - - {false, PHY_OFDM, 6000, 0x0b, 0x00, 12, 4}, - {false, PHY_OFDM, 9000, 0x0f, 0x00, 18, 4}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, 24, 6}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 6}, - {true, PHY_OFDM, 24000, 0x09, 0x00, 48, 8}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 8}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 8}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 8}, - {true, PHY_HT, 6500, 0x80, 0x00, 0, 4}, - {true, PHY_HT, 13000, 0x81, 0x00, 1, 6}, - {true, PHY_HT, 19500, 0x82, 0x00, 2, 6}, - {true, PHY_HT, 26000, 0x83, 0x00, 3, 8}, - {true, PHY_HT, 39000, 0x84, 0x00, 4, 8}, - {true, PHY_HT, 52000, 0x85, 0x00, 5, 8}, - {true, PHY_HT, 58500, 0x86, 0x00, 6, 8}, - {true, PHY_HT, 65000, 0x87, 0x00, 7, 8}, - {true, PHY_HT, 13000, 0x88, 0x00, 8, 4}, - {true, PHY_HT, 26000, 0x89, 0x00, 9, 6}, - {true, PHY_HT, 39000, 0x8a, 0x00, 10, 6}, - {true, PHY_HT, 52000, 0x8b, 0x00, 11, 8}, - {true, PHY_HT, 78000, 0x8c, 0x00, 12, 8}, - {true, PHY_HT, 104000, 0x8d, 0x00, 13, 8}, - {true, PHY_HT, 117000, 0x8e, 0x00, 14, 8}, - {true, PHY_HT, 130000, 0x8f, 0x00, 15, 8}, - }, -}; - -static struct ath9k_rate_table ar5416_11na_table = { - 24, - {0}, - { - {true, PHY_OFDM, 6000, 0x0b, 0x00, (0x80 | 12), 0}, - {true, PHY_OFDM, 9000, 0x0f, 0x00, 18, 0}, - {true, PHY_OFDM, 12000, 0x0a, 0x00, (0x80 | 24), 2}, - {true, PHY_OFDM, 18000, 0x0e, 0x00, 36, 2}, - {true, PHY_OFDM, 24000, 0x09, 0x00, (0x80 | 48), 4}, - {true, PHY_OFDM, 36000, 0x0d, 0x00, 72, 4}, - {true, PHY_OFDM, 48000, 0x08, 0x00, 96, 4}, - {true, PHY_OFDM, 54000, 0x0c, 0x00, 108, 4}, - {true, PHY_HT, 6500, 0x80, 0x00, 0, 0}, - {true, PHY_HT, 13000, 0x81, 0x00, 1, 2}, - {true, PHY_HT, 19500, 0x82, 0x00, 2, 2}, - {true, PHY_HT, 26000, 0x83, 0x00, 3, 4}, - {true, PHY_HT, 39000, 0x84, 0x00, 4, 4}, - {true, PHY_HT, 52000, 0x85, 0x00, 5, 4}, - {true, PHY_HT, 58500, 0x86, 0x00, 6, 4}, - {true, PHY_HT, 65000, 0x87, 0x00, 7, 4}, - {true, PHY_HT, 13000, 0x88, 0x00, 8, 0}, - {true, PHY_HT, 26000, 0x89, 0x00, 9, 2}, - {true, PHY_HT, 39000, 0x8a, 0x00, 10, 2}, - {true, PHY_HT, 52000, 0x8b, 0x00, 11, 4}, - {true, PHY_HT, 78000, 0x8c, 0x00, 12, 4}, - {true, PHY_HT, 104000, 0x8d, 0x00, 13, 4}, - {true, PHY_HT, 117000, 0x8e, 0x00, 14, 4}, - {true, PHY_HT, 130000, 0x8f, 0x00, 15, 4}, - }, -}; - -static enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, - const struct ath9k_channel *chan) + +extern struct hal_percal_data iq_cal_multi_sample; +extern struct hal_percal_data iq_cal_single_sample; +extern struct hal_percal_data adc_gain_cal_multi_sample; +extern struct hal_percal_data adc_gain_cal_single_sample; +extern struct hal_percal_data adc_dc_cal_multi_sample; +extern struct hal_percal_data adc_dc_cal_single_sample; +extern struct hal_percal_data adc_init_dc_cal; + +static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type); +static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode); +static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, + struct ar5416_eeprom_def *pEepData, + u32 reg, u32 value); +static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan); +static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan); + +/********************/ +/* Helper Functions */ +/********************/ + +static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks) +{ + if (ah->ah_curchan != NULL) + return clks / CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)]; + else + return clks / CLOCK_RATE[ATH9K_MODE_11B]; +} + +static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks) +{ + struct ath9k_channel *chan = ah->ah_curchan; + + if (chan && IS_CHAN_HT40(chan)) + return ath9k_hw_mac_usec(ah, clks) / 2; + else + return ath9k_hw_mac_usec(ah, clks); +} + +static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs) +{ + if (ah->ah_curchan != NULL) + return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah, + ah->ah_curchan)]; + else + return usecs * CLOCK_RATE[ATH9K_MODE_11B]; +} + +static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs) +{ + struct ath9k_channel *chan = ah->ah_curchan; + + if (chan && IS_CHAN_HT40(chan)) + return ath9k_hw_mac_clks(ah, usecs) * 2; + else + return ath9k_hw_mac_clks(ah, usecs); +} + +enum wireless_mode ath9k_hw_chan2wmode(struct ath_hal *ah, + const struct ath9k_channel *chan) { - if (IS_CHAN_CCK(chan)) - return ATH9K_MODE_11A; + if (IS_CHAN_B(chan)) + return ATH9K_MODE_11B; if (IS_CHAN_G(chan)) return ATH9K_MODE_11G; + return ATH9K_MODE_11A; } -static bool ath9k_hw_wait(struct ath_hal *ah, - u32 reg, - u32 mask, - u32 val) +bool ath9k_hw_wait(struct ath_hal *ah, u32 reg, u32 mask, u32 val) { int i; @@ -221,54 +104,178 @@ static bool ath9k_hw_wait(struct ath_hal *ah, udelay(AH_TIME_QUANTUM); } - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", - __func__, reg, REG_READ(ah, reg), mask, val); + + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n", + reg, REG_READ(ah, reg), mask, val); + return false; } -static bool ath9k_hw_eeprom_read(struct ath_hal *ah, u32 off, - u16 *data) +u32 ath9k_hw_reverse_bits(u32 val, u32 n) { - (void) REG_READ(ah, AR5416_EEPROM_OFFSET + (off << AR5416_EEPROM_S)); + u32 retval; + int i; - if (!ath9k_hw_wait(ah, - AR_EEPROM_STATUS_DATA, - AR_EEPROM_STATUS_DATA_BUSY | - AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) { - return false; + for (i = 0, retval = 0; i < n; i++) { + retval = (retval << 1) | (val & 1); + val >>= 1; } + return retval; +} - *data = MS(REG_READ(ah, AR_EEPROM_STATUS_DATA), - AR_EEPROM_STATUS_DATA_VAL); +bool ath9k_get_channel_edges(struct ath_hal *ah, + u16 flags, u16 *low, + u16 *high) +{ + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - return true; + if (flags & CHANNEL_5GHZ) { + *low = pCap->low_5ghz_chan; + *high = pCap->high_5ghz_chan; + return true; + } + if ((flags & CHANNEL_2GHZ)) { + *low = pCap->low_2ghz_chan; + *high = pCap->high_2ghz_chan; + return true; + } + return false; } -static int ath9k_hw_flash_map(struct ath_hal *ah) +u16 ath9k_hw_computetxtime(struct ath_hal *ah, + struct ath_rate_table *rates, + u32 frameLen, u16 rateix, + bool shortPreamble) { - struct ath_hal_5416 *ahp = AH5416(ah); + u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; + u32 kbps; - ahp->ah_cal_mem = ioremap(AR5416_EEPROM_START_ADDR, AR5416_EEPROM_MAX); + kbps = rates->info[rateix].ratekbps; - if (!ahp->ah_cal_mem) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: cannot remap eeprom region \n", __func__); - return -EIO; + if (kbps == 0) + return 0; + + switch (rates->info[rateix].phy) { + case WLAN_RC_PHY_CCK: + phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; + if (shortPreamble && rates->info[rateix].short_preamble) + phyTime >>= 1; + numBits = frameLen << 3; + txTime = CCK_SIFS_TIME + phyTime + ((numBits * 1000) / kbps); + break; + case WLAN_RC_PHY_OFDM: + if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME_QUARTER + + OFDM_PREAMBLE_TIME_QUARTER + + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); + } else if (ah->ah_curchan && + IS_CHAN_HALF_RATE(ah->ah_curchan)) { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME_HALF + + OFDM_PREAMBLE_TIME_HALF + + (numSymbols * OFDM_SYMBOL_TIME_HALF); + } else { + bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; + numBits = OFDM_PLCP_BITS + (frameLen << 3); + numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); + txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME + + (numSymbols * OFDM_SYMBOL_TIME); + } + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "Unknown phy %u (rate ix %u)\n", + rates->info[rateix].phy, rateix); + txTime = 0; + break; } - return 0; + return txTime; +} + +u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags) +{ + if (flags & CHANNEL_2GHZ) { + if (freq == 2484) + return 14; + if (freq < 2484) + return (freq - 2407) / 5; + else + return 15 + ((freq - 2512) / 20); + } else if (flags & CHANNEL_5GHZ) { + if (ath9k_regd_is_public_safety_sku(ah) && + IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { + return ((freq * 10) + + (((freq % 5) == 2) ? 5 : 0) - 49400) / 5; + } else if ((flags & CHANNEL_A) && (freq <= 5000)) { + return (freq - 4000) / 5; + } else { + return (freq - 5000) / 5; + } + } else { + if (freq == 2484) + return 14; + if (freq < 2484) + return (freq - 2407) / 5; + if (freq < 5000) { + if (ath9k_regd_is_public_safety_sku(ah) + && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { + return ((freq * 10) + + (((freq % 5) == + 2) ? 5 : 0) - 49400) / 5; + } else if (freq > 4900) { + return (freq - 4000) / 5; + } else { + return 15 + ((freq - 2512) / 20); + } + } + return (freq - 5000) / 5; + } } -static bool ath9k_hw_flash_read(struct ath_hal *ah, u32 off, - u16 *data) +void ath9k_hw_get_channel_centers(struct ath_hal *ah, + struct ath9k_channel *chan, + struct chan_centers *centers) { + int8_t extoff; struct ath_hal_5416 *ahp = AH5416(ah); - *data = ioread16(ahp->ah_cal_mem + off); - return true; + if (!IS_CHAN_HT40(chan)) { + centers->ctl_center = centers->ext_center = + centers->synth_center = chan->channel; + return; + } + + if ((chan->chanmode == CHANNEL_A_HT40PLUS) || + (chan->chanmode == CHANNEL_G_HT40PLUS)) { + centers->synth_center = + chan->channel + HT40_CHANNEL_CENTER_SHIFT; + extoff = 1; + } else { + centers->synth_center = + chan->channel - HT40_CHANNEL_CENTER_SHIFT; + extoff = -1; + } + + centers->ctl_center = + centers->synth_center - (extoff * HT40_CHANNEL_CENTER_SHIFT); + centers->ext_center = + centers->synth_center + (extoff * + ((ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_20) ? + HT40_CHANNEL_CENTER_SHIFT : 15)); + } +/******************/ +/* Chip Revisions */ +/******************/ + static void ath9k_hw_read_revisions(struct ath_hal *ah) { u32 val; @@ -277,14 +284,9 @@ static void ath9k_hw_read_revisions(struct ath_hal *ah) if (val == 0xFF) { val = REG_READ(ah, AR_SREV); - - ah->ah_macVersion = - (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; - + ah->ah_macVersion = (val & AR_SREV_VERSION2) >> AR_SREV_TYPE2_S; ah->ah_macRev = MS(val, AR_SREV_REVISION2); - ah->ah_isPciExpress = - (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; - + ah->ah_isPciExpress = (val & AR_SREV_TYPE2_HOST_MODE) ? 0 : 1; } else { if (!AR_SREV_9100(ah)) ah->ah_macVersion = MS(val, AR_SREV_VERSION); @@ -296,4828 +298,736 @@ static void ath9k_hw_read_revisions(struct ath_hal *ah) } } -u32 ath9k_hw_reverse_bits(u32 val, u32 n) -{ - u32 retval; - int i; - - for (i = 0, retval = 0; i < n; i++) { - retval = (retval << 1) | (val & 1); - val >>= 1; - } - return retval; -} - -static void ath9k_hw_set_defaults(struct ath_hal *ah) +static int ath9k_hw_get_radiorev(struct ath_hal *ah) { + u32 val; int i; - ah->ah_config.dma_beacon_response_time = 2; - ah->ah_config.sw_beacon_response_time = 10; - ah->ah_config.additional_swba_backoff = 0; - ah->ah_config.ack_6mb = 0x0; - ah->ah_config.cwm_ignore_extcca = 0; - ah->ah_config.pcie_powersave_enable = 0; - ah->ah_config.pcie_l1skp_enable = 0; - ah->ah_config.pcie_clock_req = 0; - ah->ah_config.pcie_power_reset = 0x100; - ah->ah_config.pcie_restore = 0; - ah->ah_config.pcie_waen = 0; - ah->ah_config.analog_shiftreg = 1; - ah->ah_config.ht_enable = 1; - ah->ah_config.ofdm_trig_low = 200; - ah->ah_config.ofdm_trig_high = 500; - ah->ah_config.cck_trig_high = 200; - ah->ah_config.cck_trig_low = 100; - ah->ah_config.enable_ani = 1; - ah->ah_config.noise_immunity_level = 4; - ah->ah_config.ofdm_weaksignal_det = 1; - ah->ah_config.cck_weaksignal_thr = 0; - ah->ah_config.spur_immunity_level = 2; - ah->ah_config.firstep_level = 0; - ah->ah_config.rssi_thr_high = 40; - ah->ah_config.rssi_thr_low = 7; - ah->ah_config.diversity_control = 0; - ah->ah_config.antenna_switch_swap = 0; + REG_WRITE(ah, AR_PHY(0x36), 0x00007058); - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - ah->ah_config.spurchans[i][0] = AR_NO_SPUR; - ah->ah_config.spurchans[i][1] = AR_NO_SPUR; - } + for (i = 0; i < 8; i++) + REG_WRITE(ah, AR_PHY(0x20), 0x00010000); + val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; + val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); - ah->ah_config.intr_mitigation = 0; + return ath9k_hw_reverse_bits(val, 8); } -static void ath9k_hw_override_ini(struct ath_hal *ah, - struct ath9k_channel *chan) +/************************************/ +/* HW Attach, Detach, Init Routines */ +/************************************/ + +static void ath9k_hw_disablepcie(struct ath_hal *ah) { - if (!AR_SREV_5416_V20_OR_LATER(ah) - || AR_SREV_9280_10_OR_LATER(ah)) + if (!AR_SREV_9100(ah)) return; - REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029); + REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824); + REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579); + REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000); + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007); + + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); } -static void ath9k_hw_init_bb(struct ath_hal *ah, - struct ath9k_channel *chan) +static bool ath9k_hw_chip_test(struct ath_hal *ah) { - u32 synthDelay; + u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) }; + u32 regHold[2]; + u32 patternData[4] = { 0x55555555, + 0xaaaaaaaa, + 0x66666666, + 0x99999999 }; + int i, j; - synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_CCK(chan)) - synthDelay = (4 * synthDelay) / 22; - else - synthDelay /= 10; - - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); + for (i = 0; i < 2; i++) { + u32 addr = regAddr[i]; + u32 wrData, rdData; - udelay(synthDelay + BASE_ACTIVATE_DELAY); + regHold[i] = REG_READ(ah, addr); + for (j = 0; j < 0x100; j++) { + wrData = (j << 16) | j; + REG_WRITE(ah, addr, wrData); + rdData = REG_READ(ah, addr); + if (rdData != wrData) { + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "address test failed " + "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + addr, wrData, rdData); + return false; + } + } + for (j = 0; j < 4; j++) { + wrData = patternData[j]; + REG_WRITE(ah, addr, wrData); + rdData = REG_READ(ah, addr); + if (wrData != rdData) { + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "address test failed " + "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", + addr, wrData, rdData); + return false; + } + } + REG_WRITE(ah, regAddr[i], regHold[i]); + } + udelay(100); + return true; } -static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, - enum ath9k_opmode opmode) +static const char *ath9k_hw_devname(u16 devid) { - struct ath_hal_5416 *ahp = AH5416(ah); - - ahp->ah_maskReg = AR_IMR_TXERR | - AR_IMR_TXURN | - AR_IMR_RXERR | - AR_IMR_RXORN | - AR_IMR_BCNMISC; - - if (ahp->ah_intrMitigation) - ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; - else - ahp->ah_maskReg |= AR_IMR_RXOK; + switch (devid) { + case AR5416_DEVID_PCI: + return "Atheros 5416"; + case AR5416_DEVID_PCIE: + return "Atheros 5418"; + case AR9160_DEVID_PCI: + return "Atheros 9160"; + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + return "Atheros 9280"; + case AR9285_DEVID_PCIE: + return "Atheros 9285"; + } - ahp->ah_maskReg |= AR_IMR_TXOK; + return NULL; +} - if (opmode == ATH9K_M_HOSTAP) - ahp->ah_maskReg |= AR_IMR_MIB; +static void ath9k_hw_set_defaults(struct ath_hal *ah) +{ + int i; - REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); - REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); + ah->ah_config.dma_beacon_response_time = 2; + ah->ah_config.sw_beacon_response_time = 10; + ah->ah_config.additional_swba_backoff = 0; + ah->ah_config.ack_6mb = 0x0; + ah->ah_config.cwm_ignore_extcca = 0; + ah->ah_config.pcie_powersave_enable = 0; + ah->ah_config.pcie_l1skp_enable = 0; + ah->ah_config.pcie_clock_req = 0; + ah->ah_config.pcie_power_reset = 0x100; + ah->ah_config.pcie_restore = 0; + ah->ah_config.pcie_waen = 0; + ah->ah_config.analog_shiftreg = 1; + ah->ah_config.ht_enable = 1; + ah->ah_config.ofdm_trig_low = 200; + ah->ah_config.ofdm_trig_high = 500; + ah->ah_config.cck_trig_high = 200; + ah->ah_config.cck_trig_low = 100; + ah->ah_config.enable_ani = 1; + ah->ah_config.noise_immunity_level = 4; + ah->ah_config.ofdm_weaksignal_det = 1; + ah->ah_config.cck_weaksignal_thr = 0; + ah->ah_config.spur_immunity_level = 2; + ah->ah_config.firstep_level = 0; + ah->ah_config.rssi_thr_high = 40; + ah->ah_config.rssi_thr_low = 7; + ah->ah_config.diversity_control = 0; + ah->ah_config.antenna_switch_swap = 0; - if (!AR_SREV_9100(ah)) { - REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); - REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + ah->ah_config.spurchans[i][0] = AR_NO_SPUR; + ah->ah_config.spurchans[i][1] = AR_NO_SPUR; } + + ah->ah_config.intr_mitigation = 1; } -static void ath9k_hw_init_qos(struct ath_hal *ah) +static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, + struct ath_softc *sc, + void __iomem *mem, + int *status) { - REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); - REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); - - REG_WRITE(ah, AR_QOS_NO_ACK, - SM(2, AR_QOS_NO_ACK_TWO_BIT) | - SM(5, AR_QOS_NO_ACK_BIT_OFF) | - SM(0, AR_QOS_NO_ACK_BYTE_OFF)); + static const u8 defbssidmask[ETH_ALEN] = + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct ath_hal_5416 *ahp; + struct ath_hal *ah; - REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); - REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); - REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); -} + ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL); + if (ahp == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "Cannot allocate memory for state block\n"); + *status = -ENOMEM; + return NULL; + } -static void ath9k_hw_analog_shift_rmw(struct ath_hal *ah, - u32 reg, - u32 mask, - u32 shift, - u32 val) -{ - u32 regVal; + ah = &ahp->ah; + ah->ah_sc = sc; + ah->ah_sh = mem; + ah->ah_magic = AR5416_MAGIC; + ah->ah_countryCode = CTRY_DEFAULT; + ah->ah_devid = devid; + ah->ah_subvendorid = 0; - regVal = REG_READ(ah, reg) & ~mask; - regVal |= (val << shift) & mask; + ah->ah_flags = 0; + if ((devid == AR5416_AR9100_DEVID)) + ah->ah_macVersion = AR_SREV_VERSION_9100; + if (!AR_SREV_9100(ah)) + ah->ah_flags = AH_USE_EEPROM; - REG_WRITE(ah, reg, regVal); + ah->ah_powerLimit = MAX_RATE_POWER; + ah->ah_tpScale = ATH9K_TP_SCALE_MAX; + ahp->ah_atimWindow = 0; + ahp->ah_diversityControl = ah->ah_config.diversity_control; + ahp->ah_antennaSwitchSwap = + ah->ah_config.antenna_switch_swap; + ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE; + ahp->ah_beaconInterval = 100; + ahp->ah_enable32kHzClock = DONT_USE_32KHZ; + ahp->ah_slottime = (u32) -1; + ahp->ah_acktimeout = (u32) -1; + ahp->ah_ctstimeout = (u32) -1; + ahp->ah_globaltxtimeout = (u32) -1; + memcpy(&ahp->ah_bssidmask, defbssidmask, ETH_ALEN); - if (ah->ah_config.analog_shiftreg) - udelay(100); + ahp->ah_gBeaconRate = 0; - return; + return ahp; } -static u8 ath9k_hw_get_num_ant_config(struct ath_hal_5416 *ahp, - enum ieee80211_band freq_band) +static int ath9k_hw_rfattach(struct ath_hal *ah) { - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - struct modal_eep_header *pModal = - &(eep->modalHeader[IEEE80211_BAND_5GHZ == freq_band]); - struct base_eep_header *pBase = &eep->baseEepHeader; - u8 num_ant_config; - - num_ant_config = 1; + bool rfStatus = false; + int ecode = 0; - if (pBase->version >= 0x0E0D) - if (pModal->useAnt1) - num_ant_config += 1; + rfStatus = ath9k_hw_init_rf(ah, &ecode); + if (!rfStatus) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "RF setup failed, status %u\n", ecode); + return ecode; + } - return num_ant_config; + return 0; } -static int -ath9k_hw_get_eeprom_antenna_cfg(struct ath_hal_5416 *ahp, - struct ath9k_channel *chan, - u8 index, - u16 *config) +static int ath9k_hw_rf_claim(struct ath_hal *ah) { - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - struct modal_eep_header *pModal = - &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - struct base_eep_header *pBase = &eep->baseEepHeader; + u32 val; + + REG_WRITE(ah, AR_PHY(0), 0x00000007); - switch (index) { + val = ath9k_hw_get_radiorev(ah); + switch (val & AR_RADIO_SREV_MAJOR) { case 0: - *config = pModal->antCtrlCommon & 0xFFFF; - return 0; - case 1: - if (pBase->version >= 0x0E0D) { - if (pModal->useAnt1) { - *config = - ((pModal->antCtrlCommon & 0xFFFF0000) >> 16); - return 0; - } - } + val = AR_RAD5133_SREV_MAJOR; break; - default: + case AR_RAD5133_SREV_MAJOR: + case AR_RAD5122_SREV_MAJOR: + case AR_RAD2133_SREV_MAJOR: + case AR_RAD2122_SREV_MAJOR: break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "5G Radio Chip Rev 0x%02X is not " + "supported by this driver\n", + ah->ah_analog5GhzRev); + return -EOPNOTSUPP; } - return -EINVAL; -} + ah->ah_analog5GhzRev = val; -static inline bool ath9k_hw_nvram_read(struct ath_hal *ah, - u32 off, - u16 *data) -{ - if (ath9k_hw_use_flash(ah)) - return ath9k_hw_flash_read(ah, off, data); - else - return ath9k_hw_eeprom_read(ah, off, data); + return 0; } -static bool ath9k_hw_fill_eeprom(struct ath_hal *ah) +static int ath9k_hw_init_macaddr(struct ath_hal *ah) { + u32 sum; + int i; + u16 eeval; struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - u16 *eep_data; - int addr, ar5416_eep_start_loc = 0; - if (!ath9k_hw_use_flash(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Reading from EEPROM, not flash\n", __func__); - ar5416_eep_start_loc = 256; + sum = 0; + for (i = 0; i < 3; i++) { + eeval = ath9k_hw_get_eeprom(ah, AR_EEPROM_MAC(i)); + sum += eeval; + ahp->ah_macaddr[2 * i] = eeval >> 8; + ahp->ah_macaddr[2 * i + 1] = eeval & 0xff; } - if (AR_SREV_9100(ah)) - ar5416_eep_start_loc = 256; - - eep_data = (u16 *) eep; - for (addr = 0; - addr < sizeof(struct ar5416_eeprom) / sizeof(u16); - addr++) { - if (!ath9k_hw_nvram_read(ah, addr + ar5416_eep_start_loc, - eep_data)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Unable to read eeprom region \n", - __func__); - return false; - } - eep_data++; + if (sum == 0 || sum == 0xffff * 3) { + DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, + "mac address read failed: %pM\n", + ahp->ah_macaddr); + return -EADDRNOTAVAIL; } - return true; + + return 0; } -/* XXX: Clean me up, make me more legible */ -static bool -ath9k_hw_eeprom_set_board_values(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_rxgain_ini(struct ath_hal *ah) { - struct modal_eep_header *pModal; - int i, regChainOffset; + u32 rxgain_type; struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - u8 txRxAttenLocal; - u16 ant_config; - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); + if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_17) { + rxgain_type = ath9k_hw_get_eeprom(ah, EEP_RXGAIN_TYPE); - txRxAttenLocal = IS_CHAN_2GHZ(chan) ? 23 : 44; + if (rxgain_type == AR5416_EEP_RXGAIN_13DB_BACKOFF) + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_backoff_13db_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_backoff_13db_rxgain_9280_2), 6); + else if (rxgain_type == AR5416_EEP_RXGAIN_23DB_BACKOFF) + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_backoff_23db_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_backoff_23db_rxgain_9280_2), 6); + else + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_original_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); + } else + INIT_INI_ARRAY(&ahp->ah_iniModesRxGain, + ar9280Modes_original_rxgain_9280_2, + ARRAY_SIZE(ar9280Modes_original_rxgain_9280_2), 6); +} - ath9k_hw_get_eeprom_antenna_cfg(ahp, chan, 1, &ant_config); - REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); +static void ath9k_hw_init_txgain_ini(struct ath_hal *ah) +{ + u32 txgain_type; + struct ath_hal_5416 *ahp = AH5416(ah); - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_9280(ah)) { - if (i >= 2) - break; - } + if (ath9k_hw_get_eeprom(ah, EEP_MINOR_REV) >= AR5416_EEP_MINOR_VER_19) { + txgain_type = ath9k_hw_get_eeprom(ah, EEP_TXGAIN_TYPE); - if (AR_SREV_5416_V20_OR_LATER(ah) && - (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) - && (i != 0)) - regChainOffset = (i == 1) ? 0x2000 : 0x1000; + if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) + INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + ar9280Modes_high_power_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_high_power_tx_gain_9280_2), 6); else - regChainOffset = i * 0x1000; - - REG_WRITE(ah, AR_PHY_SWITCH_CHAIN_0 + regChainOffset, - pModal->antCtrlChain[i]); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0) + regChainOffset, - (REG_READ(ah, - AR_PHY_TIMING_CTRL4(0) + - regChainOffset) & - ~(AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF | - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF)) | - SM(pModal->iqCalICh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF) | - SM(pModal->iqCalQCh[i], - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF)); - - if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { - if ((eep->baseEepHeader.version & - AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - txRxAttenLocal = pModal->txRxAttenCh[i]; - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_MARGIN, - pModal-> - bswMargin[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN1_DB, - pModal-> - bswAtten[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_MARGIN, - pModal-> - xatten2Margin[i]); - REG_RMW_FIELD(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - AR_PHY_GAIN_2GHZ_XATTEN2_DB, - pModal-> - xatten2Db[i]); - } else { - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_MARGIN) - | SM(pModal-> - bswMargin[i], - AR_PHY_GAIN_2GHZ_BSW_MARGIN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_BSW_ATTEN) - | SM(pModal->bswAtten[i], - AR_PHY_GAIN_2GHZ_BSW_ATTEN)); - } - } - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + - regChainOffset, - AR9280_PHY_RXGAIN_TXRX_ATTEN, - txRxAttenLocal); - REG_RMW_FIELD(ah, - AR_PHY_RXGAIN + - regChainOffset, - AR9280_PHY_RXGAIN_TXRX_MARGIN, - pModal->rxTxMarginCh[i]); - } else { - REG_WRITE(ah, - AR_PHY_RXGAIN + regChainOffset, - (REG_READ(ah, - AR_PHY_RXGAIN + - regChainOffset) & - ~AR_PHY_RXGAIN_TXRX_ATTEN) | - SM(txRxAttenLocal, - AR_PHY_RXGAIN_TXRX_ATTEN)); - REG_WRITE(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset, - (REG_READ(ah, - AR_PHY_GAIN_2GHZ + - regChainOffset) & - ~AR_PHY_GAIN_2GHZ_RXTX_MARGIN) | - SM(pModal->rxTxMarginCh[i], - AR_PHY_GAIN_2GHZ_RXTX_MARGIN)); - } - } - } + INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + ar9280Modes_original_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); + } else + INIT_INI_ARRAY(&ahp->ah_iniModesTxGain, + ar9280Modes_original_tx_gain_9280_2, + ARRAY_SIZE(ar9280Modes_original_tx_gain_9280_2), 6); +} - if (AR_SREV_9280_10_OR_LATER(ah)) { - if (IS_CHAN_2GHZ(chan)) { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_OB, - AR_AN_RF2G1_CH0_OB_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH0, - AR_AN_RF2G1_CH0_DB, - AR_AN_RF2G1_CH0_DB_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_OB, - AR_AN_RF2G1_CH1_OB_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF2G1_CH1, - AR_AN_RF2G1_CH1_DB, - AR_AN_RF2G1_CH1_DB_S, - pModal->db_ch1); - } else { - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_OB5, - AR_AN_RF5G1_CH0_OB5_S, - pModal->ob); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH0, - AR_AN_RF5G1_CH0_DB5, - AR_AN_RF5G1_CH0_DB5_S, - pModal->db); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_OB5, - AR_AN_RF5G1_CH1_OB5_S, - pModal->ob_ch1); - ath9k_hw_analog_shift_rmw(ah, AR_AN_RF5G1_CH1, - AR_AN_RF5G1_CH1_DB5, - AR_AN_RF5G1_CH1_DB5_S, - pModal->db_ch1); - } - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_XPABIAS_LVL, - AR_AN_TOP2_XPABIAS_LVL_S, - pModal->xpaBiasLvl); - ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2, - AR_AN_TOP2_LOCALBIAS, - AR_AN_TOP2_LOCALBIAS_S, - pModal->local_bias); - DPRINTF(ah->ah_sc, ATH_DBG_ANY, "ForceXPAon: %d\n", - pModal->force_xpaon); - REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG, - pModal->force_xpaon); +static int ath9k_hw_post_attach(struct ath_hal *ah) +{ + int ecode; + + if (!ath9k_hw_chip_test(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "hardware self-test failed\n"); + return -ENODEV; } - REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH, - pModal->switchSettling); - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, AR_PHY_DESIRED_SZ_ADC, - pModal->adcDesiredSize); + ecode = ath9k_hw_rf_claim(ah); + if (ecode != 0) + return ecode; - if (!AR_SREV_9280_10_OR_LATER(ah)) - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_PGA, - pModal->pgaDesiredSize); - - REG_WRITE(ah, AR_PHY_RF_CTL4, - SM(pModal->txEndToXpaOff, AR_PHY_RF_CTL4_TX_END_XPAA_OFF) - | SM(pModal->txEndToXpaOff, - AR_PHY_RF_CTL4_TX_END_XPAB_OFF) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAA_ON) - | SM(pModal->txFrameToXpaOn, - AR_PHY_RF_CTL4_FRAME_XPAB_ON)); - - REG_RMW_FIELD(ah, AR_PHY_RF_CTL3, AR_PHY_TX_END_TO_A2_RX_ON, - pModal->txEndToRxOn); - if (AR_SREV_9280_10_OR_LATER(ah)) { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR9280_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA0, - AR_PHY_EXT_CCA0_THRESH62, - pModal->thresh62); - } else { - REG_RMW_FIELD(ah, AR_PHY_CCA, AR_PHY_CCA_THRESH62, - pModal->thresh62); - REG_RMW_FIELD(ah, AR_PHY_EXT_CCA, - AR_PHY_EXT_CCA_THRESH62, - pModal->thresh62); - } + ecode = ath9k_hw_eeprom_attach(ah); + if (ecode != 0) + return ecode; + ecode = ath9k_hw_rfattach(ah); + if (ecode != 0) + return ecode; - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, - AR_PHY_TX_END_DATA_START, - pModal->txFrameToDataStart); - REG_RMW_FIELD(ah, AR_PHY_RF_CTL2, AR_PHY_TX_END_PA_ON, - pModal->txFrameToPaOn); + if (!AR_SREV_9100(ah)) { + ath9k_hw_ani_setup(ah); + ath9k_hw_ani_attach(ah); } - if ((eep->baseEepHeader.version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_3) { - if (IS_CHAN_HT40(chan)) - REG_RMW_FIELD(ah, AR_PHY_SETTLING, - AR_PHY_SETTLING_SWITCH, - pModal->swSettleHt40); - } + return 0; +} - return true; -} - -static int ath9k_hw_check_eeprom(struct ath_hal *ah) +static struct ath_hal *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc, + void __iomem *mem, int *status) { - u32 sum = 0, el; - u16 *eepdata; - int i; - struct ath_hal_5416 *ahp = AH5416(ah); - bool need_swap = false; - struct ar5416_eeprom *eep = - (struct ar5416_eeprom *) &ahp->ah_eeprom; - - if (!ath9k_hw_use_flash(ah)) { - u16 magic, magic2; - int addr; - - if (!ath9k_hw_nvram_read(ah, AR5416_EEPROM_MAGIC_OFFSET, - &magic)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: Reading Magic # failed\n", __func__); - return false; - } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "%s: Read Magic = 0x%04X\n", - __func__, magic); - - if (magic != AR5416_EEPROM_MAGIC) { - magic2 = swab16(magic); - - if (magic2 == AR5416_EEPROM_MAGIC) { - need_swap = true; - eepdata = (u16 *) (&ahp->ah_eeprom); - - for (addr = 0; - addr < - sizeof(struct ar5416_eeprom) / - sizeof(u16); addr++) { - u16 temp; - - temp = swab16(*eepdata); - *eepdata = temp; - eepdata++; - - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "0x%04X ", *eepdata); - if (((addr + 1) % 6) == 0) - DPRINTF(ah->ah_sc, - ATH_DBG_EEPROM, - "\n"); - } - } else { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Invalid EEPROM Magic. " - "endianness missmatch.\n"); - return -EINVAL; - } + struct ath_hal_5416 *ahp; + struct ath_hal *ah; + int ecode; + u32 i, j; + + ahp = ath9k_hw_newstate(devid, sc, mem, status); + if (ahp == NULL) + return NULL; + + ah = &ahp->ah; + + ath9k_hw_set_defaults(ah); + + if (ah->ah_config.intr_mitigation != 0) + ahp->ah_intrMitigation = true; + + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't reset chip\n"); + ecode = -EIO; + goto bad; + } + + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "Couldn't wakeup chip\n"); + ecode = -EIO; + goto bad; + } + + if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) { + if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) { + ah->ah_config.serialize_regmode = + SER_REG_MODE_ON; + } else { + ah->ah_config.serialize_regmode = + SER_REG_MODE_OFF; } } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, "need_swap = %s.\n", - need_swap ? "True" : "False"); - if (need_swap) - el = swab16(ahp->ah_eeprom.baseEepHeader.length); - else - el = ahp->ah_eeprom.baseEepHeader.length; + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "serialize_regmode is %d\n", + ah->ah_config.serialize_regmode); - if (el > sizeof(struct ar5416_eeprom)) - el = sizeof(struct ar5416_eeprom) / sizeof(u16); - else - el = el / sizeof(u16); + if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) && + (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) && + (ah->ah_macVersion != AR_SREV_VERSION_9160) && + (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah)) && (!AR_SREV_9285(ah))) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "Mac Chip Rev 0x%02x.%x is not supported by " + "this driver\n", ah->ah_macVersion, ah->ah_macRev); + ecode = -EOPNOTSUPP; + goto bad; + } - eepdata = (u16 *) (&ahp->ah_eeprom); + if (AR_SREV_9100(ah)) { + ahp->ah_iqCalData.calData = &iq_cal_multi_sample; + ahp->ah_suppCals = IQ_MISMATCH_CAL; + ah->ah_isPciExpress = false; + } + ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID); - for (i = 0; i < el; i++) - sum ^= *eepdata++; + if (AR_SREV_9160_10_OR_LATER(ah)) { + if (AR_SREV_9280_10_OR_LATER(ah)) { + ahp->ah_iqCalData.calData = &iq_cal_single_sample; + ahp->ah_adcGainCalData.calData = + &adc_gain_cal_single_sample; + ahp->ah_adcDcCalData.calData = + &adc_dc_cal_single_sample; + ahp->ah_adcDcCalInitData.calData = + &adc_init_dc_cal; + } else { + ahp->ah_iqCalData.calData = &iq_cal_multi_sample; + ahp->ah_adcGainCalData.calData = + &adc_gain_cal_multi_sample; + ahp->ah_adcDcCalData.calData = + &adc_dc_cal_multi_sample; + ahp->ah_adcDcCalInitData.calData = + &adc_init_dc_cal; + } + ahp->ah_suppCals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; + } - if (need_swap) { - u32 integer, j; - u16 word; + if (AR_SREV_9160(ah)) { + ah->ah_config.enable_ani = 1; + ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | + ATH9K_ANI_FIRSTEP_LEVEL); + } else { + ahp->ah_ani_function = ATH9K_ANI_ALL; + if (AR_SREV_9280_10_OR_LATER(ah)) { + ahp->ah_ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; + } + } - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "EEPROM Endianness is not native.. Changing \n"); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "This Mac Chip Rev 0x%02x.%x is \n", + ah->ah_macVersion, ah->ah_macRev); - word = swab16(eep->baseEepHeader.length); - eep->baseEepHeader.length = word; + if (AR_SREV_9285_12_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285_1_2, + ARRAY_SIZE(ar9285Modes_9285_1_2), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285_1_2, + ARRAY_SIZE(ar9285Common_9285_1_2), 2); - word = swab16(eep->baseEepHeader.checksum); - eep->baseEepHeader.checksum = word; + if (ah->ah_config.pcie_clock_req) { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_off_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285_1_2), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_always_on_L1_9285_1_2, + ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285_1_2), + 2); + } + } else if (AR_SREV_9285_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9285Modes_9285, + ARRAY_SIZE(ar9285Modes_9285), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9285Common_9285, + ARRAY_SIZE(ar9285Common_9285), 2); - word = swab16(eep->baseEepHeader.version); - eep->baseEepHeader.version = word; + if (ah->ah_config.pcie_clock_req) { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_off_L1_9285, + ARRAY_SIZE(ar9285PciePhy_clkreq_off_L1_9285), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9285PciePhy_clkreq_always_on_L1_9285, + ARRAY_SIZE(ar9285PciePhy_clkreq_always_on_L1_9285), 2); + } + } else if (AR_SREV_9280_20_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2, + ARRAY_SIZE(ar9280Modes_9280_2), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2, + ARRAY_SIZE(ar9280Common_9280_2), 2); - word = swab16(eep->baseEepHeader.regDmn[0]); - eep->baseEepHeader.regDmn[0] = word; + if (ah->ah_config.pcie_clock_req) { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9280PciePhy_clkreq_off_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_off_L1_9280),2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, + ar9280PciePhy_clkreq_always_on_L1_9280, + ARRAY_SIZE(ar9280PciePhy_clkreq_always_on_L1_9280), 2); + } + INIT_INI_ARRAY(&ahp->ah_iniModesAdditional, + ar9280Modes_fast_clock_9280_2, + ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), 3); + } else if (AR_SREV_9280_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280, + ARRAY_SIZE(ar9280Modes_9280), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280, + ARRAY_SIZE(ar9280Common_9280), 2); + } else if (AR_SREV_9160_10_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160, + ARRAY_SIZE(ar5416Modes_9160), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160, + ARRAY_SIZE(ar5416Common_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160, + ARRAY_SIZE(ar5416Bank0_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160, + ARRAY_SIZE(ar5416BB_RfGain_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160, + ARRAY_SIZE(ar5416Bank1_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160, + ARRAY_SIZE(ar5416Bank2_9160), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160, + ARRAY_SIZE(ar5416Bank3_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160, + ARRAY_SIZE(ar5416Bank6_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160, + ARRAY_SIZE(ar5416Bank6TPC_9160), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160, + ARRAY_SIZE(ar5416Bank7_9160), 2); + if (AR_SREV_9160_11(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniAddac, + ar5416Addac_91601_1, + ARRAY_SIZE(ar5416Addac_91601_1), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160, + ARRAY_SIZE(ar5416Addac_9160), 2); + } + } else if (AR_SREV_9100_OR_LATER(ah)) { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100, + ARRAY_SIZE(ar5416Modes_9100), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100, + ARRAY_SIZE(ar5416Common_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100, + ARRAY_SIZE(ar5416Bank0_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100, + ARRAY_SIZE(ar5416BB_RfGain_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100, + ARRAY_SIZE(ar5416Bank1_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100, + ARRAY_SIZE(ar5416Bank2_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100, + ARRAY_SIZE(ar5416Bank3_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100, + ARRAY_SIZE(ar5416Bank6_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100, + ARRAY_SIZE(ar5416Bank6TPC_9100), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100, + ARRAY_SIZE(ar5416Bank7_9100), 2); + INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100, + ARRAY_SIZE(ar5416Addac_9100), 2); + } else { + INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes, + ARRAY_SIZE(ar5416Modes), 6); + INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common, + ARRAY_SIZE(ar5416Common), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0, + ARRAY_SIZE(ar5416Bank0), 2); + INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain, + ARRAY_SIZE(ar5416BB_RfGain), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1, + ARRAY_SIZE(ar5416Bank1), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2, + ARRAY_SIZE(ar5416Bank2), 2); + INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3, + ARRAY_SIZE(ar5416Bank3), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6, + ARRAY_SIZE(ar5416Bank6), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC, + ARRAY_SIZE(ar5416Bank6TPC), 3); + INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7, + ARRAY_SIZE(ar5416Bank7), 2); + INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac, + ARRAY_SIZE(ar5416Addac), 2); + } - word = swab16(eep->baseEepHeader.regDmn[1]); - eep->baseEepHeader.regDmn[1] = word; + if (ah->ah_isPciExpress) + ath9k_hw_configpcipowersave(ah, 0); + else + ath9k_hw_disablepcie(ah); - word = swab16(eep->baseEepHeader.rfSilent); - eep->baseEepHeader.rfSilent = word; + ecode = ath9k_hw_post_attach(ah); + if (ecode != 0) + goto bad; - word = swab16(eep->baseEepHeader.blueToothOptions); - eep->baseEepHeader.blueToothOptions = word; + /* rxgain table */ + if (AR_SREV_9280_20(ah)) + ath9k_hw_init_rxgain_ini(ah); - word = swab16(eep->baseEepHeader.deviceCap); - eep->baseEepHeader.deviceCap = word; + /* txgain table */ + if (AR_SREV_9280_20(ah)) + ath9k_hw_init_txgain_ini(ah); - for (j = 0; j < ARRAY_SIZE(eep->modalHeader); j++) { - struct modal_eep_header *pModal = - &eep->modalHeader[j]; - integer = swab32(pModal->antCtrlCommon); - pModal->antCtrlCommon = integer; + if (ah->ah_devid == AR9280_DEVID_PCI) { + for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { + u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - integer = swab32(pModal->antCtrlChain[i]); - pModal->antCtrlChain[i] = integer; - } + for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) { + u32 val = INI_RA(&ahp->ah_iniModes, i, j); - for (i = 0; i < AR5416_EEPROM_MODAL_SPURS; i++) { - word = swab16(pModal->spurChans[i].spurChan); - pModal->spurChans[i].spurChan = word; + INI_RA(&ahp->ah_iniModes, i, j) = + ath9k_hw_ini_fixup(ah, + &ahp->ah_eeprom.def, + reg, val); } } } - if (sum != 0xffff || ar5416_get_eep_ver(ahp) != AR5416_EEP_VER || - ar5416_get_eep_rev(ahp) < AR5416_EEP_NO_BACK_VER) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "Bad EEPROM checksum 0x%x or revision 0x%04x\n", - sum, ar5416_get_eep_ver(ahp)); - return -EINVAL; + if (!ath9k_hw_fill_cap_info(ah)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "failed ath9k_hw_fill_cap_info\n"); + ecode = -EINVAL; + goto bad; } - return 0; + ecode = ath9k_hw_init_macaddr(ah); + if (ecode != 0) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "failed initializing mac address\n"); + goto bad; + } + + if (AR_SREV_9285(ah)) + ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S); + else + ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S); + + ath9k_init_nfcal_hist_buffer(ah); + + return ah; +bad: + if (ahp) + ath9k_hw_detach((struct ath_hal *) ahp); + if (status) + *status = ecode; + + return NULL; } -static bool ath9k_hw_chip_test(struct ath_hal *ah) +static void ath9k_hw_init_bb(struct ath_hal *ah, + struct ath9k_channel *chan) { - u32 regAddr[2] = { AR_STA_ID0, AR_PHY_BASE + (8 << 2) }; - u32 regHold[2]; - u32 patternData[4] = { 0x55555555, - 0xaaaaaaaa, - 0x66666666, - 0x99999999 }; - int i, j; + u32 synthDelay; - for (i = 0; i < 2; i++) { - u32 addr = regAddr[i]; - u32 wrData, rdData; + synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; + if (IS_CHAN_B(chan)) + synthDelay = (4 * synthDelay) / 22; + else + synthDelay /= 10; - regHold[i] = REG_READ(ah, addr); - for (j = 0; j < 0x100; j++) { - wrData = (j << 16) | j; - REG_WRITE(ah, addr, wrData); - rdData = REG_READ(ah, addr); - if (rdData != wrData) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: address test failed " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - __func__, addr, wrData, rdData); - return false; - } - } - for (j = 0; j < 4; j++) { - wrData = patternData[j]; - REG_WRITE(ah, addr, wrData); - rdData = REG_READ(ah, addr); - if (wrData != rdData) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: address test failed " - "addr: 0x%08x - wr:0x%08x != rd:0x%08x\n", - __func__, addr, wrData, rdData); - return false; - } - } - REG_WRITE(ah, regAddr[i], regHold[i]); - } - udelay(100); - return true; -} - -u32 ath9k_hw_getrxfilter(struct ath_hal *ah) -{ - u32 bits = REG_READ(ah, AR_RX_FILTER); - u32 phybits = REG_READ(ah, AR_PHY_ERR); + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_EN); - if (phybits & AR_PHY_ERR_RADAR) - bits |= ATH9K_RX_FILTER_PHYRADAR; - if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING)) - bits |= ATH9K_RX_FILTER_PHYERR; - return bits; + udelay(synthDelay + BASE_ACTIVATE_DELAY); } -void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits) +static void ath9k_hw_init_qos(struct ath_hal *ah) { - u32 phybits; + REG_WRITE(ah, AR_MIC_QOS_CONTROL, 0x100aa); + REG_WRITE(ah, AR_MIC_QOS_SELECT, 0x3210); - REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); - phybits = 0; - if (bits & ATH9K_RX_FILTER_PHYRADAR) - phybits |= AR_PHY_ERR_RADAR; - if (bits & ATH9K_RX_FILTER_PHYERR) - phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; - REG_WRITE(ah, AR_PHY_ERR, phybits); + REG_WRITE(ah, AR_QOS_NO_ACK, + SM(2, AR_QOS_NO_ACK_TWO_BIT) | + SM(5, AR_QOS_NO_ACK_BIT_OFF) | + SM(0, AR_QOS_NO_ACK_BYTE_OFF)); - if (phybits) - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); - else - REG_WRITE(ah, AR_RXCFG, - REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); + REG_WRITE(ah, AR_TXOP_X, AR_TXOP_X_VAL); + REG_WRITE(ah, AR_TXOP_0_3, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_4_7, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_8_11, 0xFFFFFFFF); + REG_WRITE(ah, AR_TXOP_12_15, 0xFFFFFFFF); } -bool ath9k_hw_setcapability(struct ath_hal *ah, - enum ath9k_capability_type type, - u32 capability, - u32 setting, - int *status) +static void ath9k_hw_init_pll(struct ath_hal *ah, + struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); - u32 v; + u32 pll; - switch (type) { - case ATH9K_CAP_TKIP_MIC: - if (setting) - ahp->ah_staId1Defaults |= - AR_STA_ID1_CRPT_MIC_ENABLE; - else - ahp->ah_staId1Defaults &= - ~AR_STA_ID1_CRPT_MIC_ENABLE; - return true; - case ATH9K_CAP_DIVERSITY: - v = REG_READ(ah, AR_PHY_CCK_DETECT); - if (setting) - v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - else - v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; - REG_WRITE(ah, AR_PHY_CCK_DETECT, v); - return true; - case ATH9K_CAP_MCAST_KEYSRCH: - if (setting) - ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; - else - ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; - return true; - case ATH9K_CAP_TSF_ADJUST: - if (setting) - ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; + if (AR_SREV_9100(ah)) { + if (chan && IS_CHAN_5GHZ(chan)) + pll = 0x1450; else - ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; - return true; - default: - return false; - } -} - -void ath9k_hw_dmaRegDump(struct ath_hal *ah) -{ - u32 val[ATH9K_NUM_DMA_DEBUG_REGS]; - int qcuOffset = 0, dcuOffset = 0; - u32 *qcuBase = &val[0], *dcuBase = &val[4]; - int i; - - REG_WRITE(ah, AR_MACMISC, - ((AR_MACMISC_DMA_OBS_LINE_8 << AR_MACMISC_DMA_OBS_S) | - (AR_MACMISC_MISC_OBS_BUS_1 << - AR_MACMISC_MISC_OBS_BUS_MSB_S))); - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "Raw DMA Debug values:\n"); - for (i = 0; i < ATH9K_NUM_DMA_DEBUG_REGS; i++) { - if (i % 4 == 0) - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n"); - - val[i] = REG_READ(ah, AR_DMADBG_0 + (i * sizeof(u32))); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "%d: %08x ", i, val[i]); - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n\n"); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "Num QCU: chain_st fsp_ok fsp_st DCU: chain_st\n"); - - for (i = 0; i < ATH9K_NUM_QUEUES; - i++, qcuOffset += 4, dcuOffset += 5) { - if (i == 8) { - qcuOffset = 0; - qcuBase++; - } - - if (i == 6) { - dcuOffset = 0; - dcuBase++; - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%2d %2x %1x %2x %2x\n", - i, (*qcuBase & (0x7 << qcuOffset)) >> qcuOffset, - (*qcuBase & (0x8 << qcuOffset)) >> (qcuOffset + - 3), - val[2] & (0x7 << (i * 3)) >> (i * 3), - (*dcuBase & (0x1f << dcuOffset)) >> dcuOffset); - } - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "\n"); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "qcu_stitch state: %2x qcu_fetch state: %2x\n", - (val[3] & 0x003c0000) >> 18, (val[3] & 0x03c00000) >> 22); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "qcu_complete state: %2x dcu_complete state: %2x\n", - (val[3] & 0x1c000000) >> 26, (val[6] & 0x3)); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "dcu_arb state: %2x dcu_fp state: %2x\n", - (val[5] & 0x06000000) >> 25, (val[5] & 0x38000000) >> 27); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "chan_idle_dur: %3d chan_idle_dur_valid: %1d\n", - (val[6] & 0x000003fc) >> 2, (val[6] & 0x00000400) >> 10); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "txfifo_valid_0: %1d txfifo_valid_1: %1d\n", - (val[6] & 0x00000800) >> 11, (val[6] & 0x00001000) >> 12); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "txfifo_dcu_num_0: %2d txfifo_dcu_num_1: %2d\n", - (val[6] & 0x0001e000) >> 13, (val[6] & 0x001e0000) >> 17); - - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, "pcu observe 0x%x \n", - REG_READ(ah, AR_OBS_BUS_1)); - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "AR_CR 0x%x \n", REG_READ(ah, AR_CR)); -} - -u32 ath9k_hw_GetMibCycleCountsPct(struct ath_hal *ah, - u32 *rxc_pcnt, - u32 *rxf_pcnt, - u32 *txf_pcnt) -{ - static u32 cycles, rx_clear, rx_frame, tx_frame; - u32 good = 1; - - u32 rc = REG_READ(ah, AR_RCCNT); - u32 rf = REG_READ(ah, AR_RFCNT); - u32 tf = REG_READ(ah, AR_TFCNT); - u32 cc = REG_READ(ah, AR_CCCNT); - - if (cycles == 0 || cycles > cc) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: cycle counter wrap. ExtBusy = 0\n", - __func__); - good = 0; + pll = 0x1458; } else { - u32 cc_d = cc - cycles; - u32 rc_d = rc - rx_clear; - u32 rf_d = rf - rx_frame; - u32 tf_d = tf - tx_frame; - - if (cc_d != 0) { - *rxc_pcnt = rc_d * 100 / cc_d; - *rxf_pcnt = rf_d * 100 / cc_d; - *txf_pcnt = tf_d * 100 / cc_d; - } else { - good = 0; - } - } - - cycles = cc; - rx_frame = rf; - rx_clear = rc; - tx_frame = tf; - - return good; -} - -void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode) -{ - u32 macmode; - - if (mode == ATH9K_HT_MACMODE_2040 && - !ah->ah_config.cwm_ignore_extcca) - macmode = AR_2040_JOINED_RX_CLEAR; - else - macmode = 0; - - REG_WRITE(ah, AR_2040_MODE, macmode); -} - -static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah) -{ - REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); -} - - -static struct ath_hal_5416 *ath9k_hw_newstate(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *status) -{ - static const u8 defbssidmask[ETH_ALEN] = - { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; - struct ath_hal_5416 *ahp; - struct ath_hal *ah; - - ahp = kzalloc(sizeof(struct ath_hal_5416), GFP_KERNEL); - if (ahp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: cannot allocate memory for state block\n", - __func__); - *status = -ENOMEM; - return NULL; - } - - ah = &ahp->ah; - - ah->ah_sc = sc; - ah->ah_sh = mem; - - ah->ah_magic = AR5416_MAGIC; - ah->ah_countryCode = CTRY_DEFAULT; - - ah->ah_devid = devid; - ah->ah_subvendorid = 0; - - ah->ah_flags = 0; - if ((devid == AR5416_AR9100_DEVID)) - ah->ah_macVersion = AR_SREV_VERSION_9100; - if (!AR_SREV_9100(ah)) - ah->ah_flags = AH_USE_EEPROM; - - ah->ah_powerLimit = MAX_RATE_POWER; - ah->ah_tpScale = ATH9K_TP_SCALE_MAX; - - ahp->ah_atimWindow = 0; - ahp->ah_diversityControl = ah->ah_config.diversity_control; - ahp->ah_antennaSwitchSwap = - ah->ah_config.antenna_switch_swap; - - ahp->ah_staId1Defaults = AR_STA_ID1_CRPT_MIC_ENABLE; - ahp->ah_beaconInterval = 100; - ahp->ah_enable32kHzClock = DONT_USE_32KHZ; - ahp->ah_slottime = (u32) -1; - ahp->ah_acktimeout = (u32) -1; - ahp->ah_ctstimeout = (u32) -1; - ahp->ah_globaltxtimeout = (u32) -1; - memcpy(&ahp->ah_bssidmask, defbssidmask, ETH_ALEN); - - ahp->ah_gBeaconRate = 0; - - return ahp; -} - -static int ath9k_hw_eeprom_attach(struct ath_hal *ah) -{ - int status; - - if (ath9k_hw_use_flash(ah)) - ath9k_hw_flash_map(ah); - - if (!ath9k_hw_fill_eeprom(ah)) - return -EIO; - - status = ath9k_hw_check_eeprom(ah); - - return status; -} - -u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, - enum eeprom_param param) -{ - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - struct modal_eep_header *pModal = eep->modalHeader; - struct base_eep_header *pBase = &eep->baseEepHeader; - - switch (param) { - case EEP_NFTHRESH_5: - return -pModal[0].noiseFloorThreshCh[0]; - case EEP_NFTHRESH_2: - return -pModal[1].noiseFloorThreshCh[0]; - case AR_EEPROM_MAC(0): - return pBase->macAddr[0] << 8 | pBase->macAddr[1]; - case AR_EEPROM_MAC(1): - return pBase->macAddr[2] << 8 | pBase->macAddr[3]; - case AR_EEPROM_MAC(2): - return pBase->macAddr[4] << 8 | pBase->macAddr[5]; - case EEP_REG_0: - return pBase->regDmn[0]; - case EEP_REG_1: - return pBase->regDmn[1]; - case EEP_OP_CAP: - return pBase->deviceCap; - case EEP_OP_MODE: - return pBase->opCapFlags; - case EEP_RF_SILENT: - return pBase->rfSilent; - case EEP_OB_5: - return pModal[0].ob; - case EEP_DB_5: - return pModal[0].db; - case EEP_OB_2: - return pModal[1].ob; - case EEP_DB_2: - return pModal[1].db; - case EEP_MINOR_REV: - return pBase->version & AR5416_EEP_VER_MINOR_MASK; - case EEP_TX_MASK: - return pBase->txMask; - case EEP_RX_MASK: - return pBase->rxMask; - default: - return 0; - } -} - -static int ath9k_hw_get_radiorev(struct ath_hal *ah) -{ - u32 val; - int i; - - REG_WRITE(ah, AR_PHY(0x36), 0x00007058); - for (i = 0; i < 8; i++) - REG_WRITE(ah, AR_PHY(0x20), 0x00010000); - val = (REG_READ(ah, AR_PHY(256)) >> 24) & 0xff; - val = ((val & 0xf0) >> 4) | ((val & 0x0f) << 4); - return ath9k_hw_reverse_bits(val, 8); -} + if (AR_SREV_9280_10_OR_LATER(ah)) { + pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); -static int ath9k_hw_init_macaddr(struct ath_hal *ah) -{ - u32 sum; - int i; - u16 eeval; - struct ath_hal_5416 *ahp = AH5416(ah); - DECLARE_MAC_BUF(mac); - - sum = 0; - for (i = 0; i < 3; i++) { - eeval = ath9k_hw_get_eeprom(ahp, AR_EEPROM_MAC(i)); - sum += eeval; - ahp->ah_macaddr[2 * i] = eeval >> 8; - ahp->ah_macaddr[2 * i + 1] = eeval & 0xff; - } - if (sum == 0 || sum == 0xffff * 3) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: mac address read failed: %s\n", __func__, - print_mac(mac, ahp->ah_macaddr)); - return -EADDRNOTAVAIL; - } - - return 0; -} - -static inline int16_t ath9k_hw_interpolate(u16 target, - u16 srcLeft, - u16 srcRight, - int16_t targetLeft, - int16_t targetRight) -{ - int16_t rv; - - if (srcRight == srcLeft) { - rv = targetLeft; - } else { - rv = (int16_t) (((target - srcLeft) * targetRight + - (srcRight - target) * targetLeft) / - (srcRight - srcLeft)); - } - return rv; -} - -static inline u16 ath9k_hw_fbin2freq(u8 fbin, - bool is2GHz) -{ - - if (fbin == AR5416_BCHAN_UNUSED) - return fbin; - - return (u16) ((is2GHz) ? (2300 + fbin) : (4800 + 5 * fbin)); -} - -static u16 ath9k_hw_eeprom_get_spur_chan(struct ath_hal *ah, - u16 i, - bool is2GHz) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = - (struct ar5416_eeprom *) &ahp->ah_eeprom; - u16 spur_val = AR_NO_SPUR; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur idx %d is2Ghz. %d val %x\n", - i, is2GHz, ah->ah_config.spurchans[i][is2GHz]); - - switch (ah->ah_config.spurmode) { - case SPUR_DISABLE: - break; - case SPUR_ENABLE_IOCTL: - spur_val = ah->ah_config.spurchans[i][is2GHz]; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Getting spur val from new loc. %d\n", spur_val); - break; - case SPUR_ENABLE_EEPROM: - spur_val = eep->modalHeader[is2GHz].spurChans[i].spurChan; - break; - - } - return spur_val; -} - -static int ath9k_hw_rfattach(struct ath_hal *ah) -{ - bool rfStatus = false; - int ecode = 0; - - rfStatus = ath9k_hw_init_rf(ah, &ecode); - if (!rfStatus) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: RF setup failed, status %u\n", __func__, - ecode); - return ecode; - } - - return 0; -} - -static int ath9k_hw_rf_claim(struct ath_hal *ah) -{ - u32 val; - - REG_WRITE(ah, AR_PHY(0), 0x00000007); - - val = ath9k_hw_get_radiorev(ah); - switch (val & AR_RADIO_SREV_MAJOR) { - case 0: - val = AR_RAD5133_SREV_MAJOR; - break; - case AR_RAD5133_SREV_MAJOR: - case AR_RAD5122_SREV_MAJOR: - case AR_RAD2133_SREV_MAJOR: - case AR_RAD2122_SREV_MAJOR: - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: 5G Radio Chip Rev 0x%02X is not " - "supported by this driver\n", - __func__, ah->ah_analog5GhzRev); - return -EOPNOTSUPP; - } - - ah->ah_analog5GhzRev = val; - - return 0; -} - -static void ath9k_hw_init_pll(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - u32 pll; - - if (AR_SREV_9100(ah)) { - if (chan && IS_CHAN_5GHZ(chan)) - pll = 0x1450; - else - pll = 0x1458; - } else { - if (AR_SREV_9280_10_OR_LATER(ah)) { - pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); if (chan && IS_CHAN_5GHZ(chan)) { pll |= SM(0x28, AR_RTC_9160_PLL_DIV); - if (AR_SREV_9280_20(ah)) { - if (((chan->channel % 20) == 0) - || ((chan->channel % 10) == 0)) - pll = 0x2850; - else - pll = 0x142c; - } - } else { - pll |= SM(0x2c, AR_RTC_9160_PLL_DIV); - } - - } else if (AR_SREV_9160_10_OR_LATER(ah)) { - - pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); - - if (chan && IS_CHAN_5GHZ(chan)) - pll |= SM(0x50, AR_RTC_9160_PLL_DIV); - else - pll |= SM(0x58, AR_RTC_9160_PLL_DIV); - } else { - pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; - - if (chan && IS_CHAN_HALF_RATE(chan)) - pll |= SM(0x1, AR_RTC_PLL_CLKSEL); - else if (chan && IS_CHAN_QUARTER_RATE(chan)) - pll |= SM(0x2, AR_RTC_PLL_CLKSEL); - - if (chan && IS_CHAN_5GHZ(chan)) - pll |= SM(0xa, AR_RTC_PLL_DIV); - else - pll |= SM(0xb, AR_RTC_PLL_DIV); - } - } - REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll); - - udelay(RTC_PLL_SETTLE_DELAY); - - REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); -} - -static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) -{ - u32 phymode; - struct ath_hal_5416 *ahp = AH5416(ah); - - phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 - | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH; - - if (IS_CHAN_HT40(chan)) { - phymode |= AR_PHY_FC_DYN2040_EN; - - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) - phymode |= AR_PHY_FC_DYN2040_PRI_CH; - - if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25) - phymode |= AR_PHY_FC_DYN2040_EXT_CH; - } - REG_WRITE(ah, AR_PHY_TURBO, phymode); - - ath9k_hw_set11nmac2040(ah, macmode); - - REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); - REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); -} - -static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) -{ - u32 val; - - val = REG_READ(ah, AR_STA_ID1); - val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); - switch (opmode) { - case ATH9K_M_HOSTAP: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP - | AR_STA_ID1_KSRCH_MODE); - REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; - case ATH9K_M_IBSS: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC - | AR_STA_ID1_KSRCH_MODE); - REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); - break; - case ATH9K_M_STA: - case ATH9K_M_MONITOR: - REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); - break; - } -} - -static void -ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) -{ - u32 rfMode = 0; - - if (chan == NULL) - return; - - rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) - ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; - - if (!AR_SREV_9280_10_OR_LATER(ah)) - rfMode |= (IS_CHAN_5GHZ(chan)) ? AR_PHY_MODE_RF5GHZ : - AR_PHY_MODE_RF2GHZ; - - if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) - rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); - - REG_WRITE(ah, AR_PHY_MODE, rfMode); -} - -static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) -{ - u32 rst_flags; - u32 tmpReg; - - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | - AR_RTC_FORCE_WAKE_ON_INT); - - if (AR_SREV_9100(ah)) { - rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD | - AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET; - } else { - tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE); - if (tmpReg & - (AR_INTR_SYNC_LOCAL_TIMEOUT | - AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { - REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); - REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - } else { - REG_WRITE(ah, AR_RC, AR_RC_AHB); - } - - rst_flags = AR_RTC_RC_MAC_WARM; - if (type == ATH9K_RESET_COLD) - rst_flags |= AR_RTC_RC_MAC_COLD; - } - - REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags); - udelay(50); - - REG_WRITE(ah, (u16) (AR_RTC_RC), 0); - if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: RTC stuck in MAC reset\n", - __func__); - return false; - } - - if (!AR_SREV_9100(ah)) - REG_WRITE(ah, AR_RC, 0); - - ath9k_hw_init_pll(ah, NULL); - - if (AR_SREV_9100(ah)) - udelay(50); - - return true; -} - -static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) -{ - REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | - AR_RTC_FORCE_WAKE_ON_INT); - - REG_WRITE(ah, (u16) (AR_RTC_RESET), 0); - REG_WRITE(ah, (u16) (AR_RTC_RESET), 1); - - if (!ath9k_hw_wait(ah, - AR_RTC_STATUS, - AR_RTC_STATUS_M, - AR_RTC_STATUS_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: RTC not waking up\n", - __func__); - return false; - } - - ath9k_hw_read_revisions(ah); - - return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM); -} - -static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, - u32 type) -{ - REG_WRITE(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); - - switch (type) { - case ATH9K_RESET_POWER_ON: - return ath9k_hw_set_reset_power_on(ah); - break; - case ATH9K_RESET_WARM: - case ATH9K_RESET_COLD: - return ath9k_hw_set_reset(ah, type); - break; - default: - return false; - } -} - -static -struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; not marked as " - "2GHz or 5GHz\n", __func__, chan->channel, - chan->channelFlags); - return NULL; - } - - if (!IS_CHAN_OFDM(chan) && - !IS_CHAN_CCK(chan) && - !IS_CHAN_HT20(chan) && - !IS_CHAN_HT40(chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; not marked as " - "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n", - __func__, chan->channel, chan->channelFlags); - return NULL; - } - - return ath9k_regd_check_channel(ah, chan); -} - -static inline bool -ath9k_hw_get_lower_upper_index(u8 target, - u8 *pList, - u16 listSize, - u16 *indexL, - u16 *indexR) -{ - u16 i; - - if (target <= pList[0]) { - *indexL = *indexR = 0; - return true; - } - if (target >= pList[listSize - 1]) { - *indexL = *indexR = (u16) (listSize - 1); - return true; - } - - for (i = 0; i < listSize - 1; i++) { - if (pList[i] == target) { - *indexL = *indexR = i; - return true; - } - if (target < pList[i + 1]) { - *indexL = i; - *indexR = (u16) (i + 1); - return false; - } - } - return false; -} - -static int16_t ath9k_hw_get_nf_hist_mid(int16_t *nfCalBuffer) -{ - int16_t nfval; - int16_t sort[ATH9K_NF_CAL_HIST_MAX]; - int i, j; - - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX; i++) - sort[i] = nfCalBuffer[i]; - - for (i = 0; i < ATH9K_NF_CAL_HIST_MAX - 1; i++) { - for (j = 1; j < ATH9K_NF_CAL_HIST_MAX - i; j++) { - if (sort[j] > sort[j - 1]) { - nfval = sort[j]; - sort[j] = sort[j - 1]; - sort[j - 1] = nfval; - } - } - } - nfval = sort[(ATH9K_NF_CAL_HIST_MAX - 1) >> 1]; - - return nfval; -} - -static void ath9k_hw_update_nfcal_hist_buffer(struct ath9k_nfcal_hist *h, - int16_t *nfarray) -{ - int i; - - for (i = 0; i < NUM_NF_READINGS; i++) { - h[i].nfCalBuffer[h[i].currIndex] = nfarray[i]; - - if (++h[i].currIndex >= ATH9K_NF_CAL_HIST_MAX) - h[i].currIndex = 0; - - if (h[i].invalidNFcount > 0) { - if (nfarray[i] < AR_PHY_CCA_MIN_BAD_VALUE - || nfarray[i] > AR_PHY_CCA_MAX_HIGH_VALUE) { - h[i].invalidNFcount = ATH9K_NF_CAL_HIST_MAX; - } else { - h[i].invalidNFcount--; - h[i].privNF = nfarray[i]; - } - } else { - h[i].privNF = - ath9k_hw_get_nf_hist_mid(h[i].nfCalBuffer); - } - } - return; -} - -static void ar5416GetNoiseFloor(struct ath_hal *ah, - int16_t nfarray[NUM_NF_READINGS]) -{ - int16_t nf; - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CCA), AR9280_PHY_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CCA), AR_PHY_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ctl] [chain 0] is %d\n", nf); - nfarray[0] = nf; - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR9280_PHY_CH1_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_CCA), - AR_PHY_CH1_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ctl] [chain 1] is %d\n", nf); - nfarray[1] = nf; - - if (!AR_SREV_9280(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_CCA), - AR_PHY_CH2_MINCCA_PWR); - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ctl] [chain 2] is %d\n", nf); - nfarray[2] = nf; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), - AR9280_PHY_EXT_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_EXT_CCA), - AR_PHY_EXT_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ext] [chain 0] is %d\n", nf); - nfarray[3] = nf; - - if (AR_SREV_9280_10_OR_LATER(ah)) - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR9280_PHY_CH1_EXT_MINCCA_PWR); - else - nf = MS(REG_READ(ah, AR_PHY_CH1_EXT_CCA), - AR_PHY_CH1_EXT_MINCCA_PWR); - - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "NF calibrated [ext] [chain 1] is %d\n", nf); - nfarray[4] = nf; - - if (!AR_SREV_9280(ah)) { - nf = MS(REG_READ(ah, AR_PHY_CH2_EXT_CCA), - AR_PHY_CH2_EXT_MINCCA_PWR); - if (nf & 0x100) - nf = 0 - ((nf ^ 0x1ff) + 1); - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "NF calibrated [ext] [chain 2] is %d\n", nf); - nfarray[5] = nf; - } -} - -static bool -getNoiseFloorThresh(struct ath_hal *ah, - const struct ath9k_channel *chan, - int16_t *nft) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - switch (chan->chanmode) { - case CHANNEL_A: - case CHANNEL_A_HT20: - case CHANNEL_A_HT40PLUS: - case CHANNEL_A_HT40MINUS: - *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_5); - break; - case CHANNEL_B: - case CHANNEL_G: - case CHANNEL_G_HT20: - case CHANNEL_G_HT40PLUS: - case CHANNEL_G_HT40MINUS: - *nft = (int16_t) ath9k_hw_get_eeprom(ahp, EEP_NFTHRESH_2); - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel flags 0x%x\n", __func__, - chan->channelFlags); - return false; - } - return true; -} - -static void ath9k_hw_start_nfcal(struct ath_hal *ah) -{ - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_ENABLE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_NO_UPDATE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); -} - -static void -ath9k_hw_loadnf(struct ath_hal *ah, struct ath9k_channel *chan) -{ - struct ath9k_nfcal_hist *h; - int i, j; - int32_t val; - const u32 ar5416_cca_regs[6] = { - AR_PHY_CCA, - AR_PHY_CH1_CCA, - AR_PHY_CH2_CCA, - AR_PHY_EXT_CCA, - AR_PHY_CH1_EXT_CCA, - AR_PHY_CH2_EXT_CCA - }; - u8 chainmask; - - if (AR_SREV_9280(ah)) - chainmask = 0x1B; - else - chainmask = 0x3F; - -#ifdef ATH_NF_PER_CHAN - h = chan->nfCalHist; -#else - h = ah->nfCalHist; -#endif - - for (i = 0; i < NUM_NF_READINGS; i++) { - if (chainmask & (1 << i)) { - val = REG_READ(ah, ar5416_cca_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (h[i].privNF) << 1) & 0x1ff); - REG_WRITE(ah, ar5416_cca_regs[i], val); - } - } - - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_ENABLE_NF); - REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, - AR_PHY_AGC_CONTROL_NO_UPDATE_NF); - REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_NF); - - for (j = 0; j < 1000; j++) { - if ((REG_READ(ah, AR_PHY_AGC_CONTROL) & - AR_PHY_AGC_CONTROL_NF) == 0) - break; - udelay(10); - } - - for (i = 0; i < NUM_NF_READINGS; i++) { - if (chainmask & (1 << i)) { - val = REG_READ(ah, ar5416_cca_regs[i]); - val &= 0xFFFFFE00; - val |= (((u32) (-50) << 1) & 0x1ff); - REG_WRITE(ah, ar5416_cca_regs[i], val); - } - } -} - -static int16_t ath9k_hw_getnf(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - int16_t nf, nfThresh; - int16_t nfarray[NUM_NF_READINGS] = { 0 }; - struct ath9k_nfcal_hist *h; - u8 chainmask; - - if (AR_SREV_9280(ah)) - chainmask = 0x1B; - else - chainmask = 0x3F; - - chan->channelFlags &= (~CHANNEL_CW_INT); - if (REG_READ(ah, AR_PHY_AGC_CONTROL) & AR_PHY_AGC_CONTROL_NF) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: NF did not complete in calibration window\n", - __func__); - nf = 0; - chan->rawNoiseFloor = nf; - return chan->rawNoiseFloor; - } else { - ar5416GetNoiseFloor(ah, nfarray); - nf = nfarray[0]; - if (getNoiseFloorThresh(ah, chan, &nfThresh) - && nf > nfThresh) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: noise floor failed detected; " - "detected %d, threshold %d\n", __func__, - nf, nfThresh); - chan->channelFlags |= CHANNEL_CW_INT; - } - } - -#ifdef ATH_NF_PER_CHAN - h = chan->nfCalHist; -#else - h = ah->nfCalHist; -#endif - - ath9k_hw_update_nfcal_hist_buffer(h, nfarray); - chan->rawNoiseFloor = h[0].privNF; - - return chan->rawNoiseFloor; -} - -static void ath9k_hw_update_mibstats(struct ath_hal *ah, - struct ath9k_mib_stats *stats) -{ - stats->ackrcv_bad += REG_READ(ah, AR_ACK_FAIL); - stats->rts_bad += REG_READ(ah, AR_RTS_FAIL); - stats->fcs_bad += REG_READ(ah, AR_FCS_FAIL); - stats->rts_good += REG_READ(ah, AR_RTS_OK); - stats->beacons += REG_READ(ah, AR_BEACON_CNT); -} - -static void ath9k_enable_mib_counters(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Enable mib counters\n"); - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); - REG_WRITE(ah, AR_MIBC, - ~(AR_MIBC_COW | AR_MIBC_FMC | AR_MIBC_CMC | AR_MIBC_MCS) - & 0x0f); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); -} - -static void ath9k_hw_disable_mib_counters(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disabling MIB counters\n"); - - REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC); - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); -} - -static int ath9k_hw_get_ani_channel_idx(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { - if (ahp->ah_ani[i].c.channel == chan->channel) - return i; - if (ahp->ah_ani[i].c.channel == 0) { - ahp->ah_ani[i].c.channel = chan->channel; - ahp->ah_ani[i].c.channelFlags = chan->channelFlags; - return i; - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "No more channel states left. Using channel 0\n"); - return 0; -} - -static void ath9k_hw_ani_attach(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - ahp->ah_hasHwPhyCounters = 1; - - memset(ahp->ah_ani, 0, sizeof(ahp->ah_ani)); - for (i = 0; i < ARRAY_SIZE(ahp->ah_ani); i++) { - ahp->ah_ani[i].ofdmTrigHigh = ATH9K_ANI_OFDM_TRIG_HIGH; - ahp->ah_ani[i].ofdmTrigLow = ATH9K_ANI_OFDM_TRIG_LOW; - ahp->ah_ani[i].cckTrigHigh = ATH9K_ANI_CCK_TRIG_HIGH; - ahp->ah_ani[i].cckTrigLow = ATH9K_ANI_CCK_TRIG_LOW; - ahp->ah_ani[i].rssiThrHigh = ATH9K_ANI_RSSI_THR_HIGH; - ahp->ah_ani[i].rssiThrLow = ATH9K_ANI_RSSI_THR_LOW; - ahp->ah_ani[i].ofdmWeakSigDetectOff = - !ATH9K_ANI_USE_OFDM_WEAK_SIG; - ahp->ah_ani[i].cckWeakSigThreshold = - ATH9K_ANI_CCK_WEAK_SIG_THR; - ahp->ah_ani[i].spurImmunityLevel = ATH9K_ANI_SPUR_IMMUNE_LVL; - ahp->ah_ani[i].firstepLevel = ATH9K_ANI_FIRSTEP_LVL; - if (ahp->ah_hasHwPhyCounters) { - ahp->ah_ani[i].ofdmPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_OFDM_TRIG_HIGH; - ahp->ah_ani[i].cckPhyErrBase = - AR_PHY_COUNTMAX - ATH9K_ANI_CCK_TRIG_HIGH; - } - } - if (ahp->ah_hasHwPhyCounters) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "Setting OfdmErrBase = 0x%08x\n", - ahp->ah_ani[0].ofdmPhyErrBase); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Setting cckErrBase = 0x%08x\n", - ahp->ah_ani[0].cckPhyErrBase); - - REG_WRITE(ah, AR_PHY_ERR_1, ahp->ah_ani[0].ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, ahp->ah_ani[0].cckPhyErrBase); - ath9k_enable_mib_counters(ah); - } - ahp->ah_aniPeriod = ATH9K_ANI_PERIOD; - if (ah->ah_config.enable_ani) - ahp->ah_procPhyErr |= HAL_PROCESS_ANI; -} - -static void ath9k_hw_ani_setup(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - const int totalSizeDesired[] = { -55, -55, -55, -55, -62 }; - const int coarseHigh[] = { -14, -14, -14, -14, -12 }; - const int coarseLow[] = { -64, -64, -64, -64, -70 }; - const int firpwr[] = { -78, -78, -78, -78, -80 }; - - for (i = 0; i < 5; i++) { - ahp->ah_totalSizeDesired[i] = totalSizeDesired[i]; - ahp->ah_coarseHigh[i] = coarseHigh[i]; - ahp->ah_coarseLow[i] = coarseLow[i]; - ahp->ah_firpwr[i] = firpwr[i]; - } -} - -static void ath9k_hw_ani_detach(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Detaching Ani\n"); - if (ahp->ah_hasHwPhyCounters) { - ath9k_hw_disable_mib_counters(ah); - REG_WRITE(ah, AR_PHY_ERR_1, 0); - REG_WRITE(ah, AR_PHY_ERR_2, 0); - } -} - - -static bool ath9k_hw_ani_control(struct ath_hal *ah, - enum ath9k_ani_cmd cmd, int param) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState = ahp->ah_curani; - - switch (cmd & ahp->ah_ani_function) { - case ATH9K_ANI_NOISE_IMMUNITY_LEVEL:{ - u32 level = param; - - if (level >= ARRAY_SIZE(ahp->ah_totalSizeDesired)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, - (unsigned) ARRAY_SIZE(ahp-> - ah_totalSizeDesired)); - return false; - } - - REG_RMW_FIELD(ah, AR_PHY_DESIRED_SZ, - AR_PHY_DESIRED_SZ_TOT_DES, - ahp->ah_totalSizeDesired[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_LOW, - ahp->ah_coarseLow[level]); - REG_RMW_FIELD(ah, AR_PHY_AGC_CTL1, - AR_PHY_AGC_CTL1_COARSE_HIGH, - ahp->ah_coarseHigh[level]); - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRPWR, - ahp->ah_firpwr[level]); - - if (level > aniState->noiseImmunityLevel) - ahp->ah_stats.ast_ani_niup++; - else if (level < aniState->noiseImmunityLevel) - ahp->ah_stats.ast_ani_nidown++; - aniState->noiseImmunityLevel = level; - break; - } - case ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION:{ - const int m1ThreshLow[] = { 127, 50 }; - const int m2ThreshLow[] = { 127, 40 }; - const int m1Thresh[] = { 127, 0x4d }; - const int m2Thresh[] = { 127, 0x40 }; - const int m2CountThr[] = { 31, 16 }; - const int m2CountThrLow[] = { 63, 48 }; - u32 on = param ? 1 : 0; - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2_THRESH, - m2Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR, - AR_PHY_SFCORR_M2COUNT_THR, - m2CountThr[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_M2COUNT_THR_LOW, - m2CountThrLow[on]); - - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH_LOW, - m1ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH_LOW, - m2ThreshLow[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M1_THRESH, - m1Thresh[on]); - REG_RMW_FIELD(ah, AR_PHY_SFCORR_EXT, - AR_PHY_SFCORR_EXT_M2_THRESH, - m2Thresh[on]); - - if (on) - REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - else - REG_CLR_BIT(ah, AR_PHY_SFCORR_LOW, - AR_PHY_SFCORR_LOW_USE_SELF_CORR_LOW); - - if (!on != aniState->ofdmWeakSigDetectOff) { - if (on) - ahp->ah_stats.ast_ani_ofdmon++; - else - ahp->ah_stats.ast_ani_ofdmoff++; - aniState->ofdmWeakSigDetectOff = !on; - } - break; - } - case ATH9K_ANI_CCK_WEAK_SIGNAL_THR:{ - const int weakSigThrCck[] = { 8, 6 }; - u32 high = param ? 1 : 0; - - REG_RMW_FIELD(ah, AR_PHY_CCK_DETECT, - AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK, - weakSigThrCck[high]); - if (high != aniState->cckWeakSigThreshold) { - if (high) - ahp->ah_stats.ast_ani_cckhigh++; - else - ahp->ah_stats.ast_ani_ccklow++; - aniState->cckWeakSigThreshold = high; - } - break; - } - case ATH9K_ANI_FIRSTEP_LEVEL:{ - const int firstep[] = { 0, 4, 8 }; - u32 level = param; - - if (level >= ARRAY_SIZE(firstep)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, - (unsigned) ARRAY_SIZE(firstep)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_FIND_SIG, - AR_PHY_FIND_SIG_FIRSTEP, - firstep[level]); - if (level > aniState->firstepLevel) - ahp->ah_stats.ast_ani_stepup++; - else if (level < aniState->firstepLevel) - ahp->ah_stats.ast_ani_stepdown++; - aniState->firstepLevel = level; - break; - } - case ATH9K_ANI_SPUR_IMMUNITY_LEVEL:{ - const int cycpwrThr1[] = - { 2, 4, 6, 8, 10, 12, 14, 16 }; - u32 level = param; - - if (level >= ARRAY_SIZE(cycpwrThr1)) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: level out of range (%u > %u)\n", - __func__, level, - (unsigned) - ARRAY_SIZE(cycpwrThr1)); - return false; - } - REG_RMW_FIELD(ah, AR_PHY_TIMING5, - AR_PHY_TIMING5_CYCPWR_THR1, - cycpwrThr1[level]); - if (level > aniState->spurImmunityLevel) - ahp->ah_stats.ast_ani_spurup++; - else if (level < aniState->spurImmunityLevel) - ahp->ah_stats.ast_ani_spurdown++; - aniState->spurImmunityLevel = level; - break; - } - case ATH9K_ANI_PRESENT: - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: invalid cmd %u\n", __func__, cmd); - return false; - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "%s: ANI parameters:\n", __func__); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "noiseImmunityLevel=%d, spurImmunityLevel=%d, " - "ofdmWeakSigDetectOff=%d\n", - aniState->noiseImmunityLevel, aniState->spurImmunityLevel, - !aniState->ofdmWeakSigDetectOff); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "cckWeakSigThreshold=%d, " - "firstepLevel=%d, listenTime=%d\n", - aniState->cckWeakSigThreshold, aniState->firstepLevel, - aniState->listenTime); - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "cycleCount=%d, ofdmPhyErrCount=%d, cckPhyErrCount=%d\n\n", - aniState->cycleCount, aniState->ofdmPhyErrCount, - aniState->cckPhyErrCount); - return true; -} - -static void ath9k_ani_restart(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - - if (!DO_ANI(ah)) - return; - - aniState = ahp->ah_curani; - - aniState->listenTime = 0; - if (ahp->ah_hasHwPhyCounters) { - if (aniState->ofdmTrigHigh > AR_PHY_COUNTMAX) { - aniState->ofdmPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "OFDM Trigger is too high for hw counters\n"); - } else { - aniState->ofdmPhyErrBase = - AR_PHY_COUNTMAX - aniState->ofdmTrigHigh; - } - if (aniState->cckTrigHigh > AR_PHY_COUNTMAX) { - aniState->cckPhyErrBase = 0; - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "CCK Trigger is too high for hw counters\n"); - } else { - aniState->cckPhyErrBase = - AR_PHY_COUNTMAX - aniState->cckTrigHigh; - } - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: Writing ofdmbase=%u cckbase=%u\n", - __func__, aniState->ofdmPhyErrBase, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - } - aniState->ofdmPhyErrCount = 0; - aniState->cckPhyErrCount = 0; -} - -static void ath9k_hw_ani_ofdm_err_trigger(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - struct ar5416AniState *aniState; - enum wireless_mode mode; - int32_t rssi; - - if (!DO_ANI(ah)) - return; - - aniState = ahp->ah_curani; - - if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel + 1)) { - return; - } - } - - if (aniState->spurImmunityLevel < HAL_SPUR_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel + 1)) { - return; - } - } - - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } - return; - } - rssi = BEACON_RSSI(ahp); - if (rssi > aniState->rssiThrHigh) { - if (!aniState->ofdmWeakSigDetectOff) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - false)) { - ath9k_hw_ani_control(ah, - ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - 0); - return; - } - } - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - return; - } - } else if (rssi > aniState->rssiThrLow) { - if (aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true); - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - return; - } else { - mode = ath9k_hw_chan2wmode(ah, chan); - if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { - if (!aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - false); - if (aniState->firstepLevel > 0) - ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, - 0); - return; - } - } -} - -static void ath9k_hw_ani_cck_err_trigger(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - struct ar5416AniState *aniState; - enum wireless_mode mode; - int32_t rssi; - - if (!DO_ANI(ah)) - return; - - aniState = ahp->ah_curani; - if (aniState->noiseImmunityLevel < HAL_NOISE_IMMUNE_MAX) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel + 1)) { - return; - } - } - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) { - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } - return; - } - rssi = BEACON_RSSI(ahp); - if (rssi > aniState->rssiThrLow) { - if (aniState->firstepLevel < HAL_FIRST_STEP_MAX) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel + 1); - } else { - mode = ath9k_hw_chan2wmode(ah, chan); - if (mode == ATH9K_MODE_11G || mode == ATH9K_MODE_11B) { - if (aniState->firstepLevel > 0) - ath9k_hw_ani_control(ah, - ATH9K_ANI_FIRSTEP_LEVEL, - 0); - } - } -} - -static void ath9k_ani_reset(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - struct ath9k_channel *chan = ah->ah_curchan; - int index; - - if (!DO_ANI(ah)) - return; - - index = ath9k_hw_get_ani_channel_idx(ah, chan); - aniState = &ahp->ah_ani[index]; - ahp->ah_curani = aniState; - - if (DO_ANI(ah) && ah->ah_opmode != ATH9K_M_STA - && ah->ah_opmode != ATH9K_M_IBSS) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: Reset ANI state opmode %u\n", __func__, - ah->ah_opmode); - ahp->ah_stats.ast_ani_reset++; - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, 0); - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, 0); - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - !ATH9K_ANI_USE_OFDM_WEAK_SIG); - ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, - ATH9K_ANI_CCK_WEAK_SIG_THR); - ath9k_hw_setrxfilter(ah, - ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - ahp->ah_curani->ofdmTrigHigh = - ah->ah_config.ofdm_trig_high; - ahp->ah_curani->ofdmTrigLow = - ah->ah_config.ofdm_trig_low; - ahp->ah_curani->cckTrigHigh = - ah->ah_config.cck_trig_high; - ahp->ah_curani->cckTrigLow = - ah->ah_config.cck_trig_low; - } - ath9k_ani_restart(ah); - return; - } - - if (aniState->noiseImmunityLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel); - if (aniState->spurImmunityLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel); - if (aniState->ofdmWeakSigDetectOff) - ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - !aniState->ofdmWeakSigDetectOff); - if (aniState->cckWeakSigThreshold) - ath9k_hw_ani_control(ah, ATH9K_ANI_CCK_WEAK_SIGNAL_THR, - aniState->cckWeakSigThreshold); - if (aniState->firstepLevel != 0) - ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel); - if (ahp->ah_hasHwPhyCounters) { - ath9k_hw_setrxfilter(ah, - ath9k_hw_getrxfilter(ah) & - ~ATH9K_RX_FILTER_PHYERR); - ath9k_ani_restart(ah); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, AR_PHY_ERR_OFDM_TIMING); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING); - - } else { - ath9k_ani_restart(ah); - ath9k_hw_setrxfilter(ah, - ath9k_hw_getrxfilter(ah) | - ATH9K_RX_FILTER_PHYERR); - } -} - -/* - * Process a MIB interrupt. We may potentially be invoked because - * any of the MIB counters overflow/trigger so don't assume we're - * here because a PHY error counter triggered. - */ -void ath9k_hw_procmibevent(struct ath_hal *ah, - const struct ath9k_node_stats *stats) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 phyCnt1, phyCnt2; - - DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Processing Mib Intr\n"); - /* Reset these counters regardless */ - REG_WRITE(ah, AR_FILT_OFDM, 0); - REG_WRITE(ah, AR_FILT_CCK, 0); - if (!(REG_READ(ah, AR_SLP_MIB_CTRL) & AR_SLP_MIB_PENDING)) - REG_WRITE(ah, AR_SLP_MIB_CTRL, AR_SLP_MIB_CLEAR); - - /* Clear the mib counters and save them in the stats */ - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - ahp->ah_stats.ast_nodestats = *stats; - - if (!DO_ANI(ah)) - return; - - /* NB: these are not reset-on-read */ - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - if (((phyCnt1 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK) || - ((phyCnt2 & AR_MIBCNT_INTRMASK) == AR_MIBCNT_INTRMASK)) { - struct ar5416AniState *aniState = ahp->ah_curani; - u32 ofdmPhyErrCnt, cckPhyErrCnt; - - /* NB: only use ast_ani_*errs with AH_PRIVATE_DIAG */ - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ahp->ah_stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ahp->ah_stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; - - /* - * NB: figure out which counter triggered. If both - * trigger we'll only deal with one as the processing - * clobbers the error counter so the trigger threshold - * check will never be true. - */ - if (aniState->ofdmPhyErrCount > aniState->ofdmTrigHigh) - ath9k_hw_ani_ofdm_err_trigger(ah); - if (aniState->cckPhyErrCount > aniState->cckTrigHigh) - ath9k_hw_ani_cck_err_trigger(ah); - /* NB: always restart to insure the h/w counters are reset */ - ath9k_ani_restart(ah); - } -} - -static void ath9k_hw_ani_lower_immunity(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - int32_t rssi; - - aniState = ahp->ah_curani; - - if (ah->ah_opmode == ATH9K_M_HOSTAP) { - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1)) { - return; - } - } - } else { - rssi = BEACON_RSSI(ahp); - if (rssi > aniState->rssiThrHigh) { - /* XXX: Handle me */ - } else if (rssi > aniState->rssiThrLow) { - if (aniState->ofdmWeakSigDetectOff) { - if (ath9k_hw_ani_control(ah, - ATH9K_ANI_OFDM_WEAK_SIGNAL_DETECTION, - true) == - true) { - return; - } - } - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control - (ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1) == - true) { - return; - } - } - } else { - if (aniState->firstepLevel > 0) { - if (ath9k_hw_ani_control - (ah, ATH9K_ANI_FIRSTEP_LEVEL, - aniState->firstepLevel - 1) == - true) { - return; - } - } - } - } - - if (aniState->spurImmunityLevel > 0) { - if (ath9k_hw_ani_control(ah, ATH9K_ANI_SPUR_IMMUNITY_LEVEL, - aniState->spurImmunityLevel - 1)) { - return; - } - } - - if (aniState->noiseImmunityLevel > 0) { - ath9k_hw_ani_control(ah, ATH9K_ANI_NOISE_IMMUNITY_LEVEL, - aniState->noiseImmunityLevel - 1); - return; - } -} - -static int32_t ath9k_hw_ani_get_listen_time(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - u32 txFrameCount, rxFrameCount, cycleCount; - int32_t listenTime; - - txFrameCount = REG_READ(ah, AR_TFCNT); - rxFrameCount = REG_READ(ah, AR_RFCNT); - cycleCount = REG_READ(ah, AR_CCCNT); - - aniState = ahp->ah_curani; - if (aniState->cycleCount == 0 || aniState->cycleCount > cycleCount) { - - listenTime = 0; - ahp->ah_stats.ast_ani_lzero++; - } else { - int32_t ccdelta = cycleCount - aniState->cycleCount; - int32_t rfdelta = rxFrameCount - aniState->rxFrameCount; - int32_t tfdelta = txFrameCount - aniState->txFrameCount; - listenTime = (ccdelta - rfdelta - tfdelta) / 44000; - } - aniState->cycleCount = cycleCount; - aniState->txFrameCount = txFrameCount; - aniState->rxFrameCount = rxFrameCount; - - return listenTime; -} - -void ath9k_hw_ani_monitor(struct ath_hal *ah, - const struct ath9k_node_stats *stats, - struct ath9k_channel *chan) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416AniState *aniState; - int32_t listenTime; - - aniState = ahp->ah_curani; - ahp->ah_stats.ast_nodestats = *stats; - - listenTime = ath9k_hw_ani_get_listen_time(ah); - if (listenTime < 0) { - ahp->ah_stats.ast_ani_lneg++; - ath9k_ani_restart(ah); - return; - } - - aniState->listenTime += listenTime; - - if (ahp->ah_hasHwPhyCounters) { - u32 phyCnt1, phyCnt2; - u32 ofdmPhyErrCnt, cckPhyErrCnt; - - ath9k_hw_update_mibstats(ah, &ahp->ah_mibStats); - - phyCnt1 = REG_READ(ah, AR_PHY_ERR_1); - phyCnt2 = REG_READ(ah, AR_PHY_ERR_2); - - if (phyCnt1 < aniState->ofdmPhyErrBase || - phyCnt2 < aniState->cckPhyErrBase) { - if (phyCnt1 < aniState->ofdmPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: phyCnt1 0x%x, resetting " - "counter value to 0x%x\n", - __func__, phyCnt1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_1, - aniState->ofdmPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_1, - AR_PHY_ERR_OFDM_TIMING); - } - if (phyCnt2 < aniState->cckPhyErrBase) { - DPRINTF(ah->ah_sc, ATH_DBG_ANI, - "%s: phyCnt2 0x%x, resetting " - "counter value to 0x%x\n", - __func__, phyCnt2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_2, - aniState->cckPhyErrBase); - REG_WRITE(ah, AR_PHY_ERR_MASK_2, - AR_PHY_ERR_CCK_TIMING); - } - return; - } - - ofdmPhyErrCnt = phyCnt1 - aniState->ofdmPhyErrBase; - ahp->ah_stats.ast_ani_ofdmerrs += - ofdmPhyErrCnt - aniState->ofdmPhyErrCount; - aniState->ofdmPhyErrCount = ofdmPhyErrCnt; - - cckPhyErrCnt = phyCnt2 - aniState->cckPhyErrBase; - ahp->ah_stats.ast_ani_cckerrs += - cckPhyErrCnt - aniState->cckPhyErrCount; - aniState->cckPhyErrCount = cckPhyErrCnt; - } - - if (!DO_ANI(ah)) - return; - - if (aniState->listenTime > 5 * ahp->ah_aniPeriod) { - if (aniState->ofdmPhyErrCount <= aniState->listenTime * - aniState->ofdmTrigLow / 1000 && - aniState->cckPhyErrCount <= aniState->listenTime * - aniState->cckTrigLow / 1000) - ath9k_hw_ani_lower_immunity(ah); - ath9k_ani_restart(ah); - } else if (aniState->listenTime > ahp->ah_aniPeriod) { - if (aniState->ofdmPhyErrCount > aniState->listenTime * - aniState->ofdmTrigHigh / 1000) { - ath9k_hw_ani_ofdm_err_trigger(ah); - ath9k_ani_restart(ah); - } else if (aniState->cckPhyErrCount > - aniState->listenTime * aniState->cckTrigHigh / - 1000) { - ath9k_hw_ani_cck_err_trigger(ah); - ath9k_ani_restart(ah); - } - } -} - -#ifndef ATH_NF_PER_CHAN -static void ath9k_init_nfcal_hist_buffer(struct ath_hal *ah) -{ - int i, j; - - for (i = 0; i < NUM_NF_READINGS; i++) { - ah->nfCalHist[i].currIndex = 0; - ah->nfCalHist[i].privNF = AR_PHY_CCA_MAX_GOOD_VALUE; - ah->nfCalHist[i].invalidNFcount = - AR_PHY_CCA_FILTERWINDOW_LENGTH; - for (j = 0; j < ATH9K_NF_CAL_HIST_MAX; j++) { - ah->nfCalHist[i].nfCalBuffer[j] = - AR_PHY_CCA_MAX_GOOD_VALUE; - } - } - return; -} -#endif - -static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, - u32 gpio, u32 type) -{ - int addr; - u32 gpio_shift, tmp; - - if (gpio > 11) - addr = AR_GPIO_OUTPUT_MUX3; - else if (gpio > 5) - addr = AR_GPIO_OUTPUT_MUX2; - else - addr = AR_GPIO_OUTPUT_MUX1; - - gpio_shift = (gpio % 6) * 5; - - if (AR_SREV_9280_20_OR_LATER(ah) - || (addr != AR_GPIO_OUTPUT_MUX1)) { - REG_RMW(ah, addr, (type << gpio_shift), - (0x1f << gpio_shift)); - } else { - tmp = REG_READ(ah, addr); - tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); - tmp &= ~(0x1f << gpio_shift); - tmp |= (type << gpio_shift); - REG_WRITE(ah, addr, tmp); - } -} - -void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, - u32 ah_signal_type) -{ - u32 gpio_shift; - - ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); - - gpio_shift = 2 * gpio; - - REG_RMW(ah, - AR_GPIO_OE_OUT, - (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), - (AR_GPIO_OE_OUT_DRV << gpio_shift)); -} - -void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) -{ - REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), - AR_GPIO_BIT(gpio)); -} - -/* - * Configure GPIO Input lines - */ -void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio) -{ - u32 gpio_shift; - - ASSERT(gpio < ah->ah_caps.num_gpio_pins); - - gpio_shift = gpio << 1; - - REG_RMW(ah, - AR_GPIO_OE_OUT, - (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), - (AR_GPIO_OE_OUT_DRV << gpio_shift)); -} - -#ifdef CONFIG_RFKILL -static void ath9k_enable_rfkill(struct ath_hal *ah) -{ - REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, - AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); - - REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, - AR_GPIO_INPUT_MUX2_RFSILENT); - - ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio); - REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); -} -#endif - -u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) -{ - if (gpio >= ah->ah_caps.num_gpio_pins) - return 0xffffffff; - - if (AR_SREV_9280_10_OR_LATER(ah)) { - return (MS - (REG_READ(ah, AR_GPIO_IN_OUT), - AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; - } else { - return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) & - AR_GPIO_BIT(gpio)) != 0; - } -} - -static int ath9k_hw_post_attach(struct ath_hal *ah) -{ - int ecode; - - if (!ath9k_hw_chip_test(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: hardware self-test failed\n", __func__); - return -ENODEV; - } - - ecode = ath9k_hw_rf_claim(ah); - if (ecode != 0) - return ecode; - - ecode = ath9k_hw_eeprom_attach(ah); - if (ecode != 0) - return ecode; - ecode = ath9k_hw_rfattach(ah); - if (ecode != 0) - return ecode; - - if (!AR_SREV_9100(ah)) { - ath9k_hw_ani_setup(ah); - ath9k_hw_ani_attach(ah); - } - return 0; -} - -static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - u32 reg, u32 value) -{ - struct base_eep_header *pBase = &(pEepData->baseEepHeader); - - switch (ah->ah_devid) { - case AR9280_DEVID_PCI: - if (reg == 0x7894) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "ini VAL: %x EEPROM: %x\n", value, - (pBase->version & 0xff)); - - if ((pBase->version & 0xff) > 0x0a) { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "PWDCLKIND: %d\n", - pBase->pwdclkind); - value &= ~AR_AN_TOP2_PWDCLKIND; - value |= AR_AN_TOP2_PWDCLKIND & (pBase-> - pwdclkind << AR_AN_TOP2_PWDCLKIND_S); - } else { - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "PWDCLKIND Earlier Rev\n"); - } - - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "final ini VAL: %x\n", value); - } - break; - } - return value; -} - -static bool ath9k_hw_fill_cap_info(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - u16 capField = 0, eeval; - - eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_0); - - ah->ah_currentRD = eeval; - - eeval = ath9k_hw_get_eeprom(ahp, EEP_REG_1); - ah->ah_currentRDExt = eeval; - - capField = ath9k_hw_get_eeprom(ahp, EEP_OP_CAP); - - if (ah->ah_opmode != ATH9K_M_HOSTAP && - ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) { - if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65) - ah->ah_currentRD += 5; - else if (ah->ah_currentRD == 0x41) - ah->ah_currentRD = 0x43; - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: regdomain mapped to 0x%x\n", __func__, - ah->ah_currentRD); - } - - eeval = ath9k_hw_get_eeprom(ahp, EEP_OP_MODE); - bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); - - if (eeval & AR5416_OPFLAGS_11A) { - set_bit(ATH9K_MODE_11A, pCap->wireless_modes); - if (ah->ah_config.ht_enable) { - if (!(eeval & AR5416_OPFLAGS_N_5G_HT20)) - set_bit(ATH9K_MODE_11NA_HT20, - pCap->wireless_modes); - if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) { - set_bit(ATH9K_MODE_11NA_HT40PLUS, - pCap->wireless_modes); - set_bit(ATH9K_MODE_11NA_HT40MINUS, - pCap->wireless_modes); - } - } - } - - if (eeval & AR5416_OPFLAGS_11G) { - set_bit(ATH9K_MODE_11B, pCap->wireless_modes); - set_bit(ATH9K_MODE_11G, pCap->wireless_modes); - if (ah->ah_config.ht_enable) { - if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) - set_bit(ATH9K_MODE_11NG_HT20, - pCap->wireless_modes); - if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) { - set_bit(ATH9K_MODE_11NG_HT40PLUS, - pCap->wireless_modes); - set_bit(ATH9K_MODE_11NG_HT40MINUS, - pCap->wireless_modes); - } - } - } - - pCap->tx_chainmask = ath9k_hw_get_eeprom(ahp, EEP_TX_MASK); - if ((ah->ah_isPciExpress) - || (eeval & AR5416_OPFLAGS_11A)) { - pCap->rx_chainmask = - ath9k_hw_get_eeprom(ahp, EEP_RX_MASK); - } else { - pCap->rx_chainmask = - (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7; - } - - if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0))) - ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA; - - pCap->low_2ghz_chan = 2312; - pCap->high_2ghz_chan = 2732; - - pCap->low_5ghz_chan = 4920; - pCap->high_5ghz_chan = 6100; - - pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP; - pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP; - pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM; - - pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP; - pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP; - pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM; - - pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD; - - if (ah->ah_config.ht_enable) - pCap->hw_caps |= ATH9K_HW_CAP_HT; - else - pCap->hw_caps &= ~ATH9K_HW_CAP_HT; - - pCap->hw_caps |= ATH9K_HW_CAP_GTT; - pCap->hw_caps |= ATH9K_HW_CAP_VEOL; - pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK; - pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH; - - if (capField & AR_EEPROM_EEPCAP_MAXQCU) - pCap->total_queues = - MS(capField, AR_EEPROM_EEPCAP_MAXQCU); - else - pCap->total_queues = ATH9K_NUM_TX_QUEUES; - - if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) - pCap->keycache_size = - 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); - else - pCap->keycache_size = AR_KEYTABLE_SIZE; - - pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; - pCap->num_mr_retries = 4; - pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - - if (AR_SREV_9280_10_OR_LATER(ah)) - pCap->num_gpio_pins = AR928X_NUM_GPIO; - else - pCap->num_gpio_pins = AR_NUM_GPIO; - - if (AR_SREV_9280_10_OR_LATER(ah)) { - pCap->hw_caps |= ATH9K_HW_CAP_WOW; - pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; - } else { - pCap->hw_caps &= ~ATH9K_HW_CAP_WOW; - pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; - } - - if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { - pCap->hw_caps |= ATH9K_HW_CAP_CST; - pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; - } else { - pCap->rts_aggr_limit = (8 * 1024); - } - - pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; - -#ifdef CONFIG_RFKILL - ah->ah_rfsilent = ath9k_hw_get_eeprom(ahp, EEP_RF_SILENT); - if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) { - ah->ah_rfkill_gpio = - MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL); - ah->ah_rfkill_polarity = - MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY); - - pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; - } -#endif - - if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) || - (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) || - (ah->ah_macVersion == AR_SREV_VERSION_9160) || - (ah->ah_macVersion == AR_SREV_VERSION_9100) || - (ah->ah_macVersion == AR_SREV_VERSION_9280)) - pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; - else - pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; - - if (AR_SREV_9280(ah)) - pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS; - else - pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - - if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | - AR_EEPROM_EEREGCAP_EN_KK_U2 | - AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; - } else { - pCap->reg_cap = - AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | - AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; - } - - pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; - - pCap->num_antcfg_5ghz = - ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_5GHZ); - pCap->num_antcfg_2ghz = - ath9k_hw_get_num_ant_config(ahp, IEEE80211_BAND_2GHZ); - - return true; -} - -static void ar5416DisablePciePhy(struct ath_hal *ah) -{ - if (!AR_SREV_9100(ah)) - return; - - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - REG_WRITE(ah, AR_PCIE_SERDES, 0x28000029); - REG_WRITE(ah, AR_PCIE_SERDES, 0x57160824); - REG_WRITE(ah, AR_PCIE_SERDES, 0x25980579); - REG_WRITE(ah, AR_PCIE_SERDES, 0x00000000); - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x000e1007); - - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); -} - -static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip) -{ - REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - if (setChip) { - REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - if (!AR_SREV_9100(ah)) - REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - - REG_CLR_BIT(ah, (u16) (AR_RTC_RESET), - AR_RTC_RESET_EN); - } -} - -static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip) -{ - REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - if (setChip) { - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { - REG_WRITE(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_ON_INT); - } else { - REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - } - } -} - -static bool ath9k_hw_set_power_awake(struct ath_hal *ah, - int setChip) -{ - u32 val; - int i; - - if (setChip) { - if ((REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M) == - AR_RTC_STATUS_SHUTDOWN) { - if (ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON) - != true) { - return false; - } - } - if (AR_SREV_9100(ah)) - REG_SET_BIT(ah, AR_RTC_RESET, - AR_RTC_RESET_EN); - - REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - udelay(50); - - for (i = POWER_UP_TIME / 50; i > 0; i--) { - val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; - if (val == AR_RTC_STATUS_ON) - break; - udelay(50); - REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, - AR_RTC_FORCE_WAKE_EN); - } - if (i == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: Failed to wakeup in %uus\n", - __func__, POWER_UP_TIME / 20); - return false; - } - } - - REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); - return true; -} - -bool ath9k_hw_setpower(struct ath_hal *ah, - enum ath9k_power_mode mode) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - static const char *modes[] = { - "AWAKE", - "FULL-SLEEP", - "NETWORK SLEEP", - "UNDEFINED" - }; - int status = true, setChip = true; - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s: %s -> %s (%s)\n", __func__, - modes[ahp->ah_powerMode], modes[mode], - setChip ? "set chip " : ""); - - switch (mode) { - case ATH9K_PM_AWAKE: - status = ath9k_hw_set_power_awake(ah, setChip); - break; - case ATH9K_PM_FULL_SLEEP: - ath9k_set_power_sleep(ah, setChip); - ahp->ah_chipFullSleep = true; - break; - case ATH9K_PM_NETWORK_SLEEP: - ath9k_set_power_network_sleep(ah, setChip); - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: unknown power mode %u\n", __func__, mode); - return false; - } - ahp->ah_powerMode = mode; - return status; -} - -static struct ath_hal *ath9k_hw_do_attach(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *status) -{ - struct ath_hal_5416 *ahp; - struct ath_hal *ah; - int ecode; -#ifndef CONFIG_SLOW_ANT_DIV - u32 i; - u32 j; -#endif - - ahp = ath9k_hw_newstate(devid, sc, mem, status); - if (ahp == NULL) - return NULL; - - ah = &ahp->ah; - - ath9k_hw_set_defaults(ah); - - if (ah->ah_config.intr_mitigation != 0) - ahp->ah_intrMitigation = true; - - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't reset chip\n", - __func__); - ecode = -EIO; - goto bad; - } - - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: couldn't wakeup chip\n", - __func__); - ecode = -EIO; - goto bad; - } - - if (ah->ah_config.serialize_regmode == SER_REG_MODE_AUTO) { - if (ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) { - ah->ah_config.serialize_regmode = - SER_REG_MODE_ON; - } else { - ah->ah_config.serialize_regmode = - SER_REG_MODE_OFF; - } - } - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: serialize_regmode is %d\n", - __func__, ah->ah_config.serialize_regmode); - - if ((ah->ah_macVersion != AR_SREV_VERSION_5416_PCI) && - (ah->ah_macVersion != AR_SREV_VERSION_5416_PCIE) && - (ah->ah_macVersion != AR_SREV_VERSION_9160) && - (!AR_SREV_9100(ah)) && (!AR_SREV_9280(ah))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: Mac Chip Rev 0x%02x.%x is not supported by " - "this driver\n", __func__, - ah->ah_macVersion, ah->ah_macRev); - ecode = -EOPNOTSUPP; - goto bad; - } - - if (AR_SREV_9100(ah)) { - ahp->ah_iqCalData.calData = &iq_cal_multi_sample; - ahp->ah_suppCals = IQ_MISMATCH_CAL; - ah->ah_isPciExpress = false; - } - ah->ah_phyRev = REG_READ(ah, AR_PHY_CHIP_ID); - - if (AR_SREV_9160_10_OR_LATER(ah)) { - if (AR_SREV_9280_10_OR_LATER(ah)) { - ahp->ah_iqCalData.calData = &iq_cal_single_sample; - ahp->ah_adcGainCalData.calData = - &adc_gain_cal_single_sample; - ahp->ah_adcDcCalData.calData = - &adc_dc_cal_single_sample; - ahp->ah_adcDcCalInitData.calData = - &adc_init_dc_cal; - } else { - ahp->ah_iqCalData.calData = &iq_cal_multi_sample; - ahp->ah_adcGainCalData.calData = - &adc_gain_cal_multi_sample; - ahp->ah_adcDcCalData.calData = - &adc_dc_cal_multi_sample; - ahp->ah_adcDcCalInitData.calData = - &adc_init_dc_cal; - } - ahp->ah_suppCals = - ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL; - } - - if (AR_SREV_9160(ah)) { - ah->ah_config.enable_ani = 1; - ahp->ah_ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL | - ATH9K_ANI_FIRSTEP_LEVEL); - } else { - ahp->ah_ani_function = ATH9K_ANI_ALL; - if (AR_SREV_9280_10_OR_LATER(ah)) { - ahp->ah_ani_function &= - ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL; - } - } - - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: This Mac Chip Rev 0x%02x.%x is \n", __func__, - ah->ah_macVersion, ah->ah_macRev); - - if (AR_SREV_9280_20_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280_2, - ARRAY_SIZE(ar9280Modes_9280_2), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280_2, - ARRAY_SIZE(ar9280Common_9280_2), 2); - - if (ah->ah_config.pcie_clock_req) { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, - ar9280PciePhy_clkreq_off_L1_9280, - ARRAY_SIZE - (ar9280PciePhy_clkreq_off_L1_9280), - 2); - } else { - INIT_INI_ARRAY(&ahp->ah_iniPcieSerdes, - ar9280PciePhy_clkreq_always_on_L1_9280, - ARRAY_SIZE - (ar9280PciePhy_clkreq_always_on_L1_9280), - 2); - } - INIT_INI_ARRAY(&ahp->ah_iniModesAdditional, - ar9280Modes_fast_clock_9280_2, - ARRAY_SIZE(ar9280Modes_fast_clock_9280_2), - 3); - } else if (AR_SREV_9280_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar9280Modes_9280, - ARRAY_SIZE(ar9280Modes_9280), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar9280Common_9280, - ARRAY_SIZE(ar9280Common_9280), 2); - } else if (AR_SREV_9160_10_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9160, - ARRAY_SIZE(ar5416Modes_9160), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9160, - ARRAY_SIZE(ar5416Common_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9160, - ARRAY_SIZE(ar5416Bank0_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9160, - ARRAY_SIZE(ar5416BB_RfGain_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9160, - ARRAY_SIZE(ar5416Bank1_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9160, - ARRAY_SIZE(ar5416Bank2_9160), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9160, - ARRAY_SIZE(ar5416Bank3_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9160, - ARRAY_SIZE(ar5416Bank6_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9160, - ARRAY_SIZE(ar5416Bank6TPC_9160), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9160, - ARRAY_SIZE(ar5416Bank7_9160), 2); - if (AR_SREV_9160_11(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniAddac, - ar5416Addac_91601_1, - ARRAY_SIZE(ar5416Addac_91601_1), 2); - } else { - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9160, - ARRAY_SIZE(ar5416Addac_9160), 2); - } - } else if (AR_SREV_9100_OR_LATER(ah)) { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes_9100, - ARRAY_SIZE(ar5416Modes_9100), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common_9100, - ARRAY_SIZE(ar5416Common_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0_9100, - ARRAY_SIZE(ar5416Bank0_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain_9100, - ARRAY_SIZE(ar5416BB_RfGain_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1_9100, - ARRAY_SIZE(ar5416Bank1_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2_9100, - ARRAY_SIZE(ar5416Bank2_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3_9100, - ARRAY_SIZE(ar5416Bank3_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6_9100, - ARRAY_SIZE(ar5416Bank6_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC_9100, - ARRAY_SIZE(ar5416Bank6TPC_9100), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7_9100, - ARRAY_SIZE(ar5416Bank7_9100), 2); - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac_9100, - ARRAY_SIZE(ar5416Addac_9100), 2); - } else { - INIT_INI_ARRAY(&ahp->ah_iniModes, ar5416Modes, - ARRAY_SIZE(ar5416Modes), 6); - INIT_INI_ARRAY(&ahp->ah_iniCommon, ar5416Common, - ARRAY_SIZE(ar5416Common), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank0, ar5416Bank0, - ARRAY_SIZE(ar5416Bank0), 2); - INIT_INI_ARRAY(&ahp->ah_iniBB_RfGain, ar5416BB_RfGain, - ARRAY_SIZE(ar5416BB_RfGain), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank1, ar5416Bank1, - ARRAY_SIZE(ar5416Bank1), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank2, ar5416Bank2, - ARRAY_SIZE(ar5416Bank2), 2); - INIT_INI_ARRAY(&ahp->ah_iniBank3, ar5416Bank3, - ARRAY_SIZE(ar5416Bank3), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6, ar5416Bank6, - ARRAY_SIZE(ar5416Bank6), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank6TPC, ar5416Bank6TPC, - ARRAY_SIZE(ar5416Bank6TPC), 3); - INIT_INI_ARRAY(&ahp->ah_iniBank7, ar5416Bank7, - ARRAY_SIZE(ar5416Bank7), 2); - INIT_INI_ARRAY(&ahp->ah_iniAddac, ar5416Addac, - ARRAY_SIZE(ar5416Addac), 2); - } - - if (ah->ah_isPciExpress) - ath9k_hw_configpcipowersave(ah, 0); - else - ar5416DisablePciePhy(ah); - - ecode = ath9k_hw_post_attach(ah); - if (ecode != 0) - goto bad; - -#ifndef CONFIG_SLOW_ANT_DIV - if (ah->ah_devid == AR9280_DEVID_PCI) { - for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { - u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); - - for (j = 1; j < ahp->ah_iniModes.ia_columns; j++) { - u32 val = INI_RA(&ahp->ah_iniModes, i, j); - - INI_RA(&ahp->ah_iniModes, i, j) = - ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, - reg, val); - } - } - } -#endif - - if (!ath9k_hw_fill_cap_info(ah)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s:failed ath9k_hw_fill_cap_info\n", __func__); - ecode = -EINVAL; - goto bad; - } - - ecode = ath9k_hw_init_macaddr(ah); - if (ecode != 0) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: failed initializing mac address\n", - __func__); - goto bad; - } - - if (AR_SREV_9285(ah)) - ah->ah_txTrigLevel = (AR_FTRIG_256B >> AR_FTRIG_S); - else - ah->ah_txTrigLevel = (AR_FTRIG_512B >> AR_FTRIG_S); - -#ifndef ATH_NF_PER_CHAN - - ath9k_init_nfcal_hist_buffer(ah); -#endif - - return ah; - -bad: - if (ahp) - ath9k_hw_detach((struct ath_hal *) ahp); - if (status) - *status = ecode; - return NULL; -} - -void ath9k_hw_detach(struct ath_hal *ah) -{ - if (!AR_SREV_9100(ah)) - ath9k_hw_ani_detach(ah); - ath9k_hw_rfdetach(ah); - - ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); - kfree(ah); -} - -bool ath9k_get_channel_edges(struct ath_hal *ah, - u16 flags, u16 *low, - u16 *high) -{ - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - - if (flags & CHANNEL_5GHZ) { - *low = pCap->low_5ghz_chan; - *high = pCap->high_5ghz_chan; - return true; - } - if ((flags & CHANNEL_2GHZ)) { - *low = pCap->low_2ghz_chan; - *high = pCap->high_2ghz_chan; - - return true; - } - return false; -} - -static inline bool ath9k_hw_fill_vpd_table(u8 pwrMin, - u8 pwrMax, - u8 *pPwrList, - u8 *pVpdList, - u16 - numIntercepts, - u8 *pRetVpdList) -{ - u16 i, k; - u8 currPwr = pwrMin; - u16 idxL = 0, idxR = 0; - - for (i = 0; i <= (pwrMax - pwrMin) / 2; i++) { - ath9k_hw_get_lower_upper_index(currPwr, pPwrList, - numIntercepts, &(idxL), - &(idxR)); - if (idxR < 1) - idxR = 1; - if (idxL == numIntercepts - 1) - idxL = (u16) (numIntercepts - 2); - if (pPwrList[idxL] == pPwrList[idxR]) - k = pVpdList[idxL]; - else - k = (u16) (((currPwr - - pPwrList[idxL]) * - pVpdList[idxR] + - (pPwrList[idxR] - - currPwr) * pVpdList[idxL]) / - (pPwrList[idxR] - - pPwrList[idxL])); - pRetVpdList[i] = (u8) k; - currPwr += 2; - } - - return true; -} - -static void -ath9k_hw_get_gain_boundaries_pdadcs(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_data_per_freq *pRawDataSet, - u8 *bChans, - u16 availPiers, - u16 tPdGainOverlap, - int16_t *pMinCalPower, - u16 *pPdGainBoundaries, - u8 *pPDADCValues, - u16 numXpdGains) -{ - int i, j, k; - int16_t ss; - u16 idxL = 0, idxR = 0, numPiers; - static u8 vpdTableL[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableR[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - static u8 vpdTableI[AR5416_NUM_PD_GAINS] - [AR5416_MAX_PWR_RANGE_IN_HALF_DB]; - - u8 *pVpdL, *pVpdR, *pPwrL, *pPwrR; - u8 minPwrT4[AR5416_NUM_PD_GAINS]; - u8 maxPwrT4[AR5416_NUM_PD_GAINS]; - int16_t vpdStep; - int16_t tmpVal; - u16 sizeCurrVpdTable, maxIndex, tgtIndex; - bool match; - int16_t minDelta = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - for (numPiers = 0; numPiers < availPiers; numPiers++) { - if (bChans[numPiers] == AR5416_BCHAN_UNUSED) - break; - } - - match = ath9k_hw_get_lower_upper_index((u8) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), bChans, - numPiers, &idxL, &idxR); - - if (match) { - for (i = 0; i < numXpdGains; i++) { - minPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][0]; - maxPwrT4[i] = pRawDataSet[idxL].pwrPdg[i][4]; - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pRawDataSet[idxL]. - pwrPdg[i], - pRawDataSet[idxL]. - vpdPdg[i], - AR5416_PD_GAIN_ICEPTS, - vpdTableI[i]); - } - } else { - for (i = 0; i < numXpdGains; i++) { - pVpdL = pRawDataSet[idxL].vpdPdg[i]; - pPwrL = pRawDataSet[idxL].pwrPdg[i]; - pVpdR = pRawDataSet[idxR].vpdPdg[i]; - pPwrR = pRawDataSet[idxR].pwrPdg[i]; - - minPwrT4[i] = max(pPwrL[0], pPwrR[0]); - - maxPwrT4[i] = - min(pPwrL[AR5416_PD_GAIN_ICEPTS - 1], - pPwrR[AR5416_PD_GAIN_ICEPTS - 1]); - - - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrL, pVpdL, - AR5416_PD_GAIN_ICEPTS, - vpdTableL[i]); - ath9k_hw_fill_vpd_table(minPwrT4[i], maxPwrT4[i], - pPwrR, pVpdR, - AR5416_PD_GAIN_ICEPTS, - vpdTableR[i]); - - for (j = 0; j <= (maxPwrT4[i] - minPwrT4[i]) / 2; j++) { - vpdTableI[i][j] = - (u8) (ath9k_hw_interpolate - ((u16) - FREQ2FBIN(centers. - synth_center, - IS_CHAN_2GHZ - (chan)), - bChans[idxL], - bChans[idxR], vpdTableL[i] - [j], vpdTableR[i] - [j])); - } - } - } - - *pMinCalPower = (int16_t) (minPwrT4[0] / 2); - - k = 0; - for (i = 0; i < numXpdGains; i++) { - if (i == (numXpdGains - 1)) - pPdGainBoundaries[i] = - (u16) (maxPwrT4[i] / 2); - else - pPdGainBoundaries[i] = - (u16) ((maxPwrT4[i] + - minPwrT4[i + 1]) / 4); - - pPdGainBoundaries[i] = - min((u16) AR5416_MAX_RATE_POWER, - pPdGainBoundaries[i]); - - if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) { - minDelta = pPdGainBoundaries[0] - 23; - pPdGainBoundaries[0] = 23; - } else { - minDelta = 0; - } - - if (i == 0) { - if (AR_SREV_9280_10_OR_LATER(ah)) - ss = (int16_t) (0 - (minPwrT4[i] / 2)); - else - ss = 0; - } else { - ss = (int16_t) ((pPdGainBoundaries[i - 1] - - (minPwrT4[i] / 2)) - - tPdGainOverlap + 1 + minDelta); - } - vpdStep = (int16_t) (vpdTableI[i][1] - vpdTableI[i][0]); - vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep); - - while ((ss < 0) && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t) (vpdTableI[i][0] + ss * vpdStep); - pPDADCValues[k++] = - (u8) ((tmpVal < 0) ? 0 : tmpVal); - ss++; - } - - sizeCurrVpdTable = - (u8) ((maxPwrT4[i] - minPwrT4[i]) / 2 + 1); - tgtIndex = (u8) (pPdGainBoundaries[i] + tPdGainOverlap - - (minPwrT4[i] / 2)); - maxIndex = (tgtIndex < - sizeCurrVpdTable) ? tgtIndex : sizeCurrVpdTable; - - while ((ss < maxIndex) - && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - pPDADCValues[k++] = vpdTableI[i][ss++]; - } - - vpdStep = (int16_t) (vpdTableI[i][sizeCurrVpdTable - 1] - - vpdTableI[i][sizeCurrVpdTable - 2]); - vpdStep = (int16_t) ((vpdStep < 1) ? 1 : vpdStep); - - if (tgtIndex > maxIndex) { - while ((ss <= tgtIndex) - && (k < (AR5416_NUM_PDADC_VALUES - 1))) { - tmpVal = (int16_t) ((vpdTableI[i] - [sizeCurrVpdTable - - 1] + (ss - maxIndex + - 1) * vpdStep)); - pPDADCValues[k++] = (u8) ((tmpVal > - 255) ? 255 : tmpVal); - ss++; - } - } - } - - while (i < AR5416_PD_GAINS_IN_MASK) { - pPdGainBoundaries[i] = pPdGainBoundaries[i - 1]; - i++; - } - - while (k < AR5416_NUM_PDADC_VALUES) { - pPDADCValues[k] = pPDADCValues[k - 1]; - k++; - } - return; -} - -static bool -ath9k_hw_set_power_cal_table(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - struct ath9k_channel *chan, - int16_t *pTxPowerIndexOffset) -{ - struct cal_data_per_freq *pRawDataset; - u8 *pCalBChans = NULL; - u16 pdGainOverlap_t2; - static u8 pdadcValues[AR5416_NUM_PDADC_VALUES]; - u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK]; - u16 numPiers, i, j; - int16_t tMinCalPower; - u16 numXpdGain, xpdMask; - u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 }; - u32 reg32, regOffset, regChainOffset; - int16_t modalIdx; - struct ath_hal_5416 *ahp = AH5416(ah); - - modalIdx = IS_CHAN_2GHZ(chan) ? 1 : 0; - xpdMask = pEepData->modalHeader[modalIdx].xpdGain; - - if ((pEepData->baseEepHeader. - version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - pdGainOverlap_t2 = - pEepData->modalHeader[modalIdx].pdGainOverlap; - } else { - pdGainOverlap_t2 = - (u16) (MS - (REG_READ(ah, AR_PHY_TPCRG5), - AR_PHY_TPCRG5_PD_GAIN_OVERLAP)); - } - - if (IS_CHAN_2GHZ(chan)) { - pCalBChans = pEepData->calFreqPier2G; - numPiers = AR5416_NUM_2G_CAL_PIERS; - } else { - pCalBChans = pEepData->calFreqPier5G; - numPiers = AR5416_NUM_5G_CAL_PIERS; - } - - numXpdGain = 0; - - for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) { - if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) { - if (numXpdGain >= AR5416_NUM_PD_GAINS) - break; - xpdGainValues[numXpdGain] = - (u16) (AR5416_PD_GAINS_IN_MASK - i); - numXpdGain++; - } - } - - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_NUM_PD_GAIN, - (numXpdGain - 1) & 0x3); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_1, - xpdGainValues[0]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2, - xpdGainValues[1]); - REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, - xpdGainValues[2]); - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (AR_SREV_5416_V20_OR_LATER(ah) && - (ahp->ah_rxchainmask == 5 || ahp->ah_txchainmask == 5) - && (i != 0)) { - regChainOffset = (i == 1) ? 0x2000 : 0x1000; - } else - regChainOffset = i * 0x1000; - if (pEepData->baseEepHeader.txMask & (1 << i)) { - if (IS_CHAN_2GHZ(chan)) - pRawDataset = pEepData->calPierData2G[i]; - else - pRawDataset = pEepData->calPierData5G[i]; - - ath9k_hw_get_gain_boundaries_pdadcs(ah, chan, - pRawDataset, - pCalBChans, - numPiers, - pdGainOverlap_t2, - &tMinCalPower, - gainBoundaries, - pdadcValues, - numXpdGain); - - if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) { - - REG_WRITE(ah, - AR_PHY_TPCRG5 + regChainOffset, - SM(pdGainOverlap_t2, - AR_PHY_TPCRG5_PD_GAIN_OVERLAP) - | SM(gainBoundaries[0], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1) - | SM(gainBoundaries[1], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2) - | SM(gainBoundaries[2], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3) - | SM(gainBoundaries[3], - AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4)); - } - - regOffset = - AR_PHY_BASE + (672 << 2) + regChainOffset; - for (j = 0; j < 32; j++) { - reg32 = - ((pdadcValues[4 * j + 0] & 0xFF) << 0) - | ((pdadcValues[4 * j + 1] & 0xFF) << - 8) | ((pdadcValues[4 * j + 2] & - 0xFF) << 16) | - ((pdadcValues[4 * j + 3] & 0xFF) << - 24); - REG_WRITE(ah, regOffset, reg32); - - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "PDADC (%d,%4x): %4.4x %8.8x\n", - i, regChainOffset, regOffset, - reg32); - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "PDADC: Chain %d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d | PDADC %3d Value %3d | " - "PDADC %3d Value %3d |\n", - i, 4 * j, pdadcValues[4 * j], - 4 * j + 1, pdadcValues[4 * j + 1], - 4 * j + 2, pdadcValues[4 * j + 2], - 4 * j + 3, - pdadcValues[4 * j + 3]); - - regOffset += 4; - } - } - } - *pTxPowerIndexOffset = 0; - - return true; -} - -void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u8 i; - - if (ah->ah_isPciExpress != true) - return; - - if (ah->ah_config.pcie_powersave_enable == 2) - return; - - if (restore) - return; - - if (AR_SREV_9280_20_OR_LATER(ah)) { - for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) { - REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0), - INI_RA(&ahp->ah_iniPcieSerdes, i, 1)); - } - udelay(1000); - } else if (AR_SREV_9280(ah) - && (ah->ah_macRev == AR_SREV_REVISION_9280_10)) { - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - - REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); - REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); - REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); - - if (ah->ah_config.pcie_clock_req) - REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); - else - REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); - - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); - - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); - - udelay(1000); - } else { - REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); - REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); - REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); - REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); - REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); - REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); - REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); - REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); - REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); - REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); - } - - REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); - - if (ah->ah_config.pcie_waen) { - REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen); - } else { - if (AR_SREV_9280(ah)) - REG_WRITE(ah, AR_WA, 0x0040073f); - else - REG_WRITE(ah, AR_WA, 0x0000073f); - } -} - -static void -ath9k_hw_get_legacy_target_powers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_target_power_leg *powInfo, - u16 numChannels, - struct cal_target_power_leg *pNewPower, - u16 numRates, - bool isExtTarget) -{ - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = (isExtTarget) ? centers.ext_center : centers.ctl_center; - - if (freq <= ath9k_hw_fbin2freq(powInfo[0].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = 0; - } else { - for (i = 0; (i < numChannels) - && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = i; - break; - } else if ((freq < - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) - && (freq > - ath9k_hw_fbin2freq(powInfo[i - 1]. - bChannel, - IS_CHAN_2GHZ - (chan)))) { - lowIndex = i - 1; - break; - } - } - if ((matchIndex == -1) && (lowIndex == -1)) - matchIndex = i - 1; - } - - if (matchIndex != -1) { - *pNewPower = powInfo[matchIndex]; - } else { - clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, - IS_CHAN_2GHZ(chan)); - chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, - IS_CHAN_2GHZ(chan)); - - for (i = 0; i < numRates; i++) { - pNewPower->tPow2x[i] = - (u8) ath9k_hw_interpolate(freq, clo, chi, - powInfo - [lowIndex]. - tPow2x[i], - powInfo - [lowIndex + - 1].tPow2x[i]); - } - } -} - -static void -ath9k_hw_get_target_powers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct cal_target_power_ht *powInfo, - u16 numChannels, - struct cal_target_power_ht *pNewPower, - u16 numRates, - bool isHt40Target) -{ - u16 clo, chi; - int i; - int matchIndex = -1, lowIndex = -1; - u16 freq; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = isHt40Target ? centers.synth_center : centers.ctl_center; - - if (freq <= - ath9k_hw_fbin2freq(powInfo[0].bChannel, IS_CHAN_2GHZ(chan))) { - matchIndex = 0; - } else { - for (i = 0; (i < numChannels) - && (powInfo[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) { - matchIndex = i; - break; - } else - if ((freq < - ath9k_hw_fbin2freq(powInfo[i].bChannel, - IS_CHAN_2GHZ(chan))) - && (freq > - ath9k_hw_fbin2freq(powInfo[i - 1]. - bChannel, - IS_CHAN_2GHZ - (chan)))) { - lowIndex = i - 1; - break; - } - } - if ((matchIndex == -1) && (lowIndex == -1)) - matchIndex = i - 1; - } - - if (matchIndex != -1) { - *pNewPower = powInfo[matchIndex]; - } else { - clo = ath9k_hw_fbin2freq(powInfo[lowIndex].bChannel, - IS_CHAN_2GHZ(chan)); - chi = ath9k_hw_fbin2freq(powInfo[lowIndex + 1].bChannel, - IS_CHAN_2GHZ(chan)); - - for (i = 0; i < numRates; i++) { - pNewPower->tPow2x[i] = - (u8) ath9k_hw_interpolate(freq, clo, chi, - powInfo - [lowIndex]. - tPow2x[i], - powInfo - [lowIndex + - 1].tPow2x[i]); - } - } -} - -static u16 -ath9k_hw_get_max_edge_power(u16 freq, - struct cal_ctl_edges *pRdEdgesPower, - bool is2GHz) -{ - u16 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - int i; - - for (i = 0; (i < AR5416_NUM_BAND_EDGES) - && (pRdEdgesPower[i].bChannel != AR5416_BCHAN_UNUSED); i++) { - if (freq == ath9k_hw_fbin2freq(pRdEdgesPower[i].bChannel, - is2GHz)) { - twiceMaxEdgePower = pRdEdgesPower[i].tPower; - break; - } else if ((i > 0) - && (freq < - ath9k_hw_fbin2freq(pRdEdgesPower[i]. - bChannel, is2GHz))) { - if (ath9k_hw_fbin2freq - (pRdEdgesPower[i - 1].bChannel, is2GHz) < freq - && pRdEdgesPower[i - 1].flag) { - twiceMaxEdgePower = - pRdEdgesPower[i - 1].tPower; - } - break; - } - } - return twiceMaxEdgePower; -} - -static bool -ath9k_hw_set_power_per_rate_table(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - struct ath9k_channel *chan, - int16_t *ratesArray, - u16 cfgCtl, - u8 AntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ - u8 twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - static const u16 tpScaleReductionTable[5] = - { 0, 3, 6, 9, AR5416_MAX_RATE_POWER }; - - int i; - int8_t twiceLargestAntenna; - struct cal_ctl_data *rep; - struct cal_target_power_leg targetPowerOfdm, targetPowerCck = { - 0, { 0, 0, 0, 0} - }; - struct cal_target_power_leg targetPowerOfdmExt = { - 0, { 0, 0, 0, 0} }, targetPowerCckExt = { - 0, { 0, 0, 0, 0 } - }; - struct cal_target_power_ht targetPowerHt20, targetPowerHt40 = { - 0, {0, 0, 0, 0} - }; - u8 scaledPower = 0, minCtlPower, maxRegAllowedPower; - u16 ctlModesFor11a[] = - { CTL_11A, CTL_5GHT20, CTL_11A_EXT, CTL_5GHT40 }; - u16 ctlModesFor11g[] = - { CTL_11B, CTL_11G, CTL_2GHT20, CTL_11B_EXT, CTL_11G_EXT, - CTL_2GHT40 - }; - u16 numCtlModes, *pCtlMode, ctlMode, freq; - struct chan_centers centers; - int tx_chainmask; - u8 twiceMinEdgePower; - struct ath_hal_5416 *ahp = AH5416(ah); - - tx_chainmask = ahp->ah_txchainmask; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - - twiceLargestAntenna = max( - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[0], - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[1]); - - twiceLargestAntenna = max((u8) twiceLargestAntenna, - pEepData->modalHeader - [IS_CHAN_2GHZ(chan)].antennaGainCh[2]); - - twiceLargestAntenna = - (int8_t) min(AntennaReduction - twiceLargestAntenna, 0); - - maxRegAllowedPower = twiceMaxRegulatoryPower + twiceLargestAntenna; - - if (ah->ah_tpScale != ATH9K_TP_SCALE_MAX) { - maxRegAllowedPower -= - (tpScaleReductionTable[(ah->ah_tpScale)] * 2); - } - - scaledPower = min(powerLimit, maxRegAllowedPower); - - switch (ar5416_get_ntxchains(tx_chainmask)) { - case 1: - break; - case 2: - scaledPower -= - pEepData->modalHeader[IS_CHAN_2GHZ(chan)]. - pwrDecreaseFor2Chain; - break; - case 3: - scaledPower -= - pEepData->modalHeader[IS_CHAN_2GHZ(chan)]. - pwrDecreaseFor3Chain; - break; - } - - scaledPower = max(0, (int32_t) scaledPower); - - if (IS_CHAN_2GHZ(chan)) { - numCtlModes = - ARRAY_SIZE(ctlModesFor11g) - - SUB_NUM_CTL_MODES_AT_2G_40; - pCtlMode = ctlModesFor11g; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCck, 4, - false); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdm, 4, - false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower2GHT20, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11g); - ath9k_hw_get_target_powers(ah, chan, - pEepData-> - calTargetPower2GHT40, - AR5416_NUM_2G_40_TARGET_POWERS, - &targetPowerHt40, 8, - true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPowerCck, - AR5416_NUM_2G_CCK_TARGET_POWERS, - &targetPowerCckExt, - 4, true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower2G, - AR5416_NUM_2G_20_TARGET_POWERS, - &targetPowerOfdmExt, - 4, true); - } - } else { - - numCtlModes = - ARRAY_SIZE(ctlModesFor11a) - - SUB_NUM_CTL_MODES_AT_5G_40; - pCtlMode = ctlModesFor11a; - - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdm, 4, - false); - ath9k_hw_get_target_powers(ah, chan, - pEepData->calTargetPower5GHT20, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerHt20, 8, false); - - if (IS_CHAN_HT40(chan)) { - numCtlModes = ARRAY_SIZE(ctlModesFor11a); - ath9k_hw_get_target_powers(ah, chan, - pEepData-> - calTargetPower5GHT40, - AR5416_NUM_5G_40_TARGET_POWERS, - &targetPowerHt40, 8, - true); - ath9k_hw_get_legacy_target_powers(ah, chan, - pEepData-> - calTargetPower5G, - AR5416_NUM_5G_20_TARGET_POWERS, - &targetPowerOfdmExt, - 4, true); - } - } - - for (ctlMode = 0; ctlMode < numCtlModes; ctlMode++) { - bool isHt40CtlMode = - (pCtlMode[ctlMode] == CTL_5GHT40) - || (pCtlMode[ctlMode] == CTL_2GHT40); - if (isHt40CtlMode) - freq = centers.synth_center; - else if (pCtlMode[ctlMode] & EXT_ADDITIVE) - freq = centers.ext_center; - else - freq = centers.ctl_center; - - if (ar5416_get_eep_ver(ahp) == 14 - && ar5416_get_eep_rev(ahp) <= 2) - twiceMaxEdgePower = AR5416_MAX_RATE_POWER; - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "LOOP-Mode ctlMode %d < %d, isHt40CtlMode %d, " - "EXT_ADDITIVE %d\n", - ctlMode, numCtlModes, isHt40CtlMode, - (pCtlMode[ctlMode] & EXT_ADDITIVE)); - - for (i = 0; (i < AR5416_NUM_CTLS) && pEepData->ctlIndex[i]; - i++) { - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " LOOP-Ctlidx %d: cfgCtl 0x%2.2x " - "pCtlMode 0x%2.2x ctlIndex 0x%2.2x " - "chan %d\n", - i, cfgCtl, pCtlMode[ctlMode], - pEepData->ctlIndex[i], chan->channel); - - if ((((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - pEepData->ctlIndex[i]) - || - (((cfgCtl & ~CTL_MODE_M) | - (pCtlMode[ctlMode] & CTL_MODE_M)) == - ((pEepData-> - ctlIndex[i] & CTL_MODE_M) | SD_NO_CTL))) { - rep = &(pEepData->ctlData[i]); - - twiceMinEdgePower = - ath9k_hw_get_max_edge_power(freq, - rep-> - ctlEdges - [ar5416_get_ntxchains - (tx_chainmask) - - 1], - IS_CHAN_2GHZ - (chan)); - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " MATCH-EE_IDX %d: ch %d is2 %d " - "2xMinEdge %d chainmask %d chains %d\n", - i, freq, IS_CHAN_2GHZ(chan), - twiceMinEdgePower, tx_chainmask, - ar5416_get_ntxchains - (tx_chainmask)); - if ((cfgCtl & ~CTL_MODE_M) == SD_NO_CTL) { - twiceMaxEdgePower = - min(twiceMaxEdgePower, - twiceMinEdgePower); - } else { - twiceMaxEdgePower = - twiceMinEdgePower; - break; - } - } - } - - minCtlPower = min(twiceMaxEdgePower, scaledPower); - - DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - " SEL-Min ctlMode %d pCtlMode %d " - "2xMaxEdge %d sP %d minCtlPwr %d\n", - ctlMode, pCtlMode[ctlMode], twiceMaxEdgePower, - scaledPower, minCtlPower); - - switch (pCtlMode[ctlMode]) { - case CTL_11B: - for (i = 0; i < ARRAY_SIZE(targetPowerCck.tPow2x); - i++) { - targetPowerCck.tPow2x[i] = - min(targetPowerCck.tPow2x[i], - minCtlPower); - } - break; - case CTL_11A: - case CTL_11G: - for (i = 0; i < ARRAY_SIZE(targetPowerOfdm.tPow2x); - i++) { - targetPowerOfdm.tPow2x[i] = - min(targetPowerOfdm.tPow2x[i], - minCtlPower); - } - break; - case CTL_5GHT20: - case CTL_2GHT20: - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); - i++) { - targetPowerHt20.tPow2x[i] = - min(targetPowerHt20.tPow2x[i], - minCtlPower); - } - break; - case CTL_11B_EXT: - targetPowerCckExt.tPow2x[0] = - min(targetPowerCckExt.tPow2x[0], minCtlPower); - break; - case CTL_11A_EXT: - case CTL_11G_EXT: - targetPowerOfdmExt.tPow2x[0] = - min(targetPowerOfdmExt.tPow2x[0], minCtlPower); - break; - case CTL_5GHT40: - case CTL_2GHT40: - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); - i++) { - targetPowerHt40.tPow2x[i] = - min(targetPowerHt40.tPow2x[i], - minCtlPower); - } - break; - default: - break; - } - } - - ratesArray[rate6mb] = ratesArray[rate9mb] = ratesArray[rate12mb] = - ratesArray[rate18mb] = ratesArray[rate24mb] = - targetPowerOfdm.tPow2x[0]; - ratesArray[rate36mb] = targetPowerOfdm.tPow2x[1]; - ratesArray[rate48mb] = targetPowerOfdm.tPow2x[2]; - ratesArray[rate54mb] = targetPowerOfdm.tPow2x[3]; - ratesArray[rateXr] = targetPowerOfdm.tPow2x[0]; - - for (i = 0; i < ARRAY_SIZE(targetPowerHt20.tPow2x); i++) - ratesArray[rateHt20_0 + i] = targetPowerHt20.tPow2x[i]; - - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rate1l] = targetPowerCck.tPow2x[0]; - ratesArray[rate2s] = ratesArray[rate2l] = - targetPowerCck.tPow2x[1]; - ratesArray[rate5_5s] = ratesArray[rate5_5l] = - targetPowerCck.tPow2x[2]; - ; - ratesArray[rate11s] = ratesArray[rate11l] = - targetPowerCck.tPow2x[3]; - ; - } - if (IS_CHAN_HT40(chan)) { - for (i = 0; i < ARRAY_SIZE(targetPowerHt40.tPow2x); i++) { - ratesArray[rateHt40_0 + i] = - targetPowerHt40.tPow2x[i]; - } - ratesArray[rateDupOfdm] = targetPowerHt40.tPow2x[0]; - ratesArray[rateDupCck] = targetPowerHt40.tPow2x[0]; - ratesArray[rateExtOfdm] = targetPowerOfdmExt.tPow2x[0]; - if (IS_CHAN_2GHZ(chan)) { - ratesArray[rateExtCck] = - targetPowerCckExt.tPow2x[0]; - } - } - return true; -} - -static int -ath9k_hw_set_txpower(struct ath_hal *ah, - struct ar5416_eeprom *pEepData, - struct ath9k_channel *chan, - u16 cfgCtl, - u8 twiceAntennaReduction, - u8 twiceMaxRegulatoryPower, - u8 powerLimit) -{ - struct modal_eep_header *pModal = - &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]); - int16_t ratesArray[Ar5416RateSize]; - int16_t txPowerIndexOffset = 0; - u8 ht40PowerIncForPdadc = 2; - int i; - - memset(ratesArray, 0, sizeof(ratesArray)); - - if ((pEepData->baseEepHeader. - version & AR5416_EEP_VER_MINOR_MASK) >= - AR5416_EEP_MINOR_VER_2) { - ht40PowerIncForPdadc = pModal->ht40PowerIncForPdadc; - } - - if (!ath9k_hw_set_power_per_rate_table(ah, pEepData, chan, - &ratesArray[0], cfgCtl, - twiceAntennaReduction, - twiceMaxRegulatoryPower, - powerLimit)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set " - "tx power per rate table\n"); - return -EIO; - } - - if (!ath9k_hw_set_power_cal_table - (ah, pEepData, chan, &txPowerIndexOffset)) { - DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "ath9k_hw_set_txpower: unable to set power table\n"); - return -EIO; - } - - for (i = 0; i < ARRAY_SIZE(ratesArray); i++) { - ratesArray[i] = - (int16_t) (txPowerIndexOffset + ratesArray[i]); - if (ratesArray[i] > AR5416_MAX_RATE_POWER) - ratesArray[i] = AR5416_MAX_RATE_POWER; - } - - if (AR_SREV_9280_10_OR_LATER(ah)) { - for (i = 0; i < Ar5416RateSize; i++) - ratesArray[i] -= AR5416_PWR_TABLE_OFFSET * 2; - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE1, - ATH9K_POW_SM(ratesArray[rate18mb], 24) - | ATH9K_POW_SM(ratesArray[rate12mb], 16) - | ATH9K_POW_SM(ratesArray[rate9mb], 8) - | ATH9K_POW_SM(ratesArray[rate6mb], 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE2, - ATH9K_POW_SM(ratesArray[rate54mb], 24) - | ATH9K_POW_SM(ratesArray[rate48mb], 16) - | ATH9K_POW_SM(ratesArray[rate36mb], 8) - | ATH9K_POW_SM(ratesArray[rate24mb], 0) - ); - - if (IS_CHAN_2GHZ(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE3, - ATH9K_POW_SM(ratesArray[rate2s], 24) - | ATH9K_POW_SM(ratesArray[rate2l], 16) - | ATH9K_POW_SM(ratesArray[rateXr], 8) - | ATH9K_POW_SM(ratesArray[rate1l], 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE4, - ATH9K_POW_SM(ratesArray[rate11s], 24) - | ATH9K_POW_SM(ratesArray[rate11l], 16) - | ATH9K_POW_SM(ratesArray[rate5_5s], 8) - | ATH9K_POW_SM(ratesArray[rate5_5l], 0) - ); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE5, - ATH9K_POW_SM(ratesArray[rateHt20_3], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_2], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_1], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_0], 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE6, - ATH9K_POW_SM(ratesArray[rateHt20_7], 24) - | ATH9K_POW_SM(ratesArray[rateHt20_6], 16) - | ATH9K_POW_SM(ratesArray[rateHt20_5], 8) - | ATH9K_POW_SM(ratesArray[rateHt20_4], 0) - ); - - if (IS_CHAN_HT40(chan)) { - REG_WRITE(ah, AR_PHY_POWER_TX_RATE7, - ATH9K_POW_SM(ratesArray[rateHt40_3] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_2] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_1] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_0] + - ht40PowerIncForPdadc, 0) - ); - REG_WRITE(ah, AR_PHY_POWER_TX_RATE8, - ATH9K_POW_SM(ratesArray[rateHt40_7] + - ht40PowerIncForPdadc, 24) - | ATH9K_POW_SM(ratesArray[rateHt40_6] + - ht40PowerIncForPdadc, 16) - | ATH9K_POW_SM(ratesArray[rateHt40_5] + - ht40PowerIncForPdadc, 8) - | ATH9K_POW_SM(ratesArray[rateHt40_4] + - ht40PowerIncForPdadc, 0) - ); - - REG_WRITE(ah, AR_PHY_POWER_TX_RATE9, - ATH9K_POW_SM(ratesArray[rateExtOfdm], 24) - | ATH9K_POW_SM(ratesArray[rateExtCck], 16) - | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8) - | ATH9K_POW_SM(ratesArray[rateDupCck], 0) - ); - } - - REG_WRITE(ah, AR_PHY_POWER_TX_SUB, - ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6) - | ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0) - ); - - i = rate6mb; - if (IS_CHAN_HT40(chan)) - i = rateHt40_0; - else if (IS_CHAN_HT20(chan)) - i = rateHt20_0; - - if (AR_SREV_9280_10_OR_LATER(ah)) - ah->ah_maxPowerLevel = - ratesArray[i] + AR5416_PWR_TABLE_OFFSET * 2; - else - ah->ah_maxPowerLevel = ratesArray[i]; - - return 0; -} - -static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah, - u32 coef_scaled, - u32 *coef_mantissa, - u32 *coef_exponent) -{ - u32 coef_exp, coef_man; - - for (coef_exp = 31; coef_exp > 0; coef_exp--) - if ((coef_scaled >> coef_exp) & 0x1) - break; - - coef_exp = 14 - (coef_exp - COEF_SCALE_S); - - coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); - - *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); - *coef_exponent = coef_exp - 16; -} - -static void -ath9k_hw_set_delta_slope(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - u32 coef_scaled, ds_coef_exp, ds_coef_man; - u32 clockMhzScaled = 0x64000000; - struct chan_centers centers; - - if (IS_CHAN_HALF_RATE(chan)) - clockMhzScaled = clockMhzScaled >> 1; - else if (IS_CHAN_QUARTER_RATE(chan)) - clockMhzScaled = clockMhzScaled >> 2; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - coef_scaled = clockMhzScaled / centers.synth_center; - - ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, - &ds_coef_exp); - - REG_RMW_FIELD(ah, AR_PHY_TIMING3, - AR_PHY_TIMING3_DSC_MAN, ds_coef_man); - REG_RMW_FIELD(ah, AR_PHY_TIMING3, - AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); - - coef_scaled = (9 * coef_scaled) / 10; - - ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, - &ds_coef_exp); - - REG_RMW_FIELD(ah, AR_PHY_HALFGI, - AR_PHY_HALFGI_DSC_MAN, ds_coef_man); - REG_RMW_FIELD(ah, AR_PHY_HALFGI, - AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); -} - -static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int freq; - int bin, cur_bin; - int bb_spur_off, spur_subchannel_sd; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, newVal; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - struct chan_centers centers; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - freq = centers.synth_center; - - ah->ah_config.spurmode = SPUR_ENABLE_EEPROM; - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); - - if (is2GHz) - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; - else - cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; - - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - freq; - - if (IS_CHAN_HT40(chan)) { - if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { - bb_spur = cur_bb_spur; - break; - } - } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && - (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - return; - } else { - REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, - AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); - } - - bin = bb_spur * 320; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - - newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); - - newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); - - if (IS_CHAN_HT40(chan)) { - if (bb_spur < 0) { - spur_subchannel_sd = 1; - bb_spur_off = bb_spur + 10; - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur - 10; - } - } else { - spur_subchannel_sd = 0; - bb_spur_off = bb_spur; - } - - if (IS_CHAN_HT40(chan)) - spur_delta_phase = - ((bb_spur * 262144) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - else - spur_delta_phase = - ((bb_spur * 524288) / - 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; - spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; - - newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, newVal); - - newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; - REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp = abs(cur_vit_mask - bin); - - if (tmp < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); -} - -static void ath9k_hw_spur_mitigate(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - int bb_spur = AR_NO_SPUR; - int bin, cur_bin; - int spur_freq_sd; - int spur_delta_phase; - int denominator; - int upper, lower, cur_vit_mask; - int tmp, new; - int i; - int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, - AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 - }; - int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, - AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 - }; - int inc[4] = { 0, 100, 0, 0 }; - - int8_t mask_m[123]; - int8_t mask_p[123]; - int8_t mask_amt; - int tmp_mask; - int cur_bb_spur; - bool is2GHz = IS_CHAN_2GHZ(chan); - - memset(&mask_m, 0, sizeof(int8_t) * 123); - memset(&mask_p, 0, sizeof(int8_t) * 123); - - for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { - cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); - if (AR_NO_SPUR == cur_bb_spur) - break; - cur_bb_spur = cur_bb_spur - (chan->channel * 10); - if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { - bb_spur = cur_bb_spur; - break; - } - } - - if (AR_NO_SPUR == bb_spur) - return; - - bin = bb_spur * 32; - - tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); - new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | - AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | - AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | - AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - - REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); - - new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | - AR_PHY_SPUR_REG_ENABLE_MASK_PPM | - AR_PHY_SPUR_REG_MASK_RATE_SELECT | - AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | - SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); - REG_WRITE(ah, AR_PHY_SPUR_REG, new); - - spur_delta_phase = ((bb_spur * 524288) / 100) & - AR_PHY_TIMING11_SPUR_DELTA_PHASE; - - denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; - spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; - - new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | - SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | - SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); - REG_WRITE(ah, AR_PHY_TIMING11, new); - - cur_bin = -6000; - upper = bin + 100; - lower = bin - 100; - - for (i = 0; i < 4; i++) { - int pilot_mask = 0; - int chan_mask = 0; - int bp = 0; - for (bp = 0; bp < 30; bp++) { - if ((cur_bin > lower) && (cur_bin < upper)) { - pilot_mask = pilot_mask | 0x1 << bp; - chan_mask = chan_mask | 0x1 << bp; - } - cur_bin += 100; - } - cur_bin += inc[i]; - REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); - REG_WRITE(ah, chan_mask_reg[i], chan_mask); - } - - cur_vit_mask = 6100; - upper = bin + 120; - lower = bin - 120; - - for (i = 0; i < 123; i++) { - if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { - - /* workaround for gcc bug #37014 */ - volatile int tmp = abs(cur_vit_mask - bin); - - if (tmp < 75) - mask_amt = 1; - else - mask_amt = 0; - if (cur_vit_mask < 0) - mask_m[abs(cur_vit_mask / 100)] = mask_amt; - else - mask_p[cur_vit_mask / 100] = mask_amt; - } - cur_vit_mask -= 100; - } - - tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) - | (mask_m[48] << 26) | (mask_m[49] << 24) - | (mask_m[50] << 22) | (mask_m[51] << 20) - | (mask_m[52] << 18) | (mask_m[53] << 16) - | (mask_m[54] << 14) | (mask_m[55] << 12) - | (mask_m[56] << 10) | (mask_m[57] << 8) - | (mask_m[58] << 6) | (mask_m[59] << 4) - | (mask_m[60] << 2) | (mask_m[61] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); - REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - - tmp_mask = (mask_m[31] << 28) - | (mask_m[32] << 26) | (mask_m[33] << 24) - | (mask_m[34] << 22) | (mask_m[35] << 20) - | (mask_m[36] << 18) | (mask_m[37] << 16) - | (mask_m[48] << 14) | (mask_m[39] << 12) - | (mask_m[40] << 10) | (mask_m[41] << 8) - | (mask_m[42] << 6) | (mask_m[43] << 4) - | (mask_m[44] << 2) | (mask_m[45] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + if (AR_SREV_9280_20(ah)) { + if (((chan->channel % 20) == 0) + || ((chan->channel % 10) == 0)) + pll = 0x2850; + else + pll = 0x142c; + } + } else { + pll |= SM(0x2c, AR_RTC_9160_PLL_DIV); + } - tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) - | (mask_m[18] << 26) | (mask_m[18] << 24) - | (mask_m[20] << 22) | (mask_m[20] << 20) - | (mask_m[22] << 18) | (mask_m[22] << 16) - | (mask_m[24] << 14) | (mask_m[24] << 12) - | (mask_m[25] << 10) | (mask_m[26] << 8) - | (mask_m[27] << 6) | (mask_m[28] << 4) - | (mask_m[29] << 2) | (mask_m[30] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + } else if (AR_SREV_9160_10_OR_LATER(ah)) { - tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) - | (mask_m[2] << 26) | (mask_m[3] << 24) - | (mask_m[4] << 22) | (mask_m[5] << 20) - | (mask_m[6] << 18) | (mask_m[7] << 16) - | (mask_m[8] << 14) | (mask_m[9] << 12) - | (mask_m[10] << 10) | (mask_m[11] << 8) - | (mask_m[12] << 6) | (mask_m[13] << 4) - | (mask_m[14] << 2) | (mask_m[15] << 0); - REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + pll = SM(0x5, AR_RTC_9160_PLL_REFDIV); - tmp_mask = (mask_p[15] << 28) - | (mask_p[14] << 26) | (mask_p[13] << 24) - | (mask_p[12] << 22) | (mask_p[11] << 20) - | (mask_p[10] << 18) | (mask_p[9] << 16) - | (mask_p[8] << 14) | (mask_p[7] << 12) - | (mask_p[6] << 10) | (mask_p[5] << 8) - | (mask_p[4] << 6) | (mask_p[3] << 4) - | (mask_p[2] << 2) | (mask_p[1] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_9160_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_9160_PLL_CLKSEL); - tmp_mask = (mask_p[30] << 28) - | (mask_p[29] << 26) | (mask_p[28] << 24) - | (mask_p[27] << 22) | (mask_p[26] << 20) - | (mask_p[25] << 18) | (mask_p[24] << 16) - | (mask_p[23] << 14) | (mask_p[22] << 12) - | (mask_p[21] << 10) | (mask_p[20] << 8) - | (mask_p[19] << 6) | (mask_p[18] << 4) - | (mask_p[17] << 2) | (mask_p[16] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + if (chan && IS_CHAN_5GHZ(chan)) + pll |= SM(0x50, AR_RTC_9160_PLL_DIV); + else + pll |= SM(0x58, AR_RTC_9160_PLL_DIV); + } else { + pll = AR_RTC_PLL_REFDIV_5 | AR_RTC_PLL_DIV2; - tmp_mask = (mask_p[45] << 28) - | (mask_p[44] << 26) | (mask_p[43] << 24) - | (mask_p[42] << 22) | (mask_p[41] << 20) - | (mask_p[40] << 18) | (mask_p[39] << 16) - | (mask_p[38] << 14) | (mask_p[37] << 12) - | (mask_p[36] << 10) | (mask_p[35] << 8) - | (mask_p[34] << 6) | (mask_p[33] << 4) - | (mask_p[32] << 2) | (mask_p[31] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); + if (chan && IS_CHAN_HALF_RATE(chan)) + pll |= SM(0x1, AR_RTC_PLL_CLKSEL); + else if (chan && IS_CHAN_QUARTER_RATE(chan)) + pll |= SM(0x2, AR_RTC_PLL_CLKSEL); - tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) - | (mask_p[59] << 26) | (mask_p[58] << 24) - | (mask_p[57] << 22) | (mask_p[56] << 20) - | (mask_p[55] << 18) | (mask_p[54] << 16) - | (mask_p[53] << 14) | (mask_p[52] << 12) - | (mask_p[51] << 10) | (mask_p[50] << 8) - | (mask_p[49] << 6) | (mask_p[48] << 4) - | (mask_p[47] << 2) | (mask_p[46] << 0); - REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); - REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); + if (chan && IS_CHAN_5GHZ(chan)) + pll |= SM(0xa, AR_RTC_PLL_DIV); + else + pll |= SM(0xb, AR_RTC_PLL_DIV); + } + } + REG_WRITE(ah, (u16) (AR_RTC_PLL_CONTROL), pll); + + udelay(RTC_PLL_SETTLE_DELAY); + + REG_WRITE(ah, AR_RTC_SLEEP_CLK, AR_RTC_FORCE_DERIVED_CLK); } static void ath9k_hw_init_chain_masks(struct ath_hal *ah) @@ -5140,8 +1050,6 @@ static void ath9k_hw_init_chain_masks(struct ath_hal *ah) } case 0x1: case 0x2: - if (!AR_SREV_9280(ah)) - break; case 0x7: REG_WRITE(ah, AR_PHY_RX_CHAINMASK, rx_chainmask); REG_WRITE(ah, AR_PHY_CAL_CHAINMASK, rx_chainmask); @@ -5160,102 +1068,35 @@ static void ath9k_hw_init_chain_masks(struct ath_hal *ah) REG_READ(ah, AR_PHY_ANALOG_SWAP) | 0x00000001); } -static void ath9k_hw_set_addac(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_init_interrupt_masks(struct ath_hal *ah, + enum nl80211_iftype opmode) { - struct modal_eep_header *pModal; struct ath_hal_5416 *ahp = AH5416(ah); - struct ar5416_eeprom *eep = &ahp->ah_eeprom; - u8 biaslevel; - - if (ah->ah_macVersion != AR_SREV_VERSION_9160) - return; - - if (ar5416_get_eep_rev(ahp) < AR5416_EEP_MINOR_VER_7) - return; - - pModal = &(eep->modalHeader[IS_CHAN_2GHZ(chan)]); - - if (pModal->xpaBiasLvl != 0xff) { - biaslevel = pModal->xpaBiasLvl; - } else { - - u16 resetFreqBin, freqBin, freqCount = 0; - struct chan_centers centers; - - ath9k_hw_get_channel_centers(ah, chan, ¢ers); - resetFreqBin = - FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)); - freqBin = pModal->xpaBiasLvlFreq[0] & 0xff; - biaslevel = (u8) (pModal->xpaBiasLvlFreq[0] >> 14); - - freqCount++; - - while (freqCount < 3) { - if (pModal->xpaBiasLvlFreq[freqCount] == 0x0) - break; - - freqBin = pModal->xpaBiasLvlFreq[freqCount] & 0xff; - if (resetFreqBin >= freqBin) { - biaslevel = - (u8) (pModal-> - xpaBiasLvlFreq[freqCount] - >> 14); - } else { - break; - } - freqCount++; - } - } - - if (IS_CHAN_2GHZ(chan)) { - INI_RA(&ahp->ah_iniAddac, 7, 1) = - (INI_RA(&ahp->ah_iniAddac, 7, 1) & (~0x18)) | biaslevel - << 3; - } else { - INI_RA(&ahp->ah_iniAddac, 6, 1) = - (INI_RA(&ahp->ah_iniAddac, 6, 1) & (~0xc0)) | biaslevel - << 6; - } -} + ahp->ah_maskReg = AR_IMR_TXERR | + AR_IMR_TXURN | + AR_IMR_RXERR | + AR_IMR_RXORN | + AR_IMR_BCNMISC; -static u32 ath9k_hw_mac_usec(struct ath_hal *ah, u32 clks) -{ - if (ah->ah_curchan != NULL) - return clks / - CLOCK_RATE[ath9k_hw_chan2wmode(ah, ah->ah_curchan)]; + if (ahp->ah_intrMitigation) + ahp->ah_maskReg |= AR_IMR_RXINTM | AR_IMR_RXMINTR; else - return clks / CLOCK_RATE[ATH9K_MODE_11B]; -} - -static u32 ath9k_hw_mac_to_usec(struct ath_hal *ah, u32 clks) -{ - struct ath9k_channel *chan = ah->ah_curchan; + ahp->ah_maskReg |= AR_IMR_RXOK; - if (chan && IS_CHAN_HT40(chan)) - return ath9k_hw_mac_usec(ah, clks) / 2; - else - return ath9k_hw_mac_usec(ah, clks); -} + ahp->ah_maskReg |= AR_IMR_TXOK; -static u32 ath9k_hw_mac_clks(struct ath_hal *ah, u32 usecs) -{ - if (ah->ah_curchan != NULL) - return usecs * CLOCK_RATE[ath9k_hw_chan2wmode(ah, - ah->ah_curchan)]; - else - return usecs * CLOCK_RATE[ATH9K_MODE_11B]; -} + if (opmode == NL80211_IFTYPE_AP) + ahp->ah_maskReg |= AR_IMR_MIB; -static u32 ath9k_hw_mac_to_clks(struct ath_hal *ah, u32 usecs) -{ - struct ath9k_channel *chan = ah->ah_curchan; + REG_WRITE(ah, AR_IMR, ahp->ah_maskReg); + REG_WRITE(ah, AR_IMR_S2, REG_READ(ah, AR_IMR_S2) | AR_IMR_S2_GTT); - if (chan && IS_CHAN_HT40(chan)) - return ath9k_hw_mac_clks(ah, usecs) * 2; - else - return ath9k_hw_mac_clks(ah, usecs); + if (!AR_SREV_9100(ah)) { + REG_WRITE(ah, AR_INTR_SYNC_CAUSE, 0xFFFFFFFF); + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, AR_INTR_SYNC_DEFAULT); + REG_WRITE(ah, AR_INTR_SYNC_MASK, 0); + } } static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us) @@ -5263,8 +1104,7 @@ static bool ath9k_hw_set_ack_timeout(struct ath_hal *ah, u32 us) struct ath_hal_5416 *ahp = AH5416(ah); if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_ACK))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad ack timeout %u\n", - __func__, us); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad ack timeout %u\n", us); ahp->ah_acktimeout = (u32) -1; return false; } else { @@ -5280,8 +1120,7 @@ static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us) struct ath_hal_5416 *ahp = AH5416(ah); if (us > ath9k_hw_mac_to_usec(ah, MS(0xffffffff, AR_TIME_OUT_CTS))) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad cts timeout %u\n", - __func__, us); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad cts timeout %u\n", us); ahp->ah_ctstimeout = (u32) -1; return false; } else { @@ -5291,14 +1130,14 @@ static bool ath9k_hw_set_cts_timeout(struct ath_hal *ah, u32 us) return true; } } -static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, - u32 tu) + +static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, u32 tu) { struct ath_hal_5416 *ahp = AH5416(ah); if (tu > 0xFFFF) { DPRINTF(ah->ah_sc, ATH_DBG_XMIT, - "%s: bad global tx timeout %u\n", __func__, tu); + "bad global tx timeout %u\n", tu); ahp->ah_globaltxtimeout = (u32) -1; return false; } else { @@ -5308,45 +1147,135 @@ static bool ath9k_hw_set_global_txtimeout(struct ath_hal *ah, } } -bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) -{ - struct ath_hal_5416 *ahp = AH5416(ah); +static void ath9k_hw_init_user_settings(struct ath_hal *ah) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "ahp->ah_miscMode 0x%x\n", + ahp->ah_miscMode); + + if (ahp->ah_miscMode != 0) + REG_WRITE(ah, AR_PCU_MISC, + REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode); + if (ahp->ah_slottime != (u32) -1) + ath9k_hw_setslottime(ah, ahp->ah_slottime); + if (ahp->ah_acktimeout != (u32) -1) + ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout); + if (ahp->ah_ctstimeout != (u32) -1) + ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout); + if (ahp->ah_globaltxtimeout != (u32) -1) + ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout); +} + +const char *ath9k_hw_probe(u16 vendorid, u16 devid) +{ + return vendorid == ATHEROS_VENDOR_ID ? + ath9k_hw_devname(devid) : NULL; +} + +void ath9k_hw_detach(struct ath_hal *ah) +{ + if (!AR_SREV_9100(ah)) + ath9k_hw_ani_detach(ah); + + ath9k_hw_rfdetach(ah); + ath9k_hw_setpower(ah, ATH9K_PM_FULL_SLEEP); + kfree(ah); +} + +struct ath_hal *ath9k_hw_attach(u16 devid, struct ath_softc *sc, + void __iomem *mem, int *error) +{ + struct ath_hal *ah = NULL; + + switch (devid) { + case AR5416_DEVID_PCI: + case AR5416_DEVID_PCIE: + case AR9160_DEVID_PCI: + case AR9280_DEVID_PCI: + case AR9280_DEVID_PCIE: + case AR9285_DEVID_PCIE: + ah = ath9k_hw_do_attach(devid, sc, mem, error); + break; + default: + *error = -ENXIO; + break; + } + + return ah; +} + +/*******/ +/* INI */ +/*******/ + +static void ath9k_hw_override_ini(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + /* + * Set the RX_ABORT and RX_DIS and clear if off only after + * RXE is set for MAC. This prevents frames with corrupted + * descriptor status. + */ + REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + + + if (!AR_SREV_5416_V20_OR_LATER(ah) || + AR_SREV_9280_10_OR_LATER(ah)) + return; + + REG_WRITE(ah, 0x9800 + (651 << 2), 0x11); +} + +static u32 ath9k_hw_def_ini_fixup(struct ath_hal *ah, + struct ar5416_eeprom_def *pEepData, + u32 reg, u32 value) +{ + struct base_eep_header *pBase = &(pEepData->baseEepHeader); + + switch (ah->ah_devid) { + case AR9280_DEVID_PCI: + if (reg == 0x7894) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "ini VAL: %x EEPROM: %x\n", value, + (pBase->version & 0xff)); + + if ((pBase->version & 0xff) > 0x0a) { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "PWDCLKIND: %d\n", + pBase->pwdclkind); + value &= ~AR_AN_TOP2_PWDCLKIND; + value |= AR_AN_TOP2_PWDCLKIND & + (pBase->pwdclkind << AR_AN_TOP2_PWDCLKIND_S); + } else { + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "PWDCLKIND Earlier Rev\n"); + } - if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: bad slot time %u\n", - __func__, us); - ahp->ah_slottime = (u32) -1; - return false; - } else { - REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); - ahp->ah_slottime = us; - return true; + DPRINTF(ah->ah_sc, ATH_DBG_ANY, + "final ini VAL: %x\n", value); + } + break; } + + return value; } -static void ath9k_hw_init_user_settings(struct ath_hal *ah) +static u32 ath9k_hw_ini_fixup(struct ath_hal *ah, + struct ar5416_eeprom_def *pEepData, + u32 reg, u32 value) { struct ath_hal_5416 *ahp = AH5416(ah); - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "--AP %s ahp->ah_miscMode 0x%x\n", - __func__, ahp->ah_miscMode); - if (ahp->ah_miscMode != 0) - REG_WRITE(ah, AR_PCU_MISC, - REG_READ(ah, AR_PCU_MISC) | ahp->ah_miscMode); - if (ahp->ah_slottime != (u32) -1) - ath9k_hw_setslottime(ah, ahp->ah_slottime); - if (ahp->ah_acktimeout != (u32) -1) - ath9k_hw_set_ack_timeout(ah, ahp->ah_acktimeout); - if (ahp->ah_ctstimeout != (u32) -1) - ath9k_hw_set_cts_timeout(ah, ahp->ah_ctstimeout); - if (ahp->ah_globaltxtimeout != (u32) -1) - ath9k_hw_set_global_txtimeout(ah, ahp->ah_globaltxtimeout); + if (ahp->ah_eep_map == EEP_MAP_4KBITS) + return value; + else + return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value); } -static int -ath9k_hw_process_ini(struct ath_hal *ah, - struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) +static int ath9k_hw_process_ini(struct ath_hal *ah, + struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) { int i, regWrites = 0; struct ath_hal_5416 *ahp = AH5416(ah); @@ -5397,26 +1326,20 @@ ath9k_hw_process_ini(struct ath_hal *ah, memcpy(ahp->ah_addac5416_21, ahp->ah_iniAddac.ia_array, addacSize); - (ahp->ah_addac5416_21)[31 * - ahp->ah_iniAddac.ia_columns + 1] = 0; + (ahp->ah_addac5416_21)[31 * ahp->ah_iniAddac.ia_columns + 1] = 0; temp.ia_array = ahp->ah_addac5416_21; temp.ia_columns = ahp->ah_iniAddac.ia_columns; temp.ia_rows = ahp->ah_iniAddac.ia_rows; REG_WRITE_ARRAY(&temp, 1, regWrites); } + REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_INTERNAL_ADDAC); for (i = 0; i < ahp->ah_iniModes.ia_rows; i++) { u32 reg = INI_RA(&ahp->ah_iniModes, i, 0); u32 val = INI_RA(&ahp->ah_iniModes, i, modesIndex); -#ifdef CONFIG_SLOW_ANT_DIV - if (ah->ah_devid == AR9280_DEVID_PCI) - val = ath9k_hw_ini_fixup(ah, &ahp->ah_eeprom, reg, - val); -#endif - REG_WRITE(ah, reg, val); if (reg >= 0x7800 && reg < 0x78a0 @@ -5427,6 +1350,12 @@ ath9k_hw_process_ini(struct ath_hal *ah, DO_DELAY(regWrites); } + if (AR_SREV_9280(ah)) + REG_WRITE_ARRAY(&ahp->ah_iniModesRxGain, modesIndex, regWrites); + + if (AR_SREV_9280(ah)) + REG_WRITE_ARRAY(&ahp->ah_iniModesTxGain, modesIndex, regWrites); + for (i = 0; i < ahp->ah_iniCommon.ia_rows; i++) { u32 reg = INI_RA(&ahp->ah_iniCommon, i, 0); u32 val = INI_RA(&ahp->ah_iniCommon, i, 1); @@ -5452,7 +1381,7 @@ ath9k_hw_process_ini(struct ath_hal *ah, ath9k_hw_set_regs(ah, chan, macmode); ath9k_hw_init_chain_masks(ah); - status = ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan, + status = ath9k_hw_set_txpower(ah, chan, ath9k_regd_get_ctl(ah, chan), ath9k_regd_get_antenna_allowed(ah, chan), @@ -5461,178 +1390,324 @@ ath9k_hw_process_ini(struct ath_hal *ah, (u32) ah->ah_powerLimit)); if (status != 0) { DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, - "%s: error init'ing transmit power\n", __func__); + "error init'ing transmit power\n"); return -EIO; } if (!ath9k_hw_set_rf_regs(ah, chan, freqIndex)) { DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, - "%s: ar5416SetRfRegs failed\n", __func__); + "ar5416SetRfRegs failed\n"); return -EIO; } return 0; } -static void ath9k_hw_setup_calibration(struct ath_hal *ah, - struct hal_cal_list *currCal) +/****************************************/ +/* Reset and Channel Switching Routines */ +/****************************************/ + +static void ath9k_hw_set_rfmode(struct ath_hal *ah, struct ath9k_channel *chan) { - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_IQCAL_LOG_COUNT_MAX, - currCal->calData->calCountMax); - - switch (currCal->calData->calType) { - case IQ_MISMATCH_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_IQ); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting IQ Mismatch Calibration\n", - __func__); - break; - case ADC_GAIN_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_GAIN); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting ADC Gain Calibration\n", __func__); + u32 rfMode = 0; + + if (chan == NULL) + return; + + rfMode |= (IS_CHAN_B(chan) || IS_CHAN_G(chan)) + ? AR_PHY_MODE_DYNAMIC : AR_PHY_MODE_OFDM; + + if (!AR_SREV_9280_10_OR_LATER(ah)) + rfMode |= (IS_CHAN_5GHZ(chan)) ? + AR_PHY_MODE_RF5GHZ : AR_PHY_MODE_RF2GHZ; + + if (AR_SREV_9280_20(ah) && IS_CHAN_A_5MHZ_SPACED(chan)) + rfMode |= (AR_PHY_MODE_DYNAMIC | AR_PHY_MODE_DYN_CCK_DISABLE); + + REG_WRITE(ah, AR_PHY_MODE, rfMode); +} + +static void ath9k_hw_mark_phy_inactive(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_PHY_ACTIVE, AR_PHY_ACTIVE_DIS); +} + +static inline void ath9k_hw_set_dma(struct ath_hal *ah) +{ + u32 regval; + + regval = REG_READ(ah, AR_AHB_MODE); + REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); + + regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; + REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + + REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel); + + regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; + REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + + REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + + if (AR_SREV_9285(ah)) { + REG_WRITE(ah, AR_PCU_TXBUF_CTRL, + AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); + } else { + REG_WRITE(ah, AR_PCU_TXBUF_CTRL, + AR_PCU_TXBUF_CTRL_USABLE_SIZE); + } +} + +static void ath9k_hw_set_operating_mode(struct ath_hal *ah, int opmode) +{ + u32 val; + + val = REG_READ(ah, AR_STA_ID1); + val &= ~(AR_STA_ID1_STA_AP | AR_STA_ID1_ADHOC); + switch (opmode) { + case NL80211_IFTYPE_AP: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_STA_AP + | AR_STA_ID1_KSRCH_MODE); + REG_CLR_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; - case ADC_DC_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_PER); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting ADC DC Calibration\n", __func__); + case NL80211_IFTYPE_ADHOC: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_ADHOC + | AR_STA_ID1_KSRCH_MODE); + REG_SET_BIT(ah, AR_CFG, AR_CFG_AP_ADHOC_INDICATION); break; - case ADC_DC_INIT_CAL: - REG_WRITE(ah, AR_PHY_CALMODE, AR_PHY_CALMODE_ADC_DC_INIT); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: starting Init ADC DC Calibration\n", - __func__); + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_MONITOR: + REG_WRITE(ah, AR_STA_ID1, val | AR_STA_ID1_KSRCH_MODE); break; } +} + +static inline void ath9k_hw_get_delta_slope_vals(struct ath_hal *ah, + u32 coef_scaled, + u32 *coef_mantissa, + u32 *coef_exponent) +{ + u32 coef_exp, coef_man; + + for (coef_exp = 31; coef_exp > 0; coef_exp--) + if ((coef_scaled >> coef_exp) & 0x1) + break; + + coef_exp = 14 - (coef_exp - COEF_SCALE_S); + + coef_man = coef_scaled + (1 << (COEF_SCALE_S - coef_exp - 1)); - REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_DO_CAL); + *coef_mantissa = coef_man >> (COEF_SCALE_S - coef_exp); + *coef_exponent = coef_exp - 16; } -static void ath9k_hw_reset_calibration(struct ath_hal *ah, - struct hal_cal_list *currCal) +static void ath9k_hw_set_delta_slope(struct ath_hal *ah, + struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); - int i; + u32 coef_scaled, ds_coef_exp, ds_coef_man; + u32 clockMhzScaled = 0x64000000; + struct chan_centers centers; + + if (IS_CHAN_HALF_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 1; + else if (IS_CHAN_QUARTER_RATE(chan)) + clockMhzScaled = clockMhzScaled >> 2; + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + coef_scaled = clockMhzScaled / centers.synth_center; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_TIMING3, + AR_PHY_TIMING3_DSC_EXP, ds_coef_exp); + + coef_scaled = (9 * coef_scaled) / 10; + + ath9k_hw_get_delta_slope_vals(ah, coef_scaled, &ds_coef_man, + &ds_coef_exp); + + REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_MAN, ds_coef_man); + REG_RMW_FIELD(ah, AR_PHY_HALFGI, + AR_PHY_HALFGI_DSC_EXP, ds_coef_exp); +} + +static bool ath9k_hw_set_reset(struct ath_hal *ah, int type) +{ + u32 rst_flags; + u32 tmpReg; + + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | + AR_RTC_FORCE_WAKE_ON_INT); + + if (AR_SREV_9100(ah)) { + rst_flags = AR_RTC_RC_MAC_WARM | AR_RTC_RC_MAC_COLD | + AR_RTC_RC_COLD_RESET | AR_RTC_RC_WARM_RESET; + } else { + tmpReg = REG_READ(ah, AR_INTR_SYNC_CAUSE); + if (tmpReg & + (AR_INTR_SYNC_LOCAL_TIMEOUT | + AR_INTR_SYNC_RADM_CPL_TIMEOUT)) { + REG_WRITE(ah, AR_INTR_SYNC_ENABLE, 0); + REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); + } else { + REG_WRITE(ah, AR_RC, AR_RC_AHB); + } + + rst_flags = AR_RTC_RC_MAC_WARM; + if (type == ATH9K_RESET_COLD) + rst_flags |= AR_RTC_RC_MAC_COLD; + } + + REG_WRITE(ah, (u16) (AR_RTC_RC), rst_flags); + udelay(50); + + REG_WRITE(ah, (u16) (AR_RTC_RC), 0); + if (!ath9k_hw_wait(ah, (u16) (AR_RTC_RC), AR_RTC_RC_M, 0)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "RTC stuck in MAC reset\n"); + return false; + } + + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, 0); + + ath9k_hw_init_pll(ah, NULL); - ath9k_hw_setup_calibration(ah, currCal); + if (AR_SREV_9100(ah)) + udelay(50); + + return true; +} + +static bool ath9k_hw_set_reset_power_on(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN | + AR_RTC_FORCE_WAKE_ON_INT); - currCal->calState = CAL_RUNNING; + REG_WRITE(ah, (u16) (AR_RTC_RESET), 0); + REG_WRITE(ah, (u16) (AR_RTC_RESET), 1); - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_Meas0.sign[i] = 0; - ahp->ah_Meas1.sign[i] = 0; - ahp->ah_Meas2.sign[i] = 0; - ahp->ah_Meas3.sign[i] = 0; + if (!ath9k_hw_wait(ah, + AR_RTC_STATUS, + AR_RTC_STATUS_M, + AR_RTC_STATUS_ON)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n"); + return false; } - ahp->ah_CalSamples = 0; + ath9k_hw_read_revisions(ah); + + return ath9k_hw_set_reset(ah, ATH9K_RESET_WARM); } -static void -ath9k_hw_per_calibration(struct ath_hal *ah, - struct ath9k_channel *ichan, - u8 rxchainmask, - struct hal_cal_list *currCal, - bool *isCalDone) +static bool ath9k_hw_set_reset_reg(struct ath_hal *ah, u32 type) { - struct ath_hal_5416 *ahp = AH5416(ah); + REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN | AR_RTC_FORCE_WAKE_ON_INT); - *isCalDone = false; + switch (type) { + case ATH9K_RESET_POWER_ON: + return ath9k_hw_set_reset_power_on(ah); + break; + case ATH9K_RESET_WARM: + case ATH9K_RESET_COLD: + return ath9k_hw_set_reset(ah, type); + break; + default: + return false; + } +} - if (currCal->calState == CAL_RUNNING) { - if (!(REG_READ(ah, - AR_PHY_TIMING_CTRL4(0)) & - AR_PHY_TIMING_CTRL4_DO_CAL)) { +static void ath9k_hw_set_regs(struct ath_hal *ah, struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) +{ + u32 phymode; + u32 enableDacFifo = 0; + struct ath_hal_5416 *ahp = AH5416(ah); - currCal->calData->calCollect(ah); + if (AR_SREV_9285_10_OR_LATER(ah)) + enableDacFifo = (REG_READ(ah, AR_PHY_TURBO) & + AR_PHY_FC_ENABLE_DAC_FIFO); - ahp->ah_CalSamples++; + phymode = AR_PHY_FC_HT_EN | AR_PHY_FC_SHORT_GI_40 + | AR_PHY_FC_SINGLE_HT_LTF1 | AR_PHY_FC_WALSH | enableDacFifo; - if (ahp->ah_CalSamples >= - currCal->calData->calNumSamples) { - int i, numChains = 0; - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - if (rxchainmask & (1 << i)) - numChains++; - } + if (IS_CHAN_HT40(chan)) { + phymode |= AR_PHY_FC_DYN2040_EN; - currCal->calData->calPostProc(ah, - numChains); + if ((chan->chanmode == CHANNEL_A_HT40PLUS) || + (chan->chanmode == CHANNEL_G_HT40PLUS)) + phymode |= AR_PHY_FC_DYN2040_PRI_CH; - ichan->CalValid |= - currCal->calData->calType; - currCal->calState = CAL_DONE; - *isCalDone = true; - } else { - ath9k_hw_setup_calibration(ah, currCal); - } - } - } else if (!(ichan->CalValid & currCal->calData->calType)) { - ath9k_hw_reset_calibration(ah, currCal); + if (ahp->ah_extprotspacing == ATH9K_HT_EXTPROTSPACING_25) + phymode |= AR_PHY_FC_DYN2040_EXT_CH; } + REG_WRITE(ah, AR_PHY_TURBO, phymode); + + ath9k_hw_set11nmac2040(ah, macmode); + + REG_WRITE(ah, AR_GTXTO, 25 << AR_GTXTO_TIMEOUT_LIMIT_S); + REG_WRITE(ah, AR_CST, 0xF << AR_CST_TIMEOUT_LIMIT_S); } -static inline bool ath9k_hw_run_init_cals(struct ath_hal *ah, - int init_cal_count) +static bool ath9k_hw_chip_reset(struct ath_hal *ah, + struct ath9k_channel *chan) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel ichan; - bool isCalDone; - struct hal_cal_list *currCal = ahp->ah_cal_list_curr; - const struct hal_percal_data *calData = currCal->calData; - int i; - if (currCal == NULL) + if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) return false; - ichan.CalValid = 0; + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return false; - for (i = 0; i < init_cal_count; i++) { - ath9k_hw_reset_calibration(ah, currCal); + ahp->ah_chipFullSleep = false; - if (!ath9k_hw_wait(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_DO_CAL, 0)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Cal %d failed to complete in 100ms.\n", - __func__, calData->calType); + ath9k_hw_init_pll(ah, chan); - ahp->ah_cal_list = ahp->ah_cal_list_last = - ahp->ah_cal_list_curr = NULL; - return false; - } + ath9k_hw_set_rfmode(ah, chan); - ath9k_hw_per_calibration(ah, &ichan, ahp->ah_rxchainmask, - currCal, &isCalDone); - if (!isCalDone) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Not able to run Init Cal %d.\n", - __func__, calData->calType); - } - if (currCal->calNext) { - currCal = currCal->calNext; - calData = currCal->calData; - } + return true; +} + +static struct ath9k_channel *ath9k_hw_check_chan(struct ath_hal *ah, + struct ath9k_channel *chan) +{ + if (!(IS_CHAN_2GHZ(chan) ^ IS_CHAN_5GHZ(chan))) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "invalid channel %u/0x%x; not marked as " + "2GHz or 5GHz\n", chan->channel, chan->channelFlags); + return NULL; } - ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = NULL; - return true; + if (!IS_CHAN_OFDM(chan) && + !IS_CHAN_B(chan) && + !IS_CHAN_HT20(chan) && + !IS_CHAN_HT40(chan)) { + DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, + "invalid channel %u/0x%x; not marked as " + "OFDM or CCK or HT20 or HT40PLUS or HT40MINUS\n", + chan->channel, chan->channelFlags); + return NULL; + } + + return ath9k_regd_check_channel(ah, chan); } -static bool -ath9k_hw_channel_change(struct ath_hal *ah, - struct ath9k_channel *chan, - enum ath9k_ht_macmode macmode) +static bool ath9k_hw_channel_change(struct ath_hal *ah, + struct ath9k_channel *chan, + enum ath9k_ht_macmode macmode) { u32 synthDelay, qnum; - struct ath_hal_5416 *ahp = AH5416(ah); for (qnum = 0; qnum < AR_NUM_QCU; qnum++) { if (ath9k_hw_numtxpending(ah, qnum)) { DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: Transmit frames pending on queue %d\n", - __func__, qnum); + "Transmit frames pending on queue %d\n", qnum); return false; } } @@ -5640,8 +1715,8 @@ ath9k_hw_channel_change(struct ath_hal *ah, REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN); if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN, AR_PHY_RFBUS_GRANT_EN)) { - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: Could not kill baseband RX\n", __func__); + DPRINTF(ah->ah_sc, ATH_DBG_REG_IO, + "Could not kill baseband RX\n"); return false; } @@ -5650,30 +1725,30 @@ ath9k_hw_channel_change(struct ath_hal *ah, if (AR_SREV_9280_10_OR_LATER(ah)) { if (!(ath9k_hw_ar9280_set_channel(ah, chan))) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: failed to set channel\n", __func__); + "failed to set channel\n"); return false; } } else { if (!(ath9k_hw_set_channel(ah, chan))) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: failed to set channel\n", __func__); + "failed to set channel\n"); return false; } } - if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan, + if (ath9k_hw_set_txpower(ah, chan, ath9k_regd_get_ctl(ah, chan), ath9k_regd_get_antenna_allowed(ah, chan), chan->maxRegTxPower * 2, min((u32) MAX_RATE_POWER, (u32) ah->ah_powerLimit)) != 0) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: error init'ing transmit power\n", __func__); + "error init'ing transmit power\n"); return false; } synthDelay = REG_READ(ah, AR_PHY_RX_DELAY) & AR_PHY_RX_DELAY_DELAY; - if (IS_CHAN_CCK(chan)) + if (IS_CHAN_B(chan)) synthDelay = (4 * synthDelay) / 22; else synthDelay /= 10; @@ -5690,182 +1765,468 @@ ath9k_hw_channel_change(struct ath_hal *ah, else ath9k_hw_spur_mitigate(ah, chan); - if (!chan->oneTimeCalsDone) - chan->oneTimeCalsDone = true; + if (!chan->oneTimeCalsDone) + chan->oneTimeCalsDone = true; + + return true; +} + +static void ath9k_hw_9280_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan) +{ + int bb_spur = AR_NO_SPUR; + int freq; + int bin, cur_bin; + int bb_spur_off, spur_subchannel_sd; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, newVal; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; + struct chan_centers centers; + + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); + + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); + + ath9k_hw_get_channel_centers(ah, chan, ¢ers); + freq = centers.synth_center; + + ah->ah_config.spurmode = SPUR_ENABLE_EEPROM; + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); + + if (is2GHz) + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_2GHZ; + else + cur_bb_spur = (cur_bb_spur / 10) + AR_BASE_FREQ_5GHZ; + + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - freq; + + if (IS_CHAN_HT40(chan)) { + if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT40) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT40)) { + bb_spur = cur_bb_spur; + break; + } + } else if ((cur_bb_spur > -AR_SPUR_FEEQ_BOUND_HT20) && + (cur_bb_spur < AR_SPUR_FEEQ_BOUND_HT20)) { + bb_spur = cur_bb_spur; + break; + } + } + + if (AR_NO_SPUR == bb_spur) { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + return; + } else { + REG_CLR_BIT(ah, AR_PHY_FORCE_CLKEN_CCK, + AR_PHY_FORCE_CLKEN_CCK_MRC_MUX); + } + + bin = bb_spur * 320; + + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + + newVal = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), newVal); + + newVal = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, newVal); + + if (IS_CHAN_HT40(chan)) { + if (bb_spur < 0) { + spur_subchannel_sd = 1; + bb_spur_off = bb_spur + 10; + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur - 10; + } + } else { + spur_subchannel_sd = 0; + bb_spur_off = bb_spur; + } + + if (IS_CHAN_HT40(chan)) + spur_delta_phase = + ((bb_spur * 262144) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + else + spur_delta_phase = + ((bb_spur * 524288) / + 10) & AR_PHY_TIMING11_SPUR_DELTA_PHASE; + + denominator = IS_CHAN_2GHZ(chan) ? 44 : 40; + spur_freq_sd = ((bb_spur_off * 2048) / denominator) & 0x3ff; + + newVal = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, newVal); + + newVal = spur_subchannel_sd << AR_PHY_SFCORR_SPUR_SUBCHNL_SD_S; + REG_WRITE(ah, AR_PHY_SFCORR_EXT, newVal); + + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; + + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); + } + + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; + + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { + + /* workaround for gcc bug #37014 */ + volatile int tmp = abs(cur_vit_mask - bin); + + if (tmp < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; + } + + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); + + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); + + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); + + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); + + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); + + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); + + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - return true; + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } -static bool ath9k_hw_chip_reset(struct ath_hal *ah, - struct ath9k_channel *chan) +static void ath9k_hw_spur_mitigate(struct ath_hal *ah, struct ath9k_channel *chan) { - struct ath_hal_5416 *ahp = AH5416(ah); - - if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM)) - return false; + int bb_spur = AR_NO_SPUR; + int bin, cur_bin; + int spur_freq_sd; + int spur_delta_phase; + int denominator; + int upper, lower, cur_vit_mask; + int tmp, new; + int i; + int pilot_mask_reg[4] = { AR_PHY_TIMING7, AR_PHY_TIMING8, + AR_PHY_PILOT_MASK_01_30, AR_PHY_PILOT_MASK_31_60 + }; + int chan_mask_reg[4] = { AR_PHY_TIMING9, AR_PHY_TIMING10, + AR_PHY_CHANNEL_MASK_01_30, AR_PHY_CHANNEL_MASK_31_60 + }; + int inc[4] = { 0, 100, 0, 0 }; - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return false; + int8_t mask_m[123]; + int8_t mask_p[123]; + int8_t mask_amt; + int tmp_mask; + int cur_bb_spur; + bool is2GHz = IS_CHAN_2GHZ(chan); - ahp->ah_chipFullSleep = false; + memset(&mask_m, 0, sizeof(int8_t) * 123); + memset(&mask_p, 0, sizeof(int8_t) * 123); - ath9k_hw_init_pll(ah, chan); + for (i = 0; i < AR_EEPROM_MODAL_SPURS; i++) { + cur_bb_spur = ath9k_hw_eeprom_get_spur_chan(ah, i, is2GHz); + if (AR_NO_SPUR == cur_bb_spur) + break; + cur_bb_spur = cur_bb_spur - (chan->channel * 10); + if ((cur_bb_spur > -95) && (cur_bb_spur < 95)) { + bb_spur = cur_bb_spur; + break; + } + } - ath9k_hw_set_rfmode(ah, chan); + if (AR_NO_SPUR == bb_spur) + return; - return true; -} + bin = bb_spur * 32; -static inline void ath9k_hw_set_dma(struct ath_hal *ah) -{ - u32 regval; + tmp = REG_READ(ah, AR_PHY_TIMING_CTRL4(0)); + new = tmp | (AR_PHY_TIMING_CTRL4_ENABLE_SPUR_RSSI | + AR_PHY_TIMING_CTRL4_ENABLE_SPUR_FILTER | + AR_PHY_TIMING_CTRL4_ENABLE_CHAN_MASK | + AR_PHY_TIMING_CTRL4_ENABLE_PILOT_MASK); - regval = REG_READ(ah, AR_AHB_MODE); - REG_WRITE(ah, AR_AHB_MODE, regval | AR_AHB_PREFETCH_RD_EN); + REG_WRITE(ah, AR_PHY_TIMING_CTRL4(0), new); - regval = REG_READ(ah, AR_TXCFG) & ~AR_TXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_TXCFG, regval | AR_TXCFG_DMASZ_128B); + new = (AR_PHY_SPUR_REG_MASK_RATE_CNTL | + AR_PHY_SPUR_REG_ENABLE_MASK_PPM | + AR_PHY_SPUR_REG_MASK_RATE_SELECT | + AR_PHY_SPUR_REG_ENABLE_VIT_SPUR_RSSI | + SM(SPUR_RSSI_THRESH, AR_PHY_SPUR_REG_SPUR_RSSI_THRESH)); + REG_WRITE(ah, AR_PHY_SPUR_REG, new); - REG_RMW_FIELD(ah, AR_TXCFG, AR_FTRIG, ah->ah_txTrigLevel); + spur_delta_phase = ((bb_spur * 524288) / 100) & + AR_PHY_TIMING11_SPUR_DELTA_PHASE; - regval = REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_DMASZ_MASK; - REG_WRITE(ah, AR_RXCFG, regval | AR_RXCFG_DMASZ_128B); + denominator = IS_CHAN_2GHZ(chan) ? 440 : 400; + spur_freq_sd = ((bb_spur * 2048) / denominator) & 0x3ff; - REG_WRITE(ah, AR_RXFIFO_CFG, 0x200); + new = (AR_PHY_TIMING11_USE_SPUR_IN_AGC | + SM(spur_freq_sd, AR_PHY_TIMING11_SPUR_FREQ_SD) | + SM(spur_delta_phase, AR_PHY_TIMING11_SPUR_DELTA_PHASE)); + REG_WRITE(ah, AR_PHY_TIMING11, new); - if (AR_SREV_9285(ah)) { - REG_WRITE(ah, AR_PCU_TXBUF_CTRL, - AR_9285_PCU_TXBUF_CTRL_USABLE_SIZE); - } else { - REG_WRITE(ah, AR_PCU_TXBUF_CTRL, - AR_PCU_TXBUF_CTRL_USABLE_SIZE); - } -} + cur_bin = -6000; + upper = bin + 100; + lower = bin - 100; -bool ath9k_hw_stopdmarecv(struct ath_hal *ah) -{ - REG_WRITE(ah, AR_CR, AR_CR_RXD); - if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: dma failed to stop in 10ms\n" - "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", - __func__, - REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); - return false; - } else { - return true; + for (i = 0; i < 4; i++) { + int pilot_mask = 0; + int chan_mask = 0; + int bp = 0; + for (bp = 0; bp < 30; bp++) { + if ((cur_bin > lower) && (cur_bin < upper)) { + pilot_mask = pilot_mask | 0x1 << bp; + chan_mask = chan_mask | 0x1 << bp; + } + cur_bin += 100; + } + cur_bin += inc[i]; + REG_WRITE(ah, pilot_mask_reg[i], pilot_mask); + REG_WRITE(ah, chan_mask_reg[i], chan_mask); } -} - -void ath9k_hw_startpcureceive(struct ath_hal *ah) -{ - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - ath9k_enable_mib_counters(ah); - - ath9k_ani_reset(ah); -} - -void ath9k_hw_stoppcurecv(struct ath_hal *ah) -{ - REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); + cur_vit_mask = 6100; + upper = bin + 120; + lower = bin - 120; - ath9k_hw_disable_mib_counters(ah); -} + for (i = 0; i < 123; i++) { + if ((cur_vit_mask > lower) && (cur_vit_mask < upper)) { -static bool ath9k_hw_iscal_supported(struct ath_hal *ah, - struct ath9k_channel *chan, - enum hal_cal_types calType) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - bool retval = false; + /* workaround for gcc bug #37014 */ + volatile int tmp = abs(cur_vit_mask - bin); - switch (calType & ahp->ah_suppCals) { - case IQ_MISMATCH_CAL: - if (!IS_CHAN_B(chan)) - retval = true; - break; - case ADC_GAIN_CAL: - case ADC_DC_CAL: - if (!IS_CHAN_B(chan) - && !(IS_CHAN_2GHZ(chan) && IS_CHAN_HT20(chan))) - retval = true; - break; + if (tmp < 75) + mask_amt = 1; + else + mask_amt = 0; + if (cur_vit_mask < 0) + mask_m[abs(cur_vit_mask / 100)] = mask_amt; + else + mask_p[cur_vit_mask / 100] = mask_amt; + } + cur_vit_mask -= 100; } - return retval; -} - -static bool ath9k_hw_init_cal(struct ath_hal *ah, - struct ath9k_channel *chan) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *ichan = - ath9k_regd_check_channel(ah, chan); - - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_CAL); - - if (!ath9k_hw_wait - (ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: offset calibration failed to complete in 1ms; " - "noisy environment?\n", __func__); - return false; - } + tmp_mask = (mask_m[46] << 30) | (mask_m[47] << 28) + | (mask_m[48] << 26) | (mask_m[49] << 24) + | (mask_m[50] << 22) | (mask_m[51] << 20) + | (mask_m[52] << 18) | (mask_m[53] << 16) + | (mask_m[54] << 14) | (mask_m[55] << 12) + | (mask_m[56] << 10) | (mask_m[57] << 8) + | (mask_m[58] << 6) | (mask_m[59] << 4) + | (mask_m[60] << 2) | (mask_m[61] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_1, tmp_mask); + REG_WRITE(ah, AR_PHY_VIT_MASK2_M_46_61, tmp_mask); - REG_WRITE(ah, AR_PHY_AGC_CONTROL, - REG_READ(ah, AR_PHY_AGC_CONTROL) | - AR_PHY_AGC_CONTROL_NF); + tmp_mask = (mask_m[31] << 28) + | (mask_m[32] << 26) | (mask_m[33] << 24) + | (mask_m[34] << 22) | (mask_m[35] << 20) + | (mask_m[36] << 18) | (mask_m[37] << 16) + | (mask_m[48] << 14) | (mask_m[39] << 12) + | (mask_m[40] << 10) | (mask_m[41] << 8) + | (mask_m[42] << 6) | (mask_m[43] << 4) + | (mask_m[44] << 2) | (mask_m[45] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_31_45, tmp_mask); - ahp->ah_cal_list = ahp->ah_cal_list_last = ahp->ah_cal_list_curr = - NULL; + tmp_mask = (mask_m[16] << 30) | (mask_m[16] << 28) + | (mask_m[18] << 26) | (mask_m[18] << 24) + | (mask_m[20] << 22) | (mask_m[20] << 20) + | (mask_m[22] << 18) | (mask_m[22] << 16) + | (mask_m[24] << 14) | (mask_m[24] << 12) + | (mask_m[25] << 10) | (mask_m[26] << 8) + | (mask_m[27] << 6) | (mask_m[28] << 4) + | (mask_m[29] << 2) | (mask_m[30] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_16_30, tmp_mask); - if (AR_SREV_9100(ah) || AR_SREV_9160_10_OR_LATER(ah)) { - if (ath9k_hw_iscal_supported(ah, chan, ADC_GAIN_CAL)) { - INIT_CAL(&ahp->ah_adcGainCalData); - INSERT_CAL(ahp, &ahp->ah_adcGainCalData); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling ADC Gain Calibration.\n", - __func__); - } - if (ath9k_hw_iscal_supported(ah, chan, ADC_DC_CAL)) { - INIT_CAL(&ahp->ah_adcDcCalData); - INSERT_CAL(ahp, &ahp->ah_adcDcCalData); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling ADC DC Calibration.\n", - __func__); - } - if (ath9k_hw_iscal_supported(ah, chan, IQ_MISMATCH_CAL)) { - INIT_CAL(&ahp->ah_iqCalData); - INSERT_CAL(ahp, &ahp->ah_iqCalData); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: enabling IQ Calibration.\n", - __func__); - } + tmp_mask = (mask_m[0] << 30) | (mask_m[1] << 28) + | (mask_m[2] << 26) | (mask_m[3] << 24) + | (mask_m[4] << 22) | (mask_m[5] << 20) + | (mask_m[6] << 18) | (mask_m[7] << 16) + | (mask_m[8] << 14) | (mask_m[9] << 12) + | (mask_m[10] << 10) | (mask_m[11] << 8) + | (mask_m[12] << 6) | (mask_m[13] << 4) + | (mask_m[14] << 2) | (mask_m[15] << 0); + REG_WRITE(ah, AR_PHY_MASK_CTL, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_M_00_15, tmp_mask); - ahp->ah_cal_list_curr = ahp->ah_cal_list; + tmp_mask = (mask_p[15] << 28) + | (mask_p[14] << 26) | (mask_p[13] << 24) + | (mask_p[12] << 22) | (mask_p[11] << 20) + | (mask_p[10] << 18) | (mask_p[9] << 16) + | (mask_p[8] << 14) | (mask_p[7] << 12) + | (mask_p[6] << 10) | (mask_p[5] << 8) + | (mask_p[4] << 6) | (mask_p[3] << 4) + | (mask_p[2] << 2) | (mask_p[1] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_1, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_15_01, tmp_mask); - if (ahp->ah_cal_list_curr) - ath9k_hw_reset_calibration(ah, - ahp->ah_cal_list_curr); - } + tmp_mask = (mask_p[30] << 28) + | (mask_p[29] << 26) | (mask_p[28] << 24) + | (mask_p[27] << 22) | (mask_p[26] << 20) + | (mask_p[25] << 18) | (mask_p[24] << 16) + | (mask_p[23] << 14) | (mask_p[22] << 12) + | (mask_p[21] << 10) | (mask_p[20] << 8) + | (mask_p[19] << 6) | (mask_p[18] << 4) + | (mask_p[17] << 2) | (mask_p[16] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_2, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_30_16, tmp_mask); - ichan->CalValid = 0; + tmp_mask = (mask_p[45] << 28) + | (mask_p[44] << 26) | (mask_p[43] << 24) + | (mask_p[42] << 22) | (mask_p[41] << 20) + | (mask_p[40] << 18) | (mask_p[39] << 16) + | (mask_p[38] << 14) | (mask_p[37] << 12) + | (mask_p[36] << 10) | (mask_p[35] << 8) + | (mask_p[34] << 6) | (mask_p[33] << 4) + | (mask_p[32] << 2) | (mask_p[31] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_3, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_45_31, tmp_mask); - return true; + tmp_mask = (mask_p[61] << 30) | (mask_p[60] << 28) + | (mask_p[59] << 26) | (mask_p[58] << 24) + | (mask_p[57] << 22) | (mask_p[56] << 20) + | (mask_p[55] << 18) | (mask_p[54] << 16) + | (mask_p[53] << 14) | (mask_p[52] << 12) + | (mask_p[51] << 10) | (mask_p[50] << 8) + | (mask_p[49] << 6) | (mask_p[48] << 4) + | (mask_p[47] << 2) | (mask_p[46] << 0); + REG_WRITE(ah, AR_PHY_BIN_MASK2_4, tmp_mask); + REG_WRITE(ah, AR_PHY_MASK2_P_61_45, tmp_mask); } - -bool ath9k_hw_reset(struct ath_hal *ah, - struct ath9k_channel *chan, +bool ath9k_hw_reset(struct ath_hal *ah, struct ath9k_channel *chan, enum ath9k_ht_macmode macmode, u8 txchainmask, u8 rxchainmask, enum ath9k_ht_extprotspacing extprotspacing, - bool bChannelChange, - int *status) + bool bChannelChange, int *status) { u32 saveLedState; struct ath_hal_5416 *ahp = AH5416(ah); @@ -5886,8 +2247,8 @@ bool ath9k_hw_reset(struct ath_hal *ah, if (ath9k_hw_check_chan(ah, chan) == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); + "invalid channel %u/0x%x; no mapping\n", + chan->channel, chan->channelFlags); ecode = -EINVAL; goto bad; } @@ -5907,8 +2268,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, ((chan->channelFlags & CHANNEL_ALL) == (ah->ah_curchan->channelFlags & CHANNEL_ALL)) && (!AR_SREV_9280(ah) || (!IS_CHAN_A_5MHZ_SPACED(chan) && - !IS_CHAN_A_5MHZ_SPACED(ah-> - ah_curchan)))) { + !IS_CHAN_A_5MHZ_SPACED(ah->ah_curchan)))) { if (ath9k_hw_channel_change(ah, chan, macmode)) { ath9k_hw_loadnf(ah, ah->ah_curchan); @@ -5930,8 +2290,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, ath9k_hw_mark_phy_inactive(ah); if (!ath9k_hw_chip_reset(ah, chan)) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, "%s: chip reset failed\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "chip reset failed\n"); ecode = -EINVAL; goto bad; } @@ -5965,7 +2324,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, if (!ath9k_hw_eeprom_set_board_values(ah, chan)) { DPRINTF(ah->ah_sc, ATH_DBG_EEPROM, - "%s: error setting board options\n", __func__); + "error setting board options\n"); ecode = -EIO; goto bad; } @@ -6016,7 +2375,7 @@ bool ath9k_hw_reset(struct ath_hal *ah, ath9k_hw_init_interrupt_masks(ah, ah->ah_opmode); ath9k_hw_init_qos(ah); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) ath9k_enable_rfkill(ah); #endif @@ -6055,15 +2414,13 @@ bool ath9k_hw_reset(struct ath_hal *ah, mask = REG_READ(ah, AR_CFG); if (mask & (AR_CFG_SWRB | AR_CFG_SWTB | AR_CFG_SWRG)) { DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s CFG Byte Swap Set 0x%x\n", __func__, - mask); + "CFG Byte Swap Set 0x%x\n", mask); } else { mask = INIT_CONFIG_STATUS | AR_CFG_SWRB | AR_CFG_SWTB; REG_WRITE(ah, AR_CFG, mask); DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s Setting CFG 0x%x\n", __func__, - REG_READ(ah, AR_CFG)); + "Setting CFG 0x%x\n", REG_READ(ah, AR_CFG)); } } else { #ifdef __BIG_ENDIAN @@ -6078,693 +2435,402 @@ bad: return false; } -bool ath9k_hw_phy_disable(struct ath_hal *ah) -{ - return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM); -} - -bool ath9k_hw_disable(struct ath_hal *ah) -{ - if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) - return false; - - return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); -} +/************************/ +/* Key Cache Management */ +/************************/ -bool -ath9k_hw_calibrate(struct ath_hal *ah, struct ath9k_channel *chan, - u8 rxchainmask, bool longcal, - bool *isCalDone) +bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry) { - struct ath_hal_5416 *ahp = AH5416(ah); - struct hal_cal_list *currCal = ahp->ah_cal_list_curr; - struct ath9k_channel *ichan = - ath9k_regd_check_channel(ah, chan); - - *isCalDone = true; + u32 keyType; - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); + if (entry >= ah->ah_caps.keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "entry %u out of range\n", entry); return false; } - if (currCal && - (currCal->calState == CAL_RUNNING || - currCal->calState == CAL_WAITING)) { - ath9k_hw_per_calibration(ah, ichan, rxchainmask, currCal, - isCalDone); - if (*isCalDone) { - ahp->ah_cal_list_curr = currCal = currCal->calNext; - - if (currCal->calState == CAL_WAITING) { - *isCalDone = false; - ath9k_hw_reset_calibration(ah, currCal); - } - } - } - - if (longcal) { - ath9k_hw_getnf(ah, ichan); - ath9k_hw_loadnf(ah, ah->ah_curchan); - ath9k_hw_start_nfcal(ah); - - if ((ichan->channelFlags & CHANNEL_CW_INT) != 0) { - - chan->channelFlags |= CHANNEL_CW_INT; - ichan->channelFlags &= ~CHANNEL_CW_INT; - } - } - - return true; -} - -static void ath9k_hw_iqcal_collect(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalPowerMeasI[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalPowerMeasQ[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalIqCorrMeas[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d pmi=0x%08x;pmq=0x%08x;iqcm=0x%08x;\n", - ahp->ah_CalSamples, i, ahp->ah_totalPowerMeasI[i], - ahp->ah_totalPowerMeasQ[i], - ahp->ah_totalIqCorrMeas[i]); - } -} - -static void ath9k_hw_adc_gaincal_collect(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalAdcIOddPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalAdcIEvenPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalAdcQOddPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ahp->ah_totalAdcQEvenPhase[i] += - REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ahp->ah_CalSamples, i, - ahp->ah_totalAdcIOddPhase[i], - ahp->ah_totalAdcIEvenPhase[i], - ahp->ah_totalAdcQOddPhase[i], - ahp->ah_totalAdcQEvenPhase[i]); - } -} - -static void ath9k_hw_adc_dccal_collect(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - int i; - - for (i = 0; i < AR5416_MAX_CHAINS; i++) { - ahp->ah_totalAdcDcOffsetIOddPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_0(i)); - ahp->ah_totalAdcDcOffsetIEvenPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_1(i)); - ahp->ah_totalAdcDcOffsetQOddPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_2(i)); - ahp->ah_totalAdcDcOffsetQEvenPhase[i] += - (int32_t) REG_READ(ah, AR_PHY_CAL_MEAS_3(i)); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%d: Chn %d oddi=0x%08x; eveni=0x%08x; " - "oddq=0x%08x; evenq=0x%08x;\n", - ahp->ah_CalSamples, i, - ahp->ah_totalAdcDcOffsetIOddPhase[i], - ahp->ah_totalAdcDcOffsetIEvenPhase[i], - ahp->ah_totalAdcDcOffsetQOddPhase[i], - ahp->ah_totalAdcDcOffsetQEvenPhase[i]); - } -} - -static void ath9k_hw_iqcalibrate(struct ath_hal *ah, u8 numChains) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 powerMeasQ, powerMeasI, iqCorrMeas; - u32 qCoffDenom, iCoffDenom; - int32_t qCoff, iCoff; - int iqCorrNeg, i; - - for (i = 0; i < numChains; i++) { - powerMeasI = ahp->ah_totalPowerMeasI[i]; - powerMeasQ = ahp->ah_totalPowerMeasQ[i]; - iqCorrMeas = ahp->ah_totalIqCorrMeas[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting IQ Cal and Correction for Chain %d\n", - i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Orignal: Chn %diq_corr_meas = 0x%08x\n", - i, ahp->ah_totalIqCorrMeas[i]); - - iqCorrNeg = 0; - - - if (iqCorrMeas > 0x80000000) { - iqCorrMeas = (0xffffffff - iqCorrMeas) + 1; - iqCorrNeg = 1; - } - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_i = 0x%08x\n", i, powerMeasI); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_q = 0x%08x\n", i, powerMeasQ); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "iqCorrNeg is 0x%08x\n", - iqCorrNeg); - - iCoffDenom = (powerMeasI / 2 + powerMeasQ / 2) / 128; - qCoffDenom = powerMeasQ / 64; - - if (powerMeasQ != 0) { - - iCoff = iqCorrMeas / iCoffDenom; - qCoff = powerMeasI / qCoffDenom - 64; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d iCoff = 0x%08x\n", i, iCoff); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d qCoff = 0x%08x\n", i, qCoff); - - - iCoff = iCoff & 0x3f; - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "New: Chn %d iCoff = 0x%08x\n", i, iCoff); - if (iqCorrNeg == 0x0) - iCoff = 0x40 - iCoff; - - if (qCoff > 15) - qCoff = 15; - else if (qCoff <= -16) - qCoff = 16; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d : iCoff = 0x%x qCoff = 0x%x\n", - i, iCoff, qCoff); - - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), - AR_PHY_TIMING_CTRL4_IQCORR_Q_I_COFF, - iCoff); - REG_RMW_FIELD(ah, AR_PHY_TIMING_CTRL4(i), - AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF, - qCoff); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "IQ Cal and Correction done for Chain %d\n", - i); - } - } + keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); - REG_SET_BIT(ah, AR_PHY_TIMING_CTRL4(0), - AR_PHY_TIMING_CTRL4_IQCORR_ENABLE); -} + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); + REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); -static void -ath9k_hw_adc_gaincal_calibrate(struct ath_hal *ah, u8 numChains) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 iOddMeasOffset, iEvenMeasOffset, qOddMeasOffset, - qEvenMeasOffset; - u32 qGainMismatch, iGainMismatch, val, i; - - for (i = 0; i < numChains; i++) { - iOddMeasOffset = ahp->ah_totalAdcIOddPhase[i]; - iEvenMeasOffset = ahp->ah_totalAdcIEvenPhase[i]; - qOddMeasOffset = ahp->ah_totalAdcQOddPhase[i]; - qEvenMeasOffset = ahp->ah_totalAdcQEvenPhase[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting ADC Gain Cal for Chain %d\n", i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = 0x%08x\n", i, - iOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = 0x%08x\n", i, - iEvenMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = 0x%08x\n", i, - qOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = 0x%08x\n", i, - qEvenMeasOffset); - - if (iOddMeasOffset != 0 && qEvenMeasOffset != 0) { - iGainMismatch = - ((iEvenMeasOffset * 32) / - iOddMeasOffset) & 0x3f; - qGainMismatch = - ((qOddMeasOffset * 32) / - qEvenMeasOffset) & 0x3f; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_i = 0x%08x\n", i, - iGainMismatch); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d gain_mismatch_q = 0x%08x\n", i, - qGainMismatch); - - val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); - val &= 0xfffff000; - val |= (qGainMismatch) | (iGainMismatch << 6); - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "ADC Gain Cal done for Chain %d\n", i); - } - } + if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { + u16 micentry = entry + 64; - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), - REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | - AR_PHY_NEW_ADC_GAIN_CORR_ENABLE); -} + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); -static void -ath9k_hw_adc_dccal_calibrate(struct ath_hal *ah, u8 numChains) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - u32 iOddMeasOffset, iEvenMeasOffset, val, i; - int32_t qOddMeasOffset, qEvenMeasOffset, qDcMismatch, iDcMismatch; - const struct hal_percal_data *calData = - ahp->ah_cal_list_curr->calData; - u32 numSamples = - (1 << (calData->calCountMax + 5)) * calData->calNumSamples; - - for (i = 0; i < numChains; i++) { - iOddMeasOffset = ahp->ah_totalAdcDcOffsetIOddPhase[i]; - iEvenMeasOffset = ahp->ah_totalAdcDcOffsetIEvenPhase[i]; - qOddMeasOffset = ahp->ah_totalAdcDcOffsetQOddPhase[i]; - qEvenMeasOffset = ahp->ah_totalAdcDcOffsetQEvenPhase[i]; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Starting ADC DC Offset Cal for Chain %d\n", i); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_i = %d\n", i, - iOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_i = %d\n", i, - iEvenMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_odd_q = %d\n", i, - qOddMeasOffset); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d pwr_meas_even_q = %d\n", i, - qEvenMeasOffset); - - iDcMismatch = (((iEvenMeasOffset - iOddMeasOffset) * 2) / - numSamples) & 0x1ff; - qDcMismatch = (((qOddMeasOffset - qEvenMeasOffset) * 2) / - numSamples) & 0x1ff; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_i = 0x%08x\n", i, - iDcMismatch); - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "Chn %d dc_offset_mismatch_q = 0x%08x\n", i, - qDcMismatch); - - val = REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i)); - val &= 0xc0000fff; - val |= (qDcMismatch << 12) | (iDcMismatch << 21); - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(i), val); - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "ADC DC Offset Cal done for Chain %d\n", i); } - REG_WRITE(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0), - REG_READ(ah, AR_PHY_NEW_ADC_DC_GAIN_CORR(0)) | - AR_PHY_NEW_ADC_DC_OFFSET_CORR_ENABLE); -} - -bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - - ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER); - - if (ath9k_hw_set_txpower(ah, &ahp->ah_eeprom, chan, - ath9k_regd_get_ctl(ah, chan), - ath9k_regd_get_antenna_allowed(ah, - chan), - chan->maxRegTxPower * 2, - min((u32) MAX_RATE_POWER, - (u32) ah->ah_powerLimit)) != 0) - return false; + if (ah->ah_curchan == NULL) + return true; return true; } -void -ath9k_hw_get_channel_centers(struct ath_hal *ah, - struct ath9k_channel *chan, - struct chan_centers *centers) +bool ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, const u8 *mac) { - int8_t extoff; - struct ath_hal_5416 *ahp = AH5416(ah); + u32 macHi, macLo; - if (!IS_CHAN_HT40(chan)) { - centers->ctl_center = centers->ext_center = - centers->synth_center = chan->channel; - return; + if (entry >= ah->ah_caps.keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "entry %u out of range\n", entry); + return false; } - if ((chan->chanmode == CHANNEL_A_HT40PLUS) || - (chan->chanmode == CHANNEL_G_HT40PLUS)) { - centers->synth_center = - chan->channel + HT40_CHANNEL_CENTER_SHIFT; - extoff = 1; + if (mac != NULL) { + macHi = (mac[5] << 8) | mac[4]; + macLo = (mac[3] << 24) | + (mac[2] << 16) | + (mac[1] << 8) | + mac[0]; + macLo >>= 1; + macLo |= (macHi & 1) << 31; + macHi >>= 1; } else { - centers->synth_center = - chan->channel - HT40_CHANNEL_CENTER_SHIFT; - extoff = -1; + macLo = macHi = 0; } + REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); + REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); - centers->ctl_center = centers->synth_center - (extoff * - HT40_CHANNEL_CENTER_SHIFT); - centers->ext_center = centers->synth_center + (extoff * - ((ahp-> - ah_extprotspacing - == - ATH9K_HT_EXTPROTSPACING_20) - ? - HT40_CHANNEL_CENTER_SHIFT - : 15)); - + return true; } -void -ath9k_hw_reset_calvalid(struct ath_hal *ah, struct ath9k_channel *chan, - bool *isCalDone) +bool ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, + const struct ath9k_keyval *k, + const u8 *mac, int xorKey) { + const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + u32 key0, key1, key2, key3, key4; + u32 keyType; + u32 xorMask = xorKey ? + (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8 + | ATH9K_KEY_XOR) : 0; struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *ichan = - ath9k_regd_check_channel(ah, chan); - struct hal_cal_list *currCal = ahp->ah_cal_list_curr; - - *isCalDone = true; - - if (!AR_SREV_9100(ah) && !AR_SREV_9160_10_OR_LATER(ah)) - return; - if (currCal == NULL) - return; - - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); - return; + if (entry >= pCap->keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "entry %u out of range\n", entry); + return false; } - - if (currCal->calState != CAL_DONE) { - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Calibration state incorrect, %d\n", - __func__, currCal->calState); - return; + switch (k->kv_type) { + case ATH9K_CIPHER_AES_OCB: + keyType = AR_KEYTABLE_TYPE_AES; + break; + case ATH9K_CIPHER_AES_CCM: + if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "AES-CCM not supported by mac rev 0x%x\n", + ah->ah_macRev); + return false; + } + keyType = AR_KEYTABLE_TYPE_CCM; + break; + case ATH9K_CIPHER_TKIP: + keyType = AR_KEYTABLE_TYPE_TKIP; + if (ATH9K_IS_MIC_ENABLED(ah) + && entry + 64 >= pCap->keycache_size) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "entry %u inappropriate for TKIP\n", entry); + return false; + } + break; + case ATH9K_CIPHER_WEP: + if (k->kv_len < LEN_WEP40) { + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "WEP key length %u too small\n", k->kv_len); + return false; + } + if (k->kv_len <= LEN_WEP40) + keyType = AR_KEYTABLE_TYPE_40; + else if (k->kv_len <= LEN_WEP104) + keyType = AR_KEYTABLE_TYPE_104; + else + keyType = AR_KEYTABLE_TYPE_128; + break; + case ATH9K_CIPHER_CLR: + keyType = AR_KEYTABLE_TYPE_CLR; + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, + "cipher %u not supported\n", k->kv_type); + return false; } + key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask; + key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff; + key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask; + key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff; + key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask; + if (k->kv_len <= LEN_WEP104) + key4 &= 0xff; - if (!ath9k_hw_iscal_supported(ah, chan, currCal->calData->calType)) - return; - - DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, - "%s: Resetting Cal %d state for channel %u/0x%x\n", - __func__, currCal->calData->calType, chan->channel, - chan->channelFlags); - - ichan->CalValid &= ~currCal->calData->calType; - currCal->calState = CAL_WAITING; - - *isCalDone = false; -} - -void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - memcpy(mac, ahp->ah_macaddr, ETH_ALEN); -} + if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { + u16 micentry = entry + 64; -bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + (void) ath9k_hw_keysetmac(ah, entry, mac); - memcpy(ahp->ah_macaddr, mac, ETH_ALEN); - return true; -} + if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) { + u32 mic0, mic1, mic2, mic3, mic4; -void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + mic0 = get_unaligned_le32(k->kv_mic + 0); + mic2 = get_unaligned_le32(k->kv_mic + 4); + mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; + mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; + mic4 = get_unaligned_le32(k->kv_txmic + 4); + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); + REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); - memcpy(mask, ahp->ah_bssidmask, ETH_ALEN); -} + } else { + u32 mic0, mic2; -bool -ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + mic0 = get_unaligned_le32(k->kv_mic + 0); + mic2 = get_unaligned_le32(k->kv_mic + 4); + REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), + AR_KEYTABLE_TYPE_CLR); + } + REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + } else { + REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); + REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); + REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); + REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); + REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); + REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); - memcpy(ahp->ah_bssidmask, mask, ETH_ALEN); + (void) ath9k_hw_keysetmac(ah, entry, mac); + } - REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); - REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); + if (ah->ah_curchan == NULL) + return true; return true; } -void -ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, - u16 assocId) +bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry) { - struct ath_hal_5416 *ahp = AH5416(ah); - - memcpy(ahp->ah_bssid, bssid, ETH_ALEN); - ahp->ah_assocId = assocId; - - REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid)); - REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) | - ((assocId & 0x3fff) << AR_BSS_ID1_AID_S)); + if (entry < ah->ah_caps.keycache_size) { + u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry)); + if (val & AR_KEYTABLE_VALID) + return true; + } + return false; } -u64 ath9k_hw_gettsf64(struct ath_hal *ah) +/******************************/ +/* Power Management (Chipset) */ +/******************************/ + +static void ath9k_set_power_sleep(struct ath_hal *ah, int setChip) { - u64 tsf; + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) { + REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); + if (!AR_SREV_9100(ah)) + REG_WRITE(ah, AR_RC, AR_RC_AHB | AR_RC_HOSTIF); - tsf = REG_READ(ah, AR_TSF_U32); - tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32); - return tsf; + REG_CLR_BIT(ah, (u16) (AR_RTC_RESET), + AR_RTC_RESET_EN); + } } -void ath9k_hw_reset_tsf(struct ath_hal *ah) +static void ath9k_set_power_network_sleep(struct ath_hal *ah, int setChip) { - int count; + REG_SET_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); + if (setChip) { + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - count = 0; - while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { - count++; - if (count > 10) { - DPRINTF(ah->ah_sc, ATH_DBG_RESET, - "%s: AR_SLP32_TSF_WRITE_STATUS limit exceeded\n", - __func__); - break; + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) { + REG_WRITE(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_ON_INT); + } else { + REG_CLR_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); } - udelay(10); } - REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); -} - -u32 ath9k_hw_getdefantenna(struct ath_hal *ah) -{ - return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; } -void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna) +static bool ath9k_hw_set_power_awake(struct ath_hal *ah, + int setChip) { - REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); -} + u32 val; + int i; -bool -ath9k_hw_setantennaswitch(struct ath_hal *ah, - enum ath9k_ant_setting settings, - struct ath9k_channel *chan, - u8 *tx_chainmask, - u8 *rx_chainmask, - u8 *antenna_cfgd) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - static u8 tx_chainmask_cfg, rx_chainmask_cfg; + if (setChip) { + if ((REG_READ(ah, AR_RTC_STATUS) & + AR_RTC_STATUS_M) == AR_RTC_STATUS_SHUTDOWN) { + if (ath9k_hw_set_reset_reg(ah, + ATH9K_RESET_POWER_ON) != true) { + return false; + } + } + if (AR_SREV_9100(ah)) + REG_SET_BIT(ah, AR_RTC_RESET, + AR_RTC_RESET_EN); - if (AR_SREV_9280(ah)) { - if (!tx_chainmask_cfg) { + REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); + udelay(50); - tx_chainmask_cfg = *tx_chainmask; - rx_chainmask_cfg = *rx_chainmask; + for (i = POWER_UP_TIME / 50; i > 0; i--) { + val = REG_READ(ah, AR_RTC_STATUS) & AR_RTC_STATUS_M; + if (val == AR_RTC_STATUS_ON) + break; + udelay(50); + REG_SET_BIT(ah, AR_RTC_FORCE_WAKE, + AR_RTC_FORCE_WAKE_EN); } - - switch (settings) { - case ATH9K_ANT_FIXED_A: - *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK; - *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK; - *antenna_cfgd = true; - break; - case ATH9K_ANT_FIXED_B: - if (ah->ah_caps.tx_chainmask > - ATH9K_ANTENNA1_CHAINMASK) { - *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK; - } - *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK; - *antenna_cfgd = true; - break; - case ATH9K_ANT_VARIABLE: - *tx_chainmask = tx_chainmask_cfg; - *rx_chainmask = rx_chainmask_cfg; - *antenna_cfgd = true; - break; - default: - break; + if (i == 0) { + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "Failed to wakeup in %uus\n", POWER_UP_TIME / 20); + return false; } - } else { - ahp->ah_diversityControl = settings; } - return true; -} + REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PWR_SAV); -void ath9k_hw_setopmode(struct ath_hal *ah) -{ - ath9k_hw_set_operating_mode(ah, ah->ah_opmode); + return true; } -bool -ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, - u32 capability, u32 *result) +bool ath9k_hw_setpower(struct ath_hal *ah, + enum ath9k_power_mode mode) { struct ath_hal_5416 *ahp = AH5416(ah); - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + static const char *modes[] = { + "AWAKE", + "FULL-SLEEP", + "NETWORK SLEEP", + "UNDEFINED" + }; + int status = true, setChip = true; - switch (type) { - case ATH9K_CAP_CIPHER: - switch (capability) { - case ATH9K_CIPHER_AES_CCM: - case ATH9K_CIPHER_AES_OCB: - case ATH9K_CIPHER_TKIP: - case ATH9K_CIPHER_WEP: - case ATH9K_CIPHER_MIC: - case ATH9K_CIPHER_CLR: - return true; - default: - return false; - } - case ATH9K_CAP_TKIP_MIC: - switch (capability) { - case 0: - return true; - case 1: - return (ahp->ah_staId1Defaults & - AR_STA_ID1_CRPT_MIC_ENABLE) ? true : - false; - } - case ATH9K_CAP_TKIP_SPLIT: - return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ? - false : true; - case ATH9K_CAP_WME_TKIPMIC: - return 0; - case ATH9K_CAP_PHYCOUNTERS: - return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO; - case ATH9K_CAP_DIVERSITY: - return (REG_READ(ah, AR_PHY_CCK_DETECT) & - AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? - true : false; - case ATH9K_CAP_PHYDIAG: - return true; - case ATH9K_CAP_MCAST_KEYSRCH: - switch (capability) { - case 0: - return true; - case 1: - if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) { - return false; - } else { - return (ahp->ah_staId1Defaults & - AR_STA_ID1_MCAST_KSRCH) ? true : - false; - } - } - return false; - case ATH9K_CAP_TSF_ADJUST: - return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ? - true : false; - case ATH9K_CAP_RFSILENT: - if (capability == 3) - return false; - case ATH9K_CAP_ANT_CFG_2GHZ: - *result = pCap->num_antcfg_2ghz; - return true; - case ATH9K_CAP_ANT_CFG_5GHZ: - *result = pCap->num_antcfg_5ghz; - return true; - case ATH9K_CAP_TXPOW: - switch (capability) { - case 0: - return 0; - case 1: - *result = ah->ah_powerLimit; - return 0; - case 2: - *result = ah->ah_maxPowerLevel; - return 0; - case 3: - *result = ah->ah_tpScale; - return 0; - } - return false; + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, "%s -> %s (%s)\n", + modes[ahp->ah_powerMode], modes[mode], + setChip ? "set chip " : ""); + + switch (mode) { + case ATH9K_PM_AWAKE: + status = ath9k_hw_set_power_awake(ah, setChip); + break; + case ATH9K_PM_FULL_SLEEP: + ath9k_set_power_sleep(ah, setChip); + ahp->ah_chipFullSleep = true; + break; + case ATH9K_PM_NETWORK_SLEEP: + ath9k_set_power_network_sleep(ah, setChip); + break; default: + DPRINTF(ah->ah_sc, ATH_DBG_POWER_MGMT, + "Unknown power mode %u\n", mode); return false; } + ahp->ah_powerMode = mode; + + return status; } -int -ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg) +void ath9k_hw_configpcipowersave(struct ath_hal *ah, int restore) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_channel *chan = ah->ah_curchan; - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - u16 ant_config; - u32 halNumAntConfig; + u8 i; + + if (ah->ah_isPciExpress != true) + return; + + if (ah->ah_config.pcie_powersave_enable == 2) + return; - halNumAntConfig = - IS_CHAN_2GHZ(chan) ? pCap->num_antcfg_2ghz : pCap-> - num_antcfg_5ghz; + if (restore) + return; - if (cfg < halNumAntConfig) { - if (!ath9k_hw_get_eeprom_antenna_cfg(ahp, chan, - cfg, &ant_config)) { - REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); - return 0; + if (AR_SREV_9280_20_OR_LATER(ah)) { + for (i = 0; i < ahp->ah_iniPcieSerdes.ia_rows; i++) { + REG_WRITE(ah, INI_RA(&ahp->ah_iniPcieSerdes, i, 0), + INI_RA(&ahp->ah_iniPcieSerdes, i, 1)); } + udelay(1000); + } else if (AR_SREV_9280(ah) && + (ah->ah_macRev == AR_SREV_REVISION_9280_10)) { + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fd00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + + REG_WRITE(ah, AR_PCIE_SERDES, 0xa8000019); + REG_WRITE(ah, AR_PCIE_SERDES, 0x13160820); + REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980560); + + if (ah->ah_config.pcie_clock_req) + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffc); + else + REG_WRITE(ah, AR_PCIE_SERDES, 0x401deffd); + + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x00043007); + + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); + + udelay(1000); + } else { + REG_WRITE(ah, AR_PCIE_SERDES, 0x9248fc00); + REG_WRITE(ah, AR_PCIE_SERDES, 0x24924924); + REG_WRITE(ah, AR_PCIE_SERDES, 0x28000039); + REG_WRITE(ah, AR_PCIE_SERDES, 0x53160824); + REG_WRITE(ah, AR_PCIE_SERDES, 0xe5980579); + REG_WRITE(ah, AR_PCIE_SERDES, 0x001defff); + REG_WRITE(ah, AR_PCIE_SERDES, 0x1aaabe40); + REG_WRITE(ah, AR_PCIE_SERDES, 0xbe105554); + REG_WRITE(ah, AR_PCIE_SERDES, 0x000e3007); + REG_WRITE(ah, AR_PCIE_SERDES2, 0x00000000); + } + + REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PCIE_PM_CTRL_ENA); + + if (ah->ah_config.pcie_waen) { + REG_WRITE(ah, AR_WA, ah->ah_config.pcie_waen); + } else { + if (AR_SREV_9285(ah)) + REG_WRITE(ah, AR_WA, AR9285_WA_DEFAULT); + else if (AR_SREV_9280(ah)) + REG_WRITE(ah, AR_WA, AR9280_WA_DEFAULT); + else + REG_WRITE(ah, AR_WA, AR_WA_DEFAULT); } - return -EINVAL; } +/**********************/ +/* Interrupt Handling */ +/**********************/ + bool ath9k_hw_intrpend(struct ath_hal *ah) { u32 host_isr; @@ -6791,6 +2857,7 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) struct ath9k_hw_capabilities *pCap = &ah->ah_caps; u32 sync_cause = 0; bool fatal_int = false; + struct ath_hal_5416 *ahp = AH5416(ah); if (!AR_SREV_9100(ah)) { if (REG_READ(ah, AR_INTR_ASYNC_CAUSE) & AR_INTR_MAC_IRQ) { @@ -6800,9 +2867,8 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) } } - sync_cause = - REG_READ(ah, - AR_INTR_SYNC_CAUSE) & AR_INTR_SYNC_DEFAULT; + sync_cause = REG_READ(ah, AR_INTR_SYNC_CAUSE) & + AR_INTR_SYNC_DEFAULT; *masked = 0; @@ -6814,8 +2880,6 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) } if (isr) { - struct ath_hal_5416 *ahp = AH5416(ah); - if (isr & AR_ISR_BCNMISC) { u32 isr2; isr2 = REG_READ(ah, AR_ISR_S2); @@ -6842,7 +2906,6 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) *masked = isr & ATH9K_INT_COMMON; if (ahp->ah_intrMitigation) { - if (isr & (AR_ISR_RXMINTR | AR_ISR_RXINTM)) *masked |= ATH9K_INT_RX; } @@ -6867,8 +2930,7 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) if (isr & AR_ISR_RXORN) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: receive FIFO overrun interrupt\n", - __func__); + "receive FIFO overrun interrupt\n"); } if (!AR_SREV_9100(ah)) { @@ -6881,8 +2943,10 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) *masked |= mask2; } + if (AR_SREV_9100(ah)) return true; + if (sync_cause) { fatal_int = (sync_cause & @@ -6892,32 +2956,29 @@ bool ath9k_hw_getisr(struct ath_hal *ah, enum ath9k_int *masked) if (fatal_int) { if (sync_cause & AR_INTR_SYNC_HOST1_FATAL) { DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "%s: received PCI FATAL interrupt\n", - __func__); + "received PCI FATAL interrupt\n"); } if (sync_cause & AR_INTR_SYNC_HOST1_PERR) { DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "%s: received PCI PERR interrupt\n", - __func__); + "received PCI PERR interrupt\n"); } } if (sync_cause & AR_INTR_SYNC_RADM_CPL_TIMEOUT) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: AR_INTR_SYNC_RADM_CPL_TIMEOUT\n", - __func__); + "AR_INTR_SYNC_RADM_CPL_TIMEOUT\n"); REG_WRITE(ah, AR_RC, AR_RC_HOSTIF); REG_WRITE(ah, AR_RC, 0); *masked |= ATH9K_INT_FATAL; } if (sync_cause & AR_INTR_SYNC_LOCAL_TIMEOUT) { DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: AR_INTR_SYNC_LOCAL_TIMEOUT\n", - __func__); + "AR_INTR_SYNC_LOCAL_TIMEOUT\n"); } REG_WRITE(ah, AR_INTR_SYNC_CAUSE_CLR, sync_cause); (void) REG_READ(ah, AR_INTR_SYNC_CAUSE_CLR); } + return true; } @@ -6933,12 +2994,10 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) u32 mask, mask2; struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: 0x%x => 0x%x\n", __func__, - omask, ints); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "0x%x => 0x%x\n", omask, ints); if (omask & ATH9K_INT_GLOBAL) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: disable IER\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "disable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_DISABLE); (void) REG_READ(ah, AR_IER); if (!AR_SREV_9100(ah)) { @@ -6993,8 +3052,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) mask2 |= AR_IMR_S2_CST; } - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: new IMR 0x%x\n", __func__, - mask); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "new IMR 0x%x\n", mask); REG_WRITE(ah, AR_IMR, mask); mask = REG_READ(ah, AR_IMR_S2) & ~(AR_IMR_S2_TIM | AR_IMR_S2_DTIM | @@ -7014,8 +3072,7 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) } if (ints & ATH9K_INT_GLOBAL) { - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "%s: enable IER\n", - __func__); + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, "enable IER\n"); REG_WRITE(ah, AR_IER, AR_IER_ENABLE); if (!AR_SREV_9100(ah)) { REG_WRITE(ah, AR_INTR_ASYNC_ENABLE, @@ -7035,9 +3092,11 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hal *ah, enum ath9k_int ints) return omask; } -void -ath9k_hw_beaconinit(struct ath_hal *ah, - u32 next_beacon, u32 beacon_period) +/*******************/ +/* Beacon Handling */ +/*******************/ + +void ath9k_hw_beaconinit(struct ath_hal *ah, u32 next_beacon, u32 beacon_period) { struct ath_hal_5416 *ahp = AH5416(ah); int flags = 0; @@ -7045,14 +3104,14 @@ ath9k_hw_beaconinit(struct ath_hal *ah, ahp->ah_beaconInterval = beacon_period; switch (ah->ah_opmode) { - case ATH9K_M_STA: - case ATH9K_M_MONITOR: + case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_MONITOR: REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, 0xffff); REG_WRITE(ah, AR_NEXT_SWBA, 0x7ffff); flags |= AR_TBTT_TIMER_EN; break; - case ATH9K_M_IBSS: + case NL80211_IFTYPE_ADHOC: REG_SET_BIT(ah, AR_TXCFG, AR_TXCFG_ADHOC_BEACON_ATIM_TX_POLICY); REG_WRITE(ah, AR_NEXT_NDP_TIMER, @@ -7060,7 +3119,7 @@ ath9k_hw_beaconinit(struct ath_hal *ah, (ahp->ah_atimWindow ? ahp-> ah_atimWindow : 1))); flags |= AR_NDP_TIMER_EN; - case ATH9K_M_HOSTAP: + case NL80211_IFTYPE_AP: REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(next_beacon)); REG_WRITE(ah, AR_NEXT_DMA_BEACON_ALERT, TU_TO_USEC(next_beacon - @@ -7073,6 +3132,12 @@ ath9k_hw_beaconinit(struct ath_hal *ah, flags |= AR_TBTT_TIMER_EN | AR_DBA_TIMER_EN | AR_SWBA_TIMER_EN; break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, + "%s: unsupported opmode: %d\n", + __func__, ah->ah_opmode); + return; + break; } REG_WRITE(ah, AR_BEACON_PERIOD, TU_TO_USEC(beacon_period)); @@ -7089,9 +3154,8 @@ ath9k_hw_beaconinit(struct ath_hal *ah, REG_SET_BIT(ah, AR_TIMER_MODE, flags); } -void -ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, - const struct ath9k_beacon_state *bs) +void ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, + const struct ath9k_beacon_state *bs) { u32 nextTbtt, beaconintval, dtimperiod, beacontimeout; struct ath9k_hw_capabilities *pCap = &ah->ah_caps; @@ -7120,14 +3184,10 @@ ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, else nextTbtt = bs->bs_nexttbtt; - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next DTIM %d\n", __func__, - bs->bs_nextdtim); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: next beacon %d\n", __func__, - nextTbtt); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: beacon period %d\n", __func__, - beaconintval); - DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "%s: DTIM period %d\n", __func__, - dtimperiod); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next DTIM %d\n", bs->bs_nextdtim); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "next beacon %d\n", nextTbtt); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "beacon period %d\n", beaconintval); + DPRINTF(ah->ah_sc, ATH_DBG_BEACON, "DTIM period %d\n", dtimperiod); REG_WRITE(ah, AR_NEXT_DTIM, TU_TO_USEC(bs->bs_nextdtim - SLEEP_SLOP)); @@ -7137,1327 +3197,661 @@ ath9k_hw_set_sta_beacon_timers(struct ath_hal *ah, SM((CAB_TIMEOUT_VAL << 3), AR_SLEEP1_CAB_TIMEOUT) | AR_SLEEP1_ASSUME_DTIM); - if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP) - beacontimeout = (BEACON_TIMEOUT_VAL << 3); - else - beacontimeout = MIN_BEACON_TIMEOUT_VAL; - - REG_WRITE(ah, AR_SLEEP2, - SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); - - REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); - REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); - - REG_SET_BIT(ah, AR_TIMER_MODE, - AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | - AR_DTIM_TIMER_EN); - -} - -bool ath9k_hw_keyisvalid(struct ath_hal *ah, u16 entry) -{ - if (entry < ah->ah_caps.keycache_size) { - u32 val = REG_READ(ah, AR_KEYTABLE_MAC1(entry)); - if (val & AR_KEYTABLE_VALID) - return true; - } - return false; -} - -bool ath9k_hw_keyreset(struct ath_hal *ah, u16 entry) -{ - u32 keyType; - - if (entry >= ah->ah_caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); - return false; - } - keyType = REG_READ(ah, AR_KEYTABLE_TYPE(entry)); - - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), AR_KEYTABLE_TYPE_CLR); - REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), 0); - REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), 0); - - if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { - u16 micentry = entry + 64; - - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); - - } - - if (ah->ah_curchan == NULL) - return true; - - return true; -} - -bool -ath9k_hw_keysetmac(struct ath_hal *ah, u16 entry, - const u8 *mac) -{ - u32 macHi, macLo; - - if (entry >= ah->ah_caps.keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); - return false; - } - - if (mac != NULL) { - macHi = (mac[5] << 8) | mac[4]; - macLo = (mac[3] << 24) | (mac[2] << 16) - | (mac[1] << 8) | mac[0]; - macLo >>= 1; - macLo |= (macHi & 1) << 31; - macHi >>= 1; - } else { - macLo = macHi = 0; - } - REG_WRITE(ah, AR_KEYTABLE_MAC0(entry), macLo); - REG_WRITE(ah, AR_KEYTABLE_MAC1(entry), macHi | AR_KEYTABLE_VALID); - - return true; -} - -bool -ath9k_hw_set_keycache_entry(struct ath_hal *ah, u16 entry, - const struct ath9k_keyval *k, - const u8 *mac, int xorKey) -{ - const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - u32 key0, key1, key2, key3, key4; - u32 keyType; - u32 xorMask = xorKey ? - (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8 - | ATH9K_KEY_XOR) : 0; - struct ath_hal_5416 *ahp = AH5416(ah); - - if (entry >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u out of range\n", __func__, entry); - return false; - } - switch (k->kv_type) { - case ATH9K_CIPHER_AES_OCB: - keyType = AR_KEYTABLE_TYPE_AES; - break; - case ATH9K_CIPHER_AES_CCM: - if (!(pCap->hw_caps & ATH9K_HW_CAP_CIPHER_AESCCM)) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: AES-CCM not supported by " - "mac rev 0x%x\n", __func__, - ah->ah_macRev); - return false; - } - keyType = AR_KEYTABLE_TYPE_CCM; - break; - case ATH9K_CIPHER_TKIP: - keyType = AR_KEYTABLE_TYPE_TKIP; - if (ATH9K_IS_MIC_ENABLED(ah) - && entry + 64 >= pCap->keycache_size) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: entry %u inappropriate for TKIP\n", - __func__, entry); - return false; - } - break; - case ATH9K_CIPHER_WEP: - if (k->kv_len < LEN_WEP40) { - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: WEP key length %u too small\n", - __func__, k->kv_len); - return false; - } - if (k->kv_len <= LEN_WEP40) - keyType = AR_KEYTABLE_TYPE_40; - else if (k->kv_len <= LEN_WEP104) - keyType = AR_KEYTABLE_TYPE_104; - else - keyType = AR_KEYTABLE_TYPE_128; - break; - case ATH9K_CIPHER_CLR: - keyType = AR_KEYTABLE_TYPE_CLR; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE, - "%s: cipher %u not supported\n", __func__, - k->kv_type); - return false; - } - - key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask; - key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff; - key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask; - key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff; - key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask; - if (k->kv_len <= LEN_WEP104) - key4 &= 0xff; - - if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) { - u16 micentry = entry + 64; - - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1); - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); - (void) ath9k_hw_keysetmac(ah, entry, mac); - - if (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) { - u32 mic0, mic1, mic2, mic3, mic4; - - mic0 = get_unaligned_le32(k->kv_mic + 0); - mic2 = get_unaligned_le32(k->kv_mic + 4); - mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff; - mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff; - mic4 = get_unaligned_le32(k->kv_txmic + 4); - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1); - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3); - REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), - AR_KEYTABLE_TYPE_CLR); - - } else { - u32 mic0, mic2; - - mic0 = get_unaligned_le32(k->kv_mic + 0); - mic2 = get_unaligned_le32(k->kv_mic + 4); - REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry), - AR_KEYTABLE_TYPE_CLR); - } - REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0); - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); - } else { - REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0); - REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1); - REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2); - REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3); - REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4); - REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType); + if (pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP) + beacontimeout = (BEACON_TIMEOUT_VAL << 3); + else + beacontimeout = MIN_BEACON_TIMEOUT_VAL; - (void) ath9k_hw_keysetmac(ah, entry, mac); - } + REG_WRITE(ah, AR_SLEEP2, + SM(beacontimeout, AR_SLEEP2_BEACON_TIMEOUT)); - if (ah->ah_curchan == NULL) - return true; + REG_WRITE(ah, AR_TIM_PERIOD, TU_TO_USEC(beaconintval)); + REG_WRITE(ah, AR_DTIM_PERIOD, TU_TO_USEC(dtimperiod)); + + REG_SET_BIT(ah, AR_TIMER_MODE, + AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN | + AR_DTIM_TIMER_EN); - return true; } -bool -ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel) +/*******************/ +/* HW Capabilities */ +/*******************/ + +bool ath9k_hw_fill_cap_info(struct ath_hal *ah) { struct ath_hal_5416 *ahp = AH5416(ah); - u32 txcfg, curLevel, newLevel; - enum ath9k_int omask; + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + u16 capField = 0, eeval; - if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD) - return false; + eeval = ath9k_hw_get_eeprom(ah, EEP_REG_0); - omask = ath9k_hw_set_interrupts(ah, - ahp->ah_maskReg & ~ATH9K_INT_GLOBAL); + ah->ah_currentRD = eeval; - txcfg = REG_READ(ah, AR_TXCFG); - curLevel = MS(txcfg, AR_FTRIG); - newLevel = curLevel; - if (bIncTrigLevel) { - if (curLevel < MAX_TX_FIFO_THRESHOLD) - newLevel++; - } else if (curLevel > MIN_TX_FIFO_THRESHOLD) - newLevel--; - if (newLevel != curLevel) - REG_WRITE(ah, AR_TXCFG, - (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); + eeval = ath9k_hw_get_eeprom(ah, EEP_REG_1); + ah->ah_currentRDExt = eeval; - ath9k_hw_set_interrupts(ah, omask); + capField = ath9k_hw_get_eeprom(ah, EEP_OP_CAP); - ah->ah_txTrigLevel = newLevel; + if (ah->ah_opmode != NL80211_IFTYPE_AP && + ah->ah_subvendorid == AR_SUBVENDOR_ID_NEW_A) { + if (ah->ah_currentRD == 0x64 || ah->ah_currentRD == 0x65) + ah->ah_currentRD += 5; + else if (ah->ah_currentRD == 0x41) + ah->ah_currentRD = 0x43; + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, + "regdomain mapped to 0x%x\n", ah->ah_currentRD); + } - return newLevel != curLevel; -} + eeval = ath9k_hw_get_eeprom(ah, EEP_OP_MODE); + bitmap_zero(pCap->wireless_modes, ATH9K_MODE_MAX); -bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, - const struct ath9k_tx_queue_info *qinfo) -{ - u32 cw; - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_tx_queue_info *qi; + if (eeval & AR5416_OPFLAGS_11A) { + set_bit(ATH9K_MODE_11A, pCap->wireless_modes); + if (ah->ah_config.ht_enable) { + if (!(eeval & AR5416_OPFLAGS_N_5G_HT20)) + set_bit(ATH9K_MODE_11NA_HT20, + pCap->wireless_modes); + if (!(eeval & AR5416_OPFLAGS_N_5G_HT40)) { + set_bit(ATH9K_MODE_11NA_HT40PLUS, + pCap->wireless_modes); + set_bit(ATH9K_MODE_11NA_HT40MINUS, + pCap->wireless_modes); + } + } + } - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; + if (eeval & AR5416_OPFLAGS_11G) { + set_bit(ATH9K_MODE_11B, pCap->wireless_modes); + set_bit(ATH9K_MODE_11G, pCap->wireless_modes); + if (ah->ah_config.ht_enable) { + if (!(eeval & AR5416_OPFLAGS_N_2G_HT20)) + set_bit(ATH9K_MODE_11NG_HT20, + pCap->wireless_modes); + if (!(eeval & AR5416_OPFLAGS_N_2G_HT40)) { + set_bit(ATH9K_MODE_11NG_HT40PLUS, + pCap->wireless_modes); + set_bit(ATH9K_MODE_11NG_HT40MINUS, + pCap->wireless_modes); + } + } } - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n", - __func__); - return false; + pCap->tx_chainmask = ath9k_hw_get_eeprom(ah, EEP_TX_MASK); + if ((ah->ah_isPciExpress) + || (eeval & AR5416_OPFLAGS_11A)) { + pCap->rx_chainmask = + ath9k_hw_get_eeprom(ah, EEP_RX_MASK); + } else { + pCap->rx_chainmask = + (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7; } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %p\n", __func__, qi); + if (!(AR_SREV_9280(ah) && (ah->ah_macRev == 0))) + ahp->ah_miscMode |= AR_PCU_MIC_NEW_LOC_ENA; + + pCap->low_2ghz_chan = 2312; + pCap->high_2ghz_chan = 2732; + + pCap->low_5ghz_chan = 4920; + pCap->high_5ghz_chan = 6100; + + pCap->hw_caps &= ~ATH9K_HW_CAP_CIPHER_CKIP; + pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_TKIP; + pCap->hw_caps |= ATH9K_HW_CAP_CIPHER_AESCCM; + + pCap->hw_caps &= ~ATH9K_HW_CAP_MIC_CKIP; + pCap->hw_caps |= ATH9K_HW_CAP_MIC_TKIP; + pCap->hw_caps |= ATH9K_HW_CAP_MIC_AESCCM; + + pCap->hw_caps |= ATH9K_HW_CAP_CHAN_SPREAD; - qi->tqi_ver = qinfo->tqi_ver; - qi->tqi_subtype = qinfo->tqi_subtype; - qi->tqi_qflags = qinfo->tqi_qflags; - qi->tqi_priority = qinfo->tqi_priority; - if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT) - qi->tqi_aifs = min(qinfo->tqi_aifs, 255U); + if (ah->ah_config.ht_enable) + pCap->hw_caps |= ATH9K_HW_CAP_HT; else - qi->tqi_aifs = INIT_AIFS; - if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) { - cw = min(qinfo->tqi_cwmin, 1024U); - qi->tqi_cwmin = 1; - while (qi->tqi_cwmin < cw) - qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; - } else - qi->tqi_cwmin = qinfo->tqi_cwmin; - if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) { - cw = min(qinfo->tqi_cwmax, 1024U); - qi->tqi_cwmax = 1; - while (qi->tqi_cwmax < cw) - qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; - } else - qi->tqi_cwmax = INIT_CWMAX; + pCap->hw_caps &= ~ATH9K_HW_CAP_HT; + + pCap->hw_caps |= ATH9K_HW_CAP_GTT; + pCap->hw_caps |= ATH9K_HW_CAP_VEOL; + pCap->hw_caps |= ATH9K_HW_CAP_BSSIDMASK; + pCap->hw_caps &= ~ATH9K_HW_CAP_MCAST_KEYSEARCH; - if (qinfo->tqi_shretry != 0) - qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U); + if (capField & AR_EEPROM_EEPCAP_MAXQCU) + pCap->total_queues = + MS(capField, AR_EEPROM_EEPCAP_MAXQCU); else - qi->tqi_shretry = INIT_SH_RETRY; - if (qinfo->tqi_lgretry != 0) - qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U); + pCap->total_queues = ATH9K_NUM_TX_QUEUES; + + if (capField & AR_EEPROM_EEPCAP_KC_ENTRIES) + pCap->keycache_size = + 1 << MS(capField, AR_EEPROM_EEPCAP_KC_ENTRIES); else - qi->tqi_lgretry = INIT_LG_RETRY; - qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod; - qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit; - qi->tqi_burstTime = qinfo->tqi_burstTime; - qi->tqi_readyTime = qinfo->tqi_readyTime; - - switch (qinfo->tqi_subtype) { - case ATH9K_WME_UPSD: - if (qi->tqi_type == ATH9K_TX_QUEUE_DATA) - qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS; - break; - default: - break; - } - return true; -} + pCap->keycache_size = AR_KEYTABLE_SIZE; -bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, - struct ath9k_tx_queue_info *qinfo) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_tx_queue_info *qi; + pCap->hw_caps |= ATH9K_HW_CAP_FASTCC; + pCap->num_mr_retries = 4; + pCap->tx_triglevel_max = MAX_TX_FIFO_THRESHOLD; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; - } + if (AR_SREV_9280_10_OR_LATER(ah)) + pCap->num_gpio_pins = AR928X_NUM_GPIO; + else + pCap->num_gpio_pins = AR_NUM_GPIO; - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue\n", - __func__); - return false; + if (AR_SREV_9280_10_OR_LATER(ah)) { + pCap->hw_caps |= ATH9K_HW_CAP_WOW; + pCap->hw_caps |= ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; + } else { + pCap->hw_caps &= ~ATH9K_HW_CAP_WOW; + pCap->hw_caps &= ~ATH9K_HW_CAP_WOW_MATCHPATTERN_EXACT; } - qinfo->tqi_qflags = qi->tqi_qflags; - qinfo->tqi_ver = qi->tqi_ver; - qinfo->tqi_subtype = qi->tqi_subtype; - qinfo->tqi_qflags = qi->tqi_qflags; - qinfo->tqi_priority = qi->tqi_priority; - qinfo->tqi_aifs = qi->tqi_aifs; - qinfo->tqi_cwmin = qi->tqi_cwmin; - qinfo->tqi_cwmax = qi->tqi_cwmax; - qinfo->tqi_shretry = qi->tqi_shretry; - qinfo->tqi_lgretry = qi->tqi_lgretry; - qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; - qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; - qinfo->tqi_burstTime = qi->tqi_burstTime; - qinfo->tqi_readyTime = qi->tqi_readyTime; + if (AR_SREV_9160_10_OR_LATER(ah) || AR_SREV_9100(ah)) { + pCap->hw_caps |= ATH9K_HW_CAP_CST; + pCap->rts_aggr_limit = ATH_AMPDU_LIMIT_MAX; + } else { + pCap->rts_aggr_limit = (8 * 1024); + } - return true; -} + pCap->hw_caps |= ATH9K_HW_CAP_ENHANCEDPM; -int -ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, - const struct ath9k_tx_queue_info *qinfo) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_tx_queue_info *qi; - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - int q; +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + ah->ah_rfsilent = ath9k_hw_get_eeprom(ah, EEP_RF_SILENT); + if (ah->ah_rfsilent & EEP_RFSILENT_ENABLED) { + ah->ah_rfkill_gpio = + MS(ah->ah_rfsilent, EEP_RFSILENT_GPIO_SEL); + ah->ah_rfkill_polarity = + MS(ah->ah_rfsilent, EEP_RFSILENT_POLARITY); - switch (type) { - case ATH9K_TX_QUEUE_BEACON: - q = pCap->total_queues - 1; - break; - case ATH9K_TX_QUEUE_CAB: - q = pCap->total_queues - 2; - break; - case ATH9K_TX_QUEUE_PSPOLL: - q = 1; - break; - case ATH9K_TX_QUEUE_UAPSD: - q = pCap->total_queues - 3; - break; - case ATH9K_TX_QUEUE_DATA: - for (q = 0; q < pCap->total_queues; q++) - if (ahp->ah_txq[q].tqi_type == - ATH9K_TX_QUEUE_INACTIVE) - break; - if (q == pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: no available tx queue\n", __func__); - return -1; - } - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: bad tx queue type %u\n", - __func__, type); - return -1; + pCap->hw_caps |= ATH9K_HW_CAP_RFSILENT; } +#endif + + if ((ah->ah_macVersion == AR_SREV_VERSION_5416_PCI) || + (ah->ah_macVersion == AR_SREV_VERSION_5416_PCIE) || + (ah->ah_macVersion == AR_SREV_VERSION_9160) || + (ah->ah_macVersion == AR_SREV_VERSION_9100) || + (ah->ah_macVersion == AR_SREV_VERSION_9280)) + pCap->hw_caps &= ~ATH9K_HW_CAP_AUTOSLEEP; + else + pCap->hw_caps |= ATH9K_HW_CAP_AUTOSLEEP; - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); + if (AR_SREV_9280(ah) || AR_SREV_9285(ah)) + pCap->hw_caps &= ~ATH9K_HW_CAP_4KB_SPLITTRANS; + else + pCap->hw_caps |= ATH9K_HW_CAP_4KB_SPLITTRANS; - qi = &ahp->ah_txq[q]; - if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: tx queue %u already active\n", __func__, q); - return -1; - } - memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); - qi->tqi_type = type; - if (qinfo == NULL) { - qi->tqi_qflags = - TXQ_FLAG_TXOKINT_ENABLE - | TXQ_FLAG_TXERRINT_ENABLE - | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE; - qi->tqi_aifs = INIT_AIFS; - qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT; - qi->tqi_cwmax = INIT_CWMAX; - qi->tqi_shretry = INIT_SH_RETRY; - qi->tqi_lgretry = INIT_LG_RETRY; - qi->tqi_physCompBuf = 0; + if (ah->ah_currentRDExt & (1 << REG_EXT_JAPAN_MIDBAND)) { + pCap->reg_cap = + AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | + AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN | + AR_EEPROM_EEREGCAP_EN_KK_U2 | + AR_EEPROM_EEREGCAP_EN_KK_MIDBAND; } else { - qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; - (void) ath9k_hw_set_txq_props(ah, q, qinfo); + pCap->reg_cap = + AR_EEPROM_EEREGCAP_EN_KK_NEW_11A | + AR_EEPROM_EEREGCAP_EN_KK_U1_EVEN; } - return q; -} + pCap->reg_cap |= AR_EEPROM_EEREGCAP_EN_FCC_MIDBAND; -static void -ath9k_hw_set_txq_interrupts(struct ath_hal *ah, - struct ath9k_tx_queue_info *qi) -{ - struct ath_hal_5416 *ahp = AH5416(ah); + pCap->num_antcfg_5ghz = + ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_5GHZ); + pCap->num_antcfg_2ghz = + ath9k_hw_get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ); - DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, - "%s: tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", - __func__, ahp->ah_txOkInterruptMask, - ahp->ah_txErrInterruptMask, ahp->ah_txDescInterruptMask, - ahp->ah_txEolInterruptMask, ahp->ah_txUrnInterruptMask); - - REG_WRITE(ah, AR_IMR_S0, - SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK) - | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC)); - REG_WRITE(ah, AR_IMR_S1, - SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR) - | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL)); - REG_RMW_FIELD(ah, AR_IMR_S2, - AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask); + return true; } -bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q) +bool ath9k_hw_getcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 *result) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_tx_queue_info *qi; + const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); + switch (type) { + case ATH9K_CAP_CIPHER: + switch (capability) { + case ATH9K_CIPHER_AES_CCM: + case ATH9K_CIPHER_AES_OCB: + case ATH9K_CIPHER_TKIP: + case ATH9K_CIPHER_WEP: + case ATH9K_CIPHER_MIC: + case ATH9K_CIPHER_CLR: + return true; + default: + return false; + } + case ATH9K_CAP_TKIP_MIC: + switch (capability) { + case 0: + return true; + case 1: + return (ahp->ah_staId1Defaults & + AR_STA_ID1_CRPT_MIC_ENABLE) ? true : + false; + } + case ATH9K_CAP_TKIP_SPLIT: + return (ahp->ah_miscMode & AR_PCU_MIC_NEW_LOC_ENA) ? + false : true; + case ATH9K_CAP_WME_TKIPMIC: + return 0; + case ATH9K_CAP_PHYCOUNTERS: + return ahp->ah_hasHwPhyCounters ? 0 : -ENXIO; + case ATH9K_CAP_DIVERSITY: + return (REG_READ(ah, AR_PHY_CCK_DETECT) & + AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ? + true : false; + case ATH9K_CAP_PHYDIAG: + return true; + case ATH9K_CAP_MCAST_KEYSRCH: + switch (capability) { + case 0: + return true; + case 1: + if (REG_READ(ah, AR_STA_ID1) & AR_STA_ID1_ADHOC) { + return false; + } else { + return (ahp->ah_staId1Defaults & + AR_STA_ID1_MCAST_KSRCH) ? true : + false; + } + } + return false; + case ATH9K_CAP_TSF_ADJUST: + return (ahp->ah_miscMode & AR_PCU_TX_ADD_TSF) ? + true : false; + case ATH9K_CAP_RFSILENT: + if (capability == 3) + return false; + case ATH9K_CAP_ANT_CFG_2GHZ: + *result = pCap->num_antcfg_2ghz; + return true; + case ATH9K_CAP_ANT_CFG_5GHZ: + *result = pCap->num_antcfg_5ghz; + return true; + case ATH9K_CAP_TXPOW: + switch (capability) { + case 0: + return 0; + case 1: + *result = ah->ah_powerLimit; + return 0; + case 2: + *result = ah->ah_maxPowerLevel; + return 0; + case 3: + *result = ah->ah_tpScale; + return 0; + } return false; - } - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n", - __func__, q); + default: return false; } - - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: release queue %u\n", - __func__, q); - - qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; - ahp->ah_txOkInterruptMask &= ~(1 << q); - ahp->ah_txErrInterruptMask &= ~(1 << q); - ahp->ah_txDescInterruptMask &= ~(1 << q); - ahp->ah_txEolInterruptMask &= ~(1 << q); - ahp->ah_txUrnInterruptMask &= ~(1 << q); - ath9k_hw_set_txq_interrupts(ah, qi); - - return true; } -bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) +bool ath9k_hw_setcapability(struct ath_hal *ah, enum ath9k_capability_type type, + u32 capability, u32 setting, int *status) { struct ath_hal_5416 *ahp = AH5416(ah); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - struct ath9k_channel *chan = ah->ah_curchan; - struct ath9k_tx_queue_info *qi; - u32 cwMin, chanCwMin, value; + u32 v; - if (q >= pCap->total_queues) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: invalid queue num %u\n", - __func__, q); - return false; - } - qi = &ahp->ah_txq[q]; - if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: inactive queue %u\n", - __func__, q); + switch (type) { + case ATH9K_CAP_TKIP_MIC: + if (setting) + ahp->ah_staId1Defaults |= + AR_STA_ID1_CRPT_MIC_ENABLE; + else + ahp->ah_staId1Defaults &= + ~AR_STA_ID1_CRPT_MIC_ENABLE; return true; - } - - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: reset queue %u\n", __func__, q); - - if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { - if (chan && IS_CHAN_B(chan)) - chanCwMin = INIT_CWMIN_11B; + case ATH9K_CAP_DIVERSITY: + v = REG_READ(ah, AR_PHY_CCK_DETECT); + if (setting) + v |= AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; else - chanCwMin = INIT_CWMIN; - - for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1); - } else - cwMin = qi->tqi_cwmin; - - REG_WRITE(ah, AR_DLCL_IFS(q), SM(cwMin, AR_D_LCL_IFS_CWMIN) - | SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) - | SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); - - REG_WRITE(ah, AR_DRETRY_LIMIT(q), - SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) - | SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) - | SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)); - - REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); - REG_WRITE(ah, AR_DMISC(q), - AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); - - if (qi->tqi_cbrPeriod) { - REG_WRITE(ah, AR_QCBRCFG(q), - SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) - | SM(qi->tqi_cbrOverflowLimit, - AR_Q_CBRCFG_OVF_THRESH)); - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, - AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | (qi-> - tqi_cbrOverflowLimit - ? - AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN - : - 0)); - } - if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { - REG_WRITE(ah, AR_QRDYTIMECFG(q), - SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) | - AR_Q_RDYTIMECFG_EN); - } - - REG_WRITE(ah, AR_DCHNTIME(q), - SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | - (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); - - if (qi->tqi_burstTime - && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, - AR_QMISC(q)) | - AR_Q_MISC_RDYTIME_EXP_POLICY); - - } - - if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_POST_FR_BKOFF_DIS); - } - if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - AR_D_MISC_FRAG_BKOFF_EN); - } - switch (qi->tqi_type) { - case ATH9K_TX_QUEUE_BEACON: - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_BEACON_USE - | AR_Q_MISC_CBR_INCR_DIS1); - - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << - AR_D_MISC_ARB_LOCKOUT_CNTRL_S) - | AR_D_MISC_BEACON_USE - | AR_D_MISC_POST_FR_BKOFF_DIS); - break; - case ATH9K_TX_QUEUE_CAB: - REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) - | AR_Q_MISC_FSP_DBA_GATED - | AR_Q_MISC_CBR_INCR_DIS1 - | AR_Q_MISC_CBR_INCR_DIS0); - value = (qi->tqi_readyTime - - (ah->ah_config.sw_beacon_response_time - - ah->ah_config.dma_beacon_response_time) - - - ah->ah_config.additional_swba_backoff) * - 1024; - REG_WRITE(ah, AR_QRDYTIMECFG(q), - value | AR_Q_RDYTIMECFG_EN); - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << - AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); - break; - case ATH9K_TX_QUEUE_PSPOLL: - REG_WRITE(ah, AR_QMISC(q), - REG_READ(ah, - AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); - break; - case ATH9K_TX_QUEUE_UAPSD: - REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) - | AR_D_MISC_POST_FR_BKOFF_DIS); - break; + v &= ~AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV; + REG_WRITE(ah, AR_PHY_CCK_DETECT, v); + return true; + case ATH9K_CAP_MCAST_KEYSRCH: + if (setting) + ahp->ah_staId1Defaults |= AR_STA_ID1_MCAST_KSRCH; + else + ahp->ah_staId1Defaults &= ~AR_STA_ID1_MCAST_KSRCH; + return true; + case ATH9K_CAP_TSF_ADJUST: + if (setting) + ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; + else + ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; + return true; default: - break; + return false; } +} - if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { - REG_WRITE(ah, AR_DMISC(q), - REG_READ(ah, AR_DMISC(q)) | - SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, - AR_D_MISC_ARB_LOCKOUT_CNTRL) | - AR_D_MISC_POST_FR_BKOFF_DIS); - } +/****************************/ +/* GPIO / RFKILL / Antennae */ +/****************************/ - if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) - ahp->ah_txOkInterruptMask |= 1 << q; - else - ahp->ah_txOkInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) - ahp->ah_txErrInterruptMask |= 1 << q; - else - ahp->ah_txErrInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) - ahp->ah_txDescInterruptMask |= 1 << q; - else - ahp->ah_txDescInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) - ahp->ah_txEolInterruptMask |= 1 << q; - else - ahp->ah_txEolInterruptMask &= ~(1 << q); - if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) - ahp->ah_txUrnInterruptMask |= 1 << q; - else - ahp->ah_txUrnInterruptMask &= ~(1 << q); - ath9k_hw_set_txq_interrupts(ah, qi); +static void ath9k_hw_gpio_cfg_output_mux(struct ath_hal *ah, + u32 gpio, u32 type) +{ + int addr; + u32 gpio_shift, tmp; - return true; -} + if (gpio > 11) + addr = AR_GPIO_OUTPUT_MUX3; + else if (gpio > 5) + addr = AR_GPIO_OUTPUT_MUX2; + else + addr = AR_GPIO_OUTPUT_MUX1; -void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - *txqs &= ahp->ah_intrTxqs; - ahp->ah_intrTxqs &= ~(*txqs); -} + gpio_shift = (gpio % 6) * 5; -bool -ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 segLen, bool firstSeg, - bool lastSeg, const struct ath_desc *ds0) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - if (firstSeg) { - ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); - } else if (lastSeg) { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = segLen; - ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; - ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; + if (AR_SREV_9280_20_OR_LATER(ah) + || (addr != AR_GPIO_OUTPUT_MUX1)) { + REG_RMW(ah, addr, (type << gpio_shift), + (0x1f << gpio_shift)); } else { - ads->ds_ctl0 = 0; - ads->ds_ctl1 = segLen | AR_TxMore; - ads->ds_ctl2 = 0; - ads->ds_ctl3 = 0; + tmp = REG_READ(ah, addr); + tmp = ((tmp & 0x1F0) << 1) | (tmp & ~0x1F0); + tmp &= ~(0x1f << gpio_shift); + tmp |= (type << gpio_shift); + REG_WRITE(ah, addr, tmp); } - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; - return true; -} - -void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds) -{ - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_txstatus0 = ads->ds_txstatus1 = 0; - ads->ds_txstatus2 = ads->ds_txstatus3 = 0; - ads->ds_txstatus4 = ads->ds_txstatus5 = 0; - ads->ds_txstatus6 = ads->ds_txstatus7 = 0; - ads->ds_txstatus8 = ads->ds_txstatus9 = 0; } -int -ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds) +void ath9k_hw_cfg_gpio_input(struct ath_hal *ah, u32 gpio) { - struct ar5416_desc *ads = AR5416DESC(ds); - - if ((ads->ds_txstatus9 & AR_TxDone) == 0) - return -EINPROGRESS; - - ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); - ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp; - ds->ds_txstat.ts_status = 0; - ds->ds_txstat.ts_flags = 0; - - if (ads->ds_txstatus1 & AR_ExcessiveRetries) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; - if (ads->ds_txstatus1 & AR_Filtered) - ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; - if (ads->ds_txstatus1 & AR_FIFOUnderrun) - ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO; - if (ads->ds_txstatus9 & AR_TxOpExceeded) - ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; - if (ads->ds_txstatus1 & AR_TxTimerExpired) - ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED; - - if (ads->ds_txstatus1 & AR_DescCfgErr) - ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR; - if (ads->ds_txstatus1 & AR_TxDataUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { - ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN; - ath9k_hw_updatetxtriglevel(ah, true); - } - if (ads->ds_txstatus0 & AR_TxBaStatus) { - ds->ds_txstat.ts_flags |= ATH9K_TX_BA; - ds->ds_txstat.ba_low = ads->AR_BaBitmapLow; - ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh; - } + u32 gpio_shift; - ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); - switch (ds->ds_txstat.ts_rateindex) { - case 0: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); - break; - case 1: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); - break; - case 2: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); - break; - case 3: - ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); - break; - } + ASSERT(gpio < ah->ah_caps.num_gpio_pins); - ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); - ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); - ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); - ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); - ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); - ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); - ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); - ds->ds_txstat.evm0 = ads->AR_TxEVM0; - ds->ds_txstat.evm1 = ads->AR_TxEVM1; - ds->ds_txstat.evm2 = ads->AR_TxEVM2; - ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); - ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); - ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); - ds->ds_txstat.ts_antenna = 1; + gpio_shift = gpio << 1; - return 0; + REG_RMW(ah, + AR_GPIO_OE_OUT, + (AR_GPIO_OE_OUT_DRV_NO << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); } -void -ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pktLen, enum ath9k_pkt_type type, u32 txPower, - u32 keyIx, enum ath9k_key_type keyType, u32 flags) +u32 ath9k_hw_gpio_get(struct ath_hal *ah, u32 gpio) { - struct ar5416_desc *ads = AR5416DESC(ds); - struct ath_hal_5416 *ahp = AH5416(ah); - - txPower += ahp->ah_txPowerIndexOffset; - if (txPower > 63) - txPower = 63; - - ads->ds_ctl0 = (pktLen & AR_FrameLen) - | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) - | SM(txPower, AR_XmitPower) - | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) - | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) - | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) - | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); - - ads->ds_ctl1 = - (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) - | SM(type, AR_FrameType) - | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) - | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) - | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); - - ads->ds_ctl6 = SM(keyType, AR_EncrType); - - if (AR_SREV_9285(ah)) { + if (gpio >= ah->ah_caps.num_gpio_pins) + return 0xffffffff; - ads->ds_ctl8 = 0; - ads->ds_ctl9 = 0; - ads->ds_ctl10 = 0; - ads->ds_ctl11 = 0; + if (AR_SREV_9280_10_OR_LATER(ah)) { + return (MS + (REG_READ(ah, AR_GPIO_IN_OUT), + AR928X_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) != 0; + } else { + return (MS(REG_READ(ah, AR_GPIO_IN_OUT), AR_GPIO_IN_VAL) & + AR_GPIO_BIT(gpio)) != 0; } } -void -ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, - struct ath_desc *lastds, - u32 durUpdateEn, u32 rtsctsRate, - u32 rtsctsDuration, - struct ath9k_11n_rate_series series[], - u32 nseries, u32 flags) +void ath9k_hw_cfg_output(struct ath_hal *ah, u32 gpio, + u32 ah_signal_type) { - struct ar5416_desc *ads = AR5416DESC(ds); - struct ar5416_desc *last_ads = AR5416DESC(lastds); - u32 ds_ctl0; - - (void) nseries; - (void) rtsctsDuration; + u32 gpio_shift; - if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { - ds_ctl0 = ads->ds_ctl0; + ath9k_hw_gpio_cfg_output_mux(ah, gpio, ah_signal_type); - if (flags & ATH9K_TXDESC_RTSENA) { - ds_ctl0 &= ~AR_CTSEnable; - ds_ctl0 |= AR_RTSEnable; - } else { - ds_ctl0 &= ~AR_RTSEnable; - ds_ctl0 |= AR_CTSEnable; - } + gpio_shift = 2 * gpio; - ads->ds_ctl0 = ds_ctl0; - } else { - ads->ds_ctl0 = - (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); - } + REG_RMW(ah, + AR_GPIO_OE_OUT, + (AR_GPIO_OE_OUT_DRV_ALL << gpio_shift), + (AR_GPIO_OE_OUT_DRV << gpio_shift)); +} - ads->ds_ctl2 = set11nTries(series, 0) - | set11nTries(series, 1) - | set11nTries(series, 2) - | set11nTries(series, 3) - | (durUpdateEn ? AR_DurUpdateEna : 0) - | SM(0, AR_BurstDur); - - ads->ds_ctl3 = set11nRate(series, 0) - | set11nRate(series, 1) - | set11nRate(series, 2) - | set11nRate(series, 3); - - ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) - | set11nPktDurRTSCTS(series, 1); - - ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) - | set11nPktDurRTSCTS(series, 3); - - ads->ds_ctl7 = set11nRateFlags(series, 0) - | set11nRateFlags(series, 1) - | set11nRateFlags(series, 2) - | set11nRateFlags(series, 3) - | SM(rtsctsRate, AR_RTSCTSRate); - last_ads->ds_ctl2 = ads->ds_ctl2; - last_ads->ds_ctl3 = ads->ds_ctl3; +void ath9k_hw_set_gpio(struct ath_hal *ah, u32 gpio, u32 val) +{ + REG_RMW(ah, AR_GPIO_IN_OUT, ((val & 1) << gpio), + AR_GPIO_BIT(gpio)); } -void -ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, - u32 aggrLen) +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) +void ath9k_enable_rfkill(struct ath_hal *ah) { - struct ar5416_desc *ads = AR5416DESC(ds); + REG_SET_BIT(ah, AR_GPIO_INPUT_EN_VAL, + AR_GPIO_INPUT_EN_VAL_RFSILENT_BB); - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + REG_CLR_BIT(ah, AR_GPIO_INPUT_MUX2, + AR_GPIO_INPUT_MUX2_RFSILENT); - ads->ds_ctl6 &= ~AR_AggrLen; - ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); + ath9k_hw_cfg_gpio_input(ah, ah->ah_rfkill_gpio); + REG_SET_BIT(ah, AR_PHY_TEST, RFSILENT_BB); } +#endif -void -ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, - u32 numDelims) +int ath9k_hw_select_antconfig(struct ath_hal *ah, u32 cfg) { - struct ar5416_desc *ads = AR5416DESC(ds); - unsigned int ctl6; + struct ath9k_channel *chan = ah->ah_curchan; + const struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + u16 ant_config; + u32 halNumAntConfig; - ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + halNumAntConfig = IS_CHAN_2GHZ(chan) ? + pCap->num_antcfg_2ghz : pCap->num_antcfg_5ghz; + + if (cfg < halNumAntConfig) { + if (!ath9k_hw_get_eeprom_antenna_cfg(ah, chan, + cfg, &ant_config)) { + REG_WRITE(ah, AR_PHY_SWITCH_COM, ant_config); + return 0; + } + } - ctl6 = ads->ds_ctl6; - ctl6 &= ~AR_PadDelim; - ctl6 |= SM(numDelims, AR_PadDelim); - ads->ds_ctl6 = ctl6; + return -EINVAL; } -void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds) +u32 ath9k_hw_getdefantenna(struct ath_hal *ah) { - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 |= AR_IsAggr; - ads->ds_ctl1 &= ~AR_MoreAggr; - ads->ds_ctl6 &= ~AR_PadDelim; + return REG_READ(ah, AR_DEF_ANTENNA) & 0x7; } -void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds) +void ath9k_hw_setantenna(struct ath_hal *ah, u32 antenna) { - struct ar5416_desc *ads = AR5416DESC(ds); - - ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); + REG_WRITE(ah, AR_DEF_ANTENNA, (antenna & 0x7)); } -void -ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, - u32 burstDuration) +bool ath9k_hw_setantennaswitch(struct ath_hal *ah, + enum ath9k_ant_setting settings, + struct ath9k_channel *chan, + u8 *tx_chainmask, + u8 *rx_chainmask, + u8 *antenna_cfgd) { - struct ar5416_desc *ads = AR5416DESC(ds); + struct ath_hal_5416 *ahp = AH5416(ah); + static u8 tx_chainmask_cfg, rx_chainmask_cfg; - ads->ds_ctl2 &= ~AR_BurstDur; - ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); -} + if (AR_SREV_9280(ah)) { + if (!tx_chainmask_cfg) { -void -ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, - u32 vmf) -{ - struct ar5416_desc *ads = AR5416DESC(ds); + tx_chainmask_cfg = *tx_chainmask; + rx_chainmask_cfg = *rx_chainmask; + } - if (vmf) - ads->ds_ctl0 |= AR_VirtMoreFrag; - else - ads->ds_ctl0 &= ~AR_VirtMoreFrag; -} + switch (settings) { + case ATH9K_ANT_FIXED_A: + *tx_chainmask = ATH9K_ANTENNA0_CHAINMASK; + *rx_chainmask = ATH9K_ANTENNA0_CHAINMASK; + *antenna_cfgd = true; + break; + case ATH9K_ANT_FIXED_B: + if (ah->ah_caps.tx_chainmask > + ATH9K_ANTENNA1_CHAINMASK) { + *tx_chainmask = ATH9K_ANTENNA1_CHAINMASK; + } + *rx_chainmask = ATH9K_ANTENNA1_CHAINMASK; + *antenna_cfgd = true; + break; + case ATH9K_ANT_VARIABLE: + *tx_chainmask = tx_chainmask_cfg; + *rx_chainmask = rx_chainmask_cfg; + *antenna_cfgd = true; + break; + default: + break; + } + } else { + ahp->ah_diversityControl = settings; + } -void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp) -{ - REG_WRITE(ah, AR_RXDP, rxdp); + return true; } -void ath9k_hw_rxena(struct ath_hal *ah) -{ - REG_WRITE(ah, AR_CR, AR_CR_RXE); -} +/*********************/ +/* General Operation */ +/*********************/ -bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set) +u32 ath9k_hw_getrxfilter(struct ath_hal *ah) { - if (set) { - - REG_SET_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + u32 bits = REG_READ(ah, AR_RX_FILTER); + u32 phybits = REG_READ(ah, AR_PHY_ERR); - if (!ath9k_hw_wait - (ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) { - u32 reg; + if (phybits & AR_PHY_ERR_RADAR) + bits |= ATH9K_RX_FILTER_PHYRADAR; + if (phybits & (AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING)) + bits |= ATH9K_RX_FILTER_PHYERR; - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | - AR_DIAG_RX_ABORT)); + return bits; +} - reg = REG_READ(ah, AR_OBS_BUS_1); - DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: rx failed to go idle in 10 ms RXSM=0x%x\n", - __func__, reg); +void ath9k_hw_setrxfilter(struct ath_hal *ah, u32 bits) +{ + u32 phybits; - return false; - } - } else { - REG_CLR_BIT(ah, AR_DIAG_SW, - (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); - } + REG_WRITE(ah, AR_RX_FILTER, (bits & 0xffff) | AR_RX_COMPR_BAR); + phybits = 0; + if (bits & ATH9K_RX_FILTER_PHYRADAR) + phybits |= AR_PHY_ERR_RADAR; + if (bits & ATH9K_RX_FILTER_PHYERR) + phybits |= AR_PHY_ERR_OFDM_TIMING | AR_PHY_ERR_CCK_TIMING; + REG_WRITE(ah, AR_PHY_ERR, phybits); - return true; + if (phybits) + REG_WRITE(ah, AR_RXCFG, + REG_READ(ah, AR_RXCFG) | AR_RXCFG_ZLFDMA); + else + REG_WRITE(ah, AR_RXCFG, + REG_READ(ah, AR_RXCFG) & ~AR_RXCFG_ZLFDMA); } -void -ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, - u32 filter1) +bool ath9k_hw_phy_disable(struct ath_hal *ah) { - REG_WRITE(ah, AR_MCAST_FIL0, filter0); - REG_WRITE(ah, AR_MCAST_FIL1, filter1); + return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM); } -bool -ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 size, u32 flags) +bool ath9k_hw_disable(struct ath_hal *ah) { - struct ar5416_desc *ads = AR5416DESC(ds); - struct ath9k_hw_capabilities *pCap = &ah->ah_caps; - - ads->ds_ctl1 = size & AR_BufLen; - if (flags & ATH9K_RXDESC_INTREQ) - ads->ds_ctl1 |= AR_RxIntrReq; + if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE)) + return false; - ads->ds_rxstatus8 &= ~AR_RxDone; - if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) - memset(&(ads->u), 0, sizeof(ads->u)); - return true; + return ath9k_hw_set_reset_reg(ah, ATH9K_RESET_COLD); } -int -ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, - u32 pa, struct ath_desc *nds, u64 tsf) +bool ath9k_hw_set_txpowerlimit(struct ath_hal *ah, u32 limit) { - struct ar5416_desc ads; - struct ar5416_desc *adsp = AR5416DESC(ds); - - if ((adsp->ds_rxstatus8 & AR_RxDone) == 0) - return -EINPROGRESS; - - ads.u.rx = adsp->u.rx; - - ds->ds_rxstat.rs_status = 0; - ds->ds_rxstat.rs_flags = 0; + struct ath9k_channel *chan = ah->ah_curchan; - ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; - ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; + ah->ah_powerLimit = min(limit, (u32) MAX_RATE_POWER); - ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); - ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); - ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); - ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); - ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); - ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); - ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); - if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) - ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); - else - ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID; - - ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads)); - ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; - - ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; - ds->ds_rxstat.rs_moreaggr = - (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; - ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); - ds->ds_rxstat.rs_flags = - (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; - ds->ds_rxstat.rs_flags |= - (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; - - if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE; - if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST; - if (ads.ds_rxstatus8 & AR_DecryptBusyErr) - ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY; - - if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { - - if (ads.ds_rxstatus8 & AR_CRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC; - else if (ads.ds_rxstatus8 & AR_PHYErr) { - u32 phyerr; - - ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY; - phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); - ds->ds_rxstat.rs_phyerr = phyerr; - } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT; - else if (ads.ds_rxstatus8 & AR_MichaelErr) - ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC; - } + if (ath9k_hw_set_txpower(ah, chan, + ath9k_regd_get_ctl(ah, chan), + ath9k_regd_get_antenna_allowed(ah, chan), + chan->maxRegTxPower * 2, + min((u32) MAX_RATE_POWER, + (u32) ah->ah_powerLimit)) != 0) + return false; - return 0; + return true; } -static void ath9k_hw_setup_rate_table(struct ath_hal *ah, - struct ath9k_rate_table *rt) +void ath9k_hw_getmac(struct ath_hal *ah, u8 *mac) { - int i; + struct ath_hal_5416 *ahp = AH5416(ah); - if (rt->rateCodeToIndex[0] != 0) - return; - for (i = 0; i < 256; i++) - rt->rateCodeToIndex[i] = (u8) -1; - for (i = 0; i < rt->rateCount; i++) { - u8 code = rt->info[i].rateCode; - u8 cix = rt->info[i].controlRate; - - rt->rateCodeToIndex[code] = i; - rt->rateCodeToIndex[code | rt->info[i].shortPreamble] = i; - - rt->info[i].lpAckDuration = - ath9k_hw_computetxtime(ah, rt, - WLAN_CTRL_FRAME_SIZE, - cix, - false); - rt->info[i].spAckDuration = - ath9k_hw_computetxtime(ah, rt, - WLAN_CTRL_FRAME_SIZE, - cix, - true); - } + memcpy(mac, ahp->ah_macaddr, ETH_ALEN); } -const struct ath9k_rate_table *ath9k_hw_getratetable(struct ath_hal *ah, - u32 mode) +bool ath9k_hw_setmac(struct ath_hal *ah, const u8 *mac) { - struct ath9k_rate_table *rt; - switch (mode) { - case ATH9K_MODE_11A: - rt = &ar5416_11a_table; - break; - case ATH9K_MODE_11B: - rt = &ar5416_11b_table; - break; - case ATH9K_MODE_11G: - rt = &ar5416_11g_table; - break; - case ATH9K_MODE_11NG_HT20: - case ATH9K_MODE_11NG_HT40PLUS: - case ATH9K_MODE_11NG_HT40MINUS: - rt = &ar5416_11ng_table; - break; - case ATH9K_MODE_11NA_HT20: - case ATH9K_MODE_11NA_HT40PLUS: - case ATH9K_MODE_11NA_HT40MINUS: - rt = &ar5416_11na_table; - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, "%s: invalid mode 0x%x\n", - __func__, mode); - return NULL; - } - ath9k_hw_setup_rate_table(ah, rt); - return rt; + struct ath_hal_5416 *ahp = AH5416(ah); + + memcpy(ahp->ah_macaddr, mac, ETH_ALEN); + + return true; } -static const char *ath9k_hw_devname(u16 devid) +void ath9k_hw_setopmode(struct ath_hal *ah) { - switch (devid) { - case AR5416_DEVID_PCI: - case AR5416_DEVID_PCIE: - return "Atheros 5416"; - case AR9160_DEVID_PCI: - return "Atheros 9160"; - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - return "Atheros 9280"; - } - return NULL; + ath9k_hw_set_operating_mode(ah, ah->ah_opmode); } -const char *ath9k_hw_probe(u16 vendorid, u16 devid) +void ath9k_hw_setmcastfilter(struct ath_hal *ah, u32 filter0, u32 filter1) { - return vendorid == ATHEROS_VENDOR_ID ? - ath9k_hw_devname(devid) : NULL; + REG_WRITE(ah, AR_MCAST_FIL0, filter0); + REG_WRITE(ah, AR_MCAST_FIL1, filter1); } -struct ath_hal *ath9k_hw_attach(u16 devid, - struct ath_softc *sc, - void __iomem *mem, - int *error) +void ath9k_hw_getbssidmask(struct ath_hal *ah, u8 *mask) { - struct ath_hal *ah = NULL; - - switch (devid) { - case AR5416_DEVID_PCI: - case AR5416_DEVID_PCIE: - case AR9160_DEVID_PCI: - case AR9280_DEVID_PCI: - case AR9280_DEVID_PCIE: - ah = ath9k_hw_do_attach(devid, sc, mem, error); - break; - default: - DPRINTF(ah->ah_sc, ATH_DBG_ANY, - "devid=0x%x not supported.\n", devid); - ah = NULL; - *error = -ENXIO; - break; - } + struct ath_hal_5416 *ahp = AH5416(ah); - return ah; + memcpy(mask, ahp->ah_bssidmask, ETH_ALEN); } -u16 -ath9k_hw_computetxtime(struct ath_hal *ah, - const struct ath9k_rate_table *rates, - u32 frameLen, u16 rateix, - bool shortPreamble) +bool ath9k_hw_setbssidmask(struct ath_hal *ah, const u8 *mask) { - u32 bitsPerSymbol, numBits, numSymbols, phyTime, txTime; - u32 kbps; - - kbps = rates->info[rateix].rateKbps; + struct ath_hal_5416 *ahp = AH5416(ah); - if (kbps == 0) - return 0; - switch (rates->info[rateix].phy) { + memcpy(ahp->ah_bssidmask, mask, ETH_ALEN); - case PHY_CCK: - phyTime = CCK_PREAMBLE_BITS + CCK_PLCP_BITS; - if (shortPreamble && rates->info[rateix].shortPreamble) - phyTime >>= 1; - numBits = frameLen << 3; - txTime = CCK_SIFS_TIME + phyTime - + ((numBits * 1000) / kbps); - break; - case PHY_OFDM: - if (ah->ah_curchan && IS_CHAN_QUARTER_RATE(ah->ah_curchan)) { - bitsPerSymbol = - (kbps * OFDM_SYMBOL_TIME_QUARTER) / 1000; + REG_WRITE(ah, AR_BSSMSKL, get_unaligned_le32(ahp->ah_bssidmask)); + REG_WRITE(ah, AR_BSSMSKU, get_unaligned_le16(ahp->ah_bssidmask + 4)); - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME_QUARTER - + OFDM_PREAMBLE_TIME_QUARTER - + (numSymbols * OFDM_SYMBOL_TIME_QUARTER); - } else if (ah->ah_curchan && - IS_CHAN_HALF_RATE(ah->ah_curchan)) { - bitsPerSymbol = - (kbps * OFDM_SYMBOL_TIME_HALF) / 1000; + return true; +} - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME_HALF + - OFDM_PREAMBLE_TIME_HALF - + (numSymbols * OFDM_SYMBOL_TIME_HALF); - } else { - bitsPerSymbol = (kbps * OFDM_SYMBOL_TIME) / 1000; +void ath9k_hw_write_associd(struct ath_hal *ah, const u8 *bssid, u16 assocId) +{ + struct ath_hal_5416 *ahp = AH5416(ah); - numBits = OFDM_PLCP_BITS + (frameLen << 3); - numSymbols = DIV_ROUND_UP(numBits, bitsPerSymbol); - txTime = OFDM_SIFS_TIME + OFDM_PREAMBLE_TIME - + (numSymbols * OFDM_SYMBOL_TIME); - } - break; + memcpy(ahp->ah_bssid, bssid, ETH_ALEN); + ahp->ah_assocId = assocId; - default: - DPRINTF(ah->ah_sc, ATH_DBG_PHY_IO, - "%s: unknown phy %u (rate ix %u)\n", __func__, - rates->info[rateix].phy, rateix); - txTime = 0; - break; - } - return txTime; + REG_WRITE(ah, AR_BSS_ID0, get_unaligned_le32(ahp->ah_bssid)); + REG_WRITE(ah, AR_BSS_ID1, get_unaligned_le16(ahp->ah_bssid + 4) | + ((assocId & 0x3fff) << AR_BSS_ID1_AID_S)); } -u32 ath9k_hw_mhz2ieee(struct ath_hal *ah, u32 freq, u32 flags) +u64 ath9k_hw_gettsf64(struct ath_hal *ah) { - if (flags & CHANNEL_2GHZ) { - if (freq == 2484) - return 14; - if (freq < 2484) - return (freq - 2407) / 5; - else - return 15 + ((freq - 2512) / 20); - } else if (flags & CHANNEL_5GHZ) { - if (ath9k_regd_is_public_safety_sku(ah) && - IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { - return ((freq * 10) + - (((freq % 5) == 2) ? 5 : 0) - 49400) / 5; - } else if ((flags & CHANNEL_A) && (freq <= 5000)) { - return (freq - 4000) / 5; - } else { - return (freq - 5000) / 5; - } - } else { - if (freq == 2484) - return 14; - if (freq < 2484) - return (freq - 2407) / 5; - if (freq < 5000) { - if (ath9k_regd_is_public_safety_sku(ah) - && IS_CHAN_IN_PUBLIC_SAFETY_BAND(freq)) { - return ((freq * 10) + - (((freq % 5) == - 2) ? 5 : 0) - 49400) / 5; - } else if (freq > 4900) { - return (freq - 4000) / 5; - } else { - return 15 + ((freq - 2512) / 20); - } - } - return (freq - 5000) / 5; - } -} + u64 tsf; -/* We can tune this as we go by monitoring really low values */ -#define ATH9K_NF_TOO_LOW -60 + tsf = REG_READ(ah, AR_TSF_U32); + tsf = (tsf << 32) | REG_READ(ah, AR_TSF_L32); -/* AR5416 may return very high value (like -31 dBm), in those cases the nf - * is incorrect and we should use the static NF value. Later we can try to - * find out why they are reporting these values */ -static bool ath9k_hw_nf_in_range(struct ath_hal *ah, s16 nf) -{ - if (nf > ATH9K_NF_TOO_LOW) { - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "%s: noise floor value detected (%d) is " - "lower than what we think is a " - "reasonable value (%d)\n", - __func__, nf, ATH9K_NF_TOO_LOW); - return false; - } - return true; + return tsf; } -s16 -ath9k_hw_getchan_noise(struct ath_hal *ah, struct ath9k_channel *chan) +void ath9k_hw_reset_tsf(struct ath_hal *ah) { - struct ath9k_channel *ichan; - s16 nf; - - ichan = ath9k_regd_check_channel(ah, chan); - if (ichan == NULL) { - DPRINTF(ah->ah_sc, ATH_DBG_NF_CAL, - "%s: invalid channel %u/0x%x; no mapping\n", - __func__, chan->channel, chan->channelFlags); - return ATH_DEFAULT_NOISE_FLOOR; - } - if (ichan->rawNoiseFloor == 0) { - enum wireless_mode mode = ath9k_hw_chan2wmode(ah, chan); - nf = NOISE_FLOOR[mode]; - } else - nf = ichan->rawNoiseFloor; - - if (!ath9k_hw_nf_in_range(ah, nf)) - nf = ATH_DEFAULT_NOISE_FLOOR; + int count; - return nf; + count = 0; + while (REG_READ(ah, AR_SLP32_MODE) & AR_SLP32_TSF_WRITE_STATUS) { + count++; + if (count > 10) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, + "AR_SLP32_TSF_WRITE_STATUS limit exceeded\n"); + break; + } + udelay(10); + } + REG_WRITE(ah, AR_RESET_TSF, AR_RESET_TSF_ONCE); } bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) @@ -8468,110 +3862,34 @@ bool ath9k_hw_set_tsfadjust(struct ath_hal *ah, u32 setting) ahp->ah_miscMode |= AR_PCU_TX_ADD_TSF; else ahp->ah_miscMode &= ~AR_PCU_TX_ADD_TSF; - return true; -} - -bool ath9k_hw_phycounters(struct ath_hal *ah) -{ - struct ath_hal_5416 *ahp = AH5416(ah); - - return ahp->ah_hasHwPhyCounters ? true : false; -} - -u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q) -{ - return REG_READ(ah, AR_QTXDP(q)); -} - -bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, - u32 txdp) -{ - REG_WRITE(ah, AR_QTXDP(q), txdp); - - return true; -} - -bool ath9k_hw_txstart(struct ath_hal *ah, u32 q) -{ - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "%s: queue %u\n", __func__, q); - - REG_WRITE(ah, AR_Q_TXE, 1 << q); return true; } -u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q) +bool ath9k_hw_setslottime(struct ath_hal *ah, u32 us) { - u32 npend; - - npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT; - if (npend == 0) { + struct ath_hal_5416 *ahp = AH5416(ah); - if (REG_READ(ah, AR_Q_TXE) & (1 << q)) - npend = 1; + if (us < ATH9K_SLOT_TIME_9 || us > ath9k_hw_mac_to_usec(ah, 0xffff)) { + DPRINTF(ah->ah_sc, ATH_DBG_RESET, "bad slot time %u\n", us); + ahp->ah_slottime = (u32) -1; + return false; + } else { + REG_WRITE(ah, AR_D_GBL_IFS_SLOT, ath9k_hw_mac_to_clks(ah, us)); + ahp->ah_slottime = us; + return true; } - return npend; } -bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) +void ath9k_hw_set11nmac2040(struct ath_hal *ah, enum ath9k_ht_macmode mode) { - u32 wait; - - REG_WRITE(ah, AR_Q_TXD, 1 << q); - - for (wait = 1000; wait != 0; wait--) { - if (ath9k_hw_numtxpending(ah, q) == 0) - break; - udelay(100); - } - - if (ath9k_hw_numtxpending(ah, q)) { - u32 tsfLow, j; - - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: Num of pending TX Frames %d on Q %d\n", - __func__, ath9k_hw_numtxpending(ah, q), q); - - for (j = 0; j < 2; j++) { - tsfLow = REG_READ(ah, AR_TSF_L32); - REG_WRITE(ah, AR_QUIET2, - SM(10, AR_QUIET2_QUIET_DUR)); - REG_WRITE(ah, AR_QUIET_PERIOD, 100); - REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10); - REG_SET_BIT(ah, AR_TIMER_MODE, - AR_QUIET_TIMER_EN); - - if ((REG_READ(ah, AR_TSF_L32) >> 10) == - (tsfLow >> 10)) { - break; - } - DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, - "%s: TSF have moved while trying to set " - "quiet time TSF: 0x%08x\n", - __func__, tsfLow); - } - - REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); - - udelay(200); - REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN); - - wait = 1000; - - while (ath9k_hw_numtxpending(ah, q)) { - if ((--wait) == 0) { - DPRINTF(ah->ah_sc, ATH_DBG_XMIT, - "%s: Failed to stop Tx DMA in 100 " - "msec after killing last frame\n", - __func__); - break; - } - udelay(100); - } + u32 macmode; - REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); - } + if (mode == ATH9K_HT_MACMODE_2040 && + !ah->ah_config.cwm_ignore_extcca) + macmode = AR_2040_JOINED_RX_CLEAR; + else + macmode = 0; - REG_WRITE(ah, AR_Q_TXD, 0); - return wait != 0; + REG_WRITE(ah, AR_2040_MODE, macmode); } diff --git a/drivers/net/wireless/ath9k/hw.h b/drivers/net/wireless/ath9k/hw.h index 2113818ee9348dffdd4cc2334c85abac662d4683..91d8f594af813a9d1d5100ea117c4ffef0e841d7 100644 --- a/drivers/net/wireless/ath9k/hw.h +++ b/drivers/net/wireless/ath9k/hw.h @@ -415,6 +415,9 @@ struct ar5416Stats { #define AR5416_EEP_MINOR_VER_3 0x3 #define AR5416_EEP_MINOR_VER_7 0x7 #define AR5416_EEP_MINOR_VER_9 0x9 +#define AR5416_EEP_MINOR_VER_16 0x10 +#define AR5416_EEP_MINOR_VER_17 0x11 +#define AR5416_EEP_MINOR_VER_19 0x13 #define AR5416_NUM_5G_CAL_PIERS 8 #define AR5416_NUM_2G_CAL_PIERS 4 @@ -436,6 +439,27 @@ struct ar5416Stats { #define AR5416_MAX_CHAINS 3 #define AR5416_PWR_TABLE_OFFSET -5 +/* Rx gain type values */ +#define AR5416_EEP_RXGAIN_23DB_BACKOFF 0 +#define AR5416_EEP_RXGAIN_13DB_BACKOFF 1 +#define AR5416_EEP_RXGAIN_ORIG 2 + +/* Tx gain type values */ +#define AR5416_EEP_TXGAIN_ORIGINAL 0 +#define AR5416_EEP_TXGAIN_HIGH_POWER 1 + +#define AR5416_EEP4K_START_LOC 64 +#define AR5416_EEP4K_NUM_2G_CAL_PIERS 3 +#define AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_2G_20_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_2G_40_TARGET_POWERS 3 +#define AR5416_EEP4K_NUM_CTLS 12 +#define AR5416_EEP4K_NUM_BAND_EDGES 4 +#define AR5416_EEP4K_NUM_PD_GAINS 2 +#define AR5416_EEP4K_PD_GAINS_IN_MASK 4 +#define AR5416_EEP4K_PD_GAIN_ICEPTS 5 +#define AR5416_EEP4K_MAX_CHAINS 1 + enum eeprom_param { EEP_NFTHRESH_5, EEP_NFTHRESH_2, @@ -454,6 +478,8 @@ enum eeprom_param { EEP_MINOR_REV, EEP_TX_MASK, EEP_RX_MASK, + EEP_RXGAIN_TYPE, + EEP_TXGAIN_TYPE, }; enum ar5416_rates { @@ -469,6 +495,11 @@ enum ar5416_rates { Ar5416RateSize }; +enum ath9k_hal_freq_band { + ATH9K_HAL_FREQ_BAND_5GHZ = 0, + ATH9K_HAL_FREQ_BAND_2GHZ = 1 +}; + struct base_eep_header { u16 length; u16 checksum; @@ -485,9 +516,32 @@ struct base_eep_header { u32 binBuildNumber; u8 deviceType; u8 pwdclkind; - u8 futureBase[32]; + u8 futureBase_1[2]; + u8 rxGainType; + u8 futureBase_2[3]; + u8 txGainType; + u8 futureBase_3[25]; +} __packed; + +struct base_eep_header_4k { + u16 length; + u16 checksum; + u16 version; + u8 opCapFlags; + u8 eepMisc; + u16 regDmn[2]; + u8 macAddr[6]; + u8 rxMask; + u8 txMask; + u16 rfSilent; + u16 blueToothOptions; + u16 deviceCap; + u32 binBuildNumber; + u8 deviceType; + u8 futureBase[1]; } __packed; + struct spur_chan { u16 spurChan; u8 spurRangeLow; @@ -540,11 +594,58 @@ struct modal_eep_header { struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; } __packed; +struct modal_eep_4k_header { + u32 antCtrlChain[AR5416_EEP4K_MAX_CHAINS]; + u32 antCtrlCommon; + u8 antennaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 switchSettling; + u8 txRxAttenCh[AR5416_EEP4K_MAX_CHAINS]; + u8 rxTxMarginCh[AR5416_EEP4K_MAX_CHAINS]; + u8 adcDesiredSize; + u8 pgaDesiredSize; + u8 xlnaGainCh[AR5416_EEP4K_MAX_CHAINS]; + u8 txEndToXpaOff; + u8 txEndToRxOn; + u8 txFrameToXpaOn; + u8 thresh62; + u8 noiseFloorThreshCh[AR5416_EEP4K_MAX_CHAINS]; + u8 xpdGain; + u8 xpd; + u8 iqCalICh[AR5416_EEP4K_MAX_CHAINS]; + u8 iqCalQCh[AR5416_EEP4K_MAX_CHAINS]; + u8 pdGainOverlap; + u8 ob_01; + u8 db1_01; + u8 xpaBiasLvl; + u8 txFrameToDataStart; + u8 txFrameToPaOn; + u8 ht40PowerIncForPdadc; + u8 bswAtten[AR5416_EEP4K_MAX_CHAINS]; + u8 bswMargin[AR5416_EEP4K_MAX_CHAINS]; + u8 swSettleHt40; + u8 xatten2Db[AR5416_EEP4K_MAX_CHAINS]; + u8 xatten2Margin[AR5416_EEP4K_MAX_CHAINS]; + u8 db2_01; + u8 version; + u16 ob_234; + u16 db1_234; + u16 db2_234; + u8 futureModal[4]; + + struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS]; +} __packed; + + struct cal_data_per_freq { u8 pwrPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; u8 vpdPdg[AR5416_NUM_PD_GAINS][AR5416_PD_GAIN_ICEPTS]; } __packed; +struct cal_data_per_freq_4k { + u8 pwrPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; + u8 vpdPdg[AR5416_EEP4K_NUM_PD_GAINS][AR5416_EEP4K_PD_GAIN_ICEPTS]; +} __packed; + struct cal_target_power_leg { u8 bChannel; u8 tPow2x[4]; @@ -555,6 +656,7 @@ struct cal_target_power_ht { u8 tPow2x[8]; } __packed; + #ifdef __BIG_ENDIAN_BITFIELD struct cal_ctl_edges { u8 bChannel; @@ -569,10 +671,15 @@ struct cal_ctl_edges { struct cal_ctl_data { struct cal_ctl_edges - ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; + ctlEdges[AR5416_MAX_CHAINS][AR5416_NUM_BAND_EDGES]; } __packed; -struct ar5416_eeprom { +struct cal_ctl_data_4k { + struct cal_ctl_edges + ctlEdges[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_BAND_EDGES]; +} __packed; + +struct ar5416_eeprom_def { struct base_eep_header baseEepHeader; u8 custData[64]; struct modal_eep_header modalHeader[2]; @@ -601,6 +708,26 @@ struct ar5416_eeprom { u8 padding; } __packed; +struct ar5416_eeprom_4k { + struct base_eep_header_4k baseEepHeader; + u8 custData[20]; + struct modal_eep_4k_header modalHeader; + u8 calFreqPier2G[AR5416_EEP4K_NUM_2G_CAL_PIERS]; + struct cal_data_per_freq_4k + calPierData2G[AR5416_EEP4K_MAX_CHAINS][AR5416_EEP4K_NUM_2G_CAL_PIERS]; + struct cal_target_power_leg + calTargetPowerCck[AR5416_EEP4K_NUM_2G_CCK_TARGET_POWERS]; + struct cal_target_power_leg + calTargetPower2G[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT20[AR5416_EEP4K_NUM_2G_20_TARGET_POWERS]; + struct cal_target_power_ht + calTargetPower2GHT40[AR5416_EEP4K_NUM_2G_40_TARGET_POWERS]; + u8 ctlIndex[AR5416_EEP4K_NUM_CTLS]; + struct cal_ctl_data_4k ctlData[AR5416_EEP4K_NUM_CTLS]; + u8 padding; +} __packed; + struct ar5416IniArray { u32 *ia_array; u32 ia_rows; @@ -668,9 +795,22 @@ struct hal_cal_list { struct hal_cal_list *calNext; }; +/* + * Enum to indentify the eeprom mappings + */ +enum hal_eep_map { + EEP_MAP_DEFAULT = 0x0, + EEP_MAP_4KBITS, + EEP_MAP_MAX +}; + + struct ath_hal_5416 { struct ath_hal ah; - struct ar5416_eeprom ah_eeprom; + union { + struct ar5416_eeprom_def def; + struct ar5416_eeprom_4k map4k; + } ah_eeprom; struct ar5416Stats ah_stats; struct ath9k_tx_queue_info ah_txq[ATH9K_NUM_TX_QUEUES]; void __iomem *ah_cal_mem; @@ -792,6 +932,10 @@ struct ath_hal_5416 { struct ar5416IniArray ah_iniAddac; struct ar5416IniArray ah_iniPcieSerdes; struct ar5416IniArray ah_iniModesAdditional; + struct ar5416IniArray ah_iniModesRxGain; + struct ar5416IniArray ah_iniModesTxGain; + /* To indicate EEPROM mapping used */ + enum hal_eep_map ah_eep_map; }; #define AH5416(_ah) ((struct ath_hal_5416 *)(_ah)) @@ -833,13 +977,20 @@ struct ath_hal_5416 { (AR_SREV_9100(ah)) ? 0x1fff1000 : 0x503f1200 #define AR5416_EEPROM_MAX 0xae0 #define ar5416_get_eep_ver(_ahp) \ - (((_ahp)->ah_eeprom.baseEepHeader.version >> 12) & 0xF) + (((_ahp)->ah_eeprom.def.baseEepHeader.version >> 12) & 0xF) #define ar5416_get_eep_rev(_ahp) \ - (((_ahp)->ah_eeprom.baseEepHeader.version) & 0xFFF) + (((_ahp)->ah_eeprom.def.baseEepHeader.version) & 0xFFF) #define ar5416_get_ntxchains(_txchainmask) \ (((_txchainmask >> 2) & 1) + \ ((_txchainmask >> 1) & 1) + (_txchainmask & 1)) +/* EEPROM 4K bit map definations */ +#define ar5416_get_eep4k_ver(_ahp) \ + (((_ahp)->ah_eeprom.map4k.baseEepHeader.version >> 12) & 0xF) +#define ar5416_get_eep4k_rev(_ahp) \ + (((_ahp)->ah_eeprom.map4k.baseEepHeader.version) & 0xFFF) + + #ifdef __BIG_ENDIAN #define AR5416_EEPROM_MAGIC 0x5aa5 #else @@ -923,7 +1074,7 @@ struct ath_hal_5416 { #define OFDM_PLCP_BITS_QUARTER 22 #define OFDM_SYMBOL_TIME_QUARTER 16 -u32 ath9k_hw_get_eeprom(struct ath_hal_5416 *ahp, +u32 ath9k_hw_get_eeprom(struct ath_hal *ah, enum eeprom_param param); #endif diff --git a/drivers/net/wireless/ath9k/initvals.h b/drivers/net/wireless/ath9k/initvals.h index 3dd3815940a4efa7a72ba083718d787086166706..f3cfa16525e42d029c98be3d8d681a4bd39a2096 100644 --- a/drivers/net/wireless/ath9k/initvals.h +++ b/drivers/net/wireless/ath9k/initvals.h @@ -14,6 +14,7 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ +/* AR5416 to Fowl ar5146.ini */ static const u32 ar5416Modes_9100[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -31,17 +32,17 @@ static const u32 ar5416Modes_9100[][6] = { { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6de8b4e0, 0x6de8b4e0, 0x6de8b0de, 0x6de8b0de, 0x6de8b0de }, + { 0x00009850, 0x6c48b4e0, 0x6c48b4e0, 0x6c48b0de, 0x6c48b0de, 0x6c48b0de }, { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, { 0x00009860, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18, 0x00049d18 }, { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 }, { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, { 0x00009918, 0x000001b8, 0x00000370, 0x00000268, 0x00000134, 0x00000134 }, { 0x00009924, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b, 0xd0058a0b }, - { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, + { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, { 0x00009960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, { 0x0000a960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, { 0x0000b960, 0x00000900, 0x00000900, 0x00012d80, 0x00012d80, 0x00012d80 }, @@ -207,7 +208,7 @@ static const u32 ar5416Common_9100[][2] = { { 0x00008134, 0x00000000 }, { 0x00008138, 0x00000000 }, { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, + { 0x00008144, 0xffffffff }, { 0x00008168, 0x00000000 }, { 0x0000816c, 0x00000000 }, { 0x00008170, 0x32143320 }, @@ -266,7 +267,7 @@ static const u32 ar5416Common_9100[][2] = { { 0x0000832c, 0x00000007 }, { 0x00008330, 0x00000302 }, { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, + { 0x00008338, 0x00070000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x000107ff }, { 0x00009808, 0x00000000 }, @@ -661,6 +662,7 @@ static const u32 ar5416Addac_9100[][2] = { {0x000098c4, 0x00000000 }, }; +/* ar5416 - howl ar5416_howl.ini */ static const u32 ar5416Modes[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -952,7 +954,7 @@ static const u32 ar5416Common[][2] = { { 0x0000994c, 0x00020028 }, { 0x0000c95c, 0x004b6a8e }, { 0x0000c968, 0x000003ce }, - { 0x00009970, 0x190fb514 }, + { 0x00009970, 0x190fb515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, { 0x0000997c, 0x00000000 }, @@ -1311,7 +1313,7 @@ static const u32 ar5416Addac[][2] = { {0x000098cc, 0x00000000 }, }; - +/* AR5416 9160 Sowl ar5416_sowl.ini */ static const u32 ar5416Modes_9160[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -1329,21 +1331,22 @@ static const u32 ar5416Modes_9160[][6] = { { 0x00009848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000a848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, { 0x0000b848, 0x001a6a65, 0x001a6a65, 0x00197a68, 0x00197a68, 0x00197a68 }, - { 0x00009850, 0x6d48b4e2, 0x6d48b4e2, 0x6d48b0e2, 0x6d48b0e2, 0x6d48b0e2 }, + { 0x00009850, 0x6c48b4e2, 0x6c48b4e2, 0x6c48b0e2, 0x6c48b0e2, 0x6c48b0e2 }, { 0x00009858, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e, 0x7ec82d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e, 0x31395d5e }, { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, { 0x0000c864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0, 0x409a40d0 }, { 0x0000986c, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009944, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020, 0xdfb81020 }, + { 0x00009944, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020, 0xffb81020 }, { 0x00009960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x0000a960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x0000b960, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40, 0x00009b40 }, { 0x00009964, 0x00001120, 0x00001120, 0x00001120, 0x00001120, 0x00001120 }, + { 0x0000c968, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce, 0x000003ce }, { 0x0000c9bc, 0x001a0600, 0x001a0600, 0x001a0c00, 0x001a0c00, 0x001a0c00 }, { 0x000099c0, 0x038919be, 0x038919be, 0x038919be, 0x038919be, 0x038919be }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, @@ -1505,7 +1508,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x00008134, 0x00000000 }, { 0x00008138, 0x00000000 }, { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, + { 0x00008144, 0xffffffff }, { 0x00008168, 0x00000000 }, { 0x0000816c, 0x00000000 }, { 0x00008170, 0x32143320 }, @@ -1564,7 +1567,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x0000832c, 0x00000007 }, { 0x00008330, 0x00000302 }, { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, + { 0x00008338, 0x00ff0000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x000107ff }, { 0x00009808, 0x00000000 }, @@ -1597,7 +1600,6 @@ static const u32 ar5416Common_9160[][2] = { { 0x00009958, 0x2108ecff }, { 0x00009940, 0x00750604 }, { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, { 0x00009970, 0x190fb515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, @@ -1699,7 +1701,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x0000a244, 0x00007bb6 }, { 0x0000a248, 0x0fff3ffc }, { 0x0000a24c, 0x00000001 }, - { 0x0000a250, 0x0000a000 }, + { 0x0000a250, 0x0000e000 }, { 0x0000a254, 0x00000000 }, { 0x0000a258, 0x0cc75380 }, { 0x0000a25c, 0x0f0f0f01 }, @@ -1719,7 +1721,7 @@ static const u32 ar5416Common_9160[][2] = { { 0x0000a34c, 0x3fffffff }, { 0x0000a350, 0x3fffffff }, { 0x0000a354, 0x0003ffff }, - { 0x0000a358, 0x79a8aa33 }, + { 0x0000a358, 0x79bfaa03 }, { 0x0000d35c, 0x07ffffef }, { 0x0000d360, 0x0fffffe7 }, { 0x0000d364, 0x17ffffe5 }, @@ -1842,7 +1844,6 @@ static const u32 ar5416Bank3_9160[][3] = { }; static const u32 ar5416Bank6_9160[][3] = { - { 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 }, { 0x0000989c, 0x00000000, 0x00000000 }, @@ -1920,7 +1921,6 @@ static const u32 ar5416Bank7_9160[][2] = { { 0x000098cc, 0x0000000e }, }; - static u32 ar5416Addac_9160[][2] = { {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, @@ -1956,7 +1956,6 @@ static u32 ar5416Addac_9160[][2] = { {0x000098cc, 0x00000000 }, }; - static u32 ar5416Addac_91601_1[][2] = { {0x0000989c, 0x00000000 }, {0x0000989c, 0x00000000 }, @@ -1992,8 +1991,7 @@ static u32 ar5416Addac_91601_1[][2] = { {0x000098cc, 0x00000000 }, }; - - +/* XXX 9280 1 */ static const u32 ar9280Modes_9280[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -2543,9 +2541,7 @@ static const u32 ar9280Common_9280[][2] = { { 0x00007898, 0x2a850160 }, }; - - - +/* XXX 9280 2 */ static const u32 ar9280Modes_9280_2[][6] = { { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, @@ -2560,26 +2556,24 @@ static const u32 ar9280Modes_9280_2[][6] = { { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, - { 0x00009840, 0x206a012e, 0x206a012e, 0x206a022e, 0x206a022e, 0x206a022e }, + { 0x00009840, 0x206a022e, 0x206a022e, 0x206a012e, 0x206a012e, 0x206a012e }, { 0x00009844, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0, 0x037216a0 }, - { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, - { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, - { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, - { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec88d2e, 0x7ec88d2e, 0x7ec88d2e }, - { 0x0000985c, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e }, + { 0x00009850, 0x6c4000e2, 0x6c4000e2, 0x6d4000e2, 0x6c4000e2, 0x6c4000e2 }, + { 0x00009858, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x31395d5e, 0x31395d5e, 0x3139605e, 0x31395d5e, 0x31395d5e }, { 0x00009860, 0x00048d18, 0x00048d18, 0x00048d20, 0x00048d20, 0x00048d18 }, - { 0x0000c864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009864, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, - { 0x00009914, 0x000007d0, 0x000007d0, 0x00000898, 0x00000898, 0x000007d0 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, - { 0x00009924, 0xd00a8a07, 0xd00a8a07, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, - { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010, 0xdfbc1010 }, + { 0x00009924, 0xd00a8a0b, 0xd00a8a0b, 0xd00a8a0d, 0xd00a8a0d, 0xd00a8a0d }, + { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010, 0xffbc1010 }, { 0x00009960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, { 0x0000a960, 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 }, { 0x00009964, 0x00000210, 0x00000210, 0x00000210, 0x00000210, 0x00000210 }, - { 0x0000c9b8, 0x0000000f, 0x0000000f, 0x0000001c, 0x0000001c, 0x0000001c }, - { 0x0000c9bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099b8, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c, 0x0000001c }, + { 0x000099bc, 0x00000a00, 0x00000a00, 0x00000c00, 0x00000c00, 0x00000c00 }, { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, @@ -2587,164 +2581,13 @@ static const u32 ar9280Modes_9280_2[][6] = { { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, - { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, - { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, - { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, - { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, - { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, - { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, - { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, - { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, - { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, - { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, - { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, - { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, - { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, - { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, - { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, - { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, - { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, - { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, - { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, - { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, - { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, - { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, - { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, - { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, - { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, - { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, - { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, - { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, - { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, - { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, - { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, - { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, - { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, - { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, - { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, - { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, - { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, - { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, - { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, - { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, - { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, - { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, - { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, - { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, - { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, - { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, - { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, - { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, - { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, - { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, - { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, - { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, - { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, - { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, - { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, - { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, - { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, - { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c }, - { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 }, - { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 }, - { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 }, - { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 }, - { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 }, - { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 }, - { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 }, - { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 }, - { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 }, - { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 }, - { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 }, - { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 }, - { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c }, - { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 }, - { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 }, - { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 }, - { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 }, - { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 }, - { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 }, - { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 }, - { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 }, - { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad }, - { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 }, - { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 }, - { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 }, - { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 }, - { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 }, - { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 }, - { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 }, - { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 }, - { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 }, - { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca }, - { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce }, - { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 }, - { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 }, - { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 }, - { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 }, - { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb }, - { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf }, - { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 }, - { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, - { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, { 0x0000a204, 0x00000444, 0x00000444, 0x00000444, 0x00000444, 0x00000444 }, - { 0x0000a208, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788, 0x803e4788 }, { 0x0000a20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, { 0x0000b20c, 0x00000014, 0x00000014, 0x0001f019, 0x0001f019, 0x0001f019 }, - { 0x0000a21c, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a, 0x1463800a }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, - { 0x0000a250, 0x001ff000, 0x001ff000, 0x001da000, 0x001da000, 0x001da000 }, + { 0x0000a250, 0x001ff000, 0x001ff000, 0x0004a000, 0x0004a000, 0x0004a000 }, { 0x0000a274, 0x0a19c652, 0x0a19c652, 0x0a1aa652, 0x0a1aa652, 0x0a1aa652 }, - { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, - { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 }, - { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 }, - { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b }, - { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 }, - { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 }, - { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a }, - { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 }, - { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, - { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b }, - { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 }, - { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 }, - { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a }, - { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 }, - { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b }, - { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 }, - { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 }, - { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a }, - { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 }, - { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a }, - { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 }, - { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 }, { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, { 0x0000a3d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, { 0x00007894, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000, 0x5a508000 }, @@ -2884,7 +2727,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008134, 0x00000000 }, { 0x00008138, 0x00000000 }, { 0x0000813c, 0x00000000 }, - { 0x00008144, 0x00000000 }, + { 0x00008144, 0xffffffff }, { 0x00008168, 0x00000000 }, { 0x0000816c, 0x00000000 }, { 0x00008170, 0x32143320 }, @@ -2923,6 +2766,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00008258, 0x00000000 }, { 0x0000825c, 0x400000ff }, { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, { 0x00008270, 0x00000000 }, { 0x00008274, 0x40000000 }, { 0x00008278, 0x003e4180 }, @@ -2939,7 +2783,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000832c, 0x00000007 }, { 0x00008330, 0x00000302 }, { 0x00008334, 0x00000e00 }, - { 0x00008338, 0x00000000 }, + { 0x00008338, 0x00ff0000 }, { 0x0000833c, 0x00000000 }, { 0x00008340, 0x000107ff }, { 0x00008344, 0x00581043 }, @@ -2973,7 +2817,7 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00009958, 0x2108ecff }, { 0x00009940, 0x14750604 }, { 0x0000c95c, 0x004b6a8e }, - { 0x0000c968, 0x000003ce }, + { 0x00009968, 0x000003ce }, { 0x00009970, 0x190fb515 }, { 0x00009974, 0x00000000 }, { 0x00009978, 0x00000001 }, @@ -2999,13 +2843,14 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x000099ec, 0x0cc80caa }, { 0x000099f0, 0x00000000 }, { 0x000099fc, 0x00001042 }, + { 0x0000a208, 0x803e4788 }, { 0x0000a210, 0x4080a333 }, { 0x0000a214, 0x40206c10 }, { 0x0000a218, 0x009c4060 }, { 0x0000a220, 0x01834061 }, { 0x0000a224, 0x00000400 }, { 0x0000a228, 0x000003b5 }, - { 0x0000a22c, 0x233f71c0 }, + { 0x0000a22c, 0x233f7180 }, { 0x0000a234, 0x20202020 }, { 0x0000a238, 0x20202020 }, { 0x0000a23c, 0x13c88000 }, @@ -3022,7 +2867,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000b26c, 0x0ebae9c6 }, { 0x0000d270, 0x00820820 }, { 0x0000a278, 0x1ce739ce }, - { 0x0000a27c, 0x050701ce }, { 0x0000d35c, 0x07ffffef }, { 0x0000d360, 0x0fffffe7 }, { 0x0000d364, 0x17ffffe5 }, @@ -3064,7 +2908,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x00007808, 0x04924914 }, { 0x0000780c, 0x21084210 }, { 0x00007810, 0x6d801300 }, - { 0x00007814, 0x0019beff }, { 0x00007818, 0x07e41000 }, { 0x0000781c, 0x00392000 }, { 0x00007820, 0x92592480 }, @@ -3073,7 +2916,6 @@ static const u32 ar9280Common_9280_2[][2] = { { 0x0000782c, 0x04924914 }, { 0x00007830, 0x21084210 }, { 0x00007834, 0x6d801300 }, - { 0x00007838, 0x0019beff }, { 0x0000783c, 0x07e40000 }, { 0x00007840, 0x00392000 }, { 0x00007844, 0x92592480 }, @@ -3110,36 +2952,1850 @@ static const u32 ar9280Modes_fast_clock_9280_2[][3] = { { 0x00009828, 0x0b020001, 0x0b020001 }, { 0x00009834, 0x00000f0f, 0x00000f0f }, { 0x00009844, 0x03721821, 0x03721821 }, - { 0x00009914, 0x00000898, 0x00000898 }, + { 0x00009914, 0x00000898, 0x00001130 }, { 0x00009918, 0x0000000b, 0x00000016 }, { 0x00009944, 0xdfbc1210, 0xdfbc1210 }, }; - - -static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { - {0x00004040, 0x9248fd00 }, - {0x00004040, 0x24924924 }, - {0x00004040, 0xa8000019 }, - {0x00004040, 0x13160820 }, - {0x00004040, 0xe5980560 }, - {0x00004040, 0x401dcffc }, - {0x00004040, 0x1aaabe40 }, - {0x00004040, 0xbe105554 }, - {0x00004040, 0x00043007 }, - {0x00004044, 0x00000000 }, +static const u32 ar9280Modes_backoff_23db_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b10, 0x00008b10, 0x00008b10 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b14, 0x00008b14, 0x00008b14 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b01, 0x00008b01, 0x00008b01 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b05, 0x00008b05, 0x00008b05 }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b09, 0x00008b09, 0x00008b09 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008b0d, 0x00008b0d, 0x00008b0d }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008b11, 0x00008b11, 0x00008b11 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008b15, 0x00008b15, 0x00008b15 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008b02, 0x00008b02, 0x00008b02 }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008b06, 0x00008b06, 0x00008b06 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00008b0a, 0x00008b0a, 0x00008b0a }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00008b0e, 0x00008b0e, 0x00008b0e }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00008b12, 0x00008b12, 0x00008b12 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00008b16, 0x00008b16, 0x00008b16 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00008b03, 0x00008b03, 0x00008b03 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x00008b07, 0x00008b07, 0x00008b07 }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x00008b0b, 0x00008b0b, 0x00008b0b }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x00008b0f, 0x00008b0f, 0x00008b0f }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00008b13, 0x00008b13, 0x00008b13 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00008b17, 0x00008b17, 0x00008b17 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00008b23, 0x00008b23, 0x00008b23 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x00008b27, 0x00008b27, 0x00008b27 }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00008b2b, 0x00008b2b, 0x00008b2b }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00008b2f, 0x00008b2f, 0x00008b2f }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00008b33, 0x00008b33, 0x00008b33 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x00008b37, 0x00008b37, 0x00008b37 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x00008b43, 0x00008b43, 0x00008b43 }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x00008b47, 0x00008b47, 0x00008b47 }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00008b4b, 0x00008b4b, 0x00008b4b }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00008b4f, 0x00008b4f, 0x00008b4f }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00008b53, 0x00008b53, 0x00008b53 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00008b57, 0x00008b57, 0x00008b57 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x00008b5b, 0x00008b5b, 0x00008b5b }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001050, 0x00001050, 0x00001050 }, }; - - -static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { +static const u32 ar9280Modes_original_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x0000930c, 0x0000930c, 0x0000930c }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009310, 0x00009310, 0x00009310 }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009384, 0x00009384, 0x00009384 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009388, 0x00009388, 0x00009388 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009324, 0x00009324, 0x00009324 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x00009704, 0x00009704, 0x00009704 }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x000096a4, 0x000096a4, 0x000096a4 }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x000096a8, 0x000096a8, 0x000096a8 }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009710, 0x00009710, 0x00009710 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009714, 0x00009714, 0x00009714 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009720, 0x00009720, 0x00009720 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x00009724, 0x00009724, 0x00009724 }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009728, 0x00009728, 0x00009728 }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x0000972c, 0x0000972c, 0x0000972c }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x000097a0, 0x000097a0, 0x000097a0 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x000097a4, 0x000097a4, 0x000097a4 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x000097a8, 0x000097a8, 0x000097a8 }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x000097b0, 0x000097b0, 0x000097b0 }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x000097b4, 0x000097b4, 0x000097b4 }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x000097b8, 0x000097b8, 0x000097b8 }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x000097a5, 0x000097a5, 0x000097a5 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x000097a9, 0x000097a9, 0x000097a9 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x000097ad, 0x000097ad, 0x000097ad }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x000097b1, 0x000097b1, 0x000097b1 }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x000097b5, 0x000097b5, 0x000097b5 }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x000097b9, 0x000097b9, 0x000097b9 }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x000097c5, 0x000097c5, 0x000097c5 }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x000097c9, 0x000097c9, 0x000097c9 }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x000097d1, 0x000097d1, 0x000097d1 }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x000097d5, 0x000097d5, 0x000097d5 }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x000097d9, 0x000097d9, 0x000097d9 }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x000097c6, 0x000097c6, 0x000097c6 }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x000097ca, 0x000097ca, 0x000097ca }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x000097ce, 0x000097ce, 0x000097ce }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x000097d2, 0x000097d2, 0x000097d2 }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x000097d6, 0x000097d6, 0x000097d6 }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x000097c3, 0x000097c3, 0x000097c3 }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x000097c7, 0x000097c7, 0x000097c7 }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x000097cb, 0x000097cb, 0x000097cb }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x000097cf, 0x000097cf, 0x000097cf }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x000097d7, 0x000097d7, 0x000097d7 }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x000097db, 0x000097db, 0x000097db }, + { 0x00009848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, + { 0x0000a848, 0x00001066, 0x00001066, 0x00001063, 0x00001063, 0x00001063 }, +}; + +static const u32 ar9280Modes_backoff_13db_rxgain_9280_2[][6] = { + { 0x00009a00, 0x00008184, 0x00008184, 0x00000290, 0x00000290, 0x00000290 }, + { 0x00009a04, 0x00008188, 0x00008188, 0x00000300, 0x00000300, 0x00000300 }, + { 0x00009a08, 0x0000818c, 0x0000818c, 0x00000304, 0x00000304, 0x00000304 }, + { 0x00009a0c, 0x00008190, 0x00008190, 0x00000308, 0x00000308, 0x00000308 }, + { 0x00009a10, 0x00008194, 0x00008194, 0x0000030c, 0x0000030c, 0x0000030c }, + { 0x00009a14, 0x00008200, 0x00008200, 0x00008000, 0x00008000, 0x00008000 }, + { 0x00009a18, 0x00008204, 0x00008204, 0x00008004, 0x00008004, 0x00008004 }, + { 0x00009a1c, 0x00008208, 0x00008208, 0x00008008, 0x00008008, 0x00008008 }, + { 0x00009a20, 0x0000820c, 0x0000820c, 0x0000800c, 0x0000800c, 0x0000800c }, + { 0x00009a24, 0x00008210, 0x00008210, 0x00008080, 0x00008080, 0x00008080 }, + { 0x00009a28, 0x00008214, 0x00008214, 0x00008084, 0x00008084, 0x00008084 }, + { 0x00009a2c, 0x00008280, 0x00008280, 0x00008088, 0x00008088, 0x00008088 }, + { 0x00009a30, 0x00008284, 0x00008284, 0x0000808c, 0x0000808c, 0x0000808c }, + { 0x00009a34, 0x00008288, 0x00008288, 0x00008100, 0x00008100, 0x00008100 }, + { 0x00009a38, 0x0000828c, 0x0000828c, 0x00008104, 0x00008104, 0x00008104 }, + { 0x00009a3c, 0x00008290, 0x00008290, 0x00008108, 0x00008108, 0x00008108 }, + { 0x00009a40, 0x00008300, 0x00008300, 0x0000810c, 0x0000810c, 0x0000810c }, + { 0x00009a44, 0x00008304, 0x00008304, 0x00008110, 0x00008110, 0x00008110 }, + { 0x00009a48, 0x00008308, 0x00008308, 0x00008114, 0x00008114, 0x00008114 }, + { 0x00009a4c, 0x0000830c, 0x0000830c, 0x00008180, 0x00008180, 0x00008180 }, + { 0x00009a50, 0x00008310, 0x00008310, 0x00008184, 0x00008184, 0x00008184 }, + { 0x00009a54, 0x00008314, 0x00008314, 0x00008188, 0x00008188, 0x00008188 }, + { 0x00009a58, 0x00008380, 0x00008380, 0x0000818c, 0x0000818c, 0x0000818c }, + { 0x00009a5c, 0x00008384, 0x00008384, 0x00008190, 0x00008190, 0x00008190 }, + { 0x00009a60, 0x00008388, 0x00008388, 0x00008194, 0x00008194, 0x00008194 }, + { 0x00009a64, 0x0000838c, 0x0000838c, 0x000081a0, 0x000081a0, 0x000081a0 }, + { 0x00009a68, 0x00008390, 0x00008390, 0x0000820c, 0x0000820c, 0x0000820c }, + { 0x00009a6c, 0x00008394, 0x00008394, 0x000081a8, 0x000081a8, 0x000081a8 }, + { 0x00009a70, 0x0000a380, 0x0000a380, 0x00008284, 0x00008284, 0x00008284 }, + { 0x00009a74, 0x0000a384, 0x0000a384, 0x00008288, 0x00008288, 0x00008288 }, + { 0x00009a78, 0x0000a388, 0x0000a388, 0x00008224, 0x00008224, 0x00008224 }, + { 0x00009a7c, 0x0000a38c, 0x0000a38c, 0x00008290, 0x00008290, 0x00008290 }, + { 0x00009a80, 0x0000a390, 0x0000a390, 0x00008300, 0x00008300, 0x00008300 }, + { 0x00009a84, 0x0000a394, 0x0000a394, 0x00008304, 0x00008304, 0x00008304 }, + { 0x00009a88, 0x0000a780, 0x0000a780, 0x00008308, 0x00008308, 0x00008308 }, + { 0x00009a8c, 0x0000a784, 0x0000a784, 0x0000830c, 0x0000830c, 0x0000830c }, + { 0x00009a90, 0x0000a788, 0x0000a788, 0x00008380, 0x00008380, 0x00008380 }, + { 0x00009a94, 0x0000a78c, 0x0000a78c, 0x00008384, 0x00008384, 0x00008384 }, + { 0x00009a98, 0x0000a790, 0x0000a790, 0x00008700, 0x00008700, 0x00008700 }, + { 0x00009a9c, 0x0000a794, 0x0000a794, 0x00008704, 0x00008704, 0x00008704 }, + { 0x00009aa0, 0x0000ab84, 0x0000ab84, 0x00008708, 0x00008708, 0x00008708 }, + { 0x00009aa4, 0x0000ab88, 0x0000ab88, 0x0000870c, 0x0000870c, 0x0000870c }, + { 0x00009aa8, 0x0000ab8c, 0x0000ab8c, 0x00008780, 0x00008780, 0x00008780 }, + { 0x00009aac, 0x0000ab90, 0x0000ab90, 0x00008784, 0x00008784, 0x00008784 }, + { 0x00009ab0, 0x0000ab94, 0x0000ab94, 0x00008b00, 0x00008b00, 0x00008b00 }, + { 0x00009ab4, 0x0000af80, 0x0000af80, 0x00008b04, 0x00008b04, 0x00008b04 }, + { 0x00009ab8, 0x0000af84, 0x0000af84, 0x00008b08, 0x00008b08, 0x00008b08 }, + { 0x00009abc, 0x0000af88, 0x0000af88, 0x00008b0c, 0x00008b0c, 0x00008b0c }, + { 0x00009ac0, 0x0000af8c, 0x0000af8c, 0x00008b80, 0x00008b80, 0x00008b80 }, + { 0x00009ac4, 0x0000af90, 0x0000af90, 0x00008b84, 0x00008b84, 0x00008b84 }, + { 0x00009ac8, 0x0000af94, 0x0000af94, 0x00008b88, 0x00008b88, 0x00008b88 }, + { 0x00009acc, 0x0000b380, 0x0000b380, 0x00008b8c, 0x00008b8c, 0x00008b8c }, + { 0x00009ad0, 0x0000b384, 0x0000b384, 0x00008b90, 0x00008b90, 0x00008b90 }, + { 0x00009ad4, 0x0000b388, 0x0000b388, 0x00008f80, 0x00008f80, 0x00008f80 }, + { 0x00009ad8, 0x0000b38c, 0x0000b38c, 0x00008f84, 0x00008f84, 0x00008f84 }, + { 0x00009adc, 0x0000b390, 0x0000b390, 0x00008f88, 0x00008f88, 0x00008f88 }, + { 0x00009ae0, 0x0000b394, 0x0000b394, 0x00008f8c, 0x00008f8c, 0x00008f8c }, + { 0x00009ae4, 0x0000b398, 0x0000b398, 0x00008f90, 0x00008f90, 0x00008f90 }, + { 0x00009ae8, 0x0000b780, 0x0000b780, 0x00009310, 0x00009310, 0x00009310 }, + { 0x00009aec, 0x0000b784, 0x0000b784, 0x00009314, 0x00009314, 0x00009314 }, + { 0x00009af0, 0x0000b788, 0x0000b788, 0x00009320, 0x00009320, 0x00009320 }, + { 0x00009af4, 0x0000b78c, 0x0000b78c, 0x00009324, 0x00009324, 0x00009324 }, + { 0x00009af8, 0x0000b790, 0x0000b790, 0x00009328, 0x00009328, 0x00009328 }, + { 0x00009afc, 0x0000b794, 0x0000b794, 0x0000932c, 0x0000932c, 0x0000932c }, + { 0x00009b00, 0x0000b798, 0x0000b798, 0x00009330, 0x00009330, 0x00009330 }, + { 0x00009b04, 0x0000d784, 0x0000d784, 0x00009334, 0x00009334, 0x00009334 }, + { 0x00009b08, 0x0000d788, 0x0000d788, 0x00009321, 0x00009321, 0x00009321 }, + { 0x00009b0c, 0x0000d78c, 0x0000d78c, 0x00009325, 0x00009325, 0x00009325 }, + { 0x00009b10, 0x0000d790, 0x0000d790, 0x00009329, 0x00009329, 0x00009329 }, + { 0x00009b14, 0x0000f780, 0x0000f780, 0x0000932d, 0x0000932d, 0x0000932d }, + { 0x00009b18, 0x0000f784, 0x0000f784, 0x00009331, 0x00009331, 0x00009331 }, + { 0x00009b1c, 0x0000f788, 0x0000f788, 0x00009335, 0x00009335, 0x00009335 }, + { 0x00009b20, 0x0000f78c, 0x0000f78c, 0x00009322, 0x00009322, 0x00009322 }, + { 0x00009b24, 0x0000f790, 0x0000f790, 0x00009326, 0x00009326, 0x00009326 }, + { 0x00009b28, 0x0000f794, 0x0000f794, 0x0000932a, 0x0000932a, 0x0000932a }, + { 0x00009b2c, 0x0000f7a4, 0x0000f7a4, 0x0000932e, 0x0000932e, 0x0000932e }, + { 0x00009b30, 0x0000f7a8, 0x0000f7a8, 0x00009332, 0x00009332, 0x00009332 }, + { 0x00009b34, 0x0000f7ac, 0x0000f7ac, 0x00009336, 0x00009336, 0x00009336 }, + { 0x00009b38, 0x0000f7b0, 0x0000f7b0, 0x00009323, 0x00009323, 0x00009323 }, + { 0x00009b3c, 0x0000f7b4, 0x0000f7b4, 0x00009327, 0x00009327, 0x00009327 }, + { 0x00009b40, 0x0000f7a1, 0x0000f7a1, 0x0000932b, 0x0000932b, 0x0000932b }, + { 0x00009b44, 0x0000f7a5, 0x0000f7a5, 0x0000932f, 0x0000932f, 0x0000932f }, + { 0x00009b48, 0x0000f7a9, 0x0000f7a9, 0x00009333, 0x00009333, 0x00009333 }, + { 0x00009b4c, 0x0000f7ad, 0x0000f7ad, 0x00009337, 0x00009337, 0x00009337 }, + { 0x00009b50, 0x0000f7b1, 0x0000f7b1, 0x00009343, 0x00009343, 0x00009343 }, + { 0x00009b54, 0x0000f7b5, 0x0000f7b5, 0x00009347, 0x00009347, 0x00009347 }, + { 0x00009b58, 0x0000f7c5, 0x0000f7c5, 0x0000934b, 0x0000934b, 0x0000934b }, + { 0x00009b5c, 0x0000f7c9, 0x0000f7c9, 0x0000934f, 0x0000934f, 0x0000934f }, + { 0x00009b60, 0x0000f7cd, 0x0000f7cd, 0x00009353, 0x00009353, 0x00009353 }, + { 0x00009b64, 0x0000f7d1, 0x0000f7d1, 0x00009357, 0x00009357, 0x00009357 }, + { 0x00009b68, 0x0000f7d5, 0x0000f7d5, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b6c, 0x0000f7c2, 0x0000f7c2, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b70, 0x0000f7c6, 0x0000f7c6, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b74, 0x0000f7ca, 0x0000f7ca, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b78, 0x0000f7ce, 0x0000f7ce, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b7c, 0x0000f7d2, 0x0000f7d2, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b80, 0x0000f7d6, 0x0000f7d6, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b84, 0x0000f7c3, 0x0000f7c3, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b88, 0x0000f7c7, 0x0000f7c7, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b8c, 0x0000f7cb, 0x0000f7cb, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b90, 0x0000f7d3, 0x0000f7d3, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b94, 0x0000f7d7, 0x0000f7d7, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b98, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009b9c, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009ba8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bac, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bb8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bbc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bc8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bcc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bd8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bdc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009be8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bec, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf0, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf4, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bf8, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009bfc, 0x0000f7db, 0x0000f7db, 0x0000935b, 0x0000935b, 0x0000935b }, + { 0x00009848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a }, + { 0x0000a848, 0x00001066, 0x00001066, 0x0000105a, 0x0000105a, 0x0000105a }, +}; + +static const u32 ar9280Modes_high_power_tx_gain_9280_2[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00003002, 0x00003002, 0x00004002, 0x00004002, 0x00004002 }, + { 0x0000a308, 0x00006004, 0x00006004, 0x00007008, 0x00007008, 0x00007008 }, + { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000c010, 0x0000c010, 0x0000c010 }, + { 0x0000a310, 0x0000e012, 0x0000e012, 0x00010012, 0x00010012, 0x00010012 }, + { 0x0000a314, 0x00011014, 0x00011014, 0x00013014, 0x00013014, 0x00013014 }, + { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001820a, 0x0001820a, 0x0001820a }, + { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001b211, 0x0001b211, 0x0001b211 }, + { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, + { 0x0000a324, 0x00020092, 0x00020092, 0x00022411, 0x00022411, 0x00022411 }, + { 0x0000a328, 0x0002410a, 0x0002410a, 0x00025413, 0x00025413, 0x00025413 }, + { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00029811, 0x00029811, 0x00029811 }, + { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002c813, 0x0002c813, 0x0002c813 }, + { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030a14, 0x00030a14, 0x00030a14 }, + { 0x0000a338, 0x000321ec, 0x000321ec, 0x00035a50, 0x00035a50, 0x00035a50 }, + { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00039c4c, 0x00039c4c, 0x00039c4c }, + { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003de8a, 0x0003de8a, 0x0003de8a }, + { 0x0000a344, 0x000321ec, 0x000321ec, 0x00042e92, 0x00042e92, 0x00042e92 }, + { 0x0000a348, 0x000321ec, 0x000321ec, 0x00046ed2, 0x00046ed2, 0x00046ed2 }, + { 0x0000a34c, 0x000321ec, 0x000321ec, 0x0004bed5, 0x0004bed5, 0x0004bed5 }, + { 0x0000a350, 0x000321ec, 0x000321ec, 0x0004ff54, 0x0004ff54, 0x0004ff54 }, + { 0x0000a354, 0x000321ec, 0x000321ec, 0x00053fd5, 0x00053fd5, 0x00053fd5 }, + { 0x00007814, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, + { 0x00007838, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff, 0x00198eff }, + { 0x0000a27c, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce, 0x050739ce }, +}; + +static const u32 ar9280Modes_original_tx_gain_9280_2[][6] = { + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00003002, 0x00003002, 0x00003002, 0x00003002, 0x00003002 }, + { 0x0000a308, 0x00006004, 0x00006004, 0x00008009, 0x00008009, 0x00008009 }, + { 0x0000a30c, 0x0000a006, 0x0000a006, 0x0000b00b, 0x0000b00b, 0x0000b00b }, + { 0x0000a310, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012, 0x0000e012 }, + { 0x0000a314, 0x00011014, 0x00011014, 0x00012048, 0x00012048, 0x00012048 }, + { 0x0000a318, 0x0001504a, 0x0001504a, 0x0001604a, 0x0001604a, 0x0001604a }, + { 0x0000a31c, 0x0001904c, 0x0001904c, 0x0001a211, 0x0001a211, 0x0001a211 }, + { 0x0000a320, 0x0001c04e, 0x0001c04e, 0x0001e213, 0x0001e213, 0x0001e213 }, + { 0x0000a324, 0x00020092, 0x00020092, 0x0002121b, 0x0002121b, 0x0002121b }, + { 0x0000a328, 0x0002410a, 0x0002410a, 0x00024412, 0x00024412, 0x00024412 }, + { 0x0000a32c, 0x0002710c, 0x0002710c, 0x00028414, 0x00028414, 0x00028414 }, + { 0x0000a330, 0x0002b18b, 0x0002b18b, 0x0002b44a, 0x0002b44a, 0x0002b44a }, + { 0x0000a334, 0x0002e1cc, 0x0002e1cc, 0x00030649, 0x00030649, 0x00030649 }, + { 0x0000a338, 0x000321ec, 0x000321ec, 0x0003364b, 0x0003364b, 0x0003364b }, + { 0x0000a33c, 0x000321ec, 0x000321ec, 0x00038a49, 0x00038a49, 0x00038a49 }, + { 0x0000a340, 0x000321ec, 0x000321ec, 0x0003be48, 0x0003be48, 0x0003be48 }, + { 0x0000a344, 0x000321ec, 0x000321ec, 0x0003ee4a, 0x0003ee4a, 0x0003ee4a }, + { 0x0000a348, 0x000321ec, 0x000321ec, 0x00042e88, 0x00042e88, 0x00042e88 }, + { 0x0000a34c, 0x000321ec, 0x000321ec, 0x00046e8a, 0x00046e8a, 0x00046e8a }, + { 0x0000a350, 0x000321ec, 0x000321ec, 0x00049ec9, 0x00049ec9, 0x00049ec9 }, + { 0x0000a354, 0x000321ec, 0x000321ec, 0x0004bf42, 0x0004bf42, 0x0004bf42 }, + { 0x00007814, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, + { 0x00007838, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff, 0x0019beff }, + { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce }, +}; + +static const u32 ar9280PciePhy_clkreq_off_L1_9280[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u32 ar9280PciePhy_clkreq_always_on_L1_9280[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +/* AR9285 */ +static const u_int32_t ar9285Modes_9285[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 }, + { 0x00009848, 0x00001066, 0x00001066, 0x0000004e, 0x0000004e, 0x00001059 }, + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e }, + { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, + { 0x00009944, 0xdfbc1010, 0xdfbc1010, 0xdfbc1020, 0xdfbc1020, 0xdfbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099b8, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c, 0x00cf4d1c }, + { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 }, + { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 }, + { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 }, + { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x001ff000, 0x001ff000, 0x001ca000, 0x001ca000, 0x001da000 }, + { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 }, + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002c89a, 0x0002c89a, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002e89b, 0x0002e89b, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0003089c, 0x0003089c, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0003289d, 0x0003289d, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0003489e, 0x0003489e, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x000388de, 0x000388de, 0x00000000 }, + { 0x0000a338, 0x00000000, 0x00000000, 0x0003b91e, 0x0003b91e, 0x00000000 }, + { 0x0000a33c, 0x00000000, 0x00000000, 0x0003d95e, 0x0003d95e, 0x00000000 }, + { 0x0000a340, 0x00000000, 0x00000000, 0x000419df, 0x000419df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, +}; + +static const u_int32_t ar9285Common_9285[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020045 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000031 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0x00000000 }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000001 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00000000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x00010380 }, + { 0x00008344, 0x00581043 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x01002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009940, 0x14750604 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x1927b515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x2def0a00 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x0000a208, 0x803e6788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x00206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0ccb5380 }, + { 0x0000a25c, 0x15151501 }, + { 0x0000a260, 0xdfa90f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9e6 }, + { 0x0000d270, 0x0d820820 }, + { 0x0000a278, 0x39ce739c }, + { 0x0000a27c, 0x050e039c }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x39ce739c }, + { 0x0000a398, 0x0000039c }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x39ce739c }, + { 0x0000a3e0, 0x0000039c }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x00007800, 0x00140000 }, + { 0x00007804, 0x0e4548d8 }, + { 0x00007808, 0x54214514 }, + { 0x0000780c, 0x02025820 }, + { 0x00007810, 0x71c0d388 }, + { 0x00007814, 0x924934a8 }, + { 0x0000781c, 0x00000000 }, + { 0x00007820, 0x00000c04 }, + { 0x00007824, 0x00d86fff }, + { 0x00007828, 0x26d2491b }, + { 0x0000782c, 0x6e36d97b }, + { 0x00007830, 0xedb6d96c }, + { 0x00007834, 0x71400086 }, + { 0x00007838, 0xfac68800 }, + { 0x0000783c, 0x0001fffe }, + { 0x00007840, 0xffeb1a20 }, + { 0x00007844, 0x000c0db6 }, + { 0x00007848, 0x6db61b6f }, + { 0x0000784c, 0x6d9b66db }, + { 0x00007850, 0x6d8c6dba }, + { 0x00007854, 0x00040000 }, + { 0x00007858, 0xdb003012 }, + { 0x0000785c, 0x04924914 }, + { 0x00007860, 0x21084210 }, + { 0x00007864, 0xf7d7ffde }, + { 0x00007868, 0xc2034080 }, + { 0x0000786c, 0x48609eb4 }, + { 0x00007870, 0x10142c00 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9285Modes_9285_1_2[][6] = { + { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 }, + { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 }, + { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 }, + { 0x000010f0, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000008 }, + { 0x00008014, 0x03e803e8, 0x07d007d0, 0x10801600, 0x08400b00, 0x06e006e0 }, + { 0x0000801c, 0x128d8027, 0x128d804f, 0x12e00057, 0x12e0002b, 0x0988004f }, + { 0x00008318, 0x00003e80, 0x00007d00, 0x00006880, 0x00003440, 0x00006880 }, + { 0x00009804, 0x00000300, 0x000003c4, 0x000003c4, 0x00000300, 0x00000303 }, + { 0x00009820, 0x02020200, 0x02020200, 0x02020200, 0x02020200, 0x02020200 }, + { 0x00009824, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009828, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001, 0x0a020001 }, + { 0x00009834, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e }, + { 0x00009838, 0x00000007, 0x00000007, 0x00000007, 0x00000007, 0x00000007 }, + { 0x00009840, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e, 0x206a012e }, + { 0x00009844, 0x0372161e, 0x0372161e, 0x03720020, 0x03720020, 0x037216a0 }, + { 0x00009848, 0x00001066, 0x00001066, 0x00000057, 0x00000057, 0x00001059 }, + { 0x00009850, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2, 0x6d4000e2 }, + { 0x00009858, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e, 0x7ec84d2e }, + { 0x0000985c, 0x3139605e, 0x3139605e, 0x3136605e, 0x3136605e, 0x3139605e }, + { 0x00009860, 0x00058d18, 0x00058d18, 0x00058d20, 0x00058d20, 0x00058d18 }, + { 0x00009864, 0x0000fe00, 0x0000fe00, 0x0001ce00, 0x0001ce00, 0x0001ce00 }, + { 0x00009868, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0, 0x5ac640d0 }, + { 0x0000986c, 0x06903081, 0x06903081, 0x06903881, 0x06903881, 0x06903881 }, + { 0x00009914, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898, 0x000007d0 }, + { 0x00009918, 0x0000000a, 0x00000014, 0x00000016, 0x0000000b, 0x00000016 }, + { 0x00009924, 0xd00a8007, 0xd00a8007, 0xd00a800d, 0xd00a800d, 0xd00a800d }, + { 0x00009944, 0xffbc1010, 0xffbc1010, 0xffbc1020, 0xffbc1020, 0xffbc1010 }, + { 0x00009960, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009964, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099b8, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c, 0x0000421c }, + { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 }, + { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 }, + { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 }, + { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 }, + { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 }, + { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 }, + { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x000099d8, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00009a00, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x00009a04, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x00009a08, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x00009a0c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x00009a10, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x00009a14, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x00009a18, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x00009a1c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x00009a20, 0x00000000, 0x00000000, 0x00068114, 0x00068114, 0x00000000 }, + { 0x00009a24, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x00009a28, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x00009a2c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x00009a30, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x00009a34, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x00009a38, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x00009a3c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x00009a40, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x00009a44, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x00009a48, 0x00000000, 0x00000000, 0x00068284, 0x00068284, 0x00000000 }, + { 0x00009a4c, 0x00000000, 0x00000000, 0x00068288, 0x00068288, 0x00000000 }, + { 0x00009a50, 0x00000000, 0x00000000, 0x00068220, 0x00068220, 0x00000000 }, + { 0x00009a54, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x00009a58, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x00009a5c, 0x00000000, 0x00000000, 0x00068304, 0x00068304, 0x00000000 }, + { 0x00009a60, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x00009a64, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x00009a68, 0x00000000, 0x00000000, 0x00068380, 0x00068380, 0x00000000 }, + { 0x00009a6c, 0x00000000, 0x00000000, 0x00068384, 0x00068384, 0x00000000 }, + { 0x00009a70, 0x00000000, 0x00000000, 0x00068700, 0x00068700, 0x00000000 }, + { 0x00009a74, 0x00000000, 0x00000000, 0x00068704, 0x00068704, 0x00000000 }, + { 0x00009a78, 0x00000000, 0x00000000, 0x00068708, 0x00068708, 0x00000000 }, + { 0x00009a7c, 0x00000000, 0x00000000, 0x0006870c, 0x0006870c, 0x00000000 }, + { 0x00009a80, 0x00000000, 0x00000000, 0x00068780, 0x00068780, 0x00000000 }, + { 0x00009a84, 0x00000000, 0x00000000, 0x00068784, 0x00068784, 0x00000000 }, + { 0x00009a88, 0x00000000, 0x00000000, 0x00068b04, 0x00068b04, 0x00000000 }, + { 0x00009a8c, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a90, 0x00000000, 0x00000000, 0x00068b08, 0x00068b08, 0x00000000 }, + { 0x00009a94, 0x00000000, 0x00000000, 0x00068b0c, 0x00068b0c, 0x00000000 }, + { 0x00009a98, 0x00000000, 0x00000000, 0x00068b80, 0x00068b80, 0x00000000 }, + { 0x00009a9c, 0x00000000, 0x00000000, 0x00068b84, 0x00068b84, 0x00000000 }, + { 0x00009aa0, 0x00000000, 0x00000000, 0x00068b88, 0x00068b88, 0x00000000 }, + { 0x00009aa4, 0x00000000, 0x00000000, 0x00068b8c, 0x00068b8c, 0x00000000 }, + { 0x00009aa8, 0x00000000, 0x00000000, 0x000b8b90, 0x000b8b90, 0x00000000 }, + { 0x00009aac, 0x00000000, 0x00000000, 0x000b8f80, 0x000b8f80, 0x00000000 }, + { 0x00009ab0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x00009ab4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x00009ab8, 0x00000000, 0x00000000, 0x000b8f8c, 0x000b8f8c, 0x00000000 }, + { 0x00009abc, 0x00000000, 0x00000000, 0x000b8f90, 0x000b8f90, 0x00000000 }, + { 0x00009ac0, 0x00000000, 0x00000000, 0x000bb30c, 0x000bb30c, 0x00000000 }, + { 0x00009ac4, 0x00000000, 0x00000000, 0x000bb310, 0x000bb310, 0x00000000 }, + { 0x00009ac8, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x00009acc, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x00009ad0, 0x00000000, 0x00000000, 0x000bb324, 0x000bb324, 0x00000000 }, + { 0x00009ad4, 0x00000000, 0x00000000, 0x000bb704, 0x000bb704, 0x00000000 }, + { 0x00009ad8, 0x00000000, 0x00000000, 0x000f96a4, 0x000f96a4, 0x00000000 }, + { 0x00009adc, 0x00000000, 0x00000000, 0x000f96a8, 0x000f96a8, 0x00000000 }, + { 0x00009ae0, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x00009ae4, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x00009ae8, 0x00000000, 0x00000000, 0x000f9720, 0x000f9720, 0x00000000 }, + { 0x00009aec, 0x00000000, 0x00000000, 0x000f9724, 0x000f9724, 0x00000000 }, + { 0x00009af0, 0x00000000, 0x00000000, 0x000f9728, 0x000f9728, 0x00000000 }, + { 0x00009af4, 0x00000000, 0x00000000, 0x000f972c, 0x000f972c, 0x00000000 }, + { 0x00009af8, 0x00000000, 0x00000000, 0x000f97a0, 0x000f97a0, 0x00000000 }, + { 0x00009afc, 0x00000000, 0x00000000, 0x000f97a4, 0x000f97a4, 0x00000000 }, + { 0x00009b00, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x00009b04, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x00009b08, 0x00000000, 0x00000000, 0x000fb7b4, 0x000fb7b4, 0x00000000 }, + { 0x00009b0c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x00009b10, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x00009b14, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x00009b18, 0x00000000, 0x00000000, 0x000fb7ad, 0x000fb7ad, 0x00000000 }, + { 0x00009b1c, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x00009b20, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x00009b24, 0x00000000, 0x00000000, 0x000fb7b9, 0x000fb7b9, 0x00000000 }, + { 0x00009b28, 0x00000000, 0x00000000, 0x000fb7c5, 0x000fb7c5, 0x00000000 }, + { 0x00009b2c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x00009b30, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x00009b34, 0x00000000, 0x00000000, 0x000fb7d5, 0x000fb7d5, 0x00000000 }, + { 0x00009b38, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x00009b3c, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x00009b40, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x00009b44, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x00009b48, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x00009b4c, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x00009b50, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x00009b54, 0x00000000, 0x00000000, 0x000fb7c7, 0x000fb7c7, 0x00000000 }, + { 0x00009b58, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x00009b5c, 0x00000000, 0x00000000, 0x000fb7cf, 0x000fb7cf, 0x00000000 }, + { 0x00009b60, 0x00000000, 0x00000000, 0x000fb7d7, 0x000fb7d7, 0x00000000 }, + { 0x00009b64, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b68, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b6c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b70, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b74, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b78, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b7c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b80, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b84, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b88, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b8c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b90, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b94, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b98, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009b9c, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009ba8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bac, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bb8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bbc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bc8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bcc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bd8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bdc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009be8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bec, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf0, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf4, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bf8, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x00009bfc, 0x00000000, 0x00000000, 0x000fb7db, 0x000fb7db, 0x00000000 }, + { 0x0000aa00, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa04, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa08, 0x00000000, 0x00000000, 0x0006801c, 0x0006801c, 0x00000000 }, + { 0x0000aa0c, 0x00000000, 0x00000000, 0x00068080, 0x00068080, 0x00000000 }, + { 0x0000aa10, 0x00000000, 0x00000000, 0x00068084, 0x00068084, 0x00000000 }, + { 0x0000aa14, 0x00000000, 0x00000000, 0x00068088, 0x00068088, 0x00000000 }, + { 0x0000aa18, 0x00000000, 0x00000000, 0x0006808c, 0x0006808c, 0x00000000 }, + { 0x0000aa1c, 0x00000000, 0x00000000, 0x00068100, 0x00068100, 0x00000000 }, + { 0x0000aa20, 0x00000000, 0x00000000, 0x00068104, 0x00068104, 0x00000000 }, + { 0x0000aa24, 0x00000000, 0x00000000, 0x00068108, 0x00068108, 0x00000000 }, + { 0x0000aa28, 0x00000000, 0x00000000, 0x0006810c, 0x0006810c, 0x00000000 }, + { 0x0000aa2c, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa30, 0x00000000, 0x00000000, 0x00068110, 0x00068110, 0x00000000 }, + { 0x0000aa34, 0x00000000, 0x00000000, 0x00068180, 0x00068180, 0x00000000 }, + { 0x0000aa38, 0x00000000, 0x00000000, 0x00068184, 0x00068184, 0x00000000 }, + { 0x0000aa3c, 0x00000000, 0x00000000, 0x00068188, 0x00068188, 0x00000000 }, + { 0x0000aa40, 0x00000000, 0x00000000, 0x0006818c, 0x0006818c, 0x00000000 }, + { 0x0000aa44, 0x00000000, 0x00000000, 0x00068190, 0x00068190, 0x00000000 }, + { 0x0000aa48, 0x00000000, 0x00000000, 0x00068194, 0x00068194, 0x00000000 }, + { 0x0000aa4c, 0x00000000, 0x00000000, 0x000681a0, 0x000681a0, 0x00000000 }, + { 0x0000aa50, 0x00000000, 0x00000000, 0x0006820c, 0x0006820c, 0x00000000 }, + { 0x0000aa54, 0x00000000, 0x00000000, 0x000681a8, 0x000681a8, 0x00000000 }, + { 0x0000aa58, 0x00000000, 0x00000000, 0x000681ac, 0x000681ac, 0x00000000 }, + { 0x0000aa5c, 0x00000000, 0x00000000, 0x0006821c, 0x0006821c, 0x00000000 }, + { 0x0000aa60, 0x00000000, 0x00000000, 0x00068224, 0x00068224, 0x00000000 }, + { 0x0000aa64, 0x00000000, 0x00000000, 0x00068290, 0x00068290, 0x00000000 }, + { 0x0000aa68, 0x00000000, 0x00000000, 0x00068300, 0x00068300, 0x00000000 }, + { 0x0000aa6c, 0x00000000, 0x00000000, 0x00068308, 0x00068308, 0x00000000 }, + { 0x0000aa70, 0x00000000, 0x00000000, 0x0006830c, 0x0006830c, 0x00000000 }, + { 0x0000aa74, 0x00000000, 0x00000000, 0x00068310, 0x00068310, 0x00000000 }, + { 0x0000aa78, 0x00000000, 0x00000000, 0x00068788, 0x00068788, 0x00000000 }, + { 0x0000aa7c, 0x00000000, 0x00000000, 0x0006878c, 0x0006878c, 0x00000000 }, + { 0x0000aa80, 0x00000000, 0x00000000, 0x00068790, 0x00068790, 0x00000000 }, + { 0x0000aa84, 0x00000000, 0x00000000, 0x00068794, 0x00068794, 0x00000000 }, + { 0x0000aa88, 0x00000000, 0x00000000, 0x00068798, 0x00068798, 0x00000000 }, + { 0x0000aa8c, 0x00000000, 0x00000000, 0x0006879c, 0x0006879c, 0x00000000 }, + { 0x0000aa90, 0x00000000, 0x00000000, 0x00068b89, 0x00068b89, 0x00000000 }, + { 0x0000aa94, 0x00000000, 0x00000000, 0x00068b8d, 0x00068b8d, 0x00000000 }, + { 0x0000aa98, 0x00000000, 0x00000000, 0x00068b91, 0x00068b91, 0x00000000 }, + { 0x0000aa9c, 0x00000000, 0x00000000, 0x00068b95, 0x00068b95, 0x00000000 }, + { 0x0000aaa0, 0x00000000, 0x00000000, 0x00068b99, 0x00068b99, 0x00000000 }, + { 0x0000aaa4, 0x00000000, 0x00000000, 0x00068ba5, 0x00068ba5, 0x00000000 }, + { 0x0000aaa8, 0x00000000, 0x00000000, 0x00068ba9, 0x00068ba9, 0x00000000 }, + { 0x0000aaac, 0x00000000, 0x00000000, 0x00068bad, 0x00068bad, 0x00000000 }, + { 0x0000aab0, 0x00000000, 0x00000000, 0x000b8b0c, 0x000b8b0c, 0x00000000 }, + { 0x0000aab4, 0x00000000, 0x00000000, 0x000b8f10, 0x000b8f10, 0x00000000 }, + { 0x0000aab8, 0x00000000, 0x00000000, 0x000b8f14, 0x000b8f14, 0x00000000 }, + { 0x0000aabc, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aac0, 0x00000000, 0x00000000, 0x000b8f84, 0x000b8f84, 0x00000000 }, + { 0x0000aac4, 0x00000000, 0x00000000, 0x000b8f88, 0x000b8f88, 0x00000000 }, + { 0x0000aac8, 0x00000000, 0x00000000, 0x000bb380, 0x000bb380, 0x00000000 }, + { 0x0000aacc, 0x00000000, 0x00000000, 0x000bb384, 0x000bb384, 0x00000000 }, + { 0x0000aad0, 0x00000000, 0x00000000, 0x000bb388, 0x000bb388, 0x00000000 }, + { 0x0000aad4, 0x00000000, 0x00000000, 0x000bb38c, 0x000bb38c, 0x00000000 }, + { 0x0000aad8, 0x00000000, 0x00000000, 0x000bb394, 0x000bb394, 0x00000000 }, + { 0x0000aadc, 0x00000000, 0x00000000, 0x000bb798, 0x000bb798, 0x00000000 }, + { 0x0000aae0, 0x00000000, 0x00000000, 0x000f970c, 0x000f970c, 0x00000000 }, + { 0x0000aae4, 0x00000000, 0x00000000, 0x000f9710, 0x000f9710, 0x00000000 }, + { 0x0000aae8, 0x00000000, 0x00000000, 0x000f9714, 0x000f9714, 0x00000000 }, + { 0x0000aaec, 0x00000000, 0x00000000, 0x000f9718, 0x000f9718, 0x00000000 }, + { 0x0000aaf0, 0x00000000, 0x00000000, 0x000f9705, 0x000f9705, 0x00000000 }, + { 0x0000aaf4, 0x00000000, 0x00000000, 0x000f9709, 0x000f9709, 0x00000000 }, + { 0x0000aaf8, 0x00000000, 0x00000000, 0x000f970d, 0x000f970d, 0x00000000 }, + { 0x0000aafc, 0x00000000, 0x00000000, 0x000f9711, 0x000f9711, 0x00000000 }, + { 0x0000ab00, 0x00000000, 0x00000000, 0x000f9715, 0x000f9715, 0x00000000 }, + { 0x0000ab04, 0x00000000, 0x00000000, 0x000f9719, 0x000f9719, 0x00000000 }, + { 0x0000ab08, 0x00000000, 0x00000000, 0x000fb7a4, 0x000fb7a4, 0x00000000 }, + { 0x0000ab0c, 0x00000000, 0x00000000, 0x000fb7a8, 0x000fb7a8, 0x00000000 }, + { 0x0000ab10, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab14, 0x00000000, 0x00000000, 0x000fb7ac, 0x000fb7ac, 0x00000000 }, + { 0x0000ab18, 0x00000000, 0x00000000, 0x000fb7b0, 0x000fb7b0, 0x00000000 }, + { 0x0000ab1c, 0x00000000, 0x00000000, 0x000fb7b8, 0x000fb7b8, 0x00000000 }, + { 0x0000ab20, 0x00000000, 0x00000000, 0x000fb7bc, 0x000fb7bc, 0x00000000 }, + { 0x0000ab24, 0x00000000, 0x00000000, 0x000fb7a1, 0x000fb7a1, 0x00000000 }, + { 0x0000ab28, 0x00000000, 0x00000000, 0x000fb7a5, 0x000fb7a5, 0x00000000 }, + { 0x0000ab2c, 0x00000000, 0x00000000, 0x000fb7a9, 0x000fb7a9, 0x00000000 }, + { 0x0000ab30, 0x00000000, 0x00000000, 0x000fb7b1, 0x000fb7b1, 0x00000000 }, + { 0x0000ab34, 0x00000000, 0x00000000, 0x000fb7b5, 0x000fb7b5, 0x00000000 }, + { 0x0000ab38, 0x00000000, 0x00000000, 0x000fb7bd, 0x000fb7bd, 0x00000000 }, + { 0x0000ab3c, 0x00000000, 0x00000000, 0x000fb7c9, 0x000fb7c9, 0x00000000 }, + { 0x0000ab40, 0x00000000, 0x00000000, 0x000fb7cd, 0x000fb7cd, 0x00000000 }, + { 0x0000ab44, 0x00000000, 0x00000000, 0x000fb7d1, 0x000fb7d1, 0x00000000 }, + { 0x0000ab48, 0x00000000, 0x00000000, 0x000fb7d9, 0x000fb7d9, 0x00000000 }, + { 0x0000ab4c, 0x00000000, 0x00000000, 0x000fb7c2, 0x000fb7c2, 0x00000000 }, + { 0x0000ab50, 0x00000000, 0x00000000, 0x000fb7c6, 0x000fb7c6, 0x00000000 }, + { 0x0000ab54, 0x00000000, 0x00000000, 0x000fb7ca, 0x000fb7ca, 0x00000000 }, + { 0x0000ab58, 0x00000000, 0x00000000, 0x000fb7ce, 0x000fb7ce, 0x00000000 }, + { 0x0000ab5c, 0x00000000, 0x00000000, 0x000fb7d2, 0x000fb7d2, 0x00000000 }, + { 0x0000ab60, 0x00000000, 0x00000000, 0x000fb7d6, 0x000fb7d6, 0x00000000 }, + { 0x0000ab64, 0x00000000, 0x00000000, 0x000fb7c3, 0x000fb7c3, 0x00000000 }, + { 0x0000ab68, 0x00000000, 0x00000000, 0x000fb7cb, 0x000fb7cb, 0x00000000 }, + { 0x0000ab6c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab70, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab74, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab78, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab7c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab80, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab84, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab88, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab8c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab90, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab94, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab98, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000ab9c, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000aba8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abac, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abb8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abbc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abc8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abcc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abd8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abdc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abe8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abec, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf0, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf4, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abf8, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000abfc, 0x00000000, 0x00000000, 0x000fb7d3, 0x000fb7d3, 0x00000000 }, + { 0x0000a204, 0x00000004, 0x00000004, 0x00000004, 0x00000004, 0x00000004 }, + { 0x0000a20c, 0x00000014, 0x00000014, 0x00000000, 0x00000000, 0x0001f000 }, + { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a }, + { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 }, + { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 }, + { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 }, + { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 }, + { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 }, + { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 }, + { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 }, + { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 }, + { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 }, + { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 }, + { 0x0000a320, 0x00000000, 0x00000000, 0x0002b89a, 0x0002b89a, 0x00000000 }, + { 0x0000a324, 0x00000000, 0x00000000, 0x0002d89b, 0x0002d89b, 0x00000000 }, + { 0x0000a328, 0x00000000, 0x00000000, 0x0002f89c, 0x0002f89c, 0x00000000 }, + { 0x0000a32c, 0x00000000, 0x00000000, 0x0003189d, 0x0003189d, 0x00000000 }, + { 0x0000a330, 0x00000000, 0x00000000, 0x0003389e, 0x0003389e, 0x00000000 }, + { 0x0000a334, 0x00000000, 0x00000000, 0x000368de, 0x000368de, 0x00000000 }, + { 0x0000a338, 0x00000000, 0x00000000, 0x0003891e, 0x0003891e, 0x00000000 }, + { 0x0000a33c, 0x00000000, 0x00000000, 0x0003a95e, 0x0003a95e, 0x00000000 }, + { 0x0000a340, 0x00000000, 0x00000000, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 }, + { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e }, +}; + +static const u_int32_t ar9285Common_9285_1_2[][2] = { + { 0x0000000c, 0x00000000 }, + { 0x00000030, 0x00020045 }, + { 0x00000034, 0x00000005 }, + { 0x00000040, 0x00000000 }, + { 0x00000044, 0x00000008 }, + { 0x00000048, 0x00000008 }, + { 0x0000004c, 0x00000010 }, + { 0x00000050, 0x00000000 }, + { 0x00000054, 0x0000001f }, + { 0x00000800, 0x00000000 }, + { 0x00000804, 0x00000000 }, + { 0x00000808, 0x00000000 }, + { 0x0000080c, 0x00000000 }, + { 0x00000810, 0x00000000 }, + { 0x00000814, 0x00000000 }, + { 0x00000818, 0x00000000 }, + { 0x0000081c, 0x00000000 }, + { 0x00000820, 0x00000000 }, + { 0x00000824, 0x00000000 }, + { 0x00001040, 0x002ffc0f }, + { 0x00001044, 0x002ffc0f }, + { 0x00001048, 0x002ffc0f }, + { 0x0000104c, 0x002ffc0f }, + { 0x00001050, 0x002ffc0f }, + { 0x00001054, 0x002ffc0f }, + { 0x00001058, 0x002ffc0f }, + { 0x0000105c, 0x002ffc0f }, + { 0x00001060, 0x002ffc0f }, + { 0x00001064, 0x002ffc0f }, + { 0x00001230, 0x00000000 }, + { 0x00001270, 0x00000000 }, + { 0x00001038, 0x00000000 }, + { 0x00001078, 0x00000000 }, + { 0x000010b8, 0x00000000 }, + { 0x000010f8, 0x00000000 }, + { 0x00001138, 0x00000000 }, + { 0x00001178, 0x00000000 }, + { 0x000011b8, 0x00000000 }, + { 0x000011f8, 0x00000000 }, + { 0x00001238, 0x00000000 }, + { 0x00001278, 0x00000000 }, + { 0x000012b8, 0x00000000 }, + { 0x000012f8, 0x00000000 }, + { 0x00001338, 0x00000000 }, + { 0x00001378, 0x00000000 }, + { 0x000013b8, 0x00000000 }, + { 0x000013f8, 0x00000000 }, + { 0x00001438, 0x00000000 }, + { 0x00001478, 0x00000000 }, + { 0x000014b8, 0x00000000 }, + { 0x000014f8, 0x00000000 }, + { 0x00001538, 0x00000000 }, + { 0x00001578, 0x00000000 }, + { 0x000015b8, 0x00000000 }, + { 0x000015f8, 0x00000000 }, + { 0x00001638, 0x00000000 }, + { 0x00001678, 0x00000000 }, + { 0x000016b8, 0x00000000 }, + { 0x000016f8, 0x00000000 }, + { 0x00001738, 0x00000000 }, + { 0x00001778, 0x00000000 }, + { 0x000017b8, 0x00000000 }, + { 0x000017f8, 0x00000000 }, + { 0x0000103c, 0x00000000 }, + { 0x0000107c, 0x00000000 }, + { 0x000010bc, 0x00000000 }, + { 0x000010fc, 0x00000000 }, + { 0x0000113c, 0x00000000 }, + { 0x0000117c, 0x00000000 }, + { 0x000011bc, 0x00000000 }, + { 0x000011fc, 0x00000000 }, + { 0x0000123c, 0x00000000 }, + { 0x0000127c, 0x00000000 }, + { 0x000012bc, 0x00000000 }, + { 0x000012fc, 0x00000000 }, + { 0x0000133c, 0x00000000 }, + { 0x0000137c, 0x00000000 }, + { 0x000013bc, 0x00000000 }, + { 0x000013fc, 0x00000000 }, + { 0x0000143c, 0x00000000 }, + { 0x0000147c, 0x00000000 }, + { 0x00004030, 0x00000002 }, + { 0x0000403c, 0x00000002 }, + { 0x00004024, 0x0000001f }, + { 0x00004060, 0x00000000 }, + { 0x00004064, 0x00000000 }, + { 0x00007010, 0x00000031 }, + { 0x00007034, 0x00000002 }, + { 0x00007038, 0x000004c2 }, + { 0x00008004, 0x00000000 }, + { 0x00008008, 0x00000000 }, + { 0x0000800c, 0x00000000 }, + { 0x00008018, 0x00000700 }, + { 0x00008020, 0x00000000 }, + { 0x00008038, 0x00000000 }, + { 0x0000803c, 0x00000000 }, + { 0x00008048, 0x00000000 }, + { 0x00008054, 0x00000000 }, + { 0x00008058, 0x00000000 }, + { 0x0000805c, 0x000fc78f }, + { 0x00008060, 0x0000000f }, + { 0x00008064, 0x00000000 }, + { 0x00008070, 0x00000000 }, + { 0x000080c0, 0x2a80001a }, + { 0x000080c4, 0x05dc01e0 }, + { 0x000080c8, 0x1f402710 }, + { 0x000080cc, 0x01f40000 }, + { 0x000080d0, 0x00001e00 }, + { 0x000080d4, 0x00000000 }, + { 0x000080d8, 0x00400000 }, + { 0x000080e0, 0xffffffff }, + { 0x000080e4, 0x0000ffff }, + { 0x000080e8, 0x003f3f3f }, + { 0x000080ec, 0x00000000 }, + { 0x000080f0, 0x00000000 }, + { 0x000080f4, 0x00000000 }, + { 0x000080f8, 0x00000000 }, + { 0x000080fc, 0x00020000 }, + { 0x00008100, 0x00020000 }, + { 0x00008104, 0x00000001 }, + { 0x00008108, 0x00000052 }, + { 0x0000810c, 0x00000000 }, + { 0x00008110, 0x00000168 }, + { 0x00008118, 0x000100aa }, + { 0x0000811c, 0x00003210 }, + { 0x00008120, 0x08f04800 }, + { 0x00008124, 0x00000000 }, + { 0x00008128, 0x00000000 }, + { 0x0000812c, 0x00000000 }, + { 0x00008130, 0x00000000 }, + { 0x00008134, 0x00000000 }, + { 0x00008138, 0x00000000 }, + { 0x0000813c, 0x00000000 }, + { 0x00008144, 0xffffffff }, + { 0x00008168, 0x00000000 }, + { 0x0000816c, 0x00000000 }, + { 0x00008170, 0x32143320 }, + { 0x00008174, 0xfaa4fa50 }, + { 0x00008178, 0x00000100 }, + { 0x0000817c, 0x00000000 }, + { 0x000081c0, 0x00000000 }, + { 0x000081d0, 0x00003210 }, + { 0x000081ec, 0x00000000 }, + { 0x000081f0, 0x00000000 }, + { 0x000081f4, 0x00000000 }, + { 0x000081f8, 0x00000000 }, + { 0x000081fc, 0x00000000 }, + { 0x00008200, 0x00000000 }, + { 0x00008204, 0x00000000 }, + { 0x00008208, 0x00000000 }, + { 0x0000820c, 0x00000000 }, + { 0x00008210, 0x00000000 }, + { 0x00008214, 0x00000000 }, + { 0x00008218, 0x00000000 }, + { 0x0000821c, 0x00000000 }, + { 0x00008220, 0x00000000 }, + { 0x00008224, 0x00000000 }, + { 0x00008228, 0x00000000 }, + { 0x0000822c, 0x00000000 }, + { 0x00008230, 0x00000000 }, + { 0x00008234, 0x00000000 }, + { 0x00008238, 0x00000000 }, + { 0x0000823c, 0x00000000 }, + { 0x00008240, 0x00100000 }, + { 0x00008244, 0x0010f400 }, + { 0x00008248, 0x00000100 }, + { 0x0000824c, 0x0001e800 }, + { 0x00008250, 0x00000000 }, + { 0x00008254, 0x00000000 }, + { 0x00008258, 0x00000000 }, + { 0x0000825c, 0x400000ff }, + { 0x00008260, 0x00080922 }, + { 0x00008264, 0xa8a00010 }, + { 0x00008270, 0x00000000 }, + { 0x00008274, 0x40000000 }, + { 0x00008278, 0x003e4180 }, + { 0x0000827c, 0x00000000 }, + { 0x00008284, 0x0000002c }, + { 0x00008288, 0x0000002c }, + { 0x0000828c, 0x00000000 }, + { 0x00008294, 0x00000000 }, + { 0x00008298, 0x00000000 }, + { 0x0000829c, 0x00000000 }, + { 0x00008300, 0x00000040 }, + { 0x00008314, 0x00000000 }, + { 0x00008328, 0x00000000 }, + { 0x0000832c, 0x00000001 }, + { 0x00008330, 0x00000302 }, + { 0x00008334, 0x00000e00 }, + { 0x00008338, 0x00ff0000 }, + { 0x0000833c, 0x00000000 }, + { 0x00008340, 0x00010380 }, + { 0x00008344, 0x00581043 }, + { 0x00009808, 0x00000000 }, + { 0x0000980c, 0xafe68e30 }, + { 0x00009810, 0xfd14e000 }, + { 0x00009814, 0x9c0a9f6b }, + { 0x0000981c, 0x00000000 }, + { 0x0000982c, 0x0000a000 }, + { 0x00009830, 0x00000000 }, + { 0x0000983c, 0x00200400 }, + { 0x0000984c, 0x0040233c }, + { 0x00009854, 0x00000044 }, + { 0x00009900, 0x00000000 }, + { 0x00009904, 0x00000000 }, + { 0x00009908, 0x00000000 }, + { 0x0000990c, 0x00000000 }, + { 0x00009910, 0x01002310 }, + { 0x0000991c, 0x10000fff }, + { 0x00009920, 0x04900000 }, + { 0x00009928, 0x00000001 }, + { 0x0000992c, 0x00000004 }, + { 0x00009934, 0x1e1f2022 }, + { 0x00009938, 0x0a0b0c0d }, + { 0x0000993c, 0x00000000 }, + { 0x00009940, 0x14750604 }, + { 0x00009948, 0x9280c00a }, + { 0x0000994c, 0x00020028 }, + { 0x00009954, 0x5f3ca3de }, + { 0x00009958, 0x2108ecff }, + { 0x00009968, 0x000003ce }, + { 0x00009970, 0x192bb515 }, + { 0x00009974, 0x00000000 }, + { 0x00009978, 0x00000001 }, + { 0x0000997c, 0x00000000 }, + { 0x00009980, 0x00000000 }, + { 0x00009984, 0x00000000 }, + { 0x00009988, 0x00000000 }, + { 0x0000998c, 0x00000000 }, + { 0x00009990, 0x00000000 }, + { 0x00009994, 0x00000000 }, + { 0x00009998, 0x00000000 }, + { 0x0000999c, 0x00000000 }, + { 0x000099a0, 0x00000000 }, + { 0x000099a4, 0x00000001 }, + { 0x000099a8, 0x201fff00 }, + { 0x000099ac, 0x2def1000 }, + { 0x000099b0, 0x03051000 }, + { 0x000099b4, 0x00000820 }, + { 0x000099dc, 0x00000000 }, + { 0x000099e0, 0x00000000 }, + { 0x000099e4, 0xaaaaaaaa }, + { 0x000099e8, 0x3c466478 }, + { 0x000099ec, 0x0cc80caa }, + { 0x000099f0, 0x00000000 }, + { 0x0000a208, 0x803e6788 }, + { 0x0000a210, 0x4080a333 }, + { 0x0000a214, 0x00206c10 }, + { 0x0000a218, 0x009c4060 }, + { 0x0000a220, 0x01834061 }, + { 0x0000a224, 0x00000400 }, + { 0x0000a228, 0x000003b5 }, + { 0x0000a22c, 0x00000000 }, + { 0x0000a234, 0x20202020 }, + { 0x0000a238, 0x20202020 }, + { 0x0000a244, 0x00000000 }, + { 0x0000a248, 0xfffffffc }, + { 0x0000a24c, 0x00000000 }, + { 0x0000a254, 0x00000000 }, + { 0x0000a258, 0x0ccb5380 }, + { 0x0000a25c, 0x15151501 }, + { 0x0000a260, 0xdfa90f01 }, + { 0x0000a268, 0x00000000 }, + { 0x0000a26c, 0x0ebae9e6 }, + { 0x0000d270, 0x0d820820 }, + { 0x0000a278, 0x318c6318 }, + { 0x0000a27c, 0x050c0318 }, + { 0x0000d35c, 0x07ffffef }, + { 0x0000d360, 0x0fffffe7 }, + { 0x0000d364, 0x17ffffe5 }, + { 0x0000d368, 0x1fffffe4 }, + { 0x0000d36c, 0x37ffffe3 }, + { 0x0000d370, 0x3fffffe3 }, + { 0x0000d374, 0x57ffffe3 }, + { 0x0000d378, 0x5fffffe2 }, + { 0x0000d37c, 0x7fffffe2 }, + { 0x0000d380, 0x7f3c7bba }, + { 0x0000d384, 0xf3307ff0 }, + { 0x0000a388, 0x0c000000 }, + { 0x0000a38c, 0x20202020 }, + { 0x0000a390, 0x20202020 }, + { 0x0000a394, 0x318c6318 }, + { 0x0000a398, 0x00000318 }, + { 0x0000a39c, 0x00000001 }, + { 0x0000a3a0, 0x00000000 }, + { 0x0000a3a4, 0x00000000 }, + { 0x0000a3a8, 0x00000000 }, + { 0x0000a3ac, 0x00000000 }, + { 0x0000a3b0, 0x00000000 }, + { 0x0000a3b4, 0x00000000 }, + { 0x0000a3b8, 0x00000000 }, + { 0x0000a3bc, 0x00000000 }, + { 0x0000a3c0, 0x00000000 }, + { 0x0000a3c4, 0x00000000 }, + { 0x0000a3cc, 0x20202020 }, + { 0x0000a3d0, 0x20202020 }, + { 0x0000a3d4, 0x20202020 }, + { 0x0000a3dc, 0x318c6318 }, + { 0x0000a3e0, 0x00000318 }, + { 0x0000a3e4, 0x00000000 }, + { 0x0000a3e8, 0x18c43433 }, + { 0x0000a3ec, 0x00f70081 }, + { 0x00007800, 0x00140000 }, + { 0x00007804, 0x0e4548d8 }, + { 0x00007808, 0x54214514 }, + { 0x0000780c, 0x02025820 }, + { 0x00007810, 0x71c0d388 }, + { 0x00007814, 0x924934a8 }, + { 0x0000781c, 0x00000000 }, + { 0x00007820, 0x00000c04 }, + { 0x00007824, 0x00d86fff }, + { 0x00007828, 0x26d2491b }, + { 0x0000782c, 0x6e36d97b }, + { 0x00007830, 0xedb6d96e }, + { 0x00007834, 0x71400087 }, + { 0x00007838, 0xfac68801 }, + { 0x0000783c, 0x0001fffe }, + { 0x00007840, 0xffeb1a20 }, + { 0x00007844, 0x000c0db6 }, + { 0x00007848, 0x6db61b6f }, + { 0x0000784c, 0x6d9b66db }, + { 0x00007850, 0x6d8c6dba }, + { 0x00007854, 0x00040000 }, + { 0x00007858, 0xdb003012 }, + { 0x0000785c, 0x04924914 }, + { 0x00007860, 0x21084210 }, + { 0x00007864, 0xf7d7ffde }, + { 0x00007868, 0xc2034080 }, + { 0x0000786c, 0x48609eb4 }, + { 0x00007870, 0x10142c00 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = { + {0x00004040, 0x9248fd00 }, + {0x00004040, 0x24924924 }, + {0x00004040, 0xa8000019 }, + {0x00004040, 0x13160820 }, + {0x00004040, 0xe5980560 }, + {0x00004040, 0xc01dcffd }, + {0x00004040, 0x1aaabe41 }, + {0x00004040, 0xbe105554 }, + {0x00004040, 0x00043007 }, + {0x00004044, 0x00000000 }, +}; + +static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285_1_2[][2] = { {0x00004040, 0x9248fd00 }, {0x00004040, 0x24924924 }, {0x00004040, 0xa8000019 }, {0x00004040, 0x13160820 }, {0x00004040, 0xe5980560 }, - {0x00004040, 0x401dcffd }, - {0x00004040, 0x1aaabe40 }, + {0x00004040, 0xc01dcffc }, + {0x00004040, 0x1aaabe41 }, {0x00004040, 0xbe105554 }, {0x00004040, 0x00043007 }, {0x00004044, 0x00000000 }, diff --git a/drivers/net/wireless/ath9k/mac.c b/drivers/net/wireless/ath9k/mac.c new file mode 100644 index 0000000000000000000000000000000000000000..af32d091dc38231b4d77ba321d56711e93297c7e --- /dev/null +++ b/drivers/net/wireless/ath9k/mac.c @@ -0,0 +1,946 @@ +/* + * Copyright (c) 2008 Atheros Communications Inc. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "core.h" +#include "hw.h" +#include "reg.h" +#include "phy.h" + +static void ath9k_hw_set_txq_interrupts(struct ath_hal *ah, + struct ath9k_tx_queue_info *qi) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + DPRINTF(ah->ah_sc, ATH_DBG_INTERRUPT, + "tx ok 0x%x err 0x%x desc 0x%x eol 0x%x urn 0x%x\n", + ahp->ah_txOkInterruptMask, ahp->ah_txErrInterruptMask, + ahp->ah_txDescInterruptMask, ahp->ah_txEolInterruptMask, + ahp->ah_txUrnInterruptMask); + + REG_WRITE(ah, AR_IMR_S0, + SM(ahp->ah_txOkInterruptMask, AR_IMR_S0_QCU_TXOK) + | SM(ahp->ah_txDescInterruptMask, AR_IMR_S0_QCU_TXDESC)); + REG_WRITE(ah, AR_IMR_S1, + SM(ahp->ah_txErrInterruptMask, AR_IMR_S1_QCU_TXERR) + | SM(ahp->ah_txEolInterruptMask, AR_IMR_S1_QCU_TXEOL)); + REG_RMW_FIELD(ah, AR_IMR_S2, + AR_IMR_S2_QCU_TXURN, ahp->ah_txUrnInterruptMask); +} + +u32 ath9k_hw_gettxbuf(struct ath_hal *ah, u32 q) +{ + return REG_READ(ah, AR_QTXDP(q)); +} + +bool ath9k_hw_puttxbuf(struct ath_hal *ah, u32 q, u32 txdp) +{ + REG_WRITE(ah, AR_QTXDP(q), txdp); + + return true; +} + +bool ath9k_hw_txstart(struct ath_hal *ah, u32 q) +{ + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); + + REG_WRITE(ah, AR_Q_TXE, 1 << q); + + return true; +} + +u32 ath9k_hw_numtxpending(struct ath_hal *ah, u32 q) +{ + u32 npend; + + npend = REG_READ(ah, AR_QSTS(q)) & AR_Q_STS_PEND_FR_CNT; + if (npend == 0) { + + if (REG_READ(ah, AR_Q_TXE) & (1 << q)) + npend = 1; + } + + return npend; +} + +bool ath9k_hw_updatetxtriglevel(struct ath_hal *ah, bool bIncTrigLevel) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + u32 txcfg, curLevel, newLevel; + enum ath9k_int omask; + + if (ah->ah_txTrigLevel >= MAX_TX_FIFO_THRESHOLD) + return false; + + omask = ath9k_hw_set_interrupts(ah, ahp->ah_maskReg & ~ATH9K_INT_GLOBAL); + + txcfg = REG_READ(ah, AR_TXCFG); + curLevel = MS(txcfg, AR_FTRIG); + newLevel = curLevel; + if (bIncTrigLevel) { + if (curLevel < MAX_TX_FIFO_THRESHOLD) + newLevel++; + } else if (curLevel > MIN_TX_FIFO_THRESHOLD) + newLevel--; + if (newLevel != curLevel) + REG_WRITE(ah, AR_TXCFG, + (txcfg & ~AR_FTRIG) | SM(newLevel, AR_FTRIG)); + + ath9k_hw_set_interrupts(ah, omask); + + ah->ah_txTrigLevel = newLevel; + + return newLevel != curLevel; +} + +bool ath9k_hw_stoptxdma(struct ath_hal *ah, u32 q) +{ + u32 tsfLow, j, wait; + + REG_WRITE(ah, AR_Q_TXD, 1 << q); + + for (wait = 1000; wait != 0; wait--) { + if (ath9k_hw_numtxpending(ah, q) == 0) + break; + udelay(100); + } + + if (ath9k_hw_numtxpending(ah, q)) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "%s: Num of pending TX Frames %d on Q %d\n", + __func__, ath9k_hw_numtxpending(ah, q), q); + + for (j = 0; j < 2; j++) { + tsfLow = REG_READ(ah, AR_TSF_L32); + REG_WRITE(ah, AR_QUIET2, + SM(10, AR_QUIET2_QUIET_DUR)); + REG_WRITE(ah, AR_QUIET_PERIOD, 100); + REG_WRITE(ah, AR_NEXT_QUIET_TIMER, tsfLow >> 10); + REG_SET_BIT(ah, AR_TIMER_MODE, + AR_QUIET_TIMER_EN); + + if ((REG_READ(ah, AR_TSF_L32) >> 10) == (tsfLow >> 10)) + break; + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "TSF have moved while trying to set " + "quiet time TSF: 0x%08x\n", tsfLow); + } + + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); + + udelay(200); + REG_CLR_BIT(ah, AR_TIMER_MODE, AR_QUIET_TIMER_EN); + + wait = 1000; + + while (ath9k_hw_numtxpending(ah, q)) { + if ((--wait) == 0) { + DPRINTF(ah->ah_sc, ATH_DBG_XMIT, + "Failed to stop Tx DMA in 100 " + "msec after killing last frame\n"); + break; + } + udelay(100); + } + + REG_CLR_BIT(ah, AR_DIAG_SW, AR_DIAG_FORCE_CH_IDLE_HIGH); + } + + REG_WRITE(ah, AR_Q_TXD, 0); + + return wait != 0; +} + +bool ath9k_hw_filltxdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 segLen, bool firstSeg, + bool lastSeg, const struct ath_desc *ds0) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if (firstSeg) { + ads->ds_ctl1 |= segLen | (lastSeg ? 0 : AR_TxMore); + } else if (lastSeg) { + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen; + ads->ds_ctl2 = AR5416DESC_CONST(ds0)->ds_ctl2; + ads->ds_ctl3 = AR5416DESC_CONST(ds0)->ds_ctl3; + } else { + ads->ds_ctl0 = 0; + ads->ds_ctl1 = segLen | AR_TxMore; + ads->ds_ctl2 = 0; + ads->ds_ctl3 = 0; + } + ads->ds_txstatus0 = ads->ds_txstatus1 = 0; + ads->ds_txstatus2 = ads->ds_txstatus3 = 0; + ads->ds_txstatus4 = ads->ds_txstatus5 = 0; + ads->ds_txstatus6 = ads->ds_txstatus7 = 0; + ads->ds_txstatus8 = ads->ds_txstatus9 = 0; + + return true; +} + +void ath9k_hw_cleartxdesc(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_txstatus0 = ads->ds_txstatus1 = 0; + ads->ds_txstatus2 = ads->ds_txstatus3 = 0; + ads->ds_txstatus4 = ads->ds_txstatus5 = 0; + ads->ds_txstatus6 = ads->ds_txstatus7 = 0; + ads->ds_txstatus8 = ads->ds_txstatus9 = 0; +} + +int ath9k_hw_txprocdesc(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if ((ads->ds_txstatus9 & AR_TxDone) == 0) + return -EINPROGRESS; + + ds->ds_txstat.ts_seqnum = MS(ads->ds_txstatus9, AR_SeqNum); + ds->ds_txstat.ts_tstamp = ads->AR_SendTimestamp; + ds->ds_txstat.ts_status = 0; + ds->ds_txstat.ts_flags = 0; + + if (ads->ds_txstatus1 & AR_ExcessiveRetries) + ds->ds_txstat.ts_status |= ATH9K_TXERR_XRETRY; + if (ads->ds_txstatus1 & AR_Filtered) + ds->ds_txstat.ts_status |= ATH9K_TXERR_FILT; + if (ads->ds_txstatus1 & AR_FIFOUnderrun) { + ds->ds_txstat.ts_status |= ATH9K_TXERR_FIFO; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus9 & AR_TxOpExceeded) + ds->ds_txstat.ts_status |= ATH9K_TXERR_XTXOP; + if (ads->ds_txstatus1 & AR_TxTimerExpired) + ds->ds_txstat.ts_status |= ATH9K_TXERR_TIMER_EXPIRED; + + if (ads->ds_txstatus1 & AR_DescCfgErr) + ds->ds_txstat.ts_flags |= ATH9K_TX_DESC_CFG_ERR; + if (ads->ds_txstatus1 & AR_TxDataUnderrun) { + ds->ds_txstat.ts_flags |= ATH9K_TX_DATA_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus1 & AR_TxDelimUnderrun) { + ds->ds_txstat.ts_flags |= ATH9K_TX_DELIM_UNDERRUN; + ath9k_hw_updatetxtriglevel(ah, true); + } + if (ads->ds_txstatus0 & AR_TxBaStatus) { + ds->ds_txstat.ts_flags |= ATH9K_TX_BA; + ds->ds_txstat.ba_low = ads->AR_BaBitmapLow; + ds->ds_txstat.ba_high = ads->AR_BaBitmapHigh; + } + + ds->ds_txstat.ts_rateindex = MS(ads->ds_txstatus9, AR_FinalTxIdx); + switch (ds->ds_txstat.ts_rateindex) { + case 0: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate0); + break; + case 1: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate1); + break; + case 2: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate2); + break; + case 3: + ds->ds_txstat.ts_ratecode = MS(ads->ds_ctl3, AR_XmitRate3); + break; + } + + ds->ds_txstat.ts_rssi = MS(ads->ds_txstatus5, AR_TxRSSICombined); + ds->ds_txstat.ts_rssi_ctl0 = MS(ads->ds_txstatus0, AR_TxRSSIAnt00); + ds->ds_txstat.ts_rssi_ctl1 = MS(ads->ds_txstatus0, AR_TxRSSIAnt01); + ds->ds_txstat.ts_rssi_ctl2 = MS(ads->ds_txstatus0, AR_TxRSSIAnt02); + ds->ds_txstat.ts_rssi_ext0 = MS(ads->ds_txstatus5, AR_TxRSSIAnt10); + ds->ds_txstat.ts_rssi_ext1 = MS(ads->ds_txstatus5, AR_TxRSSIAnt11); + ds->ds_txstat.ts_rssi_ext2 = MS(ads->ds_txstatus5, AR_TxRSSIAnt12); + ds->ds_txstat.evm0 = ads->AR_TxEVM0; + ds->ds_txstat.evm1 = ads->AR_TxEVM1; + ds->ds_txstat.evm2 = ads->AR_TxEVM2; + ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt); + ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt); + ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt); + ds->ds_txstat.ts_antenna = 1; + + return 0; +} + +void ath9k_hw_set11n_txdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pktLen, enum ath9k_pkt_type type, u32 txPower, + u32 keyIx, enum ath9k_key_type keyType, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ath_hal_5416 *ahp = AH5416(ah); + + txPower += ahp->ah_txPowerIndexOffset; + if (txPower > 63) + txPower = 63; + + ads->ds_ctl0 = (pktLen & AR_FrameLen) + | (flags & ATH9K_TXDESC_VMF ? AR_VirtMoreFrag : 0) + | SM(txPower, AR_XmitPower) + | (flags & ATH9K_TXDESC_VEOL ? AR_VEOL : 0) + | (flags & ATH9K_TXDESC_CLRDMASK ? AR_ClrDestMask : 0) + | (flags & ATH9K_TXDESC_INTREQ ? AR_TxIntrReq : 0) + | (keyIx != ATH9K_TXKEYIX_INVALID ? AR_DestIdxValid : 0); + + ads->ds_ctl1 = + (keyIx != ATH9K_TXKEYIX_INVALID ? SM(keyIx, AR_DestIdx) : 0) + | SM(type, AR_FrameType) + | (flags & ATH9K_TXDESC_NOACK ? AR_NoAck : 0) + | (flags & ATH9K_TXDESC_EXT_ONLY ? AR_ExtOnly : 0) + | (flags & ATH9K_TXDESC_EXT_AND_CTL ? AR_ExtAndCtl : 0); + + ads->ds_ctl6 = SM(keyType, AR_EncrType); + + if (AR_SREV_9285(ah)) { + ads->ds_ctl8 = 0; + ads->ds_ctl9 = 0; + ads->ds_ctl10 = 0; + ads->ds_ctl11 = 0; + } +} + +void ath9k_hw_set11n_ratescenario(struct ath_hal *ah, struct ath_desc *ds, + struct ath_desc *lastds, + u32 durUpdateEn, u32 rtsctsRate, + u32 rtsctsDuration, + struct ath9k_11n_rate_series series[], + u32 nseries, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ar5416_desc *last_ads = AR5416DESC(lastds); + u32 ds_ctl0; + + (void) nseries; + (void) rtsctsDuration; + + if (flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)) { + ds_ctl0 = ads->ds_ctl0; + + if (flags & ATH9K_TXDESC_RTSENA) { + ds_ctl0 &= ~AR_CTSEnable; + ds_ctl0 |= AR_RTSEnable; + } else { + ds_ctl0 &= ~AR_RTSEnable; + ds_ctl0 |= AR_CTSEnable; + } + + ads->ds_ctl0 = ds_ctl0; + } else { + ads->ds_ctl0 = + (ads->ds_ctl0 & ~(AR_RTSEnable | AR_CTSEnable)); + } + + ads->ds_ctl2 = set11nTries(series, 0) + | set11nTries(series, 1) + | set11nTries(series, 2) + | set11nTries(series, 3) + | (durUpdateEn ? AR_DurUpdateEna : 0) + | SM(0, AR_BurstDur); + + ads->ds_ctl3 = set11nRate(series, 0) + | set11nRate(series, 1) + | set11nRate(series, 2) + | set11nRate(series, 3); + + ads->ds_ctl4 = set11nPktDurRTSCTS(series, 0) + | set11nPktDurRTSCTS(series, 1); + + ads->ds_ctl5 = set11nPktDurRTSCTS(series, 2) + | set11nPktDurRTSCTS(series, 3); + + ads->ds_ctl7 = set11nRateFlags(series, 0) + | set11nRateFlags(series, 1) + | set11nRateFlags(series, 2) + | set11nRateFlags(series, 3) + | SM(rtsctsRate, AR_RTSCTSRate); + last_ads->ds_ctl2 = ads->ds_ctl2; + last_ads->ds_ctl3 = ads->ds_ctl3; +} + +void ath9k_hw_set11n_aggr_first(struct ath_hal *ah, struct ath_desc *ds, + u32 aggrLen) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + ads->ds_ctl6 &= ~AR_AggrLen; + ads->ds_ctl6 |= SM(aggrLen, AR_AggrLen); +} + +void ath9k_hw_set11n_aggr_middle(struct ath_hal *ah, struct ath_desc *ds, + u32 numDelims) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + unsigned int ctl6; + + ads->ds_ctl1 |= (AR_IsAggr | AR_MoreAggr); + + ctl6 = ads->ds_ctl6; + ctl6 &= ~AR_PadDelim; + ctl6 |= SM(numDelims, AR_PadDelim); + ads->ds_ctl6 = ctl6; +} + +void ath9k_hw_set11n_aggr_last(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 |= AR_IsAggr; + ads->ds_ctl1 &= ~AR_MoreAggr; + ads->ds_ctl6 &= ~AR_PadDelim; +} + +void ath9k_hw_clr11n_aggr(struct ath_hal *ah, struct ath_desc *ds) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl1 &= (~AR_IsAggr & ~AR_MoreAggr); +} + +void ath9k_hw_set11n_burstduration(struct ath_hal *ah, struct ath_desc *ds, + u32 burstDuration) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + ads->ds_ctl2 &= ~AR_BurstDur; + ads->ds_ctl2 |= SM(burstDuration, AR_BurstDur); +} + +void ath9k_hw_set11n_virtualmorefrag(struct ath_hal *ah, struct ath_desc *ds, + u32 vmf) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + + if (vmf) + ads->ds_ctl0 |= AR_VirtMoreFrag; + else + ads->ds_ctl0 &= ~AR_VirtMoreFrag; +} + +void ath9k_hw_gettxintrtxqs(struct ath_hal *ah, u32 *txqs) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + + *txqs &= ahp->ah_intrTxqs; + ahp->ah_intrTxqs &= ~(*txqs); +} + +bool ath9k_hw_set_txq_props(struct ath_hal *ah, int q, + const struct ath9k_tx_queue_info *qinfo) +{ + u32 cw; + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + return false; + } + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %p\n", qi); + + qi->tqi_ver = qinfo->tqi_ver; + qi->tqi_subtype = qinfo->tqi_subtype; + qi->tqi_qflags = qinfo->tqi_qflags; + qi->tqi_priority = qinfo->tqi_priority; + if (qinfo->tqi_aifs != ATH9K_TXQ_USEDEFAULT) + qi->tqi_aifs = min(qinfo->tqi_aifs, 255U); + else + qi->tqi_aifs = INIT_AIFS; + if (qinfo->tqi_cwmin != ATH9K_TXQ_USEDEFAULT) { + cw = min(qinfo->tqi_cwmin, 1024U); + qi->tqi_cwmin = 1; + while (qi->tqi_cwmin < cw) + qi->tqi_cwmin = (qi->tqi_cwmin << 1) | 1; + } else + qi->tqi_cwmin = qinfo->tqi_cwmin; + if (qinfo->tqi_cwmax != ATH9K_TXQ_USEDEFAULT) { + cw = min(qinfo->tqi_cwmax, 1024U); + qi->tqi_cwmax = 1; + while (qi->tqi_cwmax < cw) + qi->tqi_cwmax = (qi->tqi_cwmax << 1) | 1; + } else + qi->tqi_cwmax = INIT_CWMAX; + + if (qinfo->tqi_shretry != 0) + qi->tqi_shretry = min((u32) qinfo->tqi_shretry, 15U); + else + qi->tqi_shretry = INIT_SH_RETRY; + if (qinfo->tqi_lgretry != 0) + qi->tqi_lgretry = min((u32) qinfo->tqi_lgretry, 15U); + else + qi->tqi_lgretry = INIT_LG_RETRY; + qi->tqi_cbrPeriod = qinfo->tqi_cbrPeriod; + qi->tqi_cbrOverflowLimit = qinfo->tqi_cbrOverflowLimit; + qi->tqi_burstTime = qinfo->tqi_burstTime; + qi->tqi_readyTime = qinfo->tqi_readyTime; + + switch (qinfo->tqi_subtype) { + case ATH9K_WME_UPSD: + if (qi->tqi_type == ATH9K_TX_QUEUE_DATA) + qi->tqi_intFlags = ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS; + break; + default: + break; + } + + return true; +} + +bool ath9k_hw_get_txq_props(struct ath_hal *ah, int q, + struct ath9k_tx_queue_info *qinfo) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + return false; + } + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue\n"); + return false; + } + + qinfo->tqi_qflags = qi->tqi_qflags; + qinfo->tqi_ver = qi->tqi_ver; + qinfo->tqi_subtype = qi->tqi_subtype; + qinfo->tqi_qflags = qi->tqi_qflags; + qinfo->tqi_priority = qi->tqi_priority; + qinfo->tqi_aifs = qi->tqi_aifs; + qinfo->tqi_cwmin = qi->tqi_cwmin; + qinfo->tqi_cwmax = qi->tqi_cwmax; + qinfo->tqi_shretry = qi->tqi_shretry; + qinfo->tqi_lgretry = qi->tqi_lgretry; + qinfo->tqi_cbrPeriod = qi->tqi_cbrPeriod; + qinfo->tqi_cbrOverflowLimit = qi->tqi_cbrOverflowLimit; + qinfo->tqi_burstTime = qi->tqi_burstTime; + qinfo->tqi_readyTime = qi->tqi_readyTime; + + return true; +} + +int ath9k_hw_setuptxqueue(struct ath_hal *ah, enum ath9k_tx_queue type, + const struct ath9k_tx_queue_info *qinfo) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_tx_queue_info *qi; + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + int q; + + switch (type) { + case ATH9K_TX_QUEUE_BEACON: + q = pCap->total_queues - 1; + break; + case ATH9K_TX_QUEUE_CAB: + q = pCap->total_queues - 2; + break; + case ATH9K_TX_QUEUE_PSPOLL: + q = 1; + break; + case ATH9K_TX_QUEUE_UAPSD: + q = pCap->total_queues - 3; + break; + case ATH9K_TX_QUEUE_DATA: + for (q = 0; q < pCap->total_queues; q++) + if (ahp->ah_txq[q].tqi_type == + ATH9K_TX_QUEUE_INACTIVE) + break; + if (q == pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "no available tx queue\n"); + return -1; + } + break; + default: + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "bad tx queue type %u\n", type); + return -1; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "queue %u\n", q); + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type != ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "tx queue %u already active\n", q); + return -1; + } + memset(qi, 0, sizeof(struct ath9k_tx_queue_info)); + qi->tqi_type = type; + if (qinfo == NULL) { + qi->tqi_qflags = + TXQ_FLAG_TXOKINT_ENABLE + | TXQ_FLAG_TXERRINT_ENABLE + | TXQ_FLAG_TXDESCINT_ENABLE | TXQ_FLAG_TXURNINT_ENABLE; + qi->tqi_aifs = INIT_AIFS; + qi->tqi_cwmin = ATH9K_TXQ_USEDEFAULT; + qi->tqi_cwmax = INIT_CWMAX; + qi->tqi_shretry = INIT_SH_RETRY; + qi->tqi_lgretry = INIT_LG_RETRY; + qi->tqi_physCompBuf = 0; + } else { + qi->tqi_physCompBuf = qinfo->tqi_physCompBuf; + (void) ath9k_hw_set_txq_props(ah, q, qinfo); + } + + return q; +} + +bool ath9k_hw_releasetxqueue(struct ath_hal *ah, u32 q) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_tx_queue_info *qi; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + return false; + } + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); + return false; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "release queue %u\n", q); + + qi->tqi_type = ATH9K_TX_QUEUE_INACTIVE; + ahp->ah_txOkInterruptMask &= ~(1 << q); + ahp->ah_txErrInterruptMask &= ~(1 << q); + ahp->ah_txDescInterruptMask &= ~(1 << q); + ahp->ah_txEolInterruptMask &= ~(1 << q); + ahp->ah_txUrnInterruptMask &= ~(1 << q); + ath9k_hw_set_txq_interrupts(ah, qi); + + return true; +} + +bool ath9k_hw_resettxqueue(struct ath_hal *ah, u32 q) +{ + struct ath_hal_5416 *ahp = AH5416(ah); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + struct ath9k_channel *chan = ah->ah_curchan; + struct ath9k_tx_queue_info *qi; + u32 cwMin, chanCwMin, value; + + if (q >= pCap->total_queues) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "invalid queue num %u\n", q); + return false; + } + + qi = &ahp->ah_txq[q]; + if (qi->tqi_type == ATH9K_TX_QUEUE_INACTIVE) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "inactive queue %u\n", q); + return true; + } + + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, "reset queue %u\n", q); + + if (qi->tqi_cwmin == ATH9K_TXQ_USEDEFAULT) { + if (chan && IS_CHAN_B(chan)) + chanCwMin = INIT_CWMIN_11B; + else + chanCwMin = INIT_CWMIN; + + for (cwMin = 1; cwMin < chanCwMin; cwMin = (cwMin << 1) | 1); + } else + cwMin = qi->tqi_cwmin; + + REG_WRITE(ah, AR_DLCL_IFS(q), + SM(cwMin, AR_D_LCL_IFS_CWMIN) | + SM(qi->tqi_cwmax, AR_D_LCL_IFS_CWMAX) | + SM(qi->tqi_aifs, AR_D_LCL_IFS_AIFS)); + + REG_WRITE(ah, AR_DRETRY_LIMIT(q), + SM(INIT_SSH_RETRY, AR_D_RETRY_LIMIT_STA_SH) | + SM(INIT_SLG_RETRY, AR_D_RETRY_LIMIT_STA_LG) | + SM(qi->tqi_shretry, AR_D_RETRY_LIMIT_FR_SH)); + + REG_WRITE(ah, AR_QMISC(q), AR_Q_MISC_DCU_EARLY_TERM_REQ); + REG_WRITE(ah, AR_DMISC(q), + AR_D_MISC_CW_BKOFF_EN | AR_D_MISC_FRAG_WAIT_EN | 0x2); + + if (qi->tqi_cbrPeriod) { + REG_WRITE(ah, AR_QCBRCFG(q), + SM(qi->tqi_cbrPeriod, AR_Q_CBRCFG_INTERVAL) | + SM(qi->tqi_cbrOverflowLimit, AR_Q_CBRCFG_OVF_THRESH)); + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_FSP_CBR | + (qi->tqi_cbrOverflowLimit ? + AR_Q_MISC_CBR_EXP_CNTR_LIMIT_EN : 0)); + } + if (qi->tqi_readyTime && (qi->tqi_type != ATH9K_TX_QUEUE_CAB)) { + REG_WRITE(ah, AR_QRDYTIMECFG(q), + SM(qi->tqi_readyTime, AR_Q_RDYTIMECFG_DURATION) | + AR_Q_RDYTIMECFG_EN); + } + + REG_WRITE(ah, AR_DCHNTIME(q), + SM(qi->tqi_burstTime, AR_D_CHNTIME_DUR) | + (qi->tqi_burstTime ? AR_D_CHNTIME_EN : 0)); + + if (qi->tqi_burstTime + && (qi->tqi_qflags & TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)) { + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | + AR_Q_MISC_RDYTIME_EXP_POLICY); + + } + + if (qi->tqi_qflags & TXQ_FLAG_BACKOFF_DISABLE) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_POST_FR_BKOFF_DIS); + } + if (qi->tqi_qflags & TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_FRAG_BKOFF_EN); + } + switch (qi->tqi_type) { + case ATH9K_TX_QUEUE_BEACON: + REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_BEACON_USE + | AR_Q_MISC_CBR_INCR_DIS1); + + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) + | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + AR_D_MISC_ARB_LOCKOUT_CNTRL_S) + | AR_D_MISC_BEACON_USE + | AR_D_MISC_POST_FR_BKOFF_DIS); + break; + case ATH9K_TX_QUEUE_CAB: + REG_WRITE(ah, AR_QMISC(q), REG_READ(ah, AR_QMISC(q)) + | AR_Q_MISC_FSP_DBA_GATED + | AR_Q_MISC_CBR_INCR_DIS1 + | AR_Q_MISC_CBR_INCR_DIS0); + value = (qi->tqi_readyTime - + (ah->ah_config.sw_beacon_response_time - + ah->ah_config.dma_beacon_response_time) - + ah->ah_config.additional_swba_backoff) * 1024; + REG_WRITE(ah, AR_QRDYTIMECFG(q), + value | AR_Q_RDYTIMECFG_EN); + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) + | (AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL << + AR_D_MISC_ARB_LOCKOUT_CNTRL_S)); + break; + case ATH9K_TX_QUEUE_PSPOLL: + REG_WRITE(ah, AR_QMISC(q), + REG_READ(ah, AR_QMISC(q)) | AR_Q_MISC_CBR_INCR_DIS1); + break; + case ATH9K_TX_QUEUE_UAPSD: + REG_WRITE(ah, AR_DMISC(q), REG_READ(ah, AR_DMISC(q)) | + AR_D_MISC_POST_FR_BKOFF_DIS); + break; + default: + break; + } + + if (qi->tqi_intFlags & ATH9K_TXQ_USE_LOCKOUT_BKOFF_DIS) { + REG_WRITE(ah, AR_DMISC(q), + REG_READ(ah, AR_DMISC(q)) | + SM(AR_D_MISC_ARB_LOCKOUT_CNTRL_GLOBAL, + AR_D_MISC_ARB_LOCKOUT_CNTRL) | + AR_D_MISC_POST_FR_BKOFF_DIS); + } + + if (qi->tqi_qflags & TXQ_FLAG_TXOKINT_ENABLE) + ahp->ah_txOkInterruptMask |= 1 << q; + else + ahp->ah_txOkInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXERRINT_ENABLE) + ahp->ah_txErrInterruptMask |= 1 << q; + else + ahp->ah_txErrInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXDESCINT_ENABLE) + ahp->ah_txDescInterruptMask |= 1 << q; + else + ahp->ah_txDescInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXEOLINT_ENABLE) + ahp->ah_txEolInterruptMask |= 1 << q; + else + ahp->ah_txEolInterruptMask &= ~(1 << q); + if (qi->tqi_qflags & TXQ_FLAG_TXURNINT_ENABLE) + ahp->ah_txUrnInterruptMask |= 1 << q; + else + ahp->ah_txUrnInterruptMask &= ~(1 << q); + ath9k_hw_set_txq_interrupts(ah, qi); + + return true; +} + +int ath9k_hw_rxprocdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 pa, struct ath_desc *nds, u64 tsf) +{ + struct ar5416_desc ads; + struct ar5416_desc *adsp = AR5416DESC(ds); + u32 phyerr; + + if ((adsp->ds_rxstatus8 & AR_RxDone) == 0) + return -EINPROGRESS; + + ads.u.rx = adsp->u.rx; + + ds->ds_rxstat.rs_status = 0; + ds->ds_rxstat.rs_flags = 0; + + ds->ds_rxstat.rs_datalen = ads.ds_rxstatus1 & AR_DataLen; + ds->ds_rxstat.rs_tstamp = ads.AR_RcvTimestamp; + + ds->ds_rxstat.rs_rssi = MS(ads.ds_rxstatus4, AR_RxRSSICombined); + ds->ds_rxstat.rs_rssi_ctl0 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt00); + ds->ds_rxstat.rs_rssi_ctl1 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt01); + ds->ds_rxstat.rs_rssi_ctl2 = MS(ads.ds_rxstatus0, AR_RxRSSIAnt02); + ds->ds_rxstat.rs_rssi_ext0 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt10); + ds->ds_rxstat.rs_rssi_ext1 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt11); + ds->ds_rxstat.rs_rssi_ext2 = MS(ads.ds_rxstatus4, AR_RxRSSIAnt12); + if (ads.ds_rxstatus8 & AR_RxKeyIdxValid) + ds->ds_rxstat.rs_keyix = MS(ads.ds_rxstatus8, AR_KeyIdx); + else + ds->ds_rxstat.rs_keyix = ATH9K_RXKEYIX_INVALID; + + ds->ds_rxstat.rs_rate = RXSTATUS_RATE(ah, (&ads)); + ds->ds_rxstat.rs_more = (ads.ds_rxstatus1 & AR_RxMore) ? 1 : 0; + + ds->ds_rxstat.rs_isaggr = (ads.ds_rxstatus8 & AR_RxAggr) ? 1 : 0; + ds->ds_rxstat.rs_moreaggr = + (ads.ds_rxstatus8 & AR_RxMoreAggr) ? 1 : 0; + ds->ds_rxstat.rs_antenna = MS(ads.ds_rxstatus3, AR_RxAntenna); + ds->ds_rxstat.rs_flags = + (ads.ds_rxstatus3 & AR_GI) ? ATH9K_RX_GI : 0; + ds->ds_rxstat.rs_flags |= + (ads.ds_rxstatus3 & AR_2040) ? ATH9K_RX_2040 : 0; + + if (ads.ds_rxstatus8 & AR_PreDelimCRCErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_PRE; + if (ads.ds_rxstatus8 & AR_PostDelimCRCErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DELIM_CRC_POST; + if (ads.ds_rxstatus8 & AR_DecryptBusyErr) + ds->ds_rxstat.rs_flags |= ATH9K_RX_DECRYPT_BUSY; + + if ((ads.ds_rxstatus8 & AR_RxFrameOK) == 0) { + if (ads.ds_rxstatus8 & AR_CRCErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_CRC; + else if (ads.ds_rxstatus8 & AR_PHYErr) { + ds->ds_rxstat.rs_status |= ATH9K_RXERR_PHY; + phyerr = MS(ads.ds_rxstatus8, AR_PHYErrCode); + ds->ds_rxstat.rs_phyerr = phyerr; + } else if (ads.ds_rxstatus8 & AR_DecryptCRCErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_DECRYPT; + else if (ads.ds_rxstatus8 & AR_MichaelErr) + ds->ds_rxstat.rs_status |= ATH9K_RXERR_MIC; + } + + return 0; +} + +bool ath9k_hw_setuprxdesc(struct ath_hal *ah, struct ath_desc *ds, + u32 size, u32 flags) +{ + struct ar5416_desc *ads = AR5416DESC(ds); + struct ath9k_hw_capabilities *pCap = &ah->ah_caps; + + ads->ds_ctl1 = size & AR_BufLen; + if (flags & ATH9K_RXDESC_INTREQ) + ads->ds_ctl1 |= AR_RxIntrReq; + + ads->ds_rxstatus8 &= ~AR_RxDone; + if (!(pCap->hw_caps & ATH9K_HW_CAP_AUTOSLEEP)) + memset(&(ads->u), 0, sizeof(ads->u)); + + return true; +} + +bool ath9k_hw_setrxabort(struct ath_hal *ah, bool set) +{ + u32 reg; + + if (set) { + REG_SET_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + + if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) { + REG_CLR_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | + AR_DIAG_RX_ABORT)); + + reg = REG_READ(ah, AR_OBS_BUS_1); + DPRINTF(ah->ah_sc, ATH_DBG_FATAL, + "rx failed to go idle in 10 ms RXSM=0x%x\n", reg); + + return false; + } + } else { + REG_CLR_BIT(ah, AR_DIAG_SW, + (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); + } + + return true; +} + +void ath9k_hw_putrxbuf(struct ath_hal *ah, u32 rxdp) +{ + REG_WRITE(ah, AR_RXDP, rxdp); +} + +void ath9k_hw_rxena(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_CR, AR_CR_RXE); +} + +void ath9k_hw_startpcureceive(struct ath_hal *ah) +{ + ath9k_enable_mib_counters(ah); + + ath9k_ani_reset(ah); + + REG_CLR_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT)); +} + +void ath9k_hw_stoppcurecv(struct ath_hal *ah) +{ + REG_SET_BIT(ah, AR_DIAG_SW, AR_DIAG_RX_DIS); + + ath9k_hw_disable_mib_counters(ah); +} + +bool ath9k_hw_stopdmarecv(struct ath_hal *ah) +{ + REG_WRITE(ah, AR_CR, AR_CR_RXD); + + if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) { + DPRINTF(ah->ah_sc, ATH_DBG_QUEUE, + "dma failed to stop in 10ms\n" + "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n", + REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW)); + return false; + } else { + return true; + } +} diff --git a/drivers/net/wireless/ath9k/main.c b/drivers/net/wireless/ath9k/main.c index f05f584ab7bc960f9e8ba5ea29207ec63582bd2c..191eec50dc751c1fff9142f76d7960a5eb4c23db 100644 --- a/drivers/net/wireless/ath9k/main.c +++ b/drivers/net/wireless/ath9k/main.c @@ -14,15 +14,13 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* mac80211 and PCI callbacks */ - #include #include "core.h" +#include "reg.h" +#include "hw.h" #define ATH_PCI_VERSION "0.1" -#define IEEE80211_HTCAP_MAXRXAMPDU_FACTOR 13 - static char *dev_info = "ath9k"; MODULE_AUTHOR("Atheros Communications"); @@ -36,258 +34,79 @@ static struct pci_device_id ath_pci_id_table[] __devinitdata = { { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI */ { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */ + { PCI_VDEVICE(ATHEROS, 0x002B) }, /* PCI-E */ { 0 } }; -static int ath_get_channel(struct ath_softc *sc, - struct ieee80211_channel *chan) -{ - int i; +static void ath_detach(struct ath_softc *sc); - for (i = 0; i < sc->sc_ah->ah_nchan; i++) { - if (sc->sc_ah->ah_channels[i].channel == chan->center_freq) - return i; - } - - return -1; -} +/* return bus cachesize in 4B word units */ -static u32 ath_get_extchanmode(struct ath_softc *sc, - struct ieee80211_channel *chan) +static void bus_read_cachesize(struct ath_softc *sc, int *csz) { - u32 chanmode = 0; - u8 ext_chan_offset = sc->sc_ht_info.ext_chan_offset; - enum ath9k_ht_macmode tx_chan_width = sc->sc_ht_info.tx_chan_width; - - switch (chan->band) { - case IEEE80211_BAND_2GHZ: - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) && - (tx_chan_width == ATH9K_HT_MACMODE_20)) - chanmode = CHANNEL_G_HT20; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) - chanmode = CHANNEL_G_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) - chanmode = CHANNEL_G_HT40MINUS; - break; - case IEEE80211_BAND_5GHZ: - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE) && - (tx_chan_width == ATH9K_HT_MACMODE_20)) - chanmode = CHANNEL_A_HT20; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) - chanmode = CHANNEL_A_HT40PLUS; - if ((ext_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) && - (tx_chan_width == ATH9K_HT_MACMODE_2040)) - chanmode = CHANNEL_A_HT40MINUS; - break; - default: - break; - } - - return chanmode; -} + u8 u8tmp; + pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, (u8 *)&u8tmp); + *csz = (int)u8tmp; -static int ath_setkey_tkip(struct ath_softc *sc, - struct ieee80211_key_conf *key, - struct ath9k_keyval *hk, - const u8 *addr) -{ - u8 *key_rxmic = NULL; - u8 *key_txmic = NULL; - - key_txmic = key->key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; - key_rxmic = key->key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; - - if (addr == NULL) { - /* Group key installation */ - memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); - return ath_keyset(sc, key->keyidx, hk, addr); - } - if (!sc->sc_splitmic) { - /* - * data key goes at first index, - * the hal handles the MIC keys at index+64. - */ - memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); - memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); - return ath_keyset(sc, key->keyidx, hk, addr); - } /* - * TX key goes at first index, RX key at +32. - * The hal handles the MIC keys at index+64. + * This check was put in to avoid "unplesant" consequences if + * the bootrom has not fully initialized all PCI devices. + * Sometimes the cache line size register is not set */ - memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); - if (!ath_keyset(sc, key->keyidx, hk, NULL)) { - /* Txmic entry failed. No need to proceed further */ - DPRINTF(sc, ATH_DBG_KEYCACHE, - "%s Setting TX MIC Key Failed\n", __func__); - return 0; - } - memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); - /* XXX delete tx key on failure? */ - return ath_keyset(sc, key->keyidx+32, hk, addr); + if (*csz == 0) + *csz = DEFAULT_CACHELINE >> 2; /* Use the default size */ } -static int ath_key_config(struct ath_softc *sc, - const u8 *addr, - struct ieee80211_key_conf *key) +static void ath_setcurmode(struct ath_softc *sc, enum wireless_mode mode) { - struct ieee80211_vif *vif; - struct ath9k_keyval hk; - const u8 *mac = NULL; - int ret = 0; - enum nl80211_iftype opmode; - - memset(&hk, 0, sizeof(hk)); - - switch (key->alg) { - case ALG_WEP: - hk.kv_type = ATH9K_CIPHER_WEP; - break; - case ALG_TKIP: - hk.kv_type = ATH9K_CIPHER_TKIP; - break; - case ALG_CCMP: - hk.kv_type = ATH9K_CIPHER_AES_CCM; - break; - default: - return -EINVAL; - } - - hk.kv_len = key->keylen; - memcpy(hk.kv_val, key->key, key->keylen); - - if (!sc->sc_vaps[0]) - return -EIO; - - vif = sc->sc_vaps[0]->av_if_data; - opmode = vif->type; - + sc->cur_rate_table = sc->hw_rate_table[mode]; /* - * Strategy: - * For _M_STA mc tx, we will not setup a key at all since we never - * tx mc. - * _M_STA mc rx, we will use the keyID. - * for _M_IBSS mc tx, we will use the keyID, and no macaddr. - * for _M_IBSS mc rx, we will alloc a slot and plumb the mac of the - * peer node. BUT we will plumb a cleartext key so that we can do - * perSta default key table lookup in software. + * All protection frames are transmited at 2Mb/s for + * 11g, otherwise at 1Mb/s. + * XXX select protection rate index from rate table. */ - if (is_broadcast_ether_addr(addr)) { - switch (opmode) { - case NL80211_IFTYPE_STATION: - /* default key: could be group WPA key - * or could be static WEP key */ - mac = NULL; - break; - case NL80211_IFTYPE_ADHOC: - break; - case NL80211_IFTYPE_AP: - break; - default: - ASSERT(0); - break; - } - } else { - mac = addr; - } - - if (key->alg == ALG_TKIP) - ret = ath_setkey_tkip(sc, key, &hk, mac); - else - ret = ath_keyset(sc, key->keyidx, &hk, mac); - - if (!ret) - return -EIO; - - return 0; + sc->sc_protrix = (mode == ATH9K_MODE_11G ? 1 : 0); } -static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) +static enum wireless_mode ath_chan2mode(struct ath9k_channel *chan) { - int freeslot; - - freeslot = (key->keyidx >= 4) ? 1 : 0; - ath_key_reset(sc, key->keyidx, freeslot); + if (chan->chanmode == CHANNEL_A) + return ATH9K_MODE_11A; + else if (chan->chanmode == CHANNEL_G) + return ATH9K_MODE_11G; + else if (chan->chanmode == CHANNEL_B) + return ATH9K_MODE_11B; + else if (chan->chanmode == CHANNEL_A_HT20) + return ATH9K_MODE_11NA_HT20; + else if (chan->chanmode == CHANNEL_G_HT20) + return ATH9K_MODE_11NG_HT20; + else if (chan->chanmode == CHANNEL_A_HT40PLUS) + return ATH9K_MODE_11NA_HT40PLUS; + else if (chan->chanmode == CHANNEL_A_HT40MINUS) + return ATH9K_MODE_11NA_HT40MINUS; + else if (chan->chanmode == CHANNEL_G_HT40PLUS) + return ATH9K_MODE_11NG_HT40PLUS; + else if (chan->chanmode == CHANNEL_G_HT40MINUS) + return ATH9K_MODE_11NG_HT40MINUS; + + WARN_ON(1); /* should not get here */ + + return ATH9K_MODE_11B; } -static void setup_ht_cap(struct ieee80211_ht_info *ht_info) +static void ath_update_txpow(struct ath_softc *sc) { -#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ -#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ - - ht_info->ht_supported = 1; - ht_info->cap = (u16)IEEE80211_HT_CAP_SUP_WIDTH - |(u16)IEEE80211_HT_CAP_SM_PS - |(u16)IEEE80211_HT_CAP_SGI_40 - |(u16)IEEE80211_HT_CAP_DSSSCCK40; - - ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; - ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; - /* setup supported mcs set */ - memset(ht_info->supp_mcs_set, 0, 16); - ht_info->supp_mcs_set[0] = 0xff; - ht_info->supp_mcs_set[1] = 0xff; - ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; -} - -static int ath_rate2idx(struct ath_softc *sc, int rate) -{ - int i = 0, cur_band, n_rates; - struct ieee80211_hw *hw = sc->hw; - - cur_band = hw->conf.channel->band; - n_rates = sc->sbands[cur_band].n_bitrates; + struct ath_hal *ah = sc->sc_ah; + u32 txpow; - for (i = 0; i < n_rates; i++) { - if (sc->sbands[cur_band].bitrates[i].bitrate == rate) - break; + if (sc->sc_curtxpow != sc->sc_config.txpowlimit) { + ath9k_hw_set_txpowerlimit(ah, sc->sc_config.txpowlimit); + /* read back in case value is clamped */ + ath9k_hw_getcapability(ah, ATH9K_CAP_TXPOW, 1, &txpow); + sc->sc_curtxpow = txpow; } - - /* - * NB:mac80211 validates rx rate index against the supported legacy rate - * index only (should be done against ht rates also), return the highest - * legacy rate index for rx rate which does not match any one of the - * supported basic and extended rates to make mac80211 happy. - * The following hack will be cleaned up once the issue with - * the rx rate index validation in mac80211 is fixed. - */ - if (i == n_rates) - return n_rates - 1; - return i; -} - -static void ath9k_rx_prepare(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - struct ieee80211_rx_status *rx_status) -{ - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_channel *curchan = hw->conf.channel; - - memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - - rx_status->mactime = status->tsf; - rx_status->band = curchan->band; - rx_status->freq = curchan->center_freq; - rx_status->noise = sc->sc_ani.sc_noise_floor; - rx_status->signal = rx_status->noise + status->rssi; - rx_status->rate_idx = ath_rate2idx(sc, (status->rateKbps / 100)); - rx_status->antenna = status->antenna; - - /* XXX Fix me, 64 cannot be the max rssi value, rigure it out */ - rx_status->qual = status->rssi * 100 / 64; - - if (status->flags & ATH_RX_MIC_ERROR) - rx_status->flag |= RX_FLAG_MMIC_ERROR; - if (status->flags & ATH_RX_FCS_ERROR) - rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; - - rx_status->flag |= RX_FLAG_TSFT; } static u8 parse_mpdudensity(u8 mpdudensity) @@ -325,241 +144,803 @@ static u8 parse_mpdudensity(u8 mpdudensity) } } -static void ath9k_ht_conf(struct ath_softc *sc, - struct ieee80211_bss_conf *bss_conf) +static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band) { -#define IEEE80211_HT_CAP_40MHZ_INTOLERANT BIT(14) - struct ath_ht_info *ht_info = &sc->sc_ht_info; + struct ath_rate_table *rate_table = NULL; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate; + int i, maxrates; - if (bss_conf->assoc_ht) { - ht_info->ext_chan_offset = - bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_IE_CHA_SEC_OFFSET; + switch (band) { + case IEEE80211_BAND_2GHZ: + rate_table = sc->hw_rate_table[ATH9K_MODE_11G]; + break; + case IEEE80211_BAND_5GHZ: + rate_table = sc->hw_rate_table[ATH9K_MODE_11A]; + break; + default: + break; + } - if (!(bss_conf->ht_conf->cap & - IEEE80211_HT_CAP_40MHZ_INTOLERANT) && - (bss_conf->ht_bss_conf->bss_cap & - IEEE80211_HT_IE_CHA_WIDTH)) - ht_info->tx_chan_width = ATH9K_HT_MACMODE_2040; - else - ht_info->tx_chan_width = ATH9K_HT_MACMODE_20; + if (rate_table == NULL) + return; - ath9k_hw_set11nmac2040(sc->sc_ah, ht_info->tx_chan_width); - ht_info->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + - bss_conf->ht_conf->ampdu_factor); - ht_info->mpdudensity = - parse_mpdudensity(bss_conf->ht_conf->ampdu_density); + sband = &sc->sbands[band]; + rate = sc->rates[band]; + if (rate_table->rate_cnt > ATH_RATE_MAX) + maxrates = ATH_RATE_MAX; + else + maxrates = rate_table->rate_cnt; + + for (i = 0; i < maxrates; i++) { + rate[i].bitrate = rate_table->info[i].ratekbps / 100; + rate[i].hw_value = rate_table->info[i].ratecode; + sband->n_bitrates++; + DPRINTF(sc, ATH_DBG_CONFIG, "Rate: %2dMbps, ratecode: %2d\n", + rate[i].bitrate / 10, rate[i].hw_value); } - -#undef IEEE80211_HT_CAP_40MHZ_INTOLERANT } -static void ath9k_bss_assoc_info(struct ath_softc *sc, - struct ieee80211_bss_conf *bss_conf) +static int ath_setup_channels(struct ath_softc *sc) { - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_channel *curchan = hw->conf.channel; - struct ath_vap *avp; - int pos; - DECLARE_MAC_BUF(mac); + struct ath_hal *ah = sc->sc_ah; + int nchan, i, a = 0, b = 0; + u8 regclassids[ATH_REGCLASSIDS_MAX]; + u32 nregclass = 0; + struct ieee80211_supported_band *band_2ghz; + struct ieee80211_supported_band *band_5ghz; + struct ieee80211_channel *chan_2ghz; + struct ieee80211_channel *chan_5ghz; + struct ath9k_channel *c; + + /* Fill in ah->ah_channels */ + if (!ath9k_regd_init_channels(ah, ATH_CHAN_MAX, (u32 *)&nchan, + regclassids, ATH_REGCLASSIDS_MAX, + &nregclass, CTRY_DEFAULT, false, 1)) { + u32 rd = ah->ah_currentRD; + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to collect channel list; " + "regdomain likely %u country code %u\n", + rd, CTRY_DEFAULT); + return -EINVAL; + } - if (bss_conf->assoc) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Bss Info ASSOC %d\n", - __func__, - bss_conf->aid); - - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; + band_2ghz = &sc->sbands[IEEE80211_BAND_2GHZ]; + band_5ghz = &sc->sbands[IEEE80211_BAND_5GHZ]; + chan_2ghz = sc->channels[IEEE80211_BAND_2GHZ]; + chan_5ghz = sc->channels[IEEE80211_BAND_5GHZ]; + + for (i = 0; i < nchan; i++) { + c = &ah->ah_channels[i]; + if (IS_CHAN_2GHZ(c)) { + chan_2ghz[a].band = IEEE80211_BAND_2GHZ; + chan_2ghz[a].center_freq = c->channel; + chan_2ghz[a].max_power = c->maxTxPower; + + if (c->privFlags & CHANNEL_DISALLOW_ADHOC) + chan_2ghz[a].flags |= IEEE80211_CHAN_NO_IBSS; + if (c->channelFlags & CHANNEL_PASSIVE) + chan_2ghz[a].flags |= IEEE80211_CHAN_PASSIVE_SCAN; + + band_2ghz->n_channels = ++a; + + DPRINTF(sc, ATH_DBG_CONFIG, "2MHz channel: %d, " + "channelFlags: 0x%x\n", + c->channel, c->channelFlags); + } else if (IS_CHAN_5GHZ(c)) { + chan_5ghz[b].band = IEEE80211_BAND_5GHZ; + chan_5ghz[b].center_freq = c->channel; + chan_5ghz[b].max_power = c->maxTxPower; + + if (c->privFlags & CHANNEL_DISALLOW_ADHOC) + chan_5ghz[b].flags |= IEEE80211_CHAN_NO_IBSS; + if (c->channelFlags & CHANNEL_PASSIVE) + chan_5ghz[b].flags |= IEEE80211_CHAN_PASSIVE_SCAN; + + band_5ghz->n_channels = ++b; + + DPRINTF(sc, ATH_DBG_CONFIG, "5MHz channel: %d, " + "channelFlags: 0x%x\n", + c->channel, c->channelFlags); } + } - /* New association, store aid */ - if (avp->av_opmode == ATH9K_M_STA) { - sc->sc_curaid = bss_conf->aid; - ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, - sc->sc_curaid); - } + return 0; +} - /* Configure the beacon */ - ath_beacon_config(sc, 0); - sc->sc_flags |= SC_OP_BEACONS; +/* + * Set/change channels. If the channel is really being changed, it's done + * by reseting the chip. To accomplish this we must first cleanup any pending + * DMA, then restart stuff. +*/ +static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan) +{ + struct ath_hal *ah = sc->sc_ah; + bool fastcc = true, stopped; - /* Reset rssi stats */ - sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; - sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; + if (sc->sc_flags & SC_OP_INVALID) + return -EIO; + + if (hchan->channel != sc->sc_ah->ah_curchan->channel || + hchan->channelFlags != sc->sc_ah->ah_curchan->channelFlags || + (sc->sc_flags & SC_OP_CHAINMASK_UPDATE) || + (sc->sc_flags & SC_OP_FULL_RESET)) { + int status; + /* + * This is only performed if the channel settings have + * actually changed. + * + * To switch channels clear any pending DMA operations; + * wait long enough for the RX fifo to drain, reset the + * hardware at the new frequency, and then re-enable + * the relevant bits of the h/w. + */ + ath9k_hw_set_interrupts(ah, 0); + ath_draintxq(sc, false); + stopped = ath_stoprecv(sc); - /* Update chainmask */ - ath_update_chainmask(sc, bss_conf->assoc_ht); + /* XXX: do not flush receive queue here. We don't want + * to flush data frames already in queue because of + * changing channel. */ + + if (!stopped || (sc->sc_flags & SC_OP_FULL_RESET)) + fastcc = false; DPRINTF(sc, ATH_DBG_CONFIG, - "%s: bssid %s aid 0x%x\n", - __func__, - print_mac(mac, sc->sc_curbssid), sc->sc_curaid); + "(%u MHz) -> (%u MHz), cflags:%x, chanwidth: %d\n", + sc->sc_ah->ah_curchan->channel, + hchan->channel, hchan->channelFlags, sc->tx_chan_width); + + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, hchan, sc->tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, fastcc, &status)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset channel %u (%uMhz) " + "flags 0x%x hal status %u\n", + ath9k_hw_mhz2ieee(ah, hchan->channel, + hchan->channelFlags), + hchan->channel, hchan->channelFlags, status); + spin_unlock_bh(&sc->sc_resetlock); + return -EIO; + } + spin_unlock_bh(&sc->sc_resetlock); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", - __func__, - curchan->center_freq); + sc->sc_flags &= ~SC_OP_CHAINMASK_UPDATE; + sc->sc_flags &= ~SC_OP_FULL_RESET; - pos = ath_get_channel(sc, curchan); - if (pos == -1) { + if (ath_startrecv(sc) != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: Invalid channel\n", __func__); - return; + "Unable to restart recv logic\n"); + return -EIO; } - if (hw->conf.ht_conf.ht_supported) - sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan); - else - sc->sc_ah->ah_channels[pos].chanmode = - (curchan->band == IEEE80211_BAND_2GHZ) ? - CHANNEL_G : CHANNEL_A; + ath_setcurmode(sc, ath_chan2mode(hchan)); + ath_update_txpow(sc); + ath9k_hw_set_interrupts(ah, sc->sc_imask); + } + return 0; +} - /* set h/w channel */ - if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to set channel\n", - __func__); +/* + * This routine performs the periodic noise floor calibration function + * that is used to adjust and optimize the chip performance. This + * takes environmental changes (location, temperature) into account. + * When the task is complete, it reschedules itself depending on the + * appropriate interval that was calculated. + */ +static void ath_ani_calibrate(unsigned long data) +{ + struct ath_softc *sc; + struct ath_hal *ah; + bool longcal = false; + bool shortcal = false; + bool aniflag = false; + unsigned int timestamp = jiffies_to_msecs(jiffies); + u32 cal_interval; - ath_rate_newstate(sc, avp); - /* Update ratectrl about the new state */ - ath_rc_node_update(hw, avp->rc_node); + sc = (struct ath_softc *)data; + ah = sc->sc_ah; - /* Start ANI */ - mod_timer(&sc->sc_ani.timer, - jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); + /* + * don't calibrate when we're scanning. + * we are most likely not on our home channel. + */ + if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC) + return; + + /* Long calibration runs independently of short calibration. */ + if ((timestamp - sc->sc_ani.sc_longcal_timer) >= ATH_LONG_CALINTERVAL) { + longcal = true; + DPRINTF(sc, ATH_DBG_ANI, "longcal @%lu\n", jiffies); + sc->sc_ani.sc_longcal_timer = timestamp; + } + /* Short calibration applies only while sc_caldone is false */ + if (!sc->sc_ani.sc_caldone) { + if ((timestamp - sc->sc_ani.sc_shortcal_timer) >= + ATH_SHORT_CALINTERVAL) { + shortcal = true; + DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies); + sc->sc_ani.sc_shortcal_timer = timestamp; + sc->sc_ani.sc_resetcal_timer = timestamp; + } } else { - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Bss Info DISSOC\n", __func__); - sc->sc_curaid = 0; + if ((timestamp - sc->sc_ani.sc_resetcal_timer) >= + ATH_RESTART_CALINTERVAL) { + ath9k_hw_reset_calvalid(ah, ah->ah_curchan, + &sc->sc_ani.sc_caldone); + if (sc->sc_ani.sc_caldone) + sc->sc_ani.sc_resetcal_timer = timestamp; + } + } + + /* Verify whether we must check ANI */ + if ((timestamp - sc->sc_ani.sc_checkani_timer) >= + ATH_ANI_POLLINTERVAL) { + aniflag = true; + sc->sc_ani.sc_checkani_timer = timestamp; + } + + /* Skip all processing if there's nothing to do. */ + if (longcal || shortcal || aniflag) { + /* Call ANI routine if necessary */ + if (aniflag) + ath9k_hw_ani_monitor(ah, &sc->sc_halstats, + ah->ah_curchan); + + /* Perform calibration if necessary */ + if (longcal || shortcal) { + bool iscaldone = false; + + if (ath9k_hw_calibrate(ah, ah->ah_curchan, + sc->sc_rx_chainmask, longcal, + &iscaldone)) { + if (longcal) + sc->sc_ani.sc_noise_floor = + ath9k_hw_getchan_noise(ah, + ah->ah_curchan); + + DPRINTF(sc, ATH_DBG_ANI, + "calibrate chan %u/%x nf: %d\n", + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags, + sc->sc_ani.sc_noise_floor); + } else { + DPRINTF(sc, ATH_DBG_ANY, + "calibrate chan %u/%x failed\n", + ah->ah_curchan->channel, + ah->ah_curchan->channelFlags); + } + sc->sc_ani.sc_caldone = iscaldone; + } } + + /* + * Set timer interval based on previous results. + * The interval must be the shortest necessary to satisfy ANI, + * short calibration and long calibration. + */ + cal_interval = ATH_LONG_CALINTERVAL; + if (sc->sc_ah->ah_config.enable_ani) + cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL); + if (!sc->sc_ani.sc_caldone) + cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL); + + mod_timer(&sc->sc_ani.timer, jiffies + msecs_to_jiffies(cal_interval)); } -void ath_get_beaconconfig(struct ath_softc *sc, - int if_id, - struct ath_beacon_config *conf) +/* + * Update tx/rx chainmask. For legacy association, + * hard code chainmask to 1x1, for 11n association, use + * the chainmask configuration. + */ +static void ath_update_chainmask(struct ath_softc *sc, int is_ht) { - struct ieee80211_hw *hw = sc->hw; + sc->sc_flags |= SC_OP_CHAINMASK_UPDATE; + if (is_ht) { + sc->sc_tx_chainmask = sc->sc_ah->ah_caps.tx_chainmask; + sc->sc_rx_chainmask = sc->sc_ah->ah_caps.rx_chainmask; + } else { + sc->sc_tx_chainmask = 1; + sc->sc_rx_chainmask = 1; + } + + DPRINTF(sc, ATH_DBG_CONFIG, "tx chmask: %d, rx chmask: %d\n", + sc->sc_tx_chainmask, sc->sc_rx_chainmask); +} + +static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta) +{ + struct ath_node *an; + + an = (struct ath_node *)sta->drv_priv; - /* fill in beacon config data */ + if (sc->sc_flags & SC_OP_TXAGGR) + ath_tx_node_init(sc, an); - conf->beacon_interval = hw->conf.beacon_int; - conf->listen_interval = 100; - conf->dtim_count = 1; - conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; + an->maxampdu = 1 << (IEEE80211_HTCAP_MAXRXAMPDU_FACTOR + + sta->ht_cap.ampdu_factor); + an->mpdudensity = parse_mpdudensity(sta->ht_cap.ampdu_density); } -void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, - struct ath_xmit_status *tx_status, struct ath_node *an) +static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta) { - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_node *an = (struct ath_node *)sta->drv_priv; + + if (sc->sc_flags & SC_OP_TXAGGR) + ath_tx_node_cleanup(sc, an); +} - DPRINTF(sc, ATH_DBG_XMIT, - "%s: TX complete: skb: %p\n", __func__, skb); +static void ath9k_tasklet(unsigned long data) +{ + struct ath_softc *sc = (struct ath_softc *)data; + u32 status = sc->sc_intrstatus; + + if (status & ATH9K_INT_FATAL) { + /* need a chip reset */ + ath_reset(sc, false); + return; + } else { - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || - tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { - /* free driver's private data area of tx_info */ - if (tx_info->driver_data[0] != NULL) - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; + if (status & + (ATH9K_INT_RX | ATH9K_INT_RXEOL | ATH9K_INT_RXORN)) { + spin_lock_bh(&sc->rx.rxflushlock); + ath_rx_tasklet(sc, 0); + spin_unlock_bh(&sc->rx.rxflushlock); + } + /* XXX: optimize this */ + if (status & ATH9K_INT_TX) + ath_tx_tasklet(sc); } - if (tx_status->flags & ATH_TX_BAR) { - tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; - tx_status->flags &= ~ATH_TX_BAR; + /* re-enable hardware interrupt */ + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); +} + +static irqreturn_t ath_isr(int irq, void *dev) +{ + struct ath_softc *sc = dev; + struct ath_hal *ah = sc->sc_ah; + enum ath9k_int status; + bool sched = false; + + do { + if (sc->sc_flags & SC_OP_INVALID) { + /* + * The hardware is not ready/present, don't + * touch anything. Note this can happen early + * on if the IRQ is shared. + */ + return IRQ_NONE; + } + if (!ath9k_hw_intrpend(ah)) { /* shared irq, not for us */ + return IRQ_NONE; + } + + /* + * Figure out the reason(s) for the interrupt. Note + * that the hal returns a pseudo-ISR that may include + * bits we haven't explicitly enabled so we mask the + * value to insure we only process bits we requested. + */ + ath9k_hw_getisr(ah, &status); /* NB: clears ISR too */ + + status &= sc->sc_imask; /* discard unasked-for bits */ + + /* + * If there are no status bits set, then this interrupt was not + * for me (should have been caught above). + */ + if (!status) + return IRQ_NONE; + + sc->sc_intrstatus = status; + + if (status & ATH9K_INT_FATAL) { + /* need a chip reset */ + sched = true; + } else if (status & ATH9K_INT_RXORN) { + /* need a chip reset */ + sched = true; + } else { + if (status & ATH9K_INT_SWBA) { + /* schedule a tasklet for beacon handling */ + tasklet_schedule(&sc->bcon_tasklet); + } + if (status & ATH9K_INT_RXEOL) { + /* + * NB: the hardware should re-read the link when + * RXE bit is written, but it doesn't work + * at least on older hardware revs. + */ + sched = true; + } + + if (status & ATH9K_INT_TXURN) + /* bump tx trigger level */ + ath9k_hw_updatetxtriglevel(ah, true); + /* XXX: optimize this */ + if (status & ATH9K_INT_RX) + sched = true; + if (status & ATH9K_INT_TX) + sched = true; + if (status & ATH9K_INT_BMISS) + sched = true; + /* carrier sense timeout */ + if (status & ATH9K_INT_CST) + sched = true; + if (status & ATH9K_INT_MIB) { + /* + * Disable interrupts until we service the MIB + * interrupt; otherwise it will continue to + * fire. + */ + ath9k_hw_set_interrupts(ah, 0); + /* + * Let the hal handle the event. We assume + * it will clear whatever condition caused + * the interrupt. + */ + ath9k_hw_procmibevent(ah, &sc->sc_halstats); + ath9k_hw_set_interrupts(ah, sc->sc_imask); + } + if (status & ATH9K_INT_TIM_TIMER) { + if (!(ah->ah_caps.hw_caps & + ATH9K_HW_CAP_AUTOSLEEP)) { + /* Clear RxAbort bit so that we can + * receive frames */ + ath9k_hw_setrxabort(ah, 0); + sched = true; + } + } + } + } while (0); + + ath_debug_stat_interrupt(sc, status); + + if (sched) { + /* turn off every interrupt except SWBA */ + ath9k_hw_set_interrupts(ah, (sc->sc_imask & ATH9K_INT_SWBA)); + tasklet_schedule(&sc->intr_tq); } - if (tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY)) { - if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { - /* Frame was not ACKed, but an ACK was expected */ - tx_info->status.excessive_retries = 1; + return IRQ_HANDLED; +} + +static int ath_get_channel(struct ath_softc *sc, + struct ieee80211_channel *chan) +{ + int i; + + for (i = 0; i < sc->sc_ah->ah_nchan; i++) { + if (sc->sc_ah->ah_channels[i].channel == chan->center_freq) + return i; + } + + return -1; +} + +static u32 ath_get_extchanmode(struct ath_softc *sc, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + u32 chanmode = 0; + + switch (chan->band) { + case IEEE80211_BAND_2GHZ: + switch(channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + chanmode = CHANNEL_G_HT20; + break; + case NL80211_CHAN_HT40PLUS: + chanmode = CHANNEL_G_HT40PLUS; + break; + case NL80211_CHAN_HT40MINUS: + chanmode = CHANNEL_G_HT40MINUS; + break; + } + break; + case IEEE80211_BAND_5GHZ: + switch(channel_type) { + case NL80211_CHAN_NO_HT: + case NL80211_CHAN_HT20: + chanmode = CHANNEL_A_HT20; + break; + case NL80211_CHAN_HT40PLUS: + chanmode = CHANNEL_A_HT40PLUS; + break; + case NL80211_CHAN_HT40MINUS: + chanmode = CHANNEL_A_HT40MINUS; + break; + } + break; + default: + break; + } + + return chanmode; +} + +static int ath_keyset(struct ath_softc *sc, u16 keyix, + struct ath9k_keyval *hk, const u8 mac[ETH_ALEN]) +{ + bool status; + + status = ath9k_hw_set_keycache_entry(sc->sc_ah, + keyix, hk, mac, false); + + return status != false; +} + +static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key, + struct ath9k_keyval *hk, + const u8 *addr) +{ + const u8 *key_rxmic; + const u8 *key_txmic; + + key_txmic = key + NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; + key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; + + if (addr == NULL) { + /* Group key installation */ + memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); + return ath_keyset(sc, keyix, hk, addr); + } + if (!sc->sc_splitmic) { + /* + * data key goes at first index, + * the hal handles the MIC keys at index+64. + */ + memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); + memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic)); + return ath_keyset(sc, keyix, hk, addr); + } + /* + * TX key goes at first index, RX key at +32. + * The hal handles the MIC keys at index+64. + */ + memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic)); + if (!ath_keyset(sc, keyix, hk, NULL)) { + /* Txmic entry failed. No need to proceed further */ + DPRINTF(sc, ATH_DBG_KEYCACHE, + "Setting TX MIC Key Failed\n"); + return 0; + } + + memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic)); + /* XXX delete tx key on failure? */ + return ath_keyset(sc, keyix + 32, hk, addr); +} + +static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc) +{ + int i; + + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) { + if (test_bit(i, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap)) + continue; /* At least one part of TKIP key allocated */ + if (sc->sc_splitmic && + (test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + continue; /* At least one part of TKIP key allocated */ + + /* Found a free slot for a TKIP key */ + return i; + } + return -1; +} + +static int ath_reserve_key_cache_slot(struct ath_softc *sc) +{ + int i; + + /* First, try to find slots that would not be available for TKIP. */ + if (sc->sc_splitmic) { + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 4; i++) { + if (!test_bit(i, sc->sc_keymap) && + (test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + return i; + if (!test_bit(i + 32, sc->sc_keymap) && + (test_bit(i, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + return i + 32; + if (!test_bit(i + 64, sc->sc_keymap) && + (test_bit(i , sc->sc_keymap) || + test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64 + 32, sc->sc_keymap))) + return i + 64; + if (!test_bit(i + 64 + 32, sc->sc_keymap) && + (test_bit(i, sc->sc_keymap) || + test_bit(i + 32, sc->sc_keymap) || + test_bit(i + 64, sc->sc_keymap))) + return i + 64 + 32; } } else { - /* Frame was ACKed */ - tx_info->flags |= IEEE80211_TX_STAT_ACK; + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax / 2; i++) { + if (!test_bit(i, sc->sc_keymap) && + test_bit(i + 64, sc->sc_keymap)) + return i; + if (test_bit(i, sc->sc_keymap) && + !test_bit(i + 64, sc->sc_keymap)) + return i + 64; + } } - tx_info->status.retry_count = tx_status->retries; + /* No partially used TKIP slots, pick any available slot */ + for (i = IEEE80211_WEP_NKID; i < sc->sc_keymax; i++) { + /* Do not allow slots that could be needed for TKIP group keys + * to be used. This limitation could be removed if we know that + * TKIP will not be used. */ + if (i >= 64 && i < 64 + IEEE80211_WEP_NKID) + continue; + if (sc->sc_splitmic) { + if (i >= 32 && i < 32 + IEEE80211_WEP_NKID) + continue; + if (i >= 64 + 32 && i < 64 + 32 + IEEE80211_WEP_NKID) + continue; + } - ieee80211_tx_status(hw, skb); - if (an) - ath_node_put(sc, an, ATH9K_BH_STATUS_CHANGE); + if (!test_bit(i, sc->sc_keymap)) + return i; /* Found a free slot for a key */ + } + + /* No free slot found */ + return -1; } -int _ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix) +static int ath_key_config(struct ath_softc *sc, + const u8 *addr, + struct ieee80211_key_conf *key) { - struct ieee80211_hw *hw = sc->hw; - struct ath_node *an = NULL; - struct ieee80211_rx_status rx_status; - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - int hdrlen = ieee80211_get_hdrlen_from_skb(skb); - int padsize; - enum ATH_RX_TYPE st; - - /* see if any padding is done by the hw and remove it */ - if (hdrlen & 3) { - padsize = hdrlen % 4; - memmove(skb->data + padsize, skb->data, hdrlen); - skb_pull(skb, padsize); + struct ath9k_keyval hk; + const u8 *mac = NULL; + int ret = 0; + int idx; + + memset(&hk, 0, sizeof(hk)); + + switch (key->alg) { + case ALG_WEP: + hk.kv_type = ATH9K_CIPHER_WEP; + break; + case ALG_TKIP: + hk.kv_type = ATH9K_CIPHER_TKIP; + break; + case ALG_CCMP: + hk.kv_type = ATH9K_CIPHER_AES_CCM; + break; + default: + return -EINVAL; + } + + hk.kv_len = key->keylen; + memcpy(hk.kv_val, key->key, key->keylen); + + if (!(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) { + /* For now, use the default keys for broadcast keys. This may + * need to change with virtual interfaces. */ + idx = key->keyidx; + } else if (key->keyidx) { + struct ieee80211_vif *vif; + + mac = addr; + vif = sc->sc_vaps[0]; + if (vif->type != NL80211_IFTYPE_AP) { + /* Only keyidx 0 should be used with unicast key, but + * allow this for client mode for now. */ + idx = key->keyidx; + } else + return -EIO; + } else { + mac = addr; + if (key->alg == ALG_TKIP) + idx = ath_reserve_key_cache_slot_tkip(sc); + else + idx = ath_reserve_key_cache_slot(sc); + if (idx < 0) + return -EIO; /* no free key cache entries */ + } + + if (key->alg == ALG_TKIP) + ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac); + else + ret = ath_keyset(sc, idx, &hk, mac); + + if (!ret) + return -EIO; + + set_bit(idx, sc->sc_keymap); + if (key->alg == ALG_TKIP) { + set_bit(idx + 64, sc->sc_keymap); + if (sc->sc_splitmic) { + set_bit(idx + 32, sc->sc_keymap); + set_bit(idx + 64 + 32, sc->sc_keymap); + } } - /* Prepare rx status */ - ath9k_rx_prepare(sc, skb, status, &rx_status); + return idx; +} + +static void ath_key_delete(struct ath_softc *sc, struct ieee80211_key_conf *key) +{ + ath9k_hw_keyreset(sc->sc_ah, key->hw_key_idx); + if (key->hw_key_idx < IEEE80211_WEP_NKID) + return; - if (!(keyix == ATH9K_RXKEYIX_INVALID) && - !(status->flags & ATH_RX_DECRYPT_ERROR)) { - rx_status.flag |= RX_FLAG_DECRYPTED; - } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) - && !(status->flags & ATH_RX_DECRYPT_ERROR) - && skb->len >= hdrlen + 4) { - keyix = skb->data[hdrlen + 3] >> 6; + clear_bit(key->hw_key_idx, sc->sc_keymap); + if (key->alg != ALG_TKIP) + return; - if (test_bit(keyix, sc->sc_keymap)) - rx_status.flag |= RX_FLAG_DECRYPTED; + clear_bit(key->hw_key_idx + 64, sc->sc_keymap); + if (sc->sc_splitmic) { + clear_bit(key->hw_key_idx + 32, sc->sc_keymap); + clear_bit(key->hw_key_idx + 64 + 32, sc->sc_keymap); } +} - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr2); - spin_unlock_bh(&sc->node_lock); +static void setup_ht_cap(struct ieee80211_sta_ht_cap *ht_info) +{ +#define ATH9K_HT_CAP_MAXRXAMPDU_65536 0x3 /* 2 ^ 16 */ +#define ATH9K_HT_CAP_MPDUDENSITY_8 0x6 /* 8 usec */ - if (an) { - ath_rx_input(sc, an, - hw->conf.ht_conf.ht_supported, - skb, status, &st); - } - if (!an || (st != ATH_RX_CONSUMED)) - __ieee80211_rx(hw, skb, &rx_status); + ht_info->ht_supported = true; + ht_info->cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | + IEEE80211_HT_CAP_SM_PS | + IEEE80211_HT_CAP_SGI_40 | + IEEE80211_HT_CAP_DSSSCCK40; - return 0; + ht_info->ampdu_factor = ATH9K_HT_CAP_MAXRXAMPDU_65536; + ht_info->ampdu_density = ATH9K_HT_CAP_MPDUDENSITY_8; + /* set up supported mcs set */ + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); + ht_info->mcs.rx_mask[0] = 0xff; + ht_info->mcs.rx_mask[1] = 0xff; + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; } -int ath_rx_subframe(struct ath_node *an, - struct sk_buff *skb, - struct ath_recv_status *status) +static void ath9k_bss_assoc_info(struct ath_softc *sc, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *bss_conf) { - struct ath_softc *sc = an->an_sc; - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_rx_status rx_status; + struct ath_vap *avp = (void *)vif->drv_priv; - /* Prepare rx status */ - ath9k_rx_prepare(sc, skb, status, &rx_status); - if (!(status->flags & ATH_RX_DECRYPT_ERROR)) - rx_status.flag |= RX_FLAG_DECRYPTED; + if (bss_conf->assoc) { + DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info ASSOC %d, bssid: %pM\n", + bss_conf->aid, sc->sc_curbssid); - __ieee80211_rx(hw, skb, &rx_status); + /* New association, store aid */ + if (avp->av_opmode == NL80211_IFTYPE_STATION) { + sc->sc_curaid = bss_conf->aid; + ath9k_hw_write_associd(sc->sc_ah, sc->sc_curbssid, + sc->sc_curaid); + } - return 0; + /* Configure the beacon */ + ath_beacon_config(sc, 0); + sc->sc_flags |= SC_OP_BEACONS; + + /* Reset rssi stats */ + sc->sc_halstats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgtxrssi = ATH_RSSI_DUMMY_MARKER; + sc->sc_halstats.ns_avgtxrate = ATH_RATE_DUMMY_MARKER; + + /* Start ANI */ + mod_timer(&sc->sc_ani.timer, + jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL)); + + } else { + DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n"); + sc->sc_curaid = 0; + } } /********************************/ @@ -677,7 +1058,8 @@ fail: ath_deinit_leds(sc); } -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + /*******************/ /* Rfkill */ /*******************/ @@ -689,14 +1071,14 @@ static void ath_radio_enable(struct ath_softc *sc) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, + sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset channel %u (%uMhz) " - "flags 0x%x hal status %u\n", __func__, + "Unable to reset channel %u (%uMhz) " + "flags 0x%x hal status %u\n", ath9k_hw_mhz2ieee(ah, ah->ah_curchan->channel, ah->ah_curchan->channelFlags), @@ -708,7 +1090,7 @@ static void ath_radio_enable(struct ath_softc *sc) ath_update_txpow(sc); if (ath_startrecv(sc) != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to restart recv logic\n", __func__); + "Unable to restart recv logic\n"); return; } @@ -747,14 +1129,14 @@ static void ath_radio_disable(struct ath_softc *sc) spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, + sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset channel %u (%uMhz) " - "flags 0x%x hal status %u\n", __func__, + "Unable to reset channel %u (%uMhz) " + "flags 0x%x hal status %u\n", ath9k_hw_mhz2ieee(ah, ah->ah_curchan->channel, ah->ah_curchan->channelFlags), @@ -834,7 +1216,7 @@ static int ath_sw_toggle_radio(void *data, enum rfkill_state state) sc->sc_flags &= ~SC_OP_RFKILL_SW_BLOCKED; if (sc->sc_flags & SC_OP_RFKILL_HW_BLOCKED) { DPRINTF(sc, ATH_DBG_FATAL, "Can't turn on the" - "radio as it is disabled by h/w \n"); + "radio as it is disabled by h/w\n"); return -EPERM; } ath_radio_enable(sc); @@ -878,61 +1260,258 @@ static void ath_deinit_rfkill(struct ath_softc *sc) sc->rf_kill.rfkill = NULL; } } + +static int ath_start_rfkill_poll(struct ath_softc *sc) +{ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + queue_delayed_work(sc->hw->workqueue, + &sc->rf_kill.rfkill_poll, 0); + + if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { + if (rfkill_register(sc->rf_kill.rfkill)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to register rfkill\n"); + rfkill_free(sc->rf_kill.rfkill); + + /* Deinitialize the device */ + ath_detach(sc); + if (sc->pdev->irq) + free_irq(sc->pdev->irq, sc); + pci_iounmap(sc->pdev, sc->mem); + pci_release_region(sc->pdev, 0); + pci_disable_device(sc->pdev); + ieee80211_free_hw(sc->hw); + return -EIO; + } else { + sc->sc_flags |= SC_OP_RFKILL_REGISTERED; + } + } + + return 0; +} #endif /* CONFIG_RFKILL */ -static int ath_detach(struct ath_softc *sc) +static void ath_detach(struct ath_softc *sc) { struct ieee80211_hw *hw = sc->hw; + int i = 0; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach ATH hw\n", __func__); + DPRINTF(sc, ATH_DBG_CONFIG, "Detach ATH hw\n"); - /* Deinit LED control */ - ath_deinit_leds(sc); - -#ifdef CONFIG_RFKILL - /* deinit rfkill */ +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) ath_deinit_rfkill(sc); #endif - - /* Unregister hw */ + ath_deinit_leds(sc); ieee80211_unregister_hw(hw); - - /* unregister Rate control */ - ath_rate_control_unregister(); - - /* tx/rx cleanup */ - ath_rx_cleanup(sc); ath_tx_cleanup(sc); - /* Deinit */ + tasklet_kill(&sc->intr_tq); + tasklet_kill(&sc->bcon_tasklet); - ath_deinit(sc); + if (!(sc->sc_flags & SC_OP_INVALID)) + ath9k_hw_setpower(sc->sc_ah, ATH9K_PM_AWAKE); - return 0; + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); + + ath9k_hw_detach(sc->sc_ah); + ath9k_exit_debug(sc); } -static int ath_attach(u16 devid, - struct ath_softc *sc) +static int ath_init(u16 devid, struct ath_softc *sc) { - struct ieee80211_hw *hw = sc->hw; - int error = 0; + struct ath_hal *ah = NULL; + int status; + int error = 0, i; + int csz = 0; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach ATH hw\n", __func__); + /* XXX: hardware will not be ready until ath_open() being called */ + sc->sc_flags |= SC_OP_INVALID; - error = ath_init(devid, sc); - if (error != 0) - return error; + if (ath9k_init_debug(sc) < 0) + printk(KERN_ERR "Unable to create debugfs files\n"); - /* Init nodes */ + spin_lock_init(&sc->sc_resetlock); + mutex_init(&sc->mutex); + tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc); + tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet, + (unsigned long)sc); + + /* + * Cache line size is used to size and align various + * structures used to communicate with the hardware. + */ + bus_read_cachesize(sc, &csz); + /* XXX assert csz is non-zero */ + sc->sc_cachelsz = csz << 2; /* convert to bytes */ - INIT_LIST_HEAD(&sc->node_list); - spin_lock_init(&sc->node_lock); + ah = ath9k_hw_attach(devid, sc, sc->mem, &status); + if (ah == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to attach hardware; HAL status %u\n", status); + error = -ENXIO; + goto bad; + } + sc->sc_ah = ah; - /* get mac address from hardware and set in mac80211 */ + /* Get the hardware key cache size. */ + sc->sc_keymax = ah->ah_caps.keycache_size; + if (sc->sc_keymax > ATH_KEYMAX) { + DPRINTF(sc, ATH_DBG_KEYCACHE, + "Warning, using only %u entries in %u key cache\n", + ATH_KEYMAX, sc->sc_keymax); + sc->sc_keymax = ATH_KEYMAX; + } - SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); + /* + * Reset the key cache since some parts do not + * reset the contents on initial power up. + */ + for (i = 0; i < sc->sc_keymax; i++) + ath9k_hw_keyreset(ah, (u16) i); + + /* Collect the channel list using the default country code */ + + error = ath_setup_channels(sc); + if (error) + goto bad; + + /* default to MONITOR mode */ + sc->sc_ah->ah_opmode = NL80211_IFTYPE_MONITOR; + + + /* Setup rate tables */ + + ath_rate_attach(sc); + ath_setup_rates(sc, IEEE80211_BAND_2GHZ); + ath_setup_rates(sc, IEEE80211_BAND_5GHZ); + + /* + * Allocate hardware transmit queues: one queue for + * beacon frames and one data queue for each QoS + * priority. Note that the hal handles reseting + * these queues at the needed time. + */ + sc->beacon.beaconq = ath_beaconq_setup(ah); + if (sc->beacon.beaconq == -1) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup a beacon xmit queue\n"); + error = -EIO; + goto bad2; + } + sc->beacon.cabq = ath_txq_setup(sc, ATH9K_TX_QUEUE_CAB, 0); + if (sc->beacon.cabq == NULL) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup CAB xmit queue\n"); + error = -EIO; + goto bad2; + } + + sc->sc_config.cabqReadytime = ATH_CABQ_READY_TIME; + ath_cabq_update(sc); + + for (i = 0; i < ARRAY_SIZE(sc->tx.hwq_map); i++) + sc->tx.hwq_map[i] = -1; + + /* Setup data queues */ + /* NB: ensure BK queue is the lowest priority h/w queue */ + if (!ath_tx_setup(sc, ATH9K_WME_AC_BK)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for BK traffic\n"); + error = -EIO; + goto bad2; + } + + if (!ath_tx_setup(sc, ATH9K_WME_AC_BE)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for BE traffic\n"); + error = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VI)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for VI traffic\n"); + error = -EIO; + goto bad2; + } + if (!ath_tx_setup(sc, ATH9K_WME_AC_VO)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to setup xmit queue for VO traffic\n"); + error = -EIO; + goto bad2; + } + + /* Initializes the noise floor to a reasonable default value. + * Later on this will be updated during ANI processing. */ + + sc->sc_ani.sc_noise_floor = ATH_DEFAULT_NOISE_FLOOR; + setup_timer(&sc->sc_ani.timer, ath_ani_calibrate, (unsigned long)sc); + + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL)) { + /* + * Whether we should enable h/w TKIP MIC. + * XXX: if we don't support WME TKIP MIC, then we wouldn't + * report WMM capable, so it's always safe to turn on + * TKIP MIC in this case. + */ + ath9k_hw_setcapability(sc->sc_ah, ATH9K_CAP_TKIP_MIC, + 0, 1, NULL); + } + + /* + * Check whether the separate key cache entries + * are required to handle both tx+rx MIC keys. + * With split mic keys the number of stations is limited + * to 27 otherwise 59. + */ + if (ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_TKIP, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_CIPHER, + ATH9K_CIPHER_MIC, NULL) + && ath9k_hw_getcapability(ah, ATH9K_CAP_TKIP_SPLIT, + 0, NULL)) + sc->sc_splitmic = 1; + + /* turn on mcast key search if possible */ + if (!ath9k_hw_getcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 0, NULL)) + (void)ath9k_hw_setcapability(ah, ATH9K_CAP_MCAST_KEYSRCH, 1, + 1, NULL); + + sc->sc_config.txpowlimit = ATH_TXPOWER_MAX; + sc->sc_config.txpowlimit_override = 0; + + /* 11n Capabilities */ + if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { + sc->sc_flags |= SC_OP_TXAGGR; + sc->sc_flags |= SC_OP_RXAGGR; + } + + sc->sc_tx_chainmask = ah->ah_caps.tx_chainmask; + sc->sc_rx_chainmask = ah->ah_caps.rx_chainmask; + + ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL); + sc->rx.defant = ath9k_hw_getdefantenna(ah); + + ath9k_hw_getmac(ah, sc->sc_myaddr); + if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) { + ath9k_hw_getbssidmask(ah, sc->sc_bssidmask); + ATH_SET_VAP_BSSID_MASK(sc->sc_bssidmask); + ath9k_hw_setbssidmask(ah, sc->sc_bssidmask); + } + + sc->beacon.slottime = ATH9K_SLOT_TIME_9; /* default to short slot time */ + + /* initialize beacon slots */ + for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) + sc->beacon.bslot[i] = ATH_IF_ID_ANY; + + /* save MISC configurations */ + sc->sc_config.swBeaconProcess = 1; /* setup channels and rates */ @@ -942,146 +1521,455 @@ static int ath_attach(u16 devid, sc->rates[IEEE80211_BAND_2GHZ]; sc->sbands[IEEE80211_BAND_2GHZ].band = IEEE80211_BAND_2GHZ; - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - /* Setup HT capabilities for 2.4Ghz*/ - setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_info); - - hw->wiphy->bands[IEEE80211_BAND_2GHZ] = - &sc->sbands[IEEE80211_BAND_2GHZ]; - if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) { sc->sbands[IEEE80211_BAND_5GHZ].channels = sc->channels[IEEE80211_BAND_5GHZ]; sc->sbands[IEEE80211_BAND_5GHZ].bitrates = sc->rates[IEEE80211_BAND_5GHZ]; - sc->sbands[IEEE80211_BAND_5GHZ].band = - IEEE80211_BAND_5GHZ; + sc->sbands[IEEE80211_BAND_5GHZ].band = IEEE80211_BAND_5GHZ; + } + + return 0; +bad2: + /* cleanup tx queues */ + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) + if (ATH_TXQ_SETUP(sc, i)) + ath_tx_cleanupq(sc, &sc->tx.txq[i]); +bad: + if (ah) + ath9k_hw_detach(ah); + + return error; +} + +static int ath_attach(u16 devid, struct ath_softc *sc) +{ + struct ieee80211_hw *hw = sc->hw; + int error = 0; + + DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n"); + + error = ath_init(devid, sc); + if (error != 0) + return error; + + /* get mac address from hardware and set in mac80211 */ + + SET_IEEE80211_PERM_ADDR(hw, sc->sc_myaddr); + + hw->flags = IEEE80211_HW_RX_INCLUDES_FCS | + IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | + IEEE80211_HW_AMPDU_AGGREGATION; + + hw->wiphy->interface_modes = + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC); + + hw->queues = 4; + hw->max_rates = 4; + hw->max_rate_tries = ATH_11N_TXMAXTRY; + hw->sta_data_size = sizeof(struct ath_node); + hw->vif_data_size = sizeof(struct ath_vap); + + hw->rate_control_algorithm = "ath9k_rate_control"; + + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { + setup_ht_cap(&sc->sbands[IEEE80211_BAND_2GHZ].ht_cap); + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) + setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_cap); + } + + hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ]; + if (test_bit(ATH9K_MODE_11A, sc->sc_ah->ah_caps.wireless_modes)) + hw->wiphy->bands[IEEE80211_BAND_5GHZ] = + &sc->sbands[IEEE80211_BAND_5GHZ]; + + /* initialize tx/rx engine */ + error = ath_tx_init(sc, ATH_TXBUF); + if (error != 0) + goto detach; + + error = ath_rx_init(sc, ATH_RXBUF); + if (error != 0) + goto detach; + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + /* Initialze h/w Rfkill */ + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) + INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); + + /* Initialize s/w rfkill */ + if (ath_init_sw_rfkill(sc)) + goto detach; +#endif + + error = ieee80211_register_hw(hw); + + /* Initialize LED control */ + ath_init_leds(sc); + + return 0; +detach: + ath_detach(sc); + return error; +} + +int ath_reset(struct ath_softc *sc, bool retry_tx) +{ + struct ath_hal *ah = sc->sc_ah; + int status; + int error = 0; + + ath9k_hw_set_interrupts(ah, 0); + ath_draintxq(sc, retry_tx); + ath_stoprecv(sc); + ath_flushrecv(sc); + + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, + sc->tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to reset hardware; hal status %u\n", status); + error = -EIO; + } + spin_unlock_bh(&sc->sc_resetlock); + + if (ath_startrecv(sc) != 0) + DPRINTF(sc, ATH_DBG_FATAL, "Unable to start recv logic\n"); + + /* + * We may be doing a reset in response to a request + * that changes the channel so update any state that + * might change as a result. + */ + ath_setcurmode(sc, ath_chan2mode(sc->sc_ah->ah_curchan)); + + ath_update_txpow(sc); + + if (sc->sc_flags & SC_OP_BEACONS) + ath_beacon_config(sc, ATH_IF_ID_ANY); /* restart beacons */ + + ath9k_hw_set_interrupts(ah, sc->sc_imask); + + if (retry_tx) { + int i; + for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { + if (ATH_TXQ_SETUP(sc, i)) { + spin_lock_bh(&sc->tx.txq[i].axq_lock); + ath_txq_schedule(sc, &sc->tx.txq[i]); + spin_unlock_bh(&sc->tx.txq[i].axq_lock); + } + } + } + + return error; +} + +/* + * This function will allocate both the DMA descriptor structure, and the + * buffers it contains. These are used to contain the descriptors used + * by the system. +*/ +int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd, + struct list_head *head, const char *name, + int nbuf, int ndesc) +{ +#define DS2PHYS(_dd, _ds) \ + ((_dd)->dd_desc_paddr + ((caddr_t)(_ds) - (caddr_t)(_dd)->dd_desc)) +#define ATH_DESC_4KB_BOUND_CHECK(_daddr) ((((_daddr) & 0xFFF) > 0xF7F) ? 1 : 0) +#define ATH_DESC_4KB_BOUND_NUM_SKIPPED(_len) ((_len) / 4096) + + struct ath_desc *ds; + struct ath_buf *bf; + int i, bsize, error; + + DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n", + name, nbuf, ndesc); + + /* ath_desc must be a multiple of DWORDs */ + if ((sizeof(struct ath_desc) % 4) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n"); + ASSERT((sizeof(struct ath_desc) % 4) == 0); + error = -ENOMEM; + goto fail; + } + + dd->dd_name = name; + dd->dd_desc_len = sizeof(struct ath_desc) * nbuf * ndesc; + + /* + * Need additional DMA memory because we can't use + * descriptors that cross the 4K page boundary. Assume + * one skipped descriptor per 4K page. + */ + if (!(sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_4KB_SPLITTRANS)) { + u32 ndesc_skipped = + ATH_DESC_4KB_BOUND_NUM_SKIPPED(dd->dd_desc_len); + u32 dma_len; - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) - /* Setup HT capabilities for 5Ghz*/ - setup_ht_cap(&sc->sbands[IEEE80211_BAND_5GHZ].ht_info); + while (ndesc_skipped) { + dma_len = ndesc_skipped * sizeof(struct ath_desc); + dd->dd_desc_len += dma_len; - hw->wiphy->bands[IEEE80211_BAND_5GHZ] = - &sc->sbands[IEEE80211_BAND_5GHZ]; + ndesc_skipped = ATH_DESC_4KB_BOUND_NUM_SKIPPED(dma_len); + }; } - /* FIXME: Have to figure out proper hw init values later */ + /* allocate descriptors */ + dd->dd_desc = pci_alloc_consistent(sc->pdev, + dd->dd_desc_len, + &dd->dd_desc_paddr); + if (dd->dd_desc == NULL) { + error = -ENOMEM; + goto fail; + } + ds = dd->dd_desc; + DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA map: %p (%u) -> %llx (%u)\n", + dd->dd_name, ds, (u32) dd->dd_desc_len, + ito64(dd->dd_desc_paddr), /*XXX*/(u32) dd->dd_desc_len); + + /* allocate buffers */ + bsize = sizeof(struct ath_buf) * nbuf; + bf = kmalloc(bsize, GFP_KERNEL); + if (bf == NULL) { + error = -ENOMEM; + goto fail2; + } + memset(bf, 0, bsize); + dd->dd_bufptr = bf; - hw->queues = 4; - hw->ampdu_queues = 1; + INIT_LIST_HEAD(head); + for (i = 0; i < nbuf; i++, bf++, ds += ndesc) { + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); - /* Register rate control */ - hw->rate_control_algorithm = "ath9k_rate_control"; - error = ath_rate_control_register(); - if (error != 0) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to register rate control " - "algorithm:%d\n", __func__, error); - ath_rate_control_unregister(); - goto bad; + if (!(sc->sc_ah->ah_caps.hw_caps & + ATH9K_HW_CAP_4KB_SPLITTRANS)) { + /* + * Skip descriptor addresses which can cause 4KB + * boundary crossing (addr + length) with a 32 dword + * descriptor fetch. + */ + while (ATH_DESC_4KB_BOUND_CHECK(bf->bf_daddr)) { + ASSERT((caddr_t) bf->bf_desc < + ((caddr_t) dd->dd_desc + + dd->dd_desc_len)); + + ds += ndesc; + bf->bf_desc = ds; + bf->bf_daddr = DS2PHYS(dd, ds); + } + } + list_add_tail(&bf->list, head); } + return 0; +fail2: + pci_free_consistent(sc->pdev, + dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); +fail: + memset(dd, 0, sizeof(*dd)); + return error; +#undef ATH_DESC_4KB_BOUND_CHECK +#undef ATH_DESC_4KB_BOUND_NUM_SKIPPED +#undef DS2PHYS +} - error = ieee80211_register_hw(hw); - if (error != 0) { - ath_rate_control_unregister(); - goto bad; - } +void ath_descdma_cleanup(struct ath_softc *sc, + struct ath_descdma *dd, + struct list_head *head) +{ + pci_free_consistent(sc->pdev, + dd->dd_desc_len, dd->dd_desc, dd->dd_desc_paddr); - /* Initialize LED control */ - ath_init_leds(sc); + INIT_LIST_HEAD(head); + kfree(dd->dd_bufptr); + memset(dd, 0, sizeof(*dd)); +} -#ifdef CONFIG_RFKILL - /* Initialze h/w Rfkill */ - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll); +int ath_get_hal_qnum(u16 queue, struct ath_softc *sc) +{ + int qnum; - /* Initialize s/w rfkill */ - if (ath_init_sw_rfkill(sc)) - goto detach; -#endif + switch (queue) { + case 0: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_VO]; + break; + case 1: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_VI]; + break; + case 2: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; + break; + case 3: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BK]; + break; + default: + qnum = sc->tx.hwq_map[ATH9K_WME_AC_BE]; + break; + } - /* initialize tx/rx engine */ + return qnum; +} - error = ath_tx_init(sc, ATH_TXBUF); - if (error != 0) - goto detach; +int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc) +{ + int qnum; - error = ath_rx_init(sc, ATH_RXBUF); - if (error != 0) - goto detach; + switch (queue) { + case ATH9K_WME_AC_VO: + qnum = 0; + break; + case ATH9K_WME_AC_VI: + qnum = 1; + break; + case ATH9K_WME_AC_BE: + qnum = 2; + break; + case ATH9K_WME_AC_BK: + qnum = 3; + break; + default: + qnum = -1; + break; + } - return 0; -detach: - ath_detach(sc); -bad: - return error; + return qnum; } +/**********************/ +/* mac80211 callbacks */ +/**********************/ + static int ath9k_start(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; struct ieee80211_channel *curchan = hw->conf.channel; - int error = 0, pos; + struct ath9k_channel *init_channel; + int error = 0, pos, status; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Starting driver with " - "initial channel: %d MHz\n", __func__, curchan->center_freq); + DPRINTF(sc, ATH_DBG_CONFIG, "Starting driver with " + "initial channel: %d MHz\n", curchan->center_freq); /* setup initial channel */ pos = ath_get_channel(sc, curchan); if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); - return -EINVAL; + DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", curchan->center_freq); + error = -EINVAL; + goto error; } + sc->tx_chan_width = ATH9K_HT_MACMODE_20; sc->sc_ah->ah_channels[pos].chanmode = (curchan->band == IEEE80211_BAND_2GHZ) ? CHANNEL_G : CHANNEL_A; + init_channel = &sc->sc_ah->ah_channels[pos]; + + /* Reset SERDES registers */ + ath9k_hw_configpcipowersave(sc->sc_ah, 0); - /* open ath_dev */ - error = ath_open(sc, &sc->sc_ah->ah_channels[pos]); - if (error) { + /* + * The basic interface to setting the hardware in a good + * state is ``reset''. On return the hardware is known to + * be powered up and with interrupts disabled. This must + * be followed by initialization of the appropriate bits + * and then setup of the interrupt mask. + */ + spin_lock_bh(&sc->sc_resetlock); + if (!ath9k_hw_reset(sc->sc_ah, init_channel, + sc->tx_chan_width, + sc->sc_tx_chainmask, sc->sc_rx_chainmask, + sc->sc_ht_extprotspacing, false, &status)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to complete ath_open\n", __func__); - return error; + "Unable to reset hardware; hal status %u " + "(freq %u flags 0x%x)\n", status, + init_channel->channel, init_channel->channelFlags); + error = -EIO; + spin_unlock_bh(&sc->sc_resetlock); + goto error; } + spin_unlock_bh(&sc->sc_resetlock); -#ifdef CONFIG_RFKILL - /* Start rfkill polling */ - if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) - queue_delayed_work(sc->hw->workqueue, - &sc->rf_kill.rfkill_poll, 0); - - if (!(sc->sc_flags & SC_OP_RFKILL_REGISTERED)) { - if (rfkill_register(sc->rf_kill.rfkill)) { - DPRINTF(sc, ATH_DBG_FATAL, - "Unable to register rfkill\n"); - rfkill_free(sc->rf_kill.rfkill); + /* + * This is needed only to setup initial state + * but it's best done after a reset. + */ + ath_update_txpow(sc); - /* Deinitialize the device */ - if (sc->pdev->irq) - free_irq(sc->pdev->irq, sc); - ath_detach(sc); - pci_iounmap(sc->pdev, sc->mem); - pci_release_region(sc->pdev, 0); - pci_disable_device(sc->pdev); - ieee80211_free_hw(hw); - return -EIO; - } else { - sc->sc_flags |= SC_OP_RFKILL_REGISTERED; - } + /* + * Setup the hardware after reset: + * The receive engine is set going. + * Frame transmit is handled entirely + * in the frame output path; there's nothing to do + * here except setup the interrupt mask. + */ + if (ath_startrecv(sc) != 0) { + DPRINTF(sc, ATH_DBG_FATAL, + "Unable to start recv logic\n"); + error = -EIO; + goto error; } + + /* Setup our intr mask. */ + sc->sc_imask = ATH9K_INT_RX | ATH9K_INT_TX + | ATH9K_INT_RXEOL | ATH9K_INT_RXORN + | ATH9K_INT_FATAL | ATH9K_INT_GLOBAL; + + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_GTT) + sc->sc_imask |= ATH9K_INT_GTT; + + if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) + sc->sc_imask |= ATH9K_INT_CST; + + /* + * Enable MIB interrupts when there are hardware phy counters. + * Note we only do this (at the moment) for station mode. + */ + if (ath9k_hw_phycounters(sc->sc_ah) && + ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) || + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC))) + sc->sc_imask |= ATH9K_INT_MIB; + /* + * Some hardware processes the TIM IE and fires an + * interrupt when the TIM bit is set. For hardware + * that does, if not overridden by configuration, + * enable the TIM interrupt when operating as station. + */ + if ((sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_ENHANCEDPM) && + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) && + !sc->sc_config.swBeaconProcess) + sc->sc_imask |= ATH9K_INT_TIM; + + ath_setcurmode(sc, ath_chan2mode(init_channel)); + + sc->sc_flags &= ~SC_OP_INVALID; + + /* Disable BMISS interrupt when we're not associated */ + sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); + ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask); + + ieee80211_wake_queues(sc->hw); + +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) + error = ath_start_rfkill_poll(sc); #endif - ieee80211_wake_queues(hw); - return 0; +error: + return error; } static int ath9k_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_softc *sc = hw->priv; + struct ath_tx_control txctl; int hdrlen, padsize; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + memset(&txctl, 0, sizeof(struct ath_tx_control)); /* * As a temporary workaround, assign seq# here; this will likely need @@ -1091,9 +1979,9 @@ static int ath9k_tx(struct ieee80211_hw *hw, if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - sc->seq_no += 0x10; + sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } /* Add the padding after the header if this is not already done */ @@ -1106,45 +1994,68 @@ static int ath9k_tx(struct ieee80211_hw *hw, memmove(skb->data, skb->data + padsize, hdrlen); } - DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting packet, skb: %p\n", - __func__, - skb); + /* Check if a tx queue is available */ - if (ath_tx_start(sc, skb) != 0) { - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX failed\n", __func__); - dev_kfree_skb_any(skb); - /* FIXME: Check for proper return value from ATH_DEV */ - return 0; + txctl.txq = ath_test_get_txq(sc, skb); + if (!txctl.txq) + goto exit; + + DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb); + + if (ath_tx_start(sc, skb, &txctl) != 0) { + DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n"); + goto exit; } + return 0; +exit: + dev_kfree_skb_any(skb); return 0; } static void ath9k_stop(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; - int error; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Driver halt\n", __func__); + if (sc->sc_flags & SC_OP_INVALID) { + DPRINTF(sc, ATH_DBG_ANY, "Device not present\n"); + return; + } + + DPRINTF(sc, ATH_DBG_CONFIG, "Cleaning up\n"); - error = ath_suspend(sc); - if (error) - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Device is no longer present\n", __func__); + ieee80211_stop_queues(sc->hw); + + /* make sure h/w will not generate any interrupt + * before setting the invalid flag. */ + ath9k_hw_set_interrupts(sc->sc_ah, 0); - ieee80211_stop_queues(hw); + if (!(sc->sc_flags & SC_OP_INVALID)) { + ath_draintxq(sc, false); + ath_stoprecv(sc); + ath9k_hw_phy_disable(sc->sc_ah); + } else + sc->rx.rxlink = NULL; -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); #endif + /* disable HAL and put h/w to sleep */ + ath9k_hw_disable(sc->sc_ah); + ath9k_hw_configpcipowersave(sc->sc_ah, 1); + + sc->sc_flags |= SC_OP_INVALID; + + DPRINTF(sc, ATH_DBG_CONFIG, "Driver halt\n"); } static int ath9k_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ath_softc *sc = hw->priv; - int error, ic_opmode = 0; + struct ath_vap *avp = (void *)conf->vif->drv_priv; + enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED; /* Support only vap for now */ @@ -1153,32 +2064,34 @@ static int ath9k_add_interface(struct ieee80211_hw *hw, switch (conf->type) { case NL80211_IFTYPE_STATION: - ic_opmode = ATH9K_M_STA; + ic_opmode = NL80211_IFTYPE_STATION; break; case NL80211_IFTYPE_ADHOC: - ic_opmode = ATH9K_M_IBSS; + ic_opmode = NL80211_IFTYPE_ADHOC; break; case NL80211_IFTYPE_AP: - ic_opmode = ATH9K_M_HOSTAP; + ic_opmode = NL80211_IFTYPE_AP; break; default: DPRINTF(sc, ATH_DBG_FATAL, - "%s: Interface type %d not yet supported\n", - __func__, conf->type); + "Interface type %d not yet supported\n", conf->type); return -EOPNOTSUPP; } - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a VAP of type: %d\n", - __func__, - ic_opmode); + DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VAP of type: %d\n", ic_opmode); - error = ath_vap_attach(sc, 0, conf->vif, ic_opmode); - if (error) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to attach vap, error: %d\n", - __func__, error); - return error; - } + /* Set the VAP opmode */ + avp->av_opmode = ic_opmode; + avp->av_bslot = -1; + + if (ic_opmode == NL80211_IFTYPE_AP) + ath9k_hw_set_tsfadjust(sc->sc_ah, 1); + + sc->sc_vaps[0] = conf->vif; + sc->sc_nvaps++; + + /* Set the device opmode */ + sc->sc_ah->ah_opmode = ic_opmode; if (conf->type == NL80211_IFTYPE_AP) { /* TODO: is this a suitable place to start ANI for AP mode? */ @@ -1194,78 +2107,76 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct ath_softc *sc = hw->priv; - struct ath_vap *avp; - int error; - - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Detach VAP\n", __func__); + struct ath_vap *avp = (void *)conf->vif->drv_priv; - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return; - } + DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n"); -#ifdef CONFIG_SLOW_ANT_DIV - ath_slow_ant_div_stop(&sc->sc_antdiv); -#endif /* Stop ANI */ del_timer_sync(&sc->sc_ani.timer); - /* Update ratectrl */ - ath_rate_newstate(sc, avp); - /* Reclaim beacon resources */ - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP || - sc->sc_ah->ah_opmode == ATH9K_M_IBSS) { - ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP || + sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) { + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); ath_beacon_return(sc, avp); } - /* Set interrupt mask */ - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_imask & ~ATH9K_INT_GLOBAL); sc->sc_flags &= ~SC_OP_BEACONS; - error = ath_vap_detach(sc, 0); - if (error) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to detach vap, error: %d\n", - __func__, error); + sc->sc_vaps[0] = NULL; + sc->sc_nvaps--; } -static int ath9k_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int ath9k_config(struct ieee80211_hw *hw, u32 changed) { struct ath_softc *sc = hw->priv; - struct ieee80211_channel *curchan = hw->conf.channel; - int pos; + struct ieee80211_conf *conf = &hw->conf; - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set channel: %d MHz\n", - __func__, - curchan->center_freq); + mutex_lock(&sc->mutex); + if (changed & (IEEE80211_CONF_CHANGE_CHANNEL | + IEEE80211_CONF_CHANGE_HT)) { + struct ieee80211_channel *curchan = hw->conf.channel; + int pos; - pos = ath_get_channel(sc, curchan); - if (pos == -1) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid channel\n", __func__); - return -EINVAL; - } + DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n", + curchan->center_freq); - sc->sc_ah->ah_channels[pos].chanmode = - (curchan->band == IEEE80211_BAND_2GHZ) ? - CHANNEL_G : CHANNEL_A; + pos = ath_get_channel(sc, curchan); + if (pos == -1) { + DPRINTF(sc, ATH_DBG_FATAL, "Invalid channel: %d\n", + curchan->center_freq); + mutex_unlock(&sc->mutex); + return -EINVAL; + } - if (sc->sc_curaid && hw->conf.ht_conf.ht_supported) + sc->tx_chan_width = ATH9K_HT_MACMODE_20; sc->sc_ah->ah_channels[pos].chanmode = - ath_get_extchanmode(sc, curchan); + (curchan->band == IEEE80211_BAND_2GHZ) ? + CHANNEL_G : CHANNEL_A; + + if (conf->ht.enabled) { + if (conf->ht.channel_type == NL80211_CHAN_HT40PLUS || + conf->ht.channel_type == NL80211_CHAN_HT40MINUS) + sc->tx_chan_width = ATH9K_HT_MACMODE_2040; + + sc->sc_ah->ah_channels[pos].chanmode = + ath_get_extchanmode(sc, curchan, + conf->ht.channel_type); + } + + if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) { + DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n"); + mutex_unlock(&sc->mutex); + return -EINVAL; + } - sc->sc_config.txpowlimit = 2 * conf->power_level; + ath_update_chainmask(sc, conf->ht.enabled); + } - /* set h/w channel */ - if (ath_set_channel(sc, &sc->sc_ah->ah_channels[pos]) < 0) - DPRINTF(sc, ATH_DBG_FATAL, "%s: Unable to set channel\n", - __func__); + if (changed & IEEE80211_CONF_CHANGE_POWER) + sc->sc_config.txpowlimit = 2 * conf->power_level; + mutex_unlock(&sc->mutex); return 0; } @@ -1275,23 +2186,15 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, { struct ath_softc *sc = hw->priv; struct ath_hal *ah = sc->sc_ah; - struct ath_vap *avp; + struct ath_vap *avp = (void *)vif->drv_priv; u32 rfilt = 0; int error, i; - DECLARE_MAC_BUF(mac); - - avp = sc->sc_vaps[0]; - if (avp == NULL) { - DPRINTF(sc, ATH_DBG_FATAL, "%s: Invalid interface\n", - __func__); - return -EINVAL; - } /* TODO: Need to decide which hw opmode to use for multi-interface * cases */ if (vif->type == NL80211_IFTYPE_AP && - ah->ah_opmode != ATH9K_M_HOSTAP) { - ah->ah_opmode = ATH9K_M_HOSTAP; + ah->ah_opmode != NL80211_IFTYPE_AP) { + ah->ah_opmode = NL80211_IFTYPE_STATION; ath9k_hw_setopmode(ah); ath9k_hw_write_associd(ah, sc->sc_myaddr, 0); /* Request full reset to get hw opmode changed properly */ @@ -1303,9 +2206,6 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, switch (vif->type) { case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: - /* Update ratectrl about the new state */ - ath_rate_newstate(sc, avp); - /* Set BSSID */ memcpy(sc->sc_curbssid, conf->bssid, ETH_ALEN); sc->sc_curaid = 0; @@ -1315,27 +2215,9 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, /* Set aggregation protection mode parameters */ sc->sc_config.ath_aggr_prot = 0; - /* - * Reset our TSF so that its value is lower than the - * beacon that we are trying to catch. - * Only then hw will update its TSF register with the - * new beacon. Reset the TSF before setting the BSSID - * to avoid allowing in any frames that would update - * our TSF only to have us clear it - * immediately thereafter. - */ - ath9k_hw_reset_tsf(sc->sc_ah); - - /* Disable BMISS interrupt when we're not associated */ - ath9k_hw_set_interrupts(sc->sc_ah, - sc->sc_imask & - ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS)); - sc->sc_imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS); - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: RX filter 0x%x bssid %s aid 0x%x\n", - __func__, rfilt, - print_mac(mac, sc->sc_curbssid), sc->sc_curaid); + "RX filter 0x%x bssid %pM aid 0x%x\n", + rfilt, sc->sc_curbssid, sc->sc_curaid); /* need to reconfigure the beacon */ sc->sc_flags &= ~SC_OP_BEACONS ; @@ -1357,7 +2239,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw, * causes reconfiguration; we may be called * with beacon transmission active. */ - ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); + ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); error = ath_beacon_alloc(sc, 0); if (error != 0) @@ -1403,7 +2285,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, changed_flags &= SUPPORTED_FILTERS; *total_flags &= SUPPORTED_FILTERS; - sc->rx_filter = *total_flags; + sc->rx.rxfilter = *total_flags; rfilt = ath_calcrxfilter(sc); ath9k_hw_setrxfilter(sc->sc_ah, rfilt); @@ -1412,8 +2294,7 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw, ath9k_hw_write_associd(sc->sc_ah, ath_bcast_mac, 0); } - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Set HW RX filter: 0x%x\n", - __func__, sc->rx_filter); + DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter); } static void ath9k_sta_notify(struct ieee80211_hw *hw, @@ -1422,37 +2303,13 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw, struct ieee80211_sta *sta) { struct ath_softc *sc = hw->priv; - struct ath_node *an; - unsigned long flags; - DECLARE_MAC_BUF(mac); - - spin_lock_irqsave(&sc->node_lock, flags); - an = ath_node_find(sc, sta->addr); - spin_unlock_irqrestore(&sc->node_lock, flags); switch (cmd) { case STA_NOTIFY_ADD: - spin_lock_irqsave(&sc->node_lock, flags); - if (!an) { - ath_node_attach(sc, sta->addr, 0); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Attach a node: %s\n", - __func__, print_mac(mac, sta->addr)); - } else { - ath_node_get(sc, sta->addr); - } - spin_unlock_irqrestore(&sc->node_lock, flags); + ath_node_attach(sc, sta); break; case STA_NOTIFY_REMOVE: - if (!an) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Removal of a non-existent node\n", - __func__); - else { - ath_node_put(sc, an, ATH9K_BH_STATUS_INTACT); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: Put a node: %s\n", - __func__, - print_mac(mac, sta->addr)); - } + ath_node_detach(sc, sta); break; default: break; @@ -1477,20 +2334,14 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw, qnum = ath_get_hal_qnum(queue, sc); DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Configure tx [queue/halq] [%d/%d], " + "Configure tx [queue/halq] [%d/%d], " "aifs: %d, cw_min: %d, cw_max: %d, txop: %d\n", - __func__, - queue, - qnum, - params->aifs, - params->cw_min, - params->cw_max, - params->txop); + queue, qnum, params->aifs, params->cw_min, + params->cw_max, params->txop); ret = ath_txq_update(sc, qnum, &qi); if (ret) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: TXQ Update failed\n", __func__); + DPRINTF(sc, ATH_DBG_FATAL, "TXQ Update failed\n"); return ret; } @@ -1504,23 +2355,22 @@ static int ath9k_set_key(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; int ret = 0; - DPRINTF(sc, ATH_DBG_KEYCACHE, " %s: Set HW Key\n", __func__); + DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n"); switch (cmd) { case SET_KEY: ret = ath_key_config(sc, addr, key); - if (!ret) { - set_bit(key->keyidx, sc->sc_keymap); - key->hw_key_idx = key->keyidx; + if (ret >= 0) { + key->hw_key_idx = ret; /* push IV and Michael MIC generation to stack */ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; if (key->alg == ALG_TKIP) key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + ret = 0; } break; case DISABLE_KEY: ath_key_delete(sc, key); - clear_bit(key->keyidx, sc->sc_keymap); break; default: ret = -EINVAL; @@ -1537,8 +2387,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, struct ath_softc *sc = hw->priv; if (changed & BSS_CHANGED_ERP_PREAMBLE) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed PREAMBLE %d\n", - __func__, + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed PREAMBLE %d\n", bss_conf->use_short_preamble); if (bss_conf->use_short_preamble) sc->sc_flags |= SC_OP_PREAMBLE_SHORT; @@ -1547,8 +2396,7 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, } if (changed & BSS_CHANGED_ERP_CTS_PROT) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed CTS PROT %d\n", - __func__, + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed CTS PROT %d\n", bss_conf->use_cts_prot); if (bss_conf->use_cts_prot && hw->conf.channel->band != IEEE80211_BAND_5GHZ) @@ -1557,18 +2405,10 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw, sc->sc_flags &= ~SC_OP_PROTECT_ENABLE; } - if (changed & BSS_CHANGED_HT) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed HT %d\n", - __func__, - bss_conf->assoc_ht); - ath9k_ht_conf(sc, bss_conf); - } - if (changed & BSS_CHANGED_ASSOC) { - DPRINTF(sc, ATH_DBG_CONFIG, "%s: BSS Changed ASSOC %d\n", - __func__, + DPRINTF(sc, ATH_DBG_CONFIG, "BSS Changed ASSOC %d\n", bss_conf->assoc); - ath9k_bss_assoc_info(sc, bss_conf); + ath9k_bss_assoc_info(sc, vif, bss_conf); } } @@ -1601,50 +2441,37 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: - ret = ath_rx_aggr_start(sc, sta->addr, tid, ssn); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to start RX aggregation\n", - __func__); + if (!(sc->sc_flags & SC_OP_RXAGGR)) + ret = -ENOTSUPP; break; case IEEE80211_AMPDU_RX_STOP: - ret = ath_rx_aggr_stop(sc, sta->addr, tid); - if (ret < 0) - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to stop RX aggregation\n", - __func__); break; case IEEE80211_AMPDU_TX_START: - ret = ath_tx_aggr_start(sc, sta->addr, tid, ssn); + ret = ath_tx_aggr_start(sc, sta, tid, ssn); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to start TX aggregation\n", - __func__); + "Unable to start TX aggregation\n"); else ieee80211_start_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; case IEEE80211_AMPDU_TX_STOP: - ret = ath_tx_aggr_stop(sc, sta->addr, tid); + ret = ath_tx_aggr_stop(sc, sta, tid); if (ret < 0) DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to stop TX aggregation\n", - __func__); + "Unable to stop TX aggregation\n"); ieee80211_stop_tx_ba_cb_irqsafe(hw, sta->addr, tid); break; + case IEEE80211_AMPDU_TX_RESUME: + ath_tx_aggr_resume(sc, sta, tid); + break; default: - DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unknown AMPDU action\n", __func__); + DPRINTF(sc, ATH_DBG_FATAL, "Unknown AMPDU action\n"); } return ret; } -static int ath9k_no_fragmentation(struct ieee80211_hw *hw, u32 value) -{ - return -EOPNOTSUPP; -} - static struct ieee80211_ops ath9k_ops = { .tx = ath9k_tx, .start = ath9k_start, @@ -1654,42 +2481,97 @@ static struct ieee80211_ops ath9k_ops = { .config = ath9k_config, .config_interface = ath9k_config_interface, .configure_filter = ath9k_configure_filter, - .get_stats = NULL, .sta_notify = ath9k_sta_notify, .conf_tx = ath9k_conf_tx, - .get_tx_stats = NULL, .bss_info_changed = ath9k_bss_info_changed, - .set_tim = NULL, .set_key = ath9k_set_key, - .hw_scan = NULL, - .get_tkip_seq = NULL, - .set_rts_threshold = NULL, - .set_frag_threshold = NULL, - .set_retry_limit = NULL, .get_tsf = ath9k_get_tsf, .reset_tsf = ath9k_reset_tsf, - .tx_last_beacon = NULL, .ampdu_action = ath9k_ampdu_action, - .set_frag_threshold = ath9k_no_fragmentation, }; +static struct { + u32 version; + const char * name; +} ath_mac_bb_names[] = { + { AR_SREV_VERSION_5416_PCI, "5416" }, + { AR_SREV_VERSION_5416_PCIE, "5418" }, + { AR_SREV_VERSION_9100, "9100" }, + { AR_SREV_VERSION_9160, "9160" }, + { AR_SREV_VERSION_9280, "9280" }, + { AR_SREV_VERSION_9285, "9285" } +}; + +static struct { + u16 version; + const char * name; +} ath_rf_names[] = { + { 0, "5133" }, + { AR_RAD5133_SREV_MAJOR, "5133" }, + { AR_RAD5122_SREV_MAJOR, "5122" }, + { AR_RAD2133_SREV_MAJOR, "2133" }, + { AR_RAD2122_SREV_MAJOR, "2122" } +}; + +/* + * Return the MAC/BB name. "????" is returned if the MAC/BB is unknown. + */ +static const char * +ath_mac_bb_name(u32 mac_bb_version) +{ + int i; + + for (i=0; iflags = IEEE80211_HW_RX_INCLUDES_FCS | - IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | - IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; - - hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); - SET_IEEE80211_DEV(hw, &pdev->dev); pci_set_drvdata(pdev, hw); @@ -1778,11 +2650,15 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) goto bad4; } - athname = ath9k_hw_probe(id->vendor, id->device); - - printk(KERN_INFO "%s: %s: mem=0x%lx, irq=%d\n", + ah = sc->sc_ah; + printk(KERN_INFO + "%s: Atheros AR%s MAC/BB Rev:%x " + "AR%s RF Rev:%x: mem=0x%lx, irq=%d\n", wiphy_name(hw->wiphy), - athname ? athname : "Atheros ???", + ath_mac_bb_name(ah->ah_macVersion), + ah->ah_macRev, + ath_rf_name((ah->ah_analog5GhzRev & AR_RADIO_SREV_MAJOR)), + ah->ah_phyRev, (unsigned long)mem, pdev->irq); return 0; @@ -1803,17 +2679,10 @@ static void ath_pci_remove(struct pci_dev *pdev) { struct ieee80211_hw *hw = pci_get_drvdata(pdev); struct ath_softc *sc = hw->priv; - enum ath9k_int status; - if (pdev->irq) { - ath9k_hw_set_interrupts(sc->sc_ah, 0); - /* clear the ISR */ - ath9k_hw_getisr(sc->sc_ah, &status); - sc->sc_flags |= SC_OP_INVALID; - free_irq(pdev->irq, sc); - } ath_detach(sc); - + if (pdev->irq) + free_irq(pdev->irq, sc); pci_iounmap(pdev, sc->mem); pci_release_region(pdev, 0); pci_disable_device(pdev); @@ -1829,7 +2698,7 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state) ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) if (sc->sc_ah->ah_caps.hw_caps & ATH9K_HW_CAP_RFSILENT) cancel_delayed_work_sync(&sc->rf_kill.rfkill_poll); #endif @@ -1866,7 +2735,7 @@ static int ath_pci_resume(struct pci_dev *pdev) AR_GPIO_OUTPUT_MUX_AS_OUTPUT); ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1); -#ifdef CONFIG_RFKILL +#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE) /* * check the h/w rfkill state on resume * and start the rfkill poll timer @@ -1896,11 +2765,24 @@ static struct pci_driver ath_pci_driver = { static int __init init_ath_pci(void) { + int error; + printk(KERN_INFO "%s: %s\n", dev_info, ATH_PCI_VERSION); + /* Register rate control algorithm */ + error = ath_rate_control_register(); + if (error != 0) { + printk(KERN_ERR + "Unable to register rate control algorithm: %d\n", + error); + ath_rate_control_unregister(); + return error; + } + if (pci_register_driver(&ath_pci_driver) < 0) { printk(KERN_ERR "ath_pci: No devices found, driver not installed.\n"); + ath_rate_control_unregister(); pci_unregister_driver(&ath_pci_driver); return -ENODEV; } @@ -1911,7 +2793,8 @@ module_init(init_ath_pci); static void __exit exit_ath_pci(void) { + ath_rate_control_unregister(); pci_unregister_driver(&ath_pci_driver); - printk(KERN_INFO "%s: driver unloaded\n", dev_info); + printk(KERN_INFO "%s: Driver unloaded\n", dev_info); } module_exit(exit_ath_pci); diff --git a/drivers/net/wireless/ath9k/phy.c b/drivers/net/wireless/ath9k/phy.c index eb9121fdfd385389087807526edcc28924e12942..766982a8196e38b154348f14944e816519abea4e 100644 --- a/drivers/net/wireless/ath9k/phy.c +++ b/drivers/net/wireless/ath9k/phy.c @@ -52,8 +52,7 @@ ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan) bModeSynth = 1; } else { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u MHz\n", __func__, - freq); + "Invalid channel %u MHz\n", freq); return false; } @@ -86,7 +85,7 @@ ath9k_hw_set_channel(struct ath_hal *ah, struct ath9k_channel *chan) aModeRefSel = ath9k_hw_reverse_bits(1, 2); } else { DPRINTF(ah->ah_sc, ATH_DBG_CHANNEL, - "%s: invalid channel %u MHz\n", __func__, freq); + "Invalid channel %u MHz\n", freq); return false; } @@ -215,7 +214,7 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan, if (AR_SREV_9280_10_OR_LATER(ah)) return true; - eepMinorRev = ath9k_hw_get_eeprom(ahp, EEP_MINOR_REV); + eepMinorRev = ath9k_hw_get_eeprom(ah, EEP_MINOR_REV); RF_BANK_SETUP(ahp->ah_analogBank0Data, &ahp->ah_iniBank0, 1); @@ -235,15 +234,15 @@ ath9k_hw_set_rf_regs(struct ath_hal *ah, struct ath9k_channel *chan, if (eepMinorRev >= 2) { if (IS_CHAN_2GHZ(chan)) { - ob2GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_2); - db2GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_2); + ob2GHz = ath9k_hw_get_eeprom(ah, EEP_OB_2); + db2GHz = ath9k_hw_get_eeprom(ah, EEP_DB_2); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, ob2GHz, 3, 197, 0); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, db2GHz, 3, 194, 0); } else { - ob5GHz = ath9k_hw_get_eeprom(ahp, EEP_OB_5); - db5GHz = ath9k_hw_get_eeprom(ahp, EEP_DB_5); + ob5GHz = ath9k_hw_get_eeprom(ah, EEP_OB_5); + db5GHz = ath9k_hw_get_eeprom(ah, EEP_DB_5); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, ob5GHz, 3, 203, 0); ath9k_phy_modify_rx_buffer(ahp->ah_analogBank6Data, @@ -348,8 +347,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status) || ahp->ah_analogBank6TPCData == NULL || ahp->ah_analogBank7Data == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: cannot allocate RF banks\n", - __func__); + "Cannot allocate RF banks\n"); *status = -ENOMEM; return false; } @@ -360,8 +358,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status) ahp->ah_iniAddac.ia_columns), GFP_KERNEL); if (ahp->ah_addac5416_21 == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: cannot allocate ah_addac5416_21\n", - __func__); + "Cannot allocate ah_addac5416_21\n"); *status = -ENOMEM; return false; } @@ -371,8 +368,7 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, int *status) ahp->ah_iniBank6.ia_rows), GFP_KERNEL); if (ahp->ah_bank6Temp == NULL) { DPRINTF(ah->ah_sc, ATH_DBG_FATAL, - "%s: cannot allocate ah_bank6Temp\n", - __func__); + "Cannot allocate ah_bank6Temp\n"); *status = -ENOMEM; return false; } diff --git a/drivers/net/wireless/ath9k/phy.h b/drivers/net/wireless/ath9k/phy.h index 14702344448be9ee15d38836550806a80c193b44..3a406a5c0593c624d0f4a5d3842778fdb342874e 100644 --- a/drivers/net/wireless/ath9k/phy.h +++ b/drivers/net/wireless/ath9k/phy.h @@ -50,6 +50,9 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, #define AR_PHY_FC_SHORT_GI_40 0x00000080 #define AR_PHY_FC_WALSH 0x00000100 #define AR_PHY_FC_SINGLE_HT_LTF1 0x00000200 +#define AR_PHY_FC_ENABLE_DAC_FIFO 0x00000800 + +#define AR_PHY_TEST2 0x9808 #define AR_PHY_TIMING2 0x9810 #define AR_PHY_TIMING3 0x9814 @@ -100,6 +103,8 @@ bool ath9k_hw_init_rf(struct ath_hal *ah, #define AR_PHY_RF_CTL4_FRAME_XPAA_ON 0x000000FF #define AR_PHY_RF_CTL4_FRAME_XPAA_ON_S 0 +#define AR_PHY_TSTDAC_CONST 0x983c + #define AR_PHY_SETTLING 0x9844 #define AR_PHY_SETTLING_SWITCH 0x00003F80 #define AR_PHY_SETTLING_SWITCH_S 7 diff --git a/drivers/net/wireless/ath9k/rc.c b/drivers/net/wireless/ath9k/rc.c index cca2fc5b07654b3e17107b4acaf2b7893e328d53..04ab457a8faa3f3bce73692b583a61866c72e6e2 100644 --- a/drivers/net/wireless/ath9k/rc.c +++ b/drivers/net/wireless/ath9k/rc.c @@ -15,143 +15,136 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * Atheros rate control algorithm - */ - #include "core.h" -/* FIXME: remove this include! */ -#include "../net/mac80211/rate.h" - -static u32 tx_triglevel_max; static struct ath_rate_table ar5416_11na_ratetable = { 42, + {0}, { - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, 0, 2, 1, 0, 0, 0, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 0, 3, 1, 1, 1, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, 24, 2, 4, 2, 2, 2, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, 2, 6, 2, 3, 3, 3, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, 48, 4, 10, 3, 4, 4, 4, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, 4, 14, 3, 5, 5, 5, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 4, 20, 3, 6, 6, 6, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, 4, 23, 3, 7, 7, 7, 7, 0 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, 0, 2, 3, 8, 24, 8, 24, 3216 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ 12700, 0x81, 0x00, 1, 2, 4, 3, 9, 25, 9, 25, 6434 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ 18800, 0x82, 0x00, 2, 2, 6, 3, 10, 26, 10, 26, 9650 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ 25000, 0x83, 0x00, 3, 4, 10, 3, 11, 27, 11, 27, 12868 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ 36700, 0x84, 0x00, 4, 4, 14, 3, 12, 28, 12, 28, 19304 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ 48100, 0x85, 0x00, 5, 4, 20, 3, 13, 29, 13, 29, 25740 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ 53500, 0x86, 0x00, 6, 4, 23, 3, 14, 30, 14, 30, 28956 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ 59000, 0x87, 0x00, 7, 4, 25, 3, 15, 31, 15, 32, 32180 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ 12700, 0x88, 0x00, 8, 0, 2, 3, 16, 33, 16, 33, 6430 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ 24800, 0x89, 0x00, 9, 2, 4, 3, 17, 34, 17, 34, 12860 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ 36600, 0x8a, 0x00, 10, 2, 6, 3, 18, 35, 18, 35, 19300 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ 48100, 0x8b, 0x00, 11, 4, 10, 3, 19, 36, 19, 36, 25736 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ 69500, 0x8c, 0x00, 12, 4, 14, 3, 20, 37, 20, 37, 38600 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ 89500, 0x8d, 0x00, 13, 4, 20, 3, 21, 38, 21, 38, 51472 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ 98900, 0x8e, 0x00, 14, 4, 23, 3, 22, 39, 22, 39, 57890 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ 108300, 0x8f, 0x00, 15, 4, 25, 3, 23, 40, 23, 41, 64320 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ 13200, 0x80, 0x00, 0, 0, 2, 3, 8, 24, 24, 24, 6684 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ 25900, 0x81, 0x00, 1, 2, 4, 3, 9, 25, 25, 25, 13368 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ 38600, 0x82, 0x00, 2, 2, 6, 3, 10, 26, 26, 26, 20052 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ 49800, 0x83, 0x00, 3, 4, 10, 3, 11, 27, 27, 27, 26738 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ 72200, 0x84, 0x00, 4, 4, 14, 3, 12, 28, 28, 28, 40104 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ 92900, 0x85, 0x00, 5, 4, 20, 3, 13, 29, 29, 29, 53476 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ 102700, 0x86, 0x00, 6, 4, 23, 3, 14, 30, 30, 30, 60156 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ 112000, 0x87, 0x00, 7, 4, 25, 3, 15, 31, 32, 32, 66840 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ 122000, 0x87, 0x00, 7, 4, 25, 3, 15, 31, 32, 32, 74200 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ 25800, 0x88, 0x00, 8, 0, 2, 3, 16, 33, 33, 33, 13360 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ 49800, 0x89, 0x00, 9, 2, 4, 3, 17, 34, 34, 34, 26720 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ 71900, 0x8a, 0x00, 10, 2, 6, 3, 18, 35, 35, 35, 40080 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ 92500, 0x8b, 0x00, 11, 4, 10, 3, 19, 36, 36, 36, 53440 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ 130300, 0x8c, 0x00, 12, 4, 14, 3, 20, 37, 37, 37, 80160 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ 162800, 0x8d, 0x00, 13, 4, 20, 3, 21, 38, 38, 38, 106880 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ 178200, 0x8e, 0x00, 14, 4, 23, 3, 22, 39, 39, 39, 120240 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ 192100, 0x8f, 0x00, 15, 4, 25, 3, 23, 40, 41, 41, 133600 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ 207000, 0x8f, 0x00, 15, 4, 25, 3, 23, 40, 41, 41, 148400 }, }, @@ -160,153 +153,149 @@ static struct ath_rate_table ar5416_11na_ratetable = { WLAN_RC_HT_FLAG, /* Phy rates allowed initially */ }; -/* TRUE_ALL - valid for 20/40/Legacy, - * TRUE - Legacy only, - * TRUE_20 - HT 20 only, - * TRUE_40 - HT 40 only */ - /* 4ms frame limit not used for NG mode. The values filled * for HT are the 64K max aggregate limit */ static struct ath_rate_table ar5416_11ng_ratetable = { 46, + {0}, { - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 1000, /* 1 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, 0, 0, 1, 0, 0, 0, 0, 0 }, - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 2000, /* 2 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1900, 0x1a, 0x04, 4, 1, 1, 1, 1, 1, 1, 1, 0 }, - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 5500, /* 5.5 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4900, 0x19, 0x04, 11, 2, 2, 2, 2, 2, 2, 2, 0 }, - { TRUE_ALL, TRUE_ALL, WLAN_PHY_CCK, 11000, /* 11 Mb */ + { VALID_ALL, VALID_ALL, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 8100, 0x18, 0x04, 22, 3, 3, 2, 3, 3, 3, 3, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, 4, 2, 1, 4, 4, 4, 4, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 4, 3, 1, 5, 5, 5, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10100, 0x0a, 0x00, 24, 6, 4, 1, 6, 6, 6, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 14100, 0x0e, 0x00, 36, 6, 6, 2, 7, 7, 7, 7, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17700, 0x09, 0x00, 48, 8, 10, 3, 8, 8, 8, 8, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23700, 0x0d, 0x00, 72, 8, 14, 3, 9, 9, 9, 9, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 8, 20, 3, 10, 10, 10, 10, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 30900, 0x0c, 0x00, 108, 8, 23, 3, 11, 11, 11, 11, 0 }, - { FALSE, FALSE, WLAN_PHY_HT_20_SS, 6500, /* 6.5 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_SS, 6500, /* 6.5 Mb */ 6400, 0x80, 0x00, 0, 4, 2, 3, 12, 28, 12, 28, 3216 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 13000, /* 13 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 13000, /* 13 Mb */ 12700, 0x81, 0x00, 1, 6, 4, 3, 13, 29, 13, 29, 6434 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 19500, /* 19.5 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 19500, /* 19.5 Mb */ 18800, 0x82, 0x00, 2, 6, 6, 3, 14, 30, 14, 30, 9650 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 26000, /* 26 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 26000, /* 26 Mb */ 25000, 0x83, 0x00, 3, 8, 10, 3, 15, 31, 15, 31, 12868 }, - { TRUE_20, TRUE_20, WLAN_PHY_HT_20_SS, 39000, /* 39 Mb */ + { VALID_20, VALID_20, WLAN_RC_PHY_HT_20_SS, 39000, /* 39 Mb */ 36700, 0x84, 0x00, 4, 8, 14, 3, 16, 32, 16, 32, 19304 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 52000, /* 52 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 52000, /* 52 Mb */ 48100, 0x85, 0x00, 5, 8, 20, 3, 17, 33, 17, 33, 25740 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 58500, /* 58.5 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 58500, /* 58.5 Mb */ 53500, 0x86, 0x00, 6, 8, 23, 3, 18, 34, 18, 34, 28956 }, - { FALSE, TRUE_20, WLAN_PHY_HT_20_SS, 65000, /* 65 Mb */ + { INVALID, VALID_20, WLAN_RC_PHY_HT_20_SS, 65000, /* 65 Mb */ 59000, 0x87, 0x00, 7, 8, 25, 3, 19, 35, 19, 36, 32180 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 13000, /* 13 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 13000, /* 13 Mb */ 12700, 0x88, 0x00, 8, 4, 2, 3, 20, 37, 20, 37, 6430 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 26000, /* 26 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 26000, /* 26 Mb */ 24800, 0x89, 0x00, 9, 6, 4, 3, 21, 38, 21, 38, 12860 }, - { FALSE, FALSE, WLAN_PHY_HT_20_DS, 39000, /* 39 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_20_DS, 39000, /* 39 Mb */ 36600, 0x8a, 0x00, 10, 6, 6, 3, 22, 39, 22, 39, 19300 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 52000, /* 52 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 52000, /* 52 Mb */ 48100, 0x8b, 0x00, 11, 8, 10, 3, 23, 40, 23, 40, 25736 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 78000, /* 78 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 78000, /* 78 Mb */ 69500, 0x8c, 0x00, 12, 8, 14, 3, 24, 41, 24, 41, 38600 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 104000, /* 104 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 104000, /* 104 Mb */ 89500, 0x8d, 0x00, 13, 8, 20, 3, 25, 42, 25, 42, 51472 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 117000, /* 117 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 117000, /* 117 Mb */ 98900, 0x8e, 0x00, 14, 8, 23, 3, 26, 43, 26, 44, 57890 }, - { TRUE_20, FALSE, WLAN_PHY_HT_20_DS, 130000, /* 130 Mb */ + { VALID_20, INVALID, WLAN_RC_PHY_HT_20_DS, 130000, /* 130 Mb */ 108300, 0x8f, 0x00, 15, 8, 25, 3, 27, 44, 27, 45, 64320 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 13500, /* 13.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 13500, /* 13.5 Mb */ 13200, 0x80, 0x00, 0, 8, 2, 3, 12, 28, 28, 28, 6684 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 27500, /* 27.0 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 27500, /* 27.0 Mb */ 25900, 0x81, 0x00, 1, 8, 4, 3, 13, 29, 29, 29, 13368 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 40500, /* 40.5 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 40500, /* 40.5 Mb */ 38600, 0x82, 0x00, 2, 8, 6, 3, 14, 30, 30, 30, 20052 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 54000, /* 54 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 54000, /* 54 Mb */ 49800, 0x83, 0x00, 3, 8, 10, 3, 15, 31, 31, 31, 26738 }, - { TRUE_40, TRUE_40, WLAN_PHY_HT_40_SS, 81500, /* 81 Mb */ + { VALID_40, VALID_40, WLAN_RC_PHY_HT_40_SS, 81500, /* 81 Mb */ 72200, 0x84, 0x00, 4, 8, 14, 3, 16, 32, 32, 32, 40104 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 108000, /* 108 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 108000, /* 108 Mb */ 92900, 0x85, 0x00, 5, 8, 20, 3, 17, 33, 33, 33, 53476 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 121500, /* 121.5 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 121500, /* 121.5 Mb */ 102700, 0x86, 0x00, 6, 8, 23, 3, 18, 34, 34, 34, 60156 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS, 135000, /* 135 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS, 135000, /* 135 Mb */ 112000, 0x87, 0x00, 7, 8, 23, 3, 19, 35, 36, 36, 66840 }, - { FALSE, TRUE_40, WLAN_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ + { INVALID, VALID_40, WLAN_RC_PHY_HT_40_SS_HGI, 150000, /* 150 Mb */ 122000, 0x87, 0x00, 7, 8, 25, 3, 19, 35, 36, 36, 74200 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 27000, /* 27 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 27000, /* 27 Mb */ 25800, 0x88, 0x00, 8, 8, 2, 3, 20, 37, 37, 37, 13360 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 54000, /* 54 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 54000, /* 54 Mb */ 49800, 0x89, 0x00, 9, 8, 4, 3, 21, 38, 38, 38, 26720 }, - { FALSE, FALSE, WLAN_PHY_HT_40_DS, 81000, /* 81 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_HT_40_DS, 81000, /* 81 Mb */ 71900, 0x8a, 0x00, 10, 8, 6, 3, 22, 39, 39, 39, 40080 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 108000, /* 108 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 108000, /* 108 Mb */ 92500, 0x8b, 0x00, 11, 8, 10, 3, 23, 40, 40, 40, 53440 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 162000, /* 162 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 162000, /* 162 Mb */ 130300, 0x8c, 0x00, 12, 8, 14, 3, 24, 41, 41, 41, 80160 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 216000, /* 216 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 216000, /* 216 Mb */ 162800, 0x8d, 0x00, 13, 8, 20, 3, 25, 42, 42, 42, 106880 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 243000, /* 243 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 243000, /* 243 Mb */ 178200, 0x8e, 0x00, 14, 8, 23, 3, 26, 43, 43, 43, 120240 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS, 270000, /* 270 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS, 270000, /* 270 Mb */ 192100, 0x8f, 0x00, 15, 8, 23, 3, 27, 44, 45, 45, 133600 }, - { TRUE_40, FALSE, WLAN_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ + { VALID_40, INVALID, WLAN_RC_PHY_HT_40_DS_HGI, 300000, /* 300 Mb */ 207000, 0x8f, 0x00, 15, 8, 25, 3, 27, 44, 45, 45, 148400 }, }, @@ -317,29 +306,30 @@ static struct ath_rate_table ar5416_11ng_ratetable = { static struct ath_rate_table ar5416_11a_ratetable = { 8, + {0}, { - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, (0x80|12), 0, 2, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 0, 3, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, (0x80|24), 2, 4, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, 2, 6, 2, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, (0x80|48), 4, 10, 3, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, 4, 14, 3, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 4, 19, 3, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, 4, 23, 3, 7, 0 }, }, @@ -348,109 +338,44 @@ static struct ath_rate_table ar5416_11a_ratetable = { 0, /* Phy rates allowed initially */ }; -static struct ath_rate_table ar5416_11a_ratetable_Half = { - 8, - { - { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 6 Mb */ - 2700, 0x0b, 0x00, (0x80|6), - 0, 2, 1, 0, 0}, - { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 9 Mb */ - 3900, 0x0f, 0x00, 9, - 0, 3, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 12 Mb */ - 5000, 0x0a, 0x00, (0x80|12), - 2, 4, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 18 Mb */ - 6950, 0x0e, 0x00, 18, - 2, 6, 2, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 24 Mb */ - 8650, 0x09, 0x00, (0x80|24), - 4, 10, 3, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 36 Mb */ - 11500, 0x0d, 0x00, 36, - 4, 14, 3, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 48 Mb */ - 13700, 0x08, 0x00, 48, - 4, 19, 3, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 27000, /* 54 Mb */ - 14650, 0x0c, 0x00, 54, - 4, 23, 3, 7, 0 }, - }, - 50, /* probe interval */ - 50, /* rssi reduce interval */ - 0, /* Phy rates allowed initially */ -}; - -static struct ath_rate_table ar5416_11a_ratetable_Quarter = { - 8, - { - { TRUE, TRUE, WLAN_PHY_OFDM, 1500, /* 6 Mb */ - 1350, 0x0b, 0x00, (0x80|3), - 0, 2, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 2250, /* 9 Mb */ - 1950, 0x0f, 0x00, 4, - 0, 3, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 3000, /* 12 Mb */ - 2500, 0x0a, 0x00, (0x80|6), - 2, 4, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 4500, /* 18 Mb */ - 3475, 0x0e, 0x00, 9, - 2, 6, 2, 3, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 6000, /* 25 Mb */ - 4325, 0x09, 0x00, (0x80|12), - 4, 10, 3, 4, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 9000, /* 36 Mb */ - 5750, 0x0d, 0x00, 18, - 4, 14, 3, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 48 Mb */ - 6850, 0x08, 0x00, 24, - 4, 19, 3, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 13500, /* 54 Mb */ - 7325, 0x0c, 0x00, 27, - 4, 23, 3, 7, 0 }, - }, - 50, /* probe interval */ - 50, /* rssi reduce interval */ - 0, /* Phy rates allowed initially */ -}; - static struct ath_rate_table ar5416_11g_ratetable = { 12, + {0}, { - { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, 2, 0, 0, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1900, 0x1a, 0x04, 4, 1, 1, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4900, 0x19, 0x04, 11, 2, 2, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 8100, 0x18, 0x04, 22, 3, 3, 2, 3, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 6000, /* 6 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 6000, /* 6 Mb */ 5400, 0x0b, 0x00, 12, 4, 2, 1, 4, 0 }, - { FALSE, FALSE, WLAN_PHY_OFDM, 9000, /* 9 Mb */ + { INVALID, INVALID, WLAN_RC_PHY_OFDM, 9000, /* 9 Mb */ 7800, 0x0f, 0x00, 18, 4, 3, 1, 5, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 12000, /* 12 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 12000, /* 12 Mb */ 10000, 0x0a, 0x00, 24, 6, 4, 1, 6, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 18000, /* 18 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 18000, /* 18 Mb */ 13900, 0x0e, 0x00, 36, 6, 6, 2, 7, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 24000, /* 24 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 24000, /* 24 Mb */ 17300, 0x09, 0x00, 48, 8, 10, 3, 8, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 36000, /* 36 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 36000, /* 36 Mb */ 23000, 0x0d, 0x00, 72, 8, 14, 3, 9, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 48000, /* 48 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 48000, /* 48 Mb */ 27400, 0x08, 0x00, 96, 8, 19, 3, 10, 0 }, - { TRUE, TRUE, WLAN_PHY_OFDM, 54000, /* 54 Mb */ + { VALID, VALID, WLAN_RC_PHY_OFDM, 54000, /* 54 Mb */ 29300, 0x0c, 0x00, 108, 8, 23, 3, 11, 0 }, }, @@ -461,17 +386,18 @@ static struct ath_rate_table ar5416_11g_ratetable = { static struct ath_rate_table ar5416_11b_ratetable = { 4, + {0}, { - { TRUE, TRUE, WLAN_PHY_CCK, 1000, /* 1 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 1000, /* 1 Mb */ 900, 0x1b, 0x00, (0x80|2), 0, 0, 1, 0, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 2000, /* 2 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 2000, /* 2 Mb */ 1800, 0x1a, 0x04, (0x80|4), 1, 1, 1, 1, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 5500, /* 5.5 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 5500, /* 5.5 Mb */ 4300, 0x19, 0x04, (0x80|11), 1, 2, 2, 2, 0 }, - { TRUE, TRUE, WLAN_PHY_CCK, 11000, /* 11 Mb */ + { VALID, VALID, WLAN_RC_PHY_CCK, 11000, /* 11 Mb */ 7100, 0x18, 0x04, (0x80|22), 1, 4, 100, 3, 0 }, }, @@ -480,48 +406,6 @@ static struct ath_rate_table ar5416_11b_ratetable = { 0, /* Phy rates allowed initially */ }; -static void ar5416_attach_ratetables(struct ath_rate_softc *sc) -{ - /* - * Attach rate tables. - */ - sc->hw_rate_table[ATH9K_MODE_11B] = &ar5416_11b_ratetable; - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable; - sc->hw_rate_table[ATH9K_MODE_11G] = &ar5416_11g_ratetable; - - sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = &ar5416_11ng_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] = - &ar5416_11na_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] = - &ar5416_11ng_ratetable; - sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = - &ar5416_11ng_ratetable; -} - -static void ar5416_setquarter_ratetable(struct ath_rate_softc *sc) -{ - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Quarter; - return; -} - -static void ar5416_sethalf_ratetable(struct ath_rate_softc *sc) -{ - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable_Half; - return; -} - -static void ar5416_setfull_ratetable(struct ath_rate_softc *sc) -{ - sc->hw_rate_table[ATH9K_MODE_11A] = &ar5416_11a_ratetable; - return; -} - -/* - * Return the median of three numbers - */ static inline int8_t median(int8_t a, int8_t b, int8_t c) { if (a >= b) { @@ -541,68 +425,65 @@ static inline int8_t median(int8_t a, int8_t b, int8_t c) } } -static void ath_rc_sort_validrates(const struct ath_rate_table *rate_table, - struct ath_tx_ratectrl *rate_ctrl) +static void ath_rc_sort_validrates(struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv) { u8 i, j, idx, idx_next; - for (i = rate_ctrl->max_valid_rate - 1; i > 0; i--) { + for (i = ath_rc_priv->max_valid_rate - 1; i > 0; i--) { for (j = 0; j <= i-1; j++) { - idx = rate_ctrl->valid_rate_index[j]; - idx_next = rate_ctrl->valid_rate_index[j+1]; + idx = ath_rc_priv->valid_rate_index[j]; + idx_next = ath_rc_priv->valid_rate_index[j+1]; if (rate_table->info[idx].ratekbps > rate_table->info[idx_next].ratekbps) { - rate_ctrl->valid_rate_index[j] = idx_next; - rate_ctrl->valid_rate_index[j+1] = idx; + ath_rc_priv->valid_rate_index[j] = idx_next; + ath_rc_priv->valid_rate_index[j+1] = idx; } } } } -/* Access functions for valid_txrate_mask */ - -static void ath_rc_init_valid_txmask(struct ath_tx_ratectrl *rate_ctrl) +static void ath_rc_init_valid_txmask(struct ath_rate_priv *ath_rc_priv) { u8 i; - for (i = 0; i < rate_ctrl->rate_table_size; i++) - rate_ctrl->valid_rate_index[i] = FALSE; + for (i = 0; i < ath_rc_priv->rate_table_size; i++) + ath_rc_priv->valid_rate_index[i] = 0; } -static inline void ath_rc_set_valid_txmask(struct ath_tx_ratectrl *rate_ctrl, +static inline void ath_rc_set_valid_txmask(struct ath_rate_priv *ath_rc_priv, u8 index, int valid_tx_rate) { - ASSERT(index <= rate_ctrl->rate_table_size); - rate_ctrl->valid_rate_index[index] = valid_tx_rate ? TRUE : FALSE; + ASSERT(index <= ath_rc_priv->rate_table_size); + ath_rc_priv->valid_rate_index[index] = valid_tx_rate ? 1 : 0; } -static inline int ath_rc_isvalid_txmask(struct ath_tx_ratectrl *rate_ctrl, +static inline int ath_rc_isvalid_txmask(struct ath_rate_priv *ath_rc_priv, u8 index) { - ASSERT(index <= rate_ctrl->rate_table_size); - return rate_ctrl->valid_rate_index[index]; + ASSERT(index <= ath_rc_priv->rate_table_size); + return ath_rc_priv->valid_rate_index[index]; } -/* Iterators for valid_txrate_mask */ -static inline int -ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, - struct ath_tx_ratectrl *rate_ctrl, - u8 cur_valid_txrate, - u8 *next_idx) +static inline int ath_rc_get_nextvalid_txrate(struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + u8 cur_valid_txrate, + u8 *next_idx) { u8 i; - for (i = 0; i < rate_ctrl->max_valid_rate - 1; i++) { - if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = rate_ctrl->valid_rate_index[i+1]; - return TRUE; + for (i = 0; i < ath_rc_priv->max_valid_rate - 1; i++) { + if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { + *next_idx = ath_rc_priv->valid_rate_index[i+1]; + return 1; } } /* No more valid rates */ *next_idx = 0; - return FALSE; + + return 0; } /* Return true only for single stream */ @@ -610,83 +491,72 @@ ath_rc_get_nextvalid_txrate(const struct ath_rate_table *rate_table, static int ath_rc_valid_phyrate(u32 phy, u32 capflag, int ignore_cw) { if (WLAN_RC_PHY_HT(phy) & !(capflag & WLAN_RC_HT_FLAG)) - return FALSE; + return 0; if (WLAN_RC_PHY_DS(phy) && !(capflag & WLAN_RC_DS_FLAG)) - return FALSE; + return 0; if (WLAN_RC_PHY_SGI(phy) && !(capflag & WLAN_RC_SGI_FLAG)) - return FALSE; + return 0; if (!ignore_cw && WLAN_RC_PHY_HT(phy)) if (WLAN_RC_PHY_40(phy) && !(capflag & WLAN_RC_40_FLAG)) - return FALSE; + return 0; if (!WLAN_RC_PHY_40(phy) && (capflag & WLAN_RC_40_FLAG)) - return FALSE; - return TRUE; + return 0; + return 1; } static inline int -ath_rc_get_nextlowervalid_txrate(const struct ath_rate_table *rate_table, - struct ath_tx_ratectrl *rate_ctrl, +ath_rc_get_nextlowervalid_txrate(struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, u8 cur_valid_txrate, u8 *next_idx) { int8_t i; - for (i = 1; i < rate_ctrl->max_valid_rate ; i++) { - if (rate_ctrl->valid_rate_index[i] == cur_valid_txrate) { - *next_idx = rate_ctrl->valid_rate_index[i-1]; - return TRUE; + for (i = 1; i < ath_rc_priv->max_valid_rate ; i++) { + if (ath_rc_priv->valid_rate_index[i] == cur_valid_txrate) { + *next_idx = ath_rc_priv->valid_rate_index[i-1]; + return 1; } } - return FALSE; + + return 0; } -/* - * Initialize the Valid Rate Index from valid entries in Rate Table - */ -static u8 -ath_rc_sib_init_validrates(struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - u32 capflag) +static u8 ath_rc_init_validrates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + u32 capflag) { - struct ath_tx_ratectrl *rate_ctrl; u8 i, hi = 0; u32 valid; - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); for (i = 0; i < rate_table->rate_cnt; i++) { valid = (ath_rc_priv->single_stream ? rate_table->info[i].valid_single_stream : rate_table->info[i].valid); - if (valid == TRUE) { + if (valid == 1) { u32 phy = rate_table->info[i].phy; u8 valid_rate_count = 0; - if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) + if (!ath_rc_valid_phyrate(phy, capflag, 0)) continue; - valid_rate_count = rate_ctrl->valid_phy_ratecnt[phy]; + valid_rate_count = ath_rc_priv->valid_phy_ratecnt[phy]; - rate_ctrl->valid_phy_rateidx[phy][valid_rate_count] = i; - rate_ctrl->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(rate_ctrl, i, TRUE); + ath_rc_priv->valid_phy_rateidx[phy][valid_rate_count] = i; + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, i, 1); hi = A_MAX(hi, i); } } + return hi; } -/* - * Initialize the Valid Rate Index from Rate Set - */ -static u8 -ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - struct ath_rateset *rateset, - u32 capflag) +static u8 ath_rc_setvalid_rates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + struct ath_rateset *rateset, + u32 capflag) { - /* XXX: Clean me up and make identation friendly */ u8 i, j, hi = 0; - struct ath_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)(ath_rc_priv); /* Use intersection of working rates and valid rates */ for (i = 0; i < rateset->rs_nrates; i++) { @@ -695,196 +565,89 @@ ath_rc_sib_setvalid_rates(struct ath_rate_node *ath_rc_priv, u32 valid = (ath_rc_priv->single_stream ? rate_table->info[j].valid_single_stream : rate_table->info[j].valid); + u8 rate = rateset->rs_rates[i]; + u8 dot11rate = rate_table->info[j].dot11rate; /* We allow a rate only if its valid and the * capflag matches one of the validity - * (TRUE/TRUE_20/TRUE_40) flags */ - - /* XXX: catch the negative of this branch - * first and then continue */ - if (((rateset->rs_rates[i] & 0x7F) == - (rate_table->info[j].dot11rate & 0x7F)) && - ((valid & WLAN_RC_CAP_MODE(capflag)) == - WLAN_RC_CAP_MODE(capflag)) && - !WLAN_RC_PHY_HT(phy)) { + * (VALID/VALID_20/VALID_40) flags */ + if (((rate & 0x7F) == (dot11rate & 0x7F)) && + ((valid & WLAN_RC_CAP_MODE(capflag)) == + WLAN_RC_CAP_MODE(capflag)) && + !WLAN_RC_PHY_HT(phy)) { u8 valid_rate_count = 0; - if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) + if (!ath_rc_valid_phyrate(phy, capflag, 0)) continue; valid_rate_count = - rate_ctrl->valid_phy_ratecnt[phy]; + ath_rc_priv->valid_phy_ratecnt[phy]; - rate_ctrl->valid_phy_rateidx[phy] + ath_rc_priv->valid_phy_rateidx[phy] [valid_rate_count] = j; - rate_ctrl->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(rate_ctrl, j, TRUE); + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, j, 1); hi = A_MAX(hi, j); } } } + return hi; } -static u8 -ath_rc_sib_setvalid_htrates(struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, - u8 *mcs_set, u32 capflag) +static u8 ath_rc_setvalid_htrates(struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, + u8 *mcs_set, u32 capflag) { + struct ath_rateset *rateset = (struct ath_rateset *)mcs_set; + u8 i, j, hi = 0; - struct ath_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)(ath_rc_priv); /* Use intersection of working rates and valid rates */ - for (i = 0; i < ((struct ath_rateset *)mcs_set)->rs_nrates; i++) { + for (i = 0; i < rateset->rs_nrates; i++) { for (j = 0; j < rate_table->rate_cnt; j++) { u32 phy = rate_table->info[j].phy; u32 valid = (ath_rc_priv->single_stream ? rate_table->info[j].valid_single_stream : rate_table->info[j].valid); + u8 rate = rateset->rs_rates[i]; + u8 dot11rate = rate_table->info[j].dot11rate; - if (((((struct ath_rateset *) - mcs_set)->rs_rates[i] & 0x7F) != - (rate_table->info[j].dot11rate & 0x7F)) || + if (((rate & 0x7F) != (dot11rate & 0x7F)) || !WLAN_RC_PHY_HT(phy) || !WLAN_RC_PHY_HT_VALID(valid, capflag)) continue; - if (!ath_rc_valid_phyrate(phy, capflag, FALSE)) + if (!ath_rc_valid_phyrate(phy, capflag, 0)) continue; - rate_ctrl->valid_phy_rateidx[phy] - [rate_ctrl->valid_phy_ratecnt[phy]] = j; - rate_ctrl->valid_phy_ratecnt[phy] += 1; - ath_rc_set_valid_txmask(rate_ctrl, j, TRUE); + ath_rc_priv->valid_phy_rateidx[phy] + [ath_rc_priv->valid_phy_ratecnt[phy]] = j; + ath_rc_priv->valid_phy_ratecnt[phy] += 1; + ath_rc_set_valid_txmask(ath_rc_priv, j, 1); hi = A_MAX(hi, j); } } - return hi; -} - -/* - * Attach to a device instance. Setup the public definition - * of how much per-node space we need and setup the private - * phy tables that have rate control parameters. - */ -struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah) -{ - struct ath_rate_softc *asc; - - /* we are only in user context so we can sleep for memory */ - asc = kzalloc(sizeof(struct ath_rate_softc), GFP_KERNEL); - if (asc == NULL) - return NULL; - - ar5416_attach_ratetables(asc); - - /* Save Maximum TX Trigger Level (used for 11n) */ - tx_triglevel_max = ah->ah_caps.tx_triglevel_max; - /* return alias for ath_rate_softc * */ - return asc; -} - -static struct ath_rate_node *ath_rate_node_alloc(struct ath_vap *avp, - struct ath_rate_softc *rsc, - gfp_t gfp) -{ - struct ath_rate_node *anode; - - anode = kzalloc(sizeof(struct ath_rate_node), gfp); - if (anode == NULL) - return NULL; - - anode->avp = avp; - anode->asc = rsc; - avp->rc_node = anode; - - return anode; -} - -static void ath_rate_node_free(struct ath_rate_node *anode) -{ - if (anode != NULL) - kfree(anode); -} - -void ath_rate_detach(struct ath_rate_softc *asc) -{ - if (asc != NULL) - kfree(asc); -} - -u8 ath_rate_findrateix(struct ath_softc *sc, - u8 dot11rate) -{ - const struct ath_rate_table *ratetable; - struct ath_rate_softc *rsc = sc->sc_rc; - int i; - - ratetable = rsc->hw_rate_table[sc->sc_curmode]; - - if (WARN_ON(!ratetable)) - return 0; - - for (i = 0; i < ratetable->rate_cnt; i++) { - if ((ratetable->info[i].dot11rate & 0x7f) == (dot11rate & 0x7f)) - return i; - } - return 0; -} - -/* - * Update rate-control state on a device state change. When - * operating as a station this includes associate/reassociate - * with an AP. Otherwise this gets called, for example, when - * the we transition to run state when operating as an AP. - */ -void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp) -{ - struct ath_rate_softc *asc = sc->sc_rc; - - /* For half and quarter rate channles use different - * rate tables - */ - if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_HALF) - ar5416_sethalf_ratetable(asc); - else if (sc->sc_ah->ah_curchan->channelFlags & CHANNEL_QUARTER) - ar5416_setquarter_ratetable(asc); - else /* full rate */ - ar5416_setfull_ratetable(asc); - - if (avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) { - asc->fixedrix = - sc->sc_rixmap[avp->av_config.av_fixed_rateset & 0xff]; - /* NB: check the fixed rate exists */ - if (asc->fixedrix == 0xff) - asc->fixedrix = IEEE80211_FIXED_RATE_NONE; - } else { - asc->fixedrix = IEEE80211_FIXED_RATE_NONE; - } + return hi; } static u8 ath_rc_ratefind_ht(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, int probe_allowed, int *is_probing, int is_retry) { u32 dt, best_thruput, this_thruput, now_msec; u8 rate, next_rate, best_rate, maxindex, minindex; int8_t rssi_last, rssi_reduce = 0, index = 0; - struct ath_tx_ratectrl *rate_ctrl = NULL; - - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv ? - (ath_rc_priv) : NULL); - *is_probing = FALSE; + *is_probing = 0; - rssi_last = median(rate_ctrl->rssi_last, - rate_ctrl->rssi_last_prev, - rate_ctrl->rssi_last_prev2); + rssi_last = median(ath_rc_priv->rssi_last, + ath_rc_priv->rssi_last_prev, + ath_rc_priv->rssi_last_prev2); /* * Age (reduce) last ack rssi based on how old it is. @@ -896,7 +659,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, */ now_msec = jiffies_to_msecs(jiffies); - dt = now_msec - rate_ctrl->rssi_time; + dt = now_msec - ath_rc_priv->rssi_time; if (dt >= 185) rssi_reduce = 10; @@ -915,7 +678,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, */ best_thruput = 0; - maxindex = rate_ctrl->max_valid_rate-1; + maxindex = ath_rc_priv->max_valid_rate-1; minindex = 0; best_rate = minindex; @@ -927,8 +690,8 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, for (index = maxindex; index >= minindex ; index--) { u8 per_thres; - rate = rate_ctrl->valid_rate_index[index]; - if (rate > rate_ctrl->rate_max_phy) + rate = ath_rc_priv->valid_rate_index[index]; + if (rate > ath_rc_priv->rate_max_phy) continue; /* @@ -942,7 +705,7 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, * 10-15 and we would be worse off then staying * at the current rate. */ - per_thres = rate_ctrl->state[rate].per; + per_thres = ath_rc_priv->state[rate].per; if (per_thres < 12) per_thres = 12; @@ -961,41 +724,35 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, * of max retries, use the min rate for the next retry */ if (is_retry) - rate = rate_ctrl->valid_rate_index[minindex]; + rate = ath_rc_priv->valid_rate_index[minindex]; - rate_ctrl->rssi_last_lookup = rssi_last; + ath_rc_priv->rssi_last_lookup = rssi_last; /* * Must check the actual rate (ratekbps) to account for * non-monoticity of 11g's rate table */ - if (rate >= rate_ctrl->rate_max_phy && probe_allowed) { - rate = rate_ctrl->rate_max_phy; + if (rate >= ath_rc_priv->rate_max_phy && probe_allowed) { + rate = ath_rc_priv->rate_max_phy; /* Probe the next allowed phy state */ /* FIXME:XXXX Check to make sure ratMax is checked properly */ if (ath_rc_get_nextvalid_txrate(rate_table, - rate_ctrl, rate, &next_rate) && - (now_msec - rate_ctrl->probe_time > + ath_rc_priv, rate, &next_rate) && + (now_msec - ath_rc_priv->probe_time > rate_table->probe_interval) && - (rate_ctrl->hw_maxretry_pktcnt >= 1)) { + (ath_rc_priv->hw_maxretry_pktcnt >= 1)) { rate = next_rate; - rate_ctrl->probe_rate = rate; - rate_ctrl->probe_time = now_msec; - rate_ctrl->hw_maxretry_pktcnt = 0; - *is_probing = TRUE; + ath_rc_priv->probe_rate = rate; + ath_rc_priv->probe_time = now_msec; + ath_rc_priv->hw_maxretry_pktcnt = 0; + *is_probing = 1; } } - /* - * Make sure rate is not higher than the allowed maximum. - * We should also enforce the min, but I suspect the min is - * normally 1 rather than 0 because of the rate 9 vs 6 issue - * in the old code. - */ - if (rate > (rate_ctrl->rate_table_size - 1)) - rate = rate_ctrl->rate_table_size - 1; + if (rate > (ath_rc_priv->rate_table_size - 1)) + rate = ath_rc_priv->rate_table_size - 1; ASSERT((rate_table->info[rate].valid && !ath_rc_priv->single_stream) || (rate_table->info[rate].valid_single_stream && @@ -1004,40 +761,36 @@ static u8 ath_rc_ratefind_ht(struct ath_softc *sc, return rate; } -static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table , - struct ath_rc_series *series, - u8 tries, - u8 rix, - int rtsctsenable) +static void ath_rc_rate_set_series(struct ath_rate_table *rate_table , + struct ieee80211_tx_rate *rate, + u8 tries, u8 rix, int rtsctsenable) { - series->tries = tries; - series->flags = (rtsctsenable ? ATH_RC_RTSCTS_FLAG : 0) | - (WLAN_RC_PHY_DS(rate_table->info[rix].phy) ? - ATH_RC_DS_FLAG : 0) | - (WLAN_RC_PHY_40(rate_table->info[rix].phy) ? - ATH_RC_CW40_FLAG : 0) | - (WLAN_RC_PHY_SGI(rate_table->info[rix].phy) ? - ATH_RC_SGI_FLAG : 0); - - series->rix = rate_table->info[rix].base_index; - series->max_4ms_framelen = rate_table->info[rix].max_4ms_framelen; + rate->count = tries; + rate->idx = rix; + + if (rtsctsenable) + rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; + if (WLAN_RC_PHY_40(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; + if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_SHORT_GI; + if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) + rate->flags |= IEEE80211_TX_RC_MCS; } static u8 ath_rc_rate_getidx(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - const struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + struct ath_rate_table *rate_table, u8 rix, u16 stepdown, u16 min_rate) { u32 j; u8 nextindex; - struct ath_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)(ath_rc_priv); if (min_rate) { for (j = RATE_TABLE_SIZE; j > 0; j--) { if (ath_rc_get_nextlowervalid_txrate(rate_table, - rate_ctrl, rix, &nextindex)) + ath_rc_priv, rix, &nextindex)) rix = nextindex; else break; @@ -1045,7 +798,7 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc, } else { for (j = stepdown; j > 0; j--) { if (ath_rc_get_nextlowervalid_txrate(rate_table, - rate_ctrl, rix, &nextindex)) + ath_rc_priv, rix, &nextindex)) rix = nextindex; else break; @@ -1055,41 +808,39 @@ static u8 ath_rc_rate_getidx(struct ath_softc *sc, } static void ath_rc_ratefind(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - int num_tries, int num_rates, unsigned int rcflag, - struct ath_rc_series series[], int *is_probe, + struct ath_rate_priv *ath_rc_priv, + int num_tries, int num_rates, + struct ieee80211_tx_info *tx_info, int *is_probe, int is_retry) { u8 try_per_rate = 0, i = 0, rix, nrix; - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; struct ath_rate_table *rate_table; + struct ieee80211_tx_rate *rates = tx_info->control.rates; - rate_table = - (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; - rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, - (rcflag & ATH_RC_PROBE_ALLOWED) ? 1 : 0, + rate_table = sc->cur_rate_table; + rix = ath_rc_ratefind_ht(sc, ath_rc_priv, rate_table, 1, is_probe, is_retry); nrix = rix; - if ((rcflag & ATH_RC_PROBE_ALLOWED) && (*is_probe)) { + if (*is_probe) { /* set one try for probe rates. For the * probes don't enable rts */ ath_rc_rate_set_series(rate_table, - &series[i++], 1, nrix, FALSE); + &rates[i++], 1, nrix, 0); try_per_rate = (num_tries/num_rates); /* Get the next tried/allowed rate. No RTS for the next series * after the probe rate */ nrix = ath_rc_rate_getidx(sc, - ath_rc_priv, rate_table, nrix, 1, FALSE); + ath_rc_priv, rate_table, nrix, 1, 0); ath_rc_rate_set_series(rate_table, - &series[i++], try_per_rate, nrix, 0); + &rates[i++], try_per_rate, nrix, 0); } else { try_per_rate = (num_tries/num_rates); /* Set the choosen rate. No RTS for first series entry. */ ath_rc_rate_set_series(rate_table, - &series[i++], try_per_rate, nrix, FALSE); + &rates[i++], try_per_rate, nrix, 0); } /* Fill in the other rates for multirate retry */ @@ -1099,14 +850,13 @@ static void ath_rc_ratefind(struct ath_softc *sc, try_num = ((i + 1) == num_rates) ? num_tries - (try_per_rate * i) : try_per_rate ; - min_rate = (((i + 1) == num_rates) && - (rcflag & ATH_RC_MINRATE_LASTRATE)) ? 1 : 0; + min_rate = (((i + 1) == num_rates) && 0); nrix = ath_rc_rate_getidx(sc, ath_rc_priv, rate_table, nrix, 1, min_rate); /* All other rates in the series have RTS enabled */ ath_rc_rate_set_series(rate_table, - &series[i], try_num, nrix, TRUE); + &rates[i], try_num, nrix, 1); } /* @@ -1124,115 +874,29 @@ static void ath_rc_ratefind(struct ath_softc *sc, * So, set fourth rate in series to be same as third one for * above conditions. */ - if ((sc->sc_curmode == ATH9K_MODE_11NG_HT20) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40PLUS) || - (sc->sc_curmode == ATH9K_MODE_11NG_HT40MINUS)) { - u8 dot11rate = rate_table->info[rix].dot11rate; + if ((sc->hw->conf.channel->band == IEEE80211_BAND_2GHZ) && + (sc->hw->conf.ht.enabled)) { + u8 dot11rate = rate_table->info[rix].dot11rate; u8 phy = rate_table->info[rix].phy; if (i == 4 && ((dot11rate == 2 && phy == WLAN_RC_PHY_HT_40_SS) || (dot11rate == 3 && phy == WLAN_RC_PHY_HT_20_SS))) { - series[3].rix = series[2].rix; - series[3].flags = series[2].flags; - series[3].max_4ms_framelen = series[2].max_4ms_framelen; - } - } -} - -/* - * Return the Tx rate series. - */ -static void ath_rate_findrate(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - int num_tries, - int num_rates, - unsigned int rcflag, - struct ath_rc_series series[], - int *is_probe, - int is_retry) -{ - struct ath_vap *avp = ath_rc_priv->avp; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - - if (!num_rates || !num_tries) - return; - - if (avp->av_config.av_fixed_rateset == IEEE80211_FIXED_RATE_NONE) { - ath_rc_ratefind(sc, ath_rc_priv, num_tries, num_rates, - rcflag, series, is_probe, is_retry); - } else { - /* Fixed rate */ - int idx; - u8 flags; - u32 rix; - struct ath_rate_softc *asc = ath_rc_priv->asc; - struct ath_rate_table *rate_table; - - rate_table = (struct ath_rate_table *) - asc->hw_rate_table[sc->sc_curmode]; - - for (idx = 0; idx < 4; idx++) { - unsigned int mcs; - u8 series_rix = 0; - - series[idx].tries = IEEE80211_RATE_IDX_ENTRY( - avp->av_config.av_fixed_retryset, idx); - - mcs = IEEE80211_RATE_IDX_ENTRY( - avp->av_config.av_fixed_rateset, idx); - - if (idx == 3 && (mcs & 0xf0) == 0x70) - mcs = (mcs & ~0xf0)|0x80; - - if (!(mcs & 0x80)) - flags = 0; - else - flags = ((ath_rc_priv->ht_cap & - WLAN_RC_DS_FLAG) ? - ATH_RC_DS_FLAG : 0) | - ((ath_rc_priv->ht_cap & - WLAN_RC_40_FLAG) ? - ATH_RC_CW40_FLAG : 0) | - ((ath_rc_priv->ht_cap & - WLAN_RC_SGI_FLAG) ? - ((ath_rc_priv->ht_cap & - WLAN_RC_40_FLAG) ? - ATH_RC_SGI_FLAG : 0) : 0); - - series[idx].rix = sc->sc_rixmap[mcs]; - series_rix = series[idx].rix; - - /* XXX: Give me some cleanup love */ - if ((flags & ATH_RC_CW40_FLAG) && - (flags & ATH_RC_SGI_FLAG)) - rix = rate_table->info[series_rix].ht_index; - else if (flags & ATH_RC_SGI_FLAG) - rix = rate_table->info[series_rix].sgi_index; - else if (flags & ATH_RC_CW40_FLAG) - rix = rate_table->info[series_rix].cw40index; - else - rix = rate_table->info[series_rix].base_index; - series[idx].max_4ms_framelen = - rate_table->info[rix].max_4ms_framelen; - series[idx].flags = flags; + rates[3].idx = rates[2].idx; + rates[3].flags = rates[2].flags; } } } -static void ath_rc_update_ht(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - struct ath_tx_info_priv *info_priv, - int tx_rate, int xretries, int retries) +static bool ath_rc_update_per(struct ath_softc *sc, + struct ath_rate_table *rate_table, + struct ath_rate_priv *ath_rc_priv, + struct ath_tx_info_priv *tx_info_priv, + int tx_rate, int xretries, int retries, + u32 now_msec) { - struct ath_tx_ratectrl *rate_ctrl; - u32 now_msec = jiffies_to_msecs(jiffies); - int state_change = FALSE, rate, count; + bool state_change = false; + int count; u8 last_per; - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; - struct ath_rate_table *rate_table = - (struct ath_rate_table *)asc->hw_rate_table[sc->sc_curmode]; - static u32 nretry_to_per_lookup[10] = { 100 * 0 / 1, 100 * 1 / 4, @@ -1246,56 +910,35 @@ static void ath_rc_update_ht(struct ath_softc *sc, 100 * 9 / 10 }; - if (!ath_rc_priv) - return; - - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); - - ASSERT(tx_rate >= 0); - if (tx_rate < 0) - return; - - /* To compensate for some imbalance between ctrl and ext. channel */ - - if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy)) - info_priv->tx.ts_rssi = - info_priv->tx.ts_rssi < 3 ? 0 : - info_priv->tx.ts_rssi - 3; - - last_per = rate_ctrl->state[tx_rate].per; + last_per = ath_rc_priv->state[tx_rate].per; if (xretries) { - /* Update the PER. */ if (xretries == 1) { - rate_ctrl->state[tx_rate].per += 30; - if (rate_ctrl->state[tx_rate].per > 100) - rate_ctrl->state[tx_rate].per = 100; + ath_rc_priv->state[tx_rate].per += 30; + if (ath_rc_priv->state[tx_rate].per > 100) + ath_rc_priv->state[tx_rate].per = 100; } else { /* xretries == 2 */ - count = sizeof(nretry_to_per_lookup) / - sizeof(nretry_to_per_lookup[0]); + count = ARRAY_SIZE(nretry_to_per_lookup); if (retries >= count) retries = count - 1; + /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - rate_ctrl->state[tx_rate].per = - (u8)(rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + - ((100) >> 3)); + ath_rc_priv->state[tx_rate].per = + (u8)(last_per - (last_per >> 3) + (100 >> 3)); } /* xretries == 1 or 2 */ - if (rate_ctrl->probe_rate == tx_rate) - rate_ctrl->probe_rate = 0; + if (ath_rc_priv->probe_rate == tx_rate) + ath_rc_priv->probe_rate = 0; - } else { /* xretries == 0 */ - /* Update the PER. */ - /* Make sure it doesn't index out of array's bounds. */ - count = sizeof(nretry_to_per_lookup) / - sizeof(nretry_to_per_lookup[0]); + } else { /* xretries == 0 */ + count = ARRAY_SIZE(nretry_to_per_lookup); if (retries >= count) retries = count - 1; - if (info_priv->n_bad_frames) { + + if (tx_info_priv->n_bad_frames) { /* new_PER = 7/8*old_PER + 1/8*(currentPER) * Assuming that n_frames is not 0. The current PER * from the retries is 100 * retries / (retries+1), @@ -1308,37 +951,35 @@ static void ath_rc_update_ht(struct ath_softc *sc, * the above PER. The expression below is a * simplified version of the sum of these two terms. */ - if (info_priv->n_frames > 0) - rate_ctrl->state[tx_rate].per - = (u8) - (rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + - ((100*(retries*info_priv->n_frames + - info_priv->n_bad_frames) / - (info_priv->n_frames * - (retries+1))) >> 3)); + if (tx_info_priv->n_frames > 0) { + int n_frames, n_bad_frames; + u8 cur_per, new_per; + + n_bad_frames = retries * tx_info_priv->n_frames + + tx_info_priv->n_bad_frames; + n_frames = tx_info_priv->n_frames * (retries + 1); + cur_per = (100 * n_bad_frames / n_frames) >> 3; + new_per = (u8)(last_per - (last_per >> 3) + cur_per); + ath_rc_priv->state[tx_rate].per = new_per; + } } else { - /* new_PER = 7/8*old_PER + 1/8*(currentPER) */ - - rate_ctrl->state[tx_rate].per = (u8) - (rate_ctrl->state[tx_rate].per - - (rate_ctrl->state[tx_rate].per >> 3) + - (nretry_to_per_lookup[retries] >> 3)); + ath_rc_priv->state[tx_rate].per = + (u8)(last_per - (last_per >> 3) + + (nretry_to_per_lookup[retries] >> 3)); } - rate_ctrl->rssi_last_prev2 = rate_ctrl->rssi_last_prev; - rate_ctrl->rssi_last_prev = rate_ctrl->rssi_last; - rate_ctrl->rssi_last = info_priv->tx.ts_rssi; - rate_ctrl->rssi_time = now_msec; + ath_rc_priv->rssi_last_prev2 = ath_rc_priv->rssi_last_prev; + ath_rc_priv->rssi_last_prev = ath_rc_priv->rssi_last; + ath_rc_priv->rssi_last = tx_info_priv->tx.ts_rssi; + ath_rc_priv->rssi_time = now_msec; /* * If we got at most one retry then increase the max rate if * this was a probe. Otherwise, ignore the probe. */ - - if (rate_ctrl->probe_rate && rate_ctrl->probe_rate == tx_rate) { - if (retries > 0 || 2 * info_priv->n_bad_frames > - info_priv->n_frames) { + if (ath_rc_priv->probe_rate && ath_rc_priv->probe_rate == tx_rate) { + if (retries > 0 || 2 * tx_info_priv->n_bad_frames > + tx_info_priv->n_frames) { /* * Since we probed with just a single attempt, * any retries means the probe failed. Also, @@ -1346,17 +987,18 @@ static void ath_rc_update_ht(struct ath_softc *sc, * the subframes were bad then also consider * the probe a failure. */ - rate_ctrl->probe_rate = 0; + ath_rc_priv->probe_rate = 0; } else { u8 probe_rate = 0; - rate_ctrl->rate_max_phy = rate_ctrl->probe_rate; - probe_rate = rate_ctrl->probe_rate; + ath_rc_priv->rate_max_phy = + ath_rc_priv->probe_rate; + probe_rate = ath_rc_priv->probe_rate; - if (rate_ctrl->state[probe_rate].per > 30) - rate_ctrl->state[probe_rate].per = 20; + if (ath_rc_priv->state[probe_rate].per > 30) + ath_rc_priv->state[probe_rate].per = 20; - rate_ctrl->probe_rate = 0; + ath_rc_priv->probe_rate = 0; /* * Since this probe succeeded, we allow the next @@ -1364,8 +1006,8 @@ static void ath_rc_update_ht(struct ath_softc *sc, * to move up faster if the probes are * succesful. */ - rate_ctrl->probe_time = now_msec - - rate_table->probe_interval / 2; + ath_rc_priv->probe_time = + now_msec - rate_table->probe_interval / 2; } } @@ -1375,74 +1017,114 @@ static void ath_rc_update_ht(struct ath_softc *sc, * this was because of collisions or poor signal. * * Later: if rssi_ack is close to - * rate_ctrl->state[txRate].rssi_thres and we see lots + * ath_rc_priv->state[txRate].rssi_thres and we see lots * of retries, then we could increase - * rate_ctrl->state[txRate].rssi_thres. + * ath_rc_priv->state[txRate].rssi_thres. */ - rate_ctrl->hw_maxretry_pktcnt = 0; + ath_rc_priv->hw_maxretry_pktcnt = 0; } else { + int32_t rssi_ackAvg; + int8_t rssi_thres; + int8_t rssi_ack_vmin; + /* * It worked with no retries. First ignore bogus (small) * rssi_ack values. */ - if (tx_rate == rate_ctrl->rate_max_phy && - rate_ctrl->hw_maxretry_pktcnt < 255) { - rate_ctrl->hw_maxretry_pktcnt++; + if (tx_rate == ath_rc_priv->rate_max_phy && + ath_rc_priv->hw_maxretry_pktcnt < 255) { + ath_rc_priv->hw_maxretry_pktcnt++; } - if (info_priv->tx.ts_rssi >= - rate_table->info[tx_rate].rssi_ack_validmin) { - /* Average the rssi */ - if (tx_rate != rate_ctrl->rssi_sum_rate) { - rate_ctrl->rssi_sum_rate = tx_rate; - rate_ctrl->rssi_sum = - rate_ctrl->rssi_sum_cnt = 0; - } + if (tx_info_priv->tx.ts_rssi < + rate_table->info[tx_rate].rssi_ack_validmin) + goto exit; - rate_ctrl->rssi_sum += info_priv->tx.ts_rssi; - rate_ctrl->rssi_sum_cnt++; - - if (rate_ctrl->rssi_sum_cnt > 4) { - int32_t rssi_ackAvg = - (rate_ctrl->rssi_sum + 2) / 4; - int8_t rssi_thres = - rate_ctrl->state[tx_rate]. - rssi_thres; - int8_t rssi_ack_vmin = - rate_table->info[tx_rate]. - rssi_ack_validmin; - - rate_ctrl->rssi_sum = - rate_ctrl->rssi_sum_cnt = 0; - - /* Now reduce the current - * rssi threshold. */ - if ((rssi_ackAvg < rssi_thres + 2) && - (rssi_thres > rssi_ack_vmin)) { - rate_ctrl->state[tx_rate]. - rssi_thres--; - } - - state_change = TRUE; - } + /* Average the rssi */ + if (tx_rate != ath_rc_priv->rssi_sum_rate) { + ath_rc_priv->rssi_sum_rate = tx_rate; + ath_rc_priv->rssi_sum = + ath_rc_priv->rssi_sum_cnt = 0; } + + ath_rc_priv->rssi_sum += tx_info_priv->tx.ts_rssi; + ath_rc_priv->rssi_sum_cnt++; + + if (ath_rc_priv->rssi_sum_cnt < 4) + goto exit; + + rssi_ackAvg = + (ath_rc_priv->rssi_sum + 2) / 4; + rssi_thres = + ath_rc_priv->state[tx_rate].rssi_thres; + rssi_ack_vmin = + rate_table->info[tx_rate].rssi_ack_validmin; + + ath_rc_priv->rssi_sum = + ath_rc_priv->rssi_sum_cnt = 0; + + /* Now reduce the current rssi threshold */ + if ((rssi_ackAvg < rssi_thres + 2) && + (rssi_thres > rssi_ack_vmin)) { + ath_rc_priv->state[tx_rate].rssi_thres--; + } + + state_change = true; } } +exit: + return state_change; +} + +/* Update PER, RSSI and whatever else that the code thinks it is doing. + If you can make sense of all this, you really need to go out more. */ + +static void ath_rc_update_ht(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ath_tx_info_priv *tx_info_priv, + int tx_rate, int xretries, int retries) +{ +#define CHK_RSSI(rate) \ + ((ath_rc_priv->state[(rate)].rssi_thres + \ + rate_table->info[(rate)].rssi_ack_deltamin) > \ + ath_rc_priv->state[(rate)+1].rssi_thres) - /* For all cases */ + u32 now_msec = jiffies_to_msecs(jiffies); + int rate; + u8 last_per; + bool state_change = false; + struct ath_rate_table *rate_table = sc->cur_rate_table; + int size = ath_rc_priv->rate_table_size; + + if ((tx_rate < 0) || (tx_rate > rate_table->rate_cnt)) + return; + + /* To compensate for some imbalance between ctrl and ext. channel */ + + if (WLAN_RC_PHY_40(rate_table->info[tx_rate].phy)) + tx_info_priv->tx.ts_rssi = + tx_info_priv->tx.ts_rssi < 3 ? 0 : + tx_info_priv->tx.ts_rssi - 3; + + last_per = ath_rc_priv->state[tx_rate].per; + + /* Update PER first */ + state_change = ath_rc_update_per(sc, rate_table, ath_rc_priv, + tx_info_priv, tx_rate, xretries, + retries, now_msec); /* * If this rate looks bad (high PER) then stop using it for * a while (except if we are probing). */ - if (rate_ctrl->state[tx_rate].per >= 55 && tx_rate > 0 && + if (ath_rc_priv->state[tx_rate].per >= 55 && tx_rate > 0 && rate_table->info[tx_rate].ratekbps <= - rate_table->info[rate_ctrl->rate_max_phy].ratekbps) { - ath_rc_get_nextlowervalid_txrate(rate_table, rate_ctrl, - (u8) tx_rate, &rate_ctrl->rate_max_phy); + rate_table->info[ath_rc_priv->rate_max_phy].ratekbps) { + ath_rc_get_nextlowervalid_txrate(rate_table, ath_rc_priv, + (u8)tx_rate, &ath_rc_priv->rate_max_phy); /* Don't probe for a little while. */ - rate_ctrl->probe_time = now_msec; + ath_rc_priv->probe_time = now_msec; } if (state_change) { @@ -1453,20 +1135,15 @@ static void ath_rc_update_ht(struct ath_softc *sc, * made to keep the rssi thresholds monotonically * increasing between the CCK and OFDM rates.) */ - for (rate = tx_rate; rate < - rate_ctrl->rate_table_size - 1; rate++) { + for (rate = tx_rate; rate < size - 1; rate++) { if (rate_table->info[rate+1].phy != - rate_table->info[tx_rate].phy) + rate_table->info[tx_rate].phy) break; - if (rate_ctrl->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { - rate_ctrl->state[rate+1].rssi_thres = - rate_ctrl->state[rate]. - rssi_thres + - rate_table->info[rate]. - rssi_ack_deltamin; + if (CHK_RSSI(rate)) { + ath_rc_priv->state[rate+1].rssi_thres = + ath_rc_priv->state[rate].rssi_thres + + rate_table->info[rate].rssi_ack_deltamin; } } @@ -1476,27 +1153,20 @@ static void ath_rc_update_ht(struct ath_softc *sc, rate_table->info[tx_rate].phy) break; - if (rate_ctrl->state[rate].rssi_thres + - rate_table->info[rate].rssi_ack_deltamin > - rate_ctrl->state[rate+1].rssi_thres) { - if (rate_ctrl->state[rate+1].rssi_thres < - rate_table->info[rate]. - rssi_ack_deltamin) - rate_ctrl->state[rate].rssi_thres = 0; + if (CHK_RSSI(rate)) { + if (ath_rc_priv->state[rate+1].rssi_thres < + rate_table->info[rate].rssi_ack_deltamin) + ath_rc_priv->state[rate].rssi_thres = 0; else { - rate_ctrl->state[rate].rssi_thres = - rate_ctrl->state[rate+1]. - rssi_thres - - rate_table->info[rate]. - rssi_ack_deltamin; + ath_rc_priv->state[rate].rssi_thres = + ath_rc_priv->state[rate+1].rssi_thres - + rate_table->info[rate].rssi_ack_deltamin; } - if (rate_ctrl->state[rate].rssi_thres < - rate_table->info[rate]. - rssi_ack_validmin) { - rate_ctrl->state[rate].rssi_thres = - rate_table->info[rate]. - rssi_ack_validmin; + if (ath_rc_priv->state[rate].rssi_thres < + rate_table->info[rate].rssi_ack_validmin) { + ath_rc_priv->state[rate].rssi_thres = + rate_table->info[rate].rssi_ack_validmin; } } } @@ -1504,74 +1174,86 @@ static void ath_rc_update_ht(struct ath_softc *sc, /* Make sure the rates below this have lower PER */ /* Monotonicity is kept only for rates below the current rate. */ - if (rate_ctrl->state[tx_rate].per < last_per) { + if (ath_rc_priv->state[tx_rate].per < last_per) { for (rate = tx_rate - 1; rate >= 0; rate--) { if (rate_table->info[rate].phy != rate_table->info[tx_rate].phy) break; - if (rate_ctrl->state[rate].per > - rate_ctrl->state[rate+1].per) { - rate_ctrl->state[rate].per = - rate_ctrl->state[rate+1].per; + if (ath_rc_priv->state[rate].per > + ath_rc_priv->state[rate+1].per) { + ath_rc_priv->state[rate].per = + ath_rc_priv->state[rate+1].per; } } } /* Maintain monotonicity for rates above the current rate */ - for (rate = tx_rate; rate < rate_ctrl->rate_table_size - 1; rate++) { - if (rate_ctrl->state[rate+1].per < rate_ctrl->state[rate].per) - rate_ctrl->state[rate+1].per = - rate_ctrl->state[rate].per; + for (rate = tx_rate; rate < size - 1; rate++) { + if (ath_rc_priv->state[rate+1].per < + ath_rc_priv->state[rate].per) + ath_rc_priv->state[rate+1].per = + ath_rc_priv->state[rate].per; } /* Every so often, we reduce the thresholds and * PER (different for CCK and OFDM). */ - if (now_msec - rate_ctrl->rssi_down_time >= + if (now_msec - ath_rc_priv->rssi_down_time >= rate_table->rssi_reduce_interval) { - for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) { - if (rate_ctrl->state[rate].rssi_thres > + for (rate = 0; rate < size; rate++) { + if (ath_rc_priv->state[rate].rssi_thres > rate_table->info[rate].rssi_ack_validmin) - rate_ctrl->state[rate].rssi_thres -= 1; + ath_rc_priv->state[rate].rssi_thres -= 1; } - rate_ctrl->rssi_down_time = now_msec; + ath_rc_priv->rssi_down_time = now_msec; } /* Every so often, we reduce the thresholds * and PER (different for CCK and OFDM). */ - if (now_msec - rate_ctrl->per_down_time >= + if (now_msec - ath_rc_priv->per_down_time >= rate_table->rssi_reduce_interval) { - for (rate = 0; rate < rate_ctrl->rate_table_size; rate++) { - rate_ctrl->state[rate].per = - 7 * rate_ctrl->state[rate].per / 8; + for (rate = 0; rate < size; rate++) { + ath_rc_priv->state[rate].per = + 7 * ath_rc_priv->state[rate].per / 8; } - rate_ctrl->per_down_time = now_msec; + ath_rc_priv->per_down_time = now_msec; } + +#undef CHK_RSSI } -/* - * This routine is called in rate control callback tx_status() to give - * the status of previous frames. - */ -static void ath_rc_update(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - struct ath_tx_info_priv *info_priv, int final_ts_idx, - int xretries, int long_retry) +static int ath_rc_get_rateindex(struct ath_rate_table *rate_table, + struct ieee80211_tx_rate *rate) { - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; + int rix; + + if ((rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (rate->flags & IEEE80211_TX_RC_SHORT_GI)) + rix = rate_table->info[rate->idx].ht_index; + else if (rate->flags & IEEE80211_TX_RC_SHORT_GI) + rix = rate_table->info[rate->idx].sgi_index; + else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + rix = rate_table->info[rate->idx].cw40index; + else + rix = rate_table->info[rate->idx].base_index; + + return rix; +} + +static void ath_rc_tx_status(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ieee80211_tx_info *tx_info, + int final_ts_idx, int xretries, int long_retry) +{ + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); struct ath_rate_table *rate_table; - struct ath_tx_ratectrl *rate_ctrl; - struct ath_rc_series rcs[4]; + struct ieee80211_tx_rate *rates = tx_info->status.rates; u8 flags; - u32 series = 0, rix; + u32 i = 0, rix; - memcpy(rcs, info_priv->rcs, 4 * sizeof(rcs[0])); - rate_table = (struct ath_rate_table *) - asc->hw_rate_table[sc->sc_curmode]; - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); - ASSERT(rcs[0].tries != 0); + rate_table = sc->cur_rate_table; /* * If the first rate is not the final index, there @@ -1579,32 +1261,22 @@ static void ath_rc_update(struct ath_softc *sc, */ if (final_ts_idx != 0) { /* Process intermediate rates that failed.*/ - for (series = 0; series < final_ts_idx ; series++) { - if (rcs[series].tries != 0) { - flags = rcs[series].flags; + for (i = 0; i < final_ts_idx ; i++) { + if (rates[i].count != 0 && (rates[i].idx >= 0)) { + flags = rates[i].flags; + /* If HT40 and we have switched mode from * 40 to 20 => don't update */ - if ((flags & ATH_RC_CW40_FLAG) && - (rate_ctrl->rc_phy_mode != - (flags & ATH_RC_CW40_FLAG))) + + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) return; - if ((flags & ATH_RC_CW40_FLAG) && - (flags & ATH_RC_SGI_FLAG)) - rix = rate_table->info[ - rcs[series].rix].ht_index; - else if (flags & ATH_RC_SGI_FLAG) - rix = rate_table->info[ - rcs[series].rix].sgi_index; - else if (flags & ATH_RC_CW40_FLAG) - rix = rate_table->info[ - rcs[series].rix].cw40index; - else - rix = rate_table->info[ - rcs[series].rix].base_index; + + rix = ath_rc_get_rateindex(rate_table, &rates[i]); ath_rc_update_ht(sc, ath_rc_priv, - info_priv, rix, + tx_info_priv, rix, xretries ? 1 : 2, - rcs[series].tries); + rates[i].count); } } } else { @@ -1614,240 +1286,152 @@ static void ath_rc_update(struct ath_softc *sc, * Treating it as an excessive retry penalizes the rate * inordinately. */ - if (rcs[0].tries == 1 && xretries == 1) + if (rates[0].count == 1 && xretries == 1) xretries = 2; } - flags = rcs[series].flags; + flags = rates[i].flags; + /* If HT40 and we have switched mode from 40 to 20 => don't update */ - if ((flags & ATH_RC_CW40_FLAG) && - (rate_ctrl->rc_phy_mode != (flags & ATH_RC_CW40_FLAG))) + if ((flags & IEEE80211_TX_RC_40_MHZ_WIDTH) && + (ath_rc_priv->rc_phy_mode != WLAN_RC_40_FLAG)) { return; + } - if ((flags & ATH_RC_CW40_FLAG) && (flags & ATH_RC_SGI_FLAG)) - rix = rate_table->info[rcs[series].rix].ht_index; - else if (flags & ATH_RC_SGI_FLAG) - rix = rate_table->info[rcs[series].rix].sgi_index; - else if (flags & ATH_RC_CW40_FLAG) - rix = rate_table->info[rcs[series].rix].cw40index; - else - rix = rate_table->info[rcs[series].rix].base_index; - - ath_rc_update_ht(sc, ath_rc_priv, info_priv, rix, - xretries, long_retry); + rix = ath_rc_get_rateindex(rate_table, &rates[i]); + ath_rc_update_ht(sc, ath_rc_priv, tx_info_priv, rix, + xretries, long_retry); } -/* - * Process a tx descriptor for a completed transmit (success or failure). - */ -static void ath_rate_tx_complete(struct ath_softc *sc, - struct ath_node *an, - struct ath_rate_node *rc_priv, - struct ath_tx_info_priv *info_priv) +static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc, + enum ieee80211_band band, + bool is_ht, bool is_cw_40) { - int final_ts_idx = info_priv->tx.ts_rateindex; - int tx_status = 0, is_underrun = 0; - struct ath_vap *avp; - - avp = rc_priv->avp; - if ((avp->av_config.av_fixed_rateset != IEEE80211_FIXED_RATE_NONE) || - (info_priv->tx.ts_status & ATH9K_TXERR_FILT)) - return; - - if (info_priv->tx.ts_rssi > 0) { - ATH_RSSI_LPF(an->an_chainmask_sel.tx_avgrssi, - info_priv->tx.ts_rssi); - } - - /* - * If underrun error is seen assume it as an excessive retry only - * if prefetch trigger level have reached the max (0x3f for 5416) - * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY - * times. This affects how ratectrl updates PER for the failed rate. - */ - if (info_priv->tx.ts_flags & - (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) && - ((sc->sc_ah->ah_txTrigLevel) >= tx_triglevel_max)) { - tx_status = 1; - is_underrun = 1; + int mode = 0; + + switch(band) { + case IEEE80211_BAND_2GHZ: + mode = ATH9K_MODE_11G; + if (is_ht) + mode = ATH9K_MODE_11NG_HT20; + if (is_cw_40) + mode = ATH9K_MODE_11NG_HT40PLUS; + break; + case IEEE80211_BAND_5GHZ: + mode = ATH9K_MODE_11A; + if (is_ht) + mode = ATH9K_MODE_11NA_HT20; + if (is_cw_40) + mode = ATH9K_MODE_11NA_HT40PLUS; + break; + default: + DPRINTF(sc, ATH_DBG_CONFIG, "Invalid band\n"); + return NULL; } - if ((info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) || - (info_priv->tx.ts_status & ATH9K_TXERR_FIFO)) - tx_status = 1; + BUG_ON(mode >= ATH9K_MODE_MAX); - ath_rc_update(sc, rc_priv, info_priv, final_ts_idx, tx_status, - (is_underrun) ? ATH_11N_TXMAXTRY : - info_priv->tx.ts_longretry); + DPRINTF(sc, ATH_DBG_CONFIG, "Choosing rate table for mode: %d\n", mode); + return sc->hw_rate_table[mode]; } -/* - * Update the SIB's rate control information - * - * This should be called when the supported rates change - * (e.g. SME operation, wireless mode change) - * - * It will determine which rates are valid for use. - */ -static void ath_rc_sib_update(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - u32 capflag, int keep_state, - struct ath_rateset *negotiated_rates, - struct ath_rateset *negotiated_htrates) +static void ath_rc_init(struct ath_softc *sc, + struct ath_rate_priv *ath_rc_priv, + struct ieee80211_supported_band *sband, + struct ieee80211_sta *sta) { struct ath_rate_table *rate_table = NULL; - struct ath_rate_softc *asc = (struct ath_rate_softc *)sc->sc_rc; - struct ath_rateset *rateset = negotiated_rates; - u8 *ht_mcs = (u8 *)negotiated_htrates; - struct ath_tx_ratectrl *rate_ctrl = - (struct ath_tx_ratectrl *)ath_rc_priv; + struct ath_rateset *rateset = &ath_rc_priv->neg_rates; + u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates; u8 i, j, k, hi = 0, hthi = 0; - rate_table = (struct ath_rate_table *) - asc->hw_rate_table[sc->sc_curmode]; + /* FIXME: Adhoc */ + if ((sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION) || + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC)) { + bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40; + rate_table = ath_choose_rate_table(sc, sband->band, + sta->ht_cap.ht_supported, + is_cw_40); + } else if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) { + /* cur_rate_table would be set on init through config() */ + rate_table = sc->cur_rate_table; + } + + if (!rate_table) { + DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n"); + return; + } + + if (sta->ht_cap.ht_supported) { + ath_rc_priv->ht_cap = (WLAN_RC_HT_FLAG | WLAN_RC_DS_FLAG); + if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) + ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG; + } /* Initial rate table size. Will change depending * on the working rate set */ - rate_ctrl->rate_table_size = MAX_TX_RATE_TBL; + ath_rc_priv->rate_table_size = RATE_TABLE_SIZE; /* Initialize thresholds according to the global rate table */ - for (i = 0 ; (i < rate_ctrl->rate_table_size) && (!keep_state); i++) { - rate_ctrl->state[i].rssi_thres = + for (i = 0 ; i < ath_rc_priv->rate_table_size; i++) { + ath_rc_priv->state[i].rssi_thres = rate_table->info[i].rssi_ack_validmin; - rate_ctrl->state[i].per = 0; + ath_rc_priv->state[i].per = 0; } /* Determine the valid rates */ - ath_rc_init_valid_txmask(rate_ctrl); + ath_rc_init_valid_txmask(ath_rc_priv); for (i = 0; i < WLAN_RC_PHY_MAX; i++) { for (j = 0; j < MAX_TX_RATE_PHY; j++) - rate_ctrl->valid_phy_rateidx[i][j] = 0; - rate_ctrl->valid_phy_ratecnt[i] = 0; + ath_rc_priv->valid_phy_rateidx[i][j] = 0; + ath_rc_priv->valid_phy_ratecnt[i] = 0; } - rate_ctrl->rc_phy_mode = (capflag & WLAN_RC_40_FLAG); + ath_rc_priv->rc_phy_mode = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG); /* Set stream capability */ - ath_rc_priv->single_stream = (capflag & WLAN_RC_DS_FLAG) ? 0 : 1; + ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1; if (!rateset->rs_nrates) { /* No working rate, just initialize valid rates */ - hi = ath_rc_sib_init_validrates(ath_rc_priv, rate_table, - capflag); + hi = ath_rc_init_validrates(ath_rc_priv, rate_table, + ath_rc_priv->ht_cap); } else { /* Use intersection of working rates and valid rates */ - hi = ath_rc_sib_setvalid_rates(ath_rc_priv, rate_table, - rateset, capflag); - if (capflag & WLAN_RC_HT_FLAG) { - hthi = ath_rc_sib_setvalid_htrates(ath_rc_priv, + hi = ath_rc_setvalid_rates(ath_rc_priv, rate_table, + rateset, ath_rc_priv->ht_cap); + if (ath_rc_priv->ht_cap & WLAN_RC_HT_FLAG) { + hthi = ath_rc_setvalid_htrates(ath_rc_priv, rate_table, ht_mcs, - capflag); + ath_rc_priv->ht_cap); } hi = A_MAX(hi, hthi); } - rate_ctrl->rate_table_size = hi + 1; - rate_ctrl->rate_max_phy = 0; - ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL); + ath_rc_priv->rate_table_size = hi + 1; + ath_rc_priv->rate_max_phy = 0; + ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); for (i = 0, k = 0; i < WLAN_RC_PHY_MAX; i++) { - for (j = 0; j < rate_ctrl->valid_phy_ratecnt[i]; j++) { - rate_ctrl->valid_rate_index[k++] = - rate_ctrl->valid_phy_rateidx[i][j]; + for (j = 0; j < ath_rc_priv->valid_phy_ratecnt[i]; j++) { + ath_rc_priv->valid_rate_index[k++] = + ath_rc_priv->valid_phy_rateidx[i][j]; } - if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, TRUE) - || !rate_ctrl->valid_phy_ratecnt[i]) + if (!ath_rc_valid_phyrate(i, rate_table->initial_ratemax, 1) + || !ath_rc_priv->valid_phy_ratecnt[i]) continue; - rate_ctrl->rate_max_phy = rate_ctrl->valid_phy_rateidx[i][j-1]; + ath_rc_priv->rate_max_phy = ath_rc_priv->valid_phy_rateidx[i][j-1]; } - ASSERT(rate_ctrl->rate_table_size <= MAX_TX_RATE_TBL); - ASSERT(k <= MAX_TX_RATE_TBL); - - rate_ctrl->max_valid_rate = k; - /* - * Some third party vendors don't send the supported rate series in - * order. So sorting to make sure its in order, otherwise our RateFind - * Algo will select wrong rates - */ - ath_rc_sort_validrates(rate_table, rate_ctrl); - rate_ctrl->rate_max_phy = rate_ctrl->valid_rate_index[k-4]; -} - -/* - * Update rate-control state on station associate/reassociate. - */ -static int ath_rate_newassoc(struct ath_softc *sc, - struct ath_rate_node *ath_rc_priv, - unsigned int capflag, - struct ath_rateset *negotiated_rates, - struct ath_rateset *negotiated_htrates) -{ - - - ath_rc_priv->ht_cap = - ((capflag & ATH_RC_DS_FLAG) ? WLAN_RC_DS_FLAG : 0) | - ((capflag & ATH_RC_SGI_FLAG) ? WLAN_RC_SGI_FLAG : 0) | - ((capflag & ATH_RC_HT_FLAG) ? WLAN_RC_HT_FLAG : 0) | - ((capflag & ATH_RC_CW40_FLAG) ? WLAN_RC_40_FLAG : 0); - - ath_rc_sib_update(sc, ath_rc_priv, ath_rc_priv->ht_cap, 0, - negotiated_rates, negotiated_htrates); - - return 0; -} - -/* - * This routine is called to initialize the rate control parameters - * in the SIB. It is called initially during system initialization - * or when a station is associated with the AP. - */ -static void ath_rc_sib_init(struct ath_rate_node *ath_rc_priv) -{ - struct ath_tx_ratectrl *rate_ctrl; - - rate_ctrl = (struct ath_tx_ratectrl *)(ath_rc_priv); - rate_ctrl->rssi_down_time = jiffies_to_msecs(jiffies); -} - - -static void ath_setup_rates(struct ath_softc *sc, - struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, - struct ath_rate_node *rc_priv) - -{ - int i, j = 0; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - - for (i = 0; i < sband->n_bitrates; i++) { - if (sta->supp_rates[sband->band] & BIT(i)) { - rc_priv->neg_rates.rs_rates[j] - = (sband->bitrates[i].bitrate * 2) / 10; - j++; - } - } - rc_priv->neg_rates.rs_nrates = j; -} - -void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv) -{ - struct ath_softc *sc = hw->priv; - u32 capflag = 0; - - if (hw->conf.ht_conf.ht_supported) { - capflag |= ATH_RC_HT_FLAG | ATH_RC_DS_FLAG; - if (sc->sc_ht_info.tx_chan_width == ATH9K_HT_MACMODE_2040) - capflag |= ATH_RC_CW40_FLAG; - } - - ath_rate_newassoc(sc, rc_priv, capflag, - &rc_priv->neg_rates, - &rc_priv->neg_ht_rates); + ASSERT(ath_rc_priv->rate_table_size <= RATE_TABLE_SIZE); + ASSERT(k <= RATE_TABLE_SIZE); + ath_rc_priv->max_valid_rate = k; + ath_rc_sort_validrates(rate_table, ath_rc_priv); + ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4]; + sc->cur_rate_table = rate_table; } /* Rate Control callbacks */ @@ -1856,163 +1440,88 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband, struct sk_buff *skb) { struct ath_softc *sc = priv; - struct ath_tx_info_priv *tx_info_priv; - struct ath_node *an; + struct ath_rate_priv *ath_rc_priv = priv_sta; + struct ath_tx_info_priv *tx_info_priv = NULL; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr; + int final_ts_idx, tx_status = 0, is_underrun = 0; __le16 fc; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; + tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + final_ts_idx = tx_info_priv->tx.ts_rateindex; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr1); - spin_unlock_bh(&sc->node_lock); + if (!priv_sta || !ieee80211_is_data(fc) || + !tx_info_priv->update_rc) + goto exit; - if (!an || !priv_sta || !ieee80211_is_data(fc)) { - if (tx_info->driver_data[0] != NULL) { - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; - } - return; - } - if (tx_info->driver_data[0] != NULL) { - ath_rate_tx_complete(sc, an, priv_sta, tx_info_priv); - kfree(tx_info->driver_data[0]); - tx_info->driver_data[0] = NULL; - } -} - -static void ath_tx_aggr_resp(struct ath_softc *sc, - struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, - struct ath_node *an, - u8 tidno) -{ - struct ath_atx_tid *txtid; - u16 buffersize = 0; - int state; - struct sta_info *si; - - if (!(sc->sc_flags & SC_OP_TXAGGR)) - return; - - txtid = ATH_AN_2_TID(an, tidno); - if (!txtid->paused) - return; + if (tx_info_priv->tx.ts_status & ATH9K_TXERR_FILT) + goto exit; /* - * XXX: This is entirely busted, we aren't supposed to - * access the sta from here because it's internal - * to mac80211, and looking at the state without - * locking is wrong too. + * If underrun error is seen assume it as an excessive retry only + * if prefetch trigger level have reached the max (0x3f for 5416) + * Adjust the long retry as if the frame was tried ATH_11N_TXMAXTRY + * times. This affects how ratectrl updates PER for the failed rate. */ - si = container_of(sta, struct sta_info, sta); - buffersize = IEEE80211_MIN_AMPDU_BUF << - sband->ht_info.ampdu_factor; /* FIXME */ - state = si->ampdu_mlme.tid_state_tx[tidno]; - - if (state & HT_ADDBA_RECEIVED_MSK) { - txtid->addba_exchangecomplete = 1; - txtid->addba_exchangeinprogress = 0; - txtid->baw_size = buffersize; - - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Resuming tid, buffersize: %d\n", - __func__, - buffersize); - - ath_tx_resume_tid(sc, txtid); + if (tx_info_priv->tx.ts_flags & + (ATH9K_TX_DATA_UNDERRUN | ATH9K_TX_DELIM_UNDERRUN) && + ((sc->sc_ah->ah_txTrigLevel) >= ath_rc_priv->tx_triglevel_max)) { + tx_status = 1; + is_underrun = 1; } + + if ((tx_info_priv->tx.ts_status & ATH9K_TXERR_XRETRY) || + (tx_info_priv->tx.ts_status & ATH9K_TXERR_FIFO)) + tx_status = 1; + + ath_rc_tx_status(sc, ath_rc_priv, tx_info, final_ts_idx, tx_status, + (is_underrun) ? ATH_11N_TXMAXTRY : + tx_info_priv->tx.ts_longretry); + +exit: + kfree(tx_info_priv); } -static void ath_get_rate(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void ath_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { + struct ieee80211_supported_band *sband = txrc->sband; + struct sk_buff *skb = txrc->skb; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ath_softc *sc = priv; struct ieee80211_hw *hw = sc->hw; - struct ath_tx_info_priv *tx_info_priv; - struct ath_rate_node *ath_rc_priv = priv_sta; - struct ath_node *an; + struct ath_rate_priv *ath_rc_priv = priv_sta; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - int is_probe = FALSE, chk, ret; - s8 lowest_idx; + int is_probe = 0; __le16 fc = hdr->frame_control; - u8 *qc, tid; - DECLARE_MAC_BUF(mac); - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); - - /* allocate driver private area of tx_info */ - tx_info->driver_data[0] = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); - ASSERT(tx_info->driver_data[0] != NULL); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - lowest_idx = rate_lowest_index(sband, sta); - tx_info_priv->min_rate = (sband->bitrates[lowest_idx].bitrate * 2) / 10; /* lowest rate for management and multicast/broadcast frames */ - if (!ieee80211_is_data(fc) || - is_multicast_ether_addr(hdr->addr1) || !sta) { - sel->rate_idx = lowest_idx; + if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || + !sta) { + tx_info->control.rates[0].idx = rate_lowest_index(sband, sta); + tx_info->control.rates[0].count = + is_multicast_ether_addr(hdr->addr1) ? 1 : ATH_MGT_TXMAXTRY; return; } /* Find tx rate for unicast frames */ - ath_rate_findrate(sc, ath_rc_priv, - ATH_11N_TXMAXTRY, 4, - ATH_RC_PROBE_ALLOWED, - tx_info_priv->rcs, - &is_probe, - false); - if (is_probe) - sel->probe_idx = ath_rc_priv->tx_ratectrl.probe_rate; - - /* Ratecontrol sometimes returns invalid rate index */ - if (tx_info_priv->rcs[0].rix != 0xff) - ath_rc_priv->prev_data_rix = tx_info_priv->rcs[0].rix; - else - tx_info_priv->rcs[0].rix = ath_rc_priv->prev_data_rix; - - sel->rate_idx = tx_info_priv->rcs[0].rix; + ath_rc_ratefind(sc, ath_rc_priv, ATH_11N_TXMAXTRY, 4, + tx_info, &is_probe, false); /* Check if aggregation has to be enabled for this tid */ - - if (hw->conf.ht_conf.ht_supported) { + if (hw->conf.ht.enabled) { if (ieee80211_is_data_qos(fc)) { + u8 *qc, tid; + struct ath_node *an; + qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; + an = (struct ath_node *)sta->drv_priv; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, hdr->addr1); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Node not found to " - "init/chk TX aggr\n", __func__); - return; - } - - chk = ath_tx_aggr_check(sc, an, tid); - if (chk == AGGR_REQUIRED) { - ret = ieee80211_start_tx_ba_session(hw, - hdr->addr1, tid); - if (ret) - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Unable to start tx " - "aggr for: %s\n", - __func__, - print_mac(mac, hdr->addr1)); - else - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Started tx aggr for: %s\n", - __func__, - print_mac(mac, hdr->addr1)); - } else if (chk == AGGR_EXCHANGE_PROGRESS) - ath_tx_aggr_resp(sc, sband, sta, an, tid); + if(ath_tx_aggr_check(sc, an, tid)) + ieee80211_start_tx_ba_session(hw, hdr->addr1, tid); } } } @@ -2021,34 +1530,33 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { struct ath_softc *sc = priv; - struct ath_rate_node *ath_rc_priv = priv_sta; + struct ath_rate_priv *ath_rc_priv = priv_sta; int i, j = 0; - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + for (i = 0; i < sband->n_bitrates; i++) { + if (sta->supp_rates[sband->band] & BIT(i)) { + ath_rc_priv->neg_rates.rs_rates[j] + = (sband->bitrates[i].bitrate * 2) / 10; + j++; + } + } + ath_rc_priv->neg_rates.rs_nrates = j; - ath_setup_rates(sc, sband, sta, ath_rc_priv); - if (sc->hw->conf.flags & IEEE80211_CONF_SUPPORT_HT_MODE) { - for (i = 0; i < MCS_SET_SIZE; i++) { - if (sc->hw->conf.ht_conf.supp_mcs_set[i/8] & (1<<(i%8))) + if (sta->ht_cap.ht_supported) { + for (i = 0, j = 0; i < 77; i++) { + if (sta->ht_cap.mcs.rx_mask[i/8] & (1<<(i%8))) ath_rc_priv->neg_ht_rates.rs_rates[j++] = i; if (j == ATH_RATE_MAX) break; } ath_rc_priv->neg_ht_rates.rs_nrates = j; } - ath_rc_node_update(sc->hw, priv_sta); -} -static void ath_rate_clear(void *priv) -{ - return; + ath_rc_init(sc, priv_sta, sband, sta); } static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { - struct ath_softc *sc = hw->priv; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); return hw->priv; } @@ -2060,19 +1568,17 @@ static void ath_rate_free(void *priv) static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { struct ath_softc *sc = priv; - struct ath_vap *avp = sc->sc_vaps[0]; - struct ath_rate_node *rate_priv; - - DPRINTF(sc, ATH_DBG_RATE, "%s\n", __func__); + struct ath_rate_priv *rate_priv; - rate_priv = ath_rate_node_alloc(avp, sc->sc_rc, gfp); + rate_priv = kzalloc(sizeof(struct ath_rate_priv), gfp); if (!rate_priv) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: Unable to allocate private rc structure\n", - __func__); + "Unable to allocate private rc structure\n"); return NULL; } - ath_rc_sib_init(rate_priv); + + rate_priv->rssi_down_time = jiffies_to_msecs(jiffies); + rate_priv->tx_triglevel_max = sc->sc_ah->ah_caps.tx_triglevel_max; return rate_priv; } @@ -2080,11 +1586,8 @@ static void *ath_rate_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp static void ath_rate_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) { - struct ath_rate_node *rate_priv = priv_sta; - struct ath_softc *sc = priv; - - DPRINTF(sc, ATH_DBG_RATE, "%s", __func__); - ath_rate_node_free(rate_priv); + struct ath_rate_priv *rate_priv = priv_sta; + kfree(rate_priv); } static struct rate_control_ops ath_rate_ops = { @@ -2093,13 +1596,69 @@ static struct rate_control_ops ath_rate_ops = { .tx_status = ath_tx_status, .get_rate = ath_get_rate, .rate_init = ath_rate_init, - .clear = ath_rate_clear, .alloc = ath_rate_alloc, .free = ath_rate_free, .alloc_sta = ath_rate_alloc_sta, .free_sta = ath_rate_free_sta, }; +static void ath_setup_rate_table(struct ath_softc *sc, + struct ath_rate_table *rate_table) +{ + int i; + + for (i = 0; i < 256; i++) + rate_table->rateCodeToIndex[i] = (u8)-1; + + for (i = 0; i < rate_table->rate_cnt; i++) { + u8 code = rate_table->info[i].ratecode; + u8 cix = rate_table->info[i].ctrl_rate; + u8 sh = rate_table->info[i].short_preamble; + + rate_table->rateCodeToIndex[code] = i; + rate_table->rateCodeToIndex[code | sh] = i; + + rate_table->info[i].lpAckDuration = + ath9k_hw_computetxtime(sc->sc_ah, rate_table, + WLAN_CTRL_FRAME_SIZE, + cix, + false); + rate_table->info[i].spAckDuration = + ath9k_hw_computetxtime(sc->sc_ah, rate_table, + WLAN_CTRL_FRAME_SIZE, + cix, + true); + } +} + +void ath_rate_attach(struct ath_softc *sc) +{ + sc->hw_rate_table[ATH9K_MODE_11B] = + &ar5416_11b_ratetable; + sc->hw_rate_table[ATH9K_MODE_11A] = + &ar5416_11a_ratetable; + sc->hw_rate_table[ATH9K_MODE_11G] = + &ar5416_11g_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT20] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT20] = + &ar5416_11ng_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT40PLUS] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NA_HT40MINUS] = + &ar5416_11na_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT40PLUS] = + &ar5416_11ng_ratetable; + sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] = + &ar5416_11ng_ratetable; + + ath_setup_rate_table(sc, &ar5416_11b_ratetable); + ath_setup_rate_table(sc, &ar5416_11a_ratetable); + ath_setup_rate_table(sc, &ar5416_11g_ratetable); + ath_setup_rate_table(sc, &ar5416_11na_ratetable); + ath_setup_rate_table(sc, &ar5416_11ng_ratetable); +} + int ath_rate_control_register(void) { return ieee80211_rate_control_register(&ath_rate_ops); @@ -2109,4 +1668,3 @@ void ath_rate_control_unregister(void) { ieee80211_rate_control_unregister(&ath_rate_ops); } - diff --git a/drivers/net/wireless/ath9k/rc.h b/drivers/net/wireless/ath9k/rc.h index b95b41508b986000174519cc451458962f4962c3..97c60d12e8aa51cbfc7e34cff14869a556888908 100644 --- a/drivers/net/wireless/ath9k/rc.h +++ b/drivers/net/wireless/ath9k/rc.h @@ -20,84 +20,24 @@ #define RC_H #include "ath9k.h" -/* - * Interface definitions for transmit rate control modules for the - * Atheros driver. - * - * A rate control module is responsible for choosing the transmit rate - * for each data frame. Management+control frames are always sent at - * a fixed rate. - * - * Only one module may be present at a time; the driver references - * rate control interfaces by symbol name. If multiple modules are - * to be supported we'll need to switch to a registration-based scheme - * as is currently done, for example, for authentication modules. - * - * An instance of the rate control module is attached to each device - * at attach time and detached when the device is destroyed. The module - * may associate data with each device and each node (station). Both - * sets of storage are opaque except for the size of the per-node storage - * which must be provided when the module is attached. - * - * The rate control module is notified for each state transition and - * station association/reassociation. Otherwise it is queried for a - * rate for each outgoing frame and provided status from each transmitted - * frame. Any ancillary processing is the responsibility of the module - * (e.g. if periodic processing is required then the module should setup - * it's own timer). - * - * In addition to the transmit rate for each frame the module must also - * indicate the number of attempts to make at the specified rate. If this - * number is != ATH_TXMAXTRY then an additional callback is made to setup - * additional transmit state. The rate control code is assumed to write - * this additional data directly to the transmit descriptor. - */ struct ath_softc; -#define TRUE 1 -#define FALSE 0 +#define ATH_RATE_MAX 30 +#define RATE_TABLE_SIZE 64 +#define MAX_TX_RATE_PHY 48 -#define ATH_RATE_MAX 30 -#define MCS_SET_SIZE 128 +/* VALID_ALL - valid for 20/40/Legacy, + * VALID - Legacy only, + * VALID_20 - HT 20 only, + * VALID_40 - HT 40 only */ -enum ieee80211_fixed_rate_mode { - IEEE80211_FIXED_RATE_NONE = 0, - IEEE80211_FIXED_RATE_MCS = 1 /* HT rates */ -}; - -/* - * Use the hal os glue code to get ms time - */ -#define IEEE80211_RATE_IDX_ENTRY(val, idx) (((val&(0xff<<(idx*8)))>>(idx*8))) - -#define WLAN_PHY_HT_20_SS WLAN_RC_PHY_HT_20_SS -#define WLAN_PHY_HT_20_DS WLAN_RC_PHY_HT_20_DS -#define WLAN_PHY_HT_20_DS_HGI WLAN_RC_PHY_HT_20_DS_HGI -#define WLAN_PHY_HT_40_SS WLAN_RC_PHY_HT_40_SS -#define WLAN_PHY_HT_40_SS_HGI WLAN_RC_PHY_HT_40_SS_HGI -#define WLAN_PHY_HT_40_DS WLAN_RC_PHY_HT_40_DS -#define WLAN_PHY_HT_40_DS_HGI WLAN_RC_PHY_HT_40_DS_HGI - -#define WLAN_PHY_OFDM PHY_OFDM -#define WLAN_PHY_CCK PHY_CCK - -#define TRUE_20 0x2 -#define TRUE_40 0x4 -#define TRUE_2040 (TRUE_20|TRUE_40) -#define TRUE_ALL (TRUE_2040|TRUE) - -enum { - WLAN_RC_PHY_HT_20_SS = 4, - WLAN_RC_PHY_HT_20_DS, - WLAN_RC_PHY_HT_40_SS, - WLAN_RC_PHY_HT_40_DS, - WLAN_RC_PHY_HT_20_SS_HGI, - WLAN_RC_PHY_HT_20_DS_HGI, - WLAN_RC_PHY_HT_40_SS_HGI, - WLAN_RC_PHY_HT_40_DS_HGI, - WLAN_RC_PHY_MAX -}; +#define INVALID 0x0 +#define VALID 0x1 +#define VALID_20 0x2 +#define VALID_40 0x4 +#define VALID_2040 (VALID_20|VALID_40) +#define VALID_ALL (VALID_2040|VALID) #define WLAN_RC_PHY_DS(_phy) ((_phy == WLAN_RC_PHY_HT_20_DS) \ || (_phy == WLAN_RC_PHY_HT_40_DS) \ @@ -114,26 +54,22 @@ enum { #define WLAN_RC_PHY_HT(_phy) (_phy >= WLAN_RC_PHY_HT_20_SS) -/* Returns the capflag mode */ #define WLAN_RC_CAP_MODE(capflag) (((capflag & WLAN_RC_HT_FLAG) ? \ - (capflag & WLAN_RC_40_FLAG) ? TRUE_40 : TRUE_20 : TRUE)) + (capflag & WLAN_RC_40_FLAG) ? VALID_40 : VALID_20 : VALID)) /* Return TRUE if flag supports HT20 && client supports HT20 or * return TRUE if flag supports HT40 && client supports HT40. * This is used becos some rates overlap between HT20/HT40. */ - -#define WLAN_RC_PHY_HT_VALID(flag, capflag) (((flag & TRUE_20) && !(capflag \ - & WLAN_RC_40_FLAG)) || ((flag & TRUE_40) && \ - (capflag & WLAN_RC_40_FLAG))) +#define WLAN_RC_PHY_HT_VALID(flag, capflag) \ + (((flag & VALID_20) && !(capflag & WLAN_RC_40_FLAG)) || \ + ((flag & VALID_40) && (capflag & WLAN_RC_40_FLAG))) #define WLAN_RC_DS_FLAG (0x01) #define WLAN_RC_40_FLAG (0x02) #define WLAN_RC_SGI_FLAG (0x04) #define WLAN_RC_HT_FLAG (0x08) -#define RATE_TABLE_SIZE 64 - /** * struct ath_rate_table - Rate Control table * @valid: valid for use in rate control @@ -150,10 +86,11 @@ enum { * @max_4ms_framelen: maximum frame length(bytes) for tx duration * @probe_interval: interval for rate control to probe for other rates * @rssi_reduce_interval: interval for rate control to reduce rssi - * @initial_ratemax: initial ratemax value used in ath_rc_sib_update() + * @initial_ratemax: initial ratemax value */ struct ath_rate_table { int rate_cnt; + u8 rateCodeToIndex[256]; struct { int valid; int valid_single_stream; @@ -171,42 +108,26 @@ struct ath_rate_table { u8 sgi_index; u8 ht_index; u32 max_4ms_framelen; + u16 lpAckDuration; + u16 spAckDuration; } info[RATE_TABLE_SIZE]; u32 probe_interval; u32 rssi_reduce_interval; u8 initial_ratemax; }; -#define ATH_RC_PROBE_ALLOWED 0x00000001 -#define ATH_RC_MINRATE_LASTRATE 0x00000002 - -struct ath_rc_series { - u8 rix; - u8 tries; - u8 flags; - u32 max_4ms_framelen; -}; - -/* rcs_flags definition */ -#define ATH_RC_DS_FLAG 0x01 -#define ATH_RC_CW40_FLAG 0x02 /* CW 40 */ -#define ATH_RC_SGI_FLAG 0x04 /* Short Guard Interval */ -#define ATH_RC_HT_FLAG 0x08 /* HT */ -#define ATH_RC_RTSCTS_FLAG 0x10 /* RTS-CTS */ - -/* - * State structures for new rate adaptation code - */ -#define MAX_TX_RATE_TBL 64 -#define MAX_TX_RATE_PHY 48 - struct ath_tx_ratectrl_state { int8_t rssi_thres; /* required rssi for this rate (dB) */ u8 per; /* recent estimate of packet error rate (%) */ }; +struct ath_rateset { + u8 rs_nrates; + u8 rs_rates[ATH_RATE_MAX]; +}; + /** - * struct ath_tx_ratectrl - TX Rate control Information + * struct ath_rate_priv - Rate Control priv data * @state: RC state * @rssi_last: last ACK rssi * @rssi_last_lookup: last ACK rssi used for lookup @@ -225,9 +146,13 @@ struct ath_tx_ratectrl_state { * @valid_phy_ratecnt: valid rate count * @rate_max_phy: phy index for the max rate * @probe_interval: interval for ratectrl to probe for other rates + * @prev_data_rix: rate idx of last data frame + * @ht_cap: HT capabilities + * @single_stream: When TRUE, only single TX stream possible + * @neg_rates: Negotatied rates + * @neg_ht_rates: Negotiated HT rates */ -struct ath_tx_ratectrl { - struct ath_tx_ratectrl_state state[MAX_TX_RATE_TBL]; +struct ath_rate_priv { int8_t rssi_last; int8_t rssi_last_lookup; int8_t rssi_last_prev; @@ -237,89 +162,40 @@ struct ath_tx_ratectrl { int32_t rssi_sum; u8 rate_table_size; u8 probe_rate; - u32 rssi_time; - u32 rssi_down_time; - u32 probe_time; u8 hw_maxretry_pktcnt; u8 max_valid_rate; - u8 valid_rate_index[MAX_TX_RATE_TBL]; - u32 per_down_time; - - /* 11n state */ + u8 valid_rate_index[RATE_TABLE_SIZE]; + u8 ht_cap; + u8 single_stream; u8 valid_phy_ratecnt[WLAN_RC_PHY_MAX]; - u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][MAX_TX_RATE_TBL]; + u8 valid_phy_rateidx[WLAN_RC_PHY_MAX][RATE_TABLE_SIZE]; u8 rc_phy_mode; u8 rate_max_phy; + u32 rssi_time; + u32 rssi_down_time; + u32 probe_time; + u32 per_down_time; u32 probe_interval; -}; - -struct ath_rateset { - u8 rs_nrates; - u8 rs_rates[ATH_RATE_MAX]; -}; - -/* per-device state */ -struct ath_rate_softc { - /* phy tables that contain rate control data */ - const void *hw_rate_table[ATH9K_MODE_MAX]; - - /* -1 or index of fixed rate */ - int fixedrix; -}; - -/* per-node state */ -struct ath_rate_node { - struct ath_tx_ratectrl tx_ratectrl; - - /* rate idx of last data frame */ u32 prev_data_rix; - - /* ht capabilities */ - u8 ht_cap; - - /* When TRUE, only single stream Tx possible */ - u8 single_stream; - - /* Negotiated rates */ + u32 tx_triglevel_max; + struct ath_tx_ratectrl_state state[RATE_TABLE_SIZE]; struct ath_rateset neg_rates; - - /* Negotiated HT rates */ struct ath_rateset neg_ht_rates; - struct ath_rate_softc *asc; - struct ath_vap *avp; }; -/* Driver data of ieee80211_tx_info */ struct ath_tx_info_priv { - struct ath_rc_series rcs[4]; struct ath_tx_status tx; int n_frames; int n_bad_frames; - u8 min_rate; + bool update_rc; }; -/* - * Attach/detach a rate control module. - */ -struct ath_rate_softc *ath_rate_attach(struct ath_hal *ah); -void ath_rate_detach(struct ath_rate_softc *asc); - -/* - * Update/reset rate control state for 802.11 state transitions. - * Important mostly as the analog to ath_rate_newassoc when operating - * in station mode. - */ -void ath_rc_node_update(struct ieee80211_hw *hw, struct ath_rate_node *rc_priv); -void ath_rate_newstate(struct ath_softc *sc, struct ath_vap *avp); - -/* - * Return rate index for given Dot11 Rate. - */ -u8 ath_rate_findrateix(struct ath_softc *sc, - u8 dot11_rate); +#define ATH_TX_INFO_PRIV(tx_info) \ + ((struct ath_tx_info_priv *)((tx_info)->rate_driver_data[0])) -/* Routines to register/unregister rate control algorithm */ +void ath_rate_attach(struct ath_softc *sc); +u8 ath_rate_findrateix(struct ath_softc *sc, u8 dot11_rate); int ath_rate_control_register(void); void ath_rate_control_unregister(void); diff --git a/drivers/net/wireless/ath9k/recv.c b/drivers/net/wireless/ath9k/recv.c index 504a0444d89f853672a4abd71886cc17e3068ff9..462e08c3d09dc4cf18693f4e39c383a7dc34c580 100644 --- a/drivers/net/wireless/ath9k/recv.c +++ b/drivers/net/wireless/ath9k/recv.c @@ -14,10 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * Implementation of receive path. - */ - #include "core.h" /* @@ -27,10 +23,7 @@ * MAC acknowledges BA status as long as it copies frames to host * buffer (or rx fifo). This can incorrectly acknowledge packets * to a sender if last desc is self-linked. - * - * NOTE: Caller should hold the rxbuf lock. */ - static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) { struct ath_hal *ah = sc->sc_ah; @@ -40,356 +33,53 @@ static void ath_rx_buf_link(struct ath_softc *sc, struct ath_buf *bf) ATH_RXBUF_RESET(bf); ds = bf->bf_desc; - ds->ds_link = 0; /* link to null */ + ds->ds_link = 0; /* link to null */ ds->ds_data = bf->bf_buf_addr; - /* XXX For RADAR? - * virtual addr of the beginning of the buffer. */ + /* virtual addr of the beginning of the buffer. */ skb = bf->bf_mpdu; ASSERT(skb != NULL); ds->ds_vdata = skb->data; - /* setup rx descriptors. The sc_rxbufsize here tells the harware + /* setup rx descriptors. The rx.bufsize here tells the harware * how much data it can DMA to us and that we are prepared * to process */ - ath9k_hw_setuprxdesc(ah, - ds, - sc->sc_rxbufsize, + ath9k_hw_setuprxdesc(ah, ds, + sc->rx.bufsize, 0); - if (sc->sc_rxlink == NULL) + if (sc->rx.rxlink == NULL) ath9k_hw_putrxbuf(ah, bf->bf_daddr); else - *sc->sc_rxlink = bf->bf_daddr; + *sc->rx.rxlink = bf->bf_daddr; - sc->sc_rxlink = &ds->ds_link; + sc->rx.rxlink = &ds->ds_link; ath9k_hw_rxena(ah); } -/* Process received BAR frame */ - -static int ath_bar_rx(struct ath_softc *sc, - struct ath_node *an, - struct sk_buff *skb) -{ - struct ieee80211_bar *bar; - struct ath_arx_tid *rxtid; - struct sk_buff *tskb; - struct ath_recv_status *rx_status; - int tidno, index, cindex; - u16 seqno; - - /* look at BAR contents */ - - bar = (struct ieee80211_bar *)skb->data; - tidno = (le16_to_cpu(bar->control) & IEEE80211_BAR_CTL_TID_M) - >> IEEE80211_BAR_CTL_TID_S; - seqno = le16_to_cpu(bar->start_seq_num) >> IEEE80211_SEQ_SEQ_SHIFT; - - /* process BAR - indicate all pending RX frames till the BAR seqno */ - - rxtid = &an->an_aggr.rx.tid[tidno]; - - spin_lock_bh(&rxtid->tidlock); - - /* get relative index */ - - index = ATH_BA_INDEX(rxtid->seq_next, seqno); - - /* drop BAR if old sequence (index is too large) */ - - if ((index > rxtid->baw_size) && - (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2)))) - /* discard frame, ieee layer may not treat frame as a dup */ - goto unlock_and_free; - - /* complete receive processing for all pending frames upto BAR seqno */ - - cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - while ((rxtid->baw_head != rxtid->baw_tail) && - (rxtid->baw_head != cindex)) { - tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf; - rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status; - rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL; - - if (tskb != NULL) - ath_rx_subframe(an, tskb, rx_status); - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* ... and indicate rest of the frames in-order */ - - while (rxtid->baw_head != rxtid->baw_tail && - rxtid->rxbuf[rxtid->baw_head].rx_wbuf != NULL) { - tskb = rxtid->rxbuf[rxtid->baw_head].rx_wbuf; - rx_status = &rxtid->rxbuf[rxtid->baw_head].rx_status; - rxtid->rxbuf[rxtid->baw_head].rx_wbuf = NULL; - - ath_rx_subframe(an, tskb, rx_status); - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - -unlock_and_free: - spin_unlock_bh(&rxtid->tidlock); - /* free bar itself */ - dev_kfree_skb(skb); - return IEEE80211_FTYPE_CTL; -} - -/* Function to handle a subframe of aggregation when HT is enabled */ - -static int ath_ampdu_input(struct ath_softc *sc, - struct ath_node *an, - struct sk_buff *skb, - struct ath_recv_status *rx_status) -{ - struct ieee80211_hdr *hdr; - struct ath_arx_tid *rxtid; - struct ath_rxbuf *rxbuf; - u8 type, subtype; - u16 rxseq; - int tid = 0, index, cindex, rxdiff; - __le16 fc; - u8 *qc; - - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - - /* collect stats of frames with non-zero version */ - - if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_VERS) != 0) { - dev_kfree_skb(skb); - return -1; - } - - type = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_FTYPE; - subtype = le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_STYPE; - - if (ieee80211_is_back_req(fc)) - return ath_bar_rx(sc, an, skb); - - /* special aggregate processing only for qos unicast data frames */ - - if (!ieee80211_is_data(fc) || - !ieee80211_is_data_qos(fc) || - is_multicast_ether_addr(hdr->addr1)) - return ath_rx_subframe(an, skb, rx_status); - - /* lookup rx tid state */ - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - } - - if (sc->sc_ah->ah_opmode == ATH9K_M_STA) { - /* Drop the frame not belonging to me. */ - if (memcmp(hdr->addr1, sc->sc_myaddr, ETH_ALEN)) { - dev_kfree_skb(skb); - return -1; - } - } - - rxtid = &an->an_aggr.rx.tid[tid]; - - spin_lock(&rxtid->tidlock); - - rxdiff = (rxtid->baw_tail - rxtid->baw_head) & - (ATH_TID_MAX_BUFS - 1); - - /* - * If the ADDBA exchange has not been completed by the source, - * process via legacy path (i.e. no reordering buffer is needed) - */ - if (!rxtid->addba_exchangecomplete) { - spin_unlock(&rxtid->tidlock); - return ath_rx_subframe(an, skb, rx_status); - } - - /* extract sequence number from recvd frame */ - - rxseq = le16_to_cpu(hdr->seq_ctrl) >> IEEE80211_SEQ_SEQ_SHIFT; - - if (rxtid->seq_reset) { - rxtid->seq_reset = 0; - rxtid->seq_next = rxseq; - } - - index = ATH_BA_INDEX(rxtid->seq_next, rxseq); - - /* drop frame if old sequence (index is too large) */ - - if (index > (IEEE80211_SEQ_MAX - (rxtid->baw_size << 2))) { - /* discard frame, ieee layer may not treat frame as a dup */ - spin_unlock(&rxtid->tidlock); - dev_kfree_skb(skb); - return IEEE80211_FTYPE_DATA; - } - - /* sequence number is beyond block-ack window */ - - if (index >= rxtid->baw_size) { - - /* complete receive processing for all pending frames */ - - while (index >= rxtid->baw_size) { - - rxbuf = rxtid->rxbuf + rxtid->baw_head; - - if (rxbuf->rx_wbuf != NULL) { - ath_rx_subframe(an, rxbuf->rx_wbuf, - &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - } - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - - index--; - } - } - - /* add buffer to the recv ba window */ - - cindex = (rxtid->baw_head + index) & (ATH_TID_MAX_BUFS - 1); - rxbuf = rxtid->rxbuf + cindex; - - if (rxbuf->rx_wbuf != NULL) { - spin_unlock(&rxtid->tidlock); - /* duplicate frame */ - dev_kfree_skb(skb); - return IEEE80211_FTYPE_DATA; - } - - rxbuf->rx_wbuf = skb; - rxbuf->rx_time = get_timestamp(); - rxbuf->rx_status = *rx_status; - - /* advance tail if sequence received is newer - * than any received so far */ - - if (index >= rxdiff) { - rxtid->baw_tail = cindex; - INCR(rxtid->baw_tail, ATH_TID_MAX_BUFS); - } - - /* indicate all in-order received frames */ - - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) - break; - - ath_rx_subframe(an, rxbuf->rx_wbuf, &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* - * start a timer to flush all received frames if there are pending - * receive frames - */ - if (rxtid->baw_head != rxtid->baw_tail) - mod_timer(&rxtid->timer, ATH_RX_TIMEOUT); - else - del_timer_sync(&rxtid->timer); - - spin_unlock(&rxtid->tidlock); - return IEEE80211_FTYPE_DATA; -} - -/* Timer to flush all received sub-frames */ - -static void ath_rx_timer(unsigned long data) +static void ath_setdefantenna(struct ath_softc *sc, u32 antenna) { - struct ath_arx_tid *rxtid = (struct ath_arx_tid *)data; - struct ath_node *an = rxtid->an; - struct ath_rxbuf *rxbuf; - int nosched; - - spin_lock_bh(&rxtid->tidlock); - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) { - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - continue; - } - - /* - * Stop if the next one is a very recent frame. - * - * Call get_timestamp in every iteration to protect against the - * case in which a new frame is received while we are executing - * this function. Using a timestamp obtained before entering - * the loop could lead to a very large time interval - * (a negative value typecast to unsigned), breaking the - * function's logic. - */ - if ((get_timestamp() - rxbuf->rx_time) < - (ATH_RX_TIMEOUT * HZ / 1000)) - break; - - ath_rx_subframe(an, rxbuf->rx_wbuf, - &rxbuf->rx_status); - rxbuf->rx_wbuf = NULL; - - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - - /* - * start a timer to flush all received frames if there are pending - * receive frames - */ - if (rxtid->baw_head != rxtid->baw_tail) - nosched = 0; - else - nosched = 1; /* no need to re-arm the timer again */ - - spin_unlock_bh(&rxtid->tidlock); + /* XXX block beacon interrupts */ + ath9k_hw_setantenna(sc->sc_ah, antenna); + sc->rx.defant = antenna; + sc->rx.rxotherant = 0; } -/* Free all pending sub-frames in the re-ordering buffer */ - -static void ath_rx_flush_tid(struct ath_softc *sc, - struct ath_arx_tid *rxtid, int drop) +/* + * Extend 15-bit time stamp from rx descriptor to + * a full 64-bit TSF using the current h/w TSF. +*/ +static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp) { - struct ath_rxbuf *rxbuf; - unsigned long flag; - - spin_lock_irqsave(&rxtid->tidlock, flag); - while (rxtid->baw_head != rxtid->baw_tail) { - rxbuf = rxtid->rxbuf + rxtid->baw_head; - if (!rxbuf->rx_wbuf) { - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - continue; - } - - if (drop) - dev_kfree_skb(rxbuf->rx_wbuf); - else - ath_rx_subframe(rxtid->an, - rxbuf->rx_wbuf, - &rxbuf->rx_status); - - rxbuf->rx_wbuf = NULL; + u64 tsf; - INCR(rxtid->baw_head, ATH_TID_MAX_BUFS); - INCR(rxtid->seq_next, IEEE80211_SEQ_MAX); - } - spin_unlock_irqrestore(&rxtid->tidlock, flag); + tsf = ath9k_hw_gettsf64(sc->sc_ah); + if ((tsf & 0x7fff) < rstamp) + tsf -= 0x8000; + return (tsf & ~0x7fff) | rstamp; } -static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, - u32 len) +static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len) { struct sk_buff *skb; u32 off; @@ -414,67 +104,131 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, skb_reserve(skb, sc->sc_cachelsz - off); } else { DPRINTF(sc, ATH_DBG_FATAL, - "%s: skbuff alloc of size %u failed\n", - __func__, len); + "skbuff alloc of size %u failed\n", len); return NULL; } return skb; } -static void ath_rx_requeue(struct ath_softc *sc, struct sk_buff *skb) +/* + * For Decrypt or Demic errors, we only mark packet status here and always push + * up the frame up to let mac80211 handle the actual error case, be it no + * decryption key or real decryption error. This let us keep statistics there. + */ +static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds, + struct ieee80211_rx_status *rx_status, bool *decrypt_error, + struct ath_softc *sc) { - struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf; + struct ieee80211_hdr *hdr; + u8 ratecode; + __le16 fc; - ASSERT(bf != NULL); + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); - spin_lock_bh(&sc->sc_rxbuflock); - if (bf->bf_status & ATH_BUFSTATUS_STALE) { + if (ds->ds_rxstat.rs_more) { /* - * This buffer is still held for hw acess. - * Mark it as free to be re-queued it later. + * Frame spans multiple descriptors; this cannot happen yet + * as we don't support jumbograms. If not in monitor mode, + * discard the frame. Enable this if you want to see + * error frames in Monitor mode. */ - bf->bf_status |= ATH_BUFSTATUS_FREE; - } else { - /* XXX: we probably never enter here, remove after - * verification */ - list_add_tail(&bf->list, &sc->sc_rxbuf); - ath_rx_buf_link(sc, bf); + if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_MONITOR) + goto rx_next; + } else if (ds->ds_rxstat.rs_status != 0) { + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) + rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) + goto rx_next; + + if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) { + *decrypt_error = true; + } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) { + if (ieee80211_is_ctl(fc)) + /* + * Sometimes, we get invalid + * MIC failures on valid control frames. + * Remove these mic errors. + */ + ds->ds_rxstat.rs_status &= ~ATH9K_RXERR_MIC; + else + rx_status->flag |= RX_FLAG_MMIC_ERROR; + } + /* + * Reject error frames with the exception of + * decryption and MIC failures. For monitor mode, + * we also ignore the CRC error. + */ + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR) { + if (ds->ds_rxstat.rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | + ATH9K_RXERR_CRC)) + goto rx_next; + } else { + if (ds->ds_rxstat.rs_status & + ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { + goto rx_next; + } + } } - spin_unlock_bh(&sc->sc_rxbuflock); -} -/* - * The skb indicated to upper stack won't be returned to us. - * So we have to allocate a new one and queue it by ourselves. - */ -static int ath_rx_indicate(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_recv_status *status, - u16 keyix) -{ - struct ath_buf *bf = ATH_RX_CONTEXT(skb)->ctx_rxbuf; - struct sk_buff *nskb; - int type; - - /* indicate frame to the stack, which will free the old skb. */ - type = _ath_rx_indicate(sc, skb, status, keyix); - - /* allocate a new skb and queue it to for H/W processing */ - nskb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); - if (nskb != NULL) { - bf->bf_mpdu = nskb; - bf->bf_buf_addr = pci_map_single(sc->pdev, nskb->data, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); - bf->bf_dmacontext = bf->bf_buf_addr; - ATH_RX_CONTEXT(nskb)->ctx_rxbuf = bf; + ratecode = ds->ds_rxstat.rs_rate; + + if (ratecode & 0x80) { + /* HT rate */ + rx_status->flag |= RX_FLAG_HT; + if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) + rx_status->flag |= RX_FLAG_40MHZ; + if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) + rx_status->flag |= RX_FLAG_SHORT_GI; + rx_status->rate_idx = ratecode & 0x7f; + } else { + int i = 0, cur_band, n_rates; + struct ieee80211_hw *hw = sc->hw; - /* queue the new wbuf to H/W */ - ath_rx_requeue(sc, nskb); + cur_band = hw->conf.channel->band; + n_rates = sc->sbands[cur_band].n_bitrates; + + for (i = 0; i < n_rates; i++) { + if (sc->sbands[cur_band].bitrates[i].hw_value == + ratecode) { + rx_status->rate_idx = i; + break; + } + + if (sc->sbands[cur_band].bitrates[i].hw_value_short == + ratecode) { + rx_status->rate_idx = i; + rx_status->flag |= RX_FLAG_SHORTPRE; + break; + } + } } - return type; + rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); + rx_status->band = sc->hw->conf.channel->band; + rx_status->freq = sc->hw->conf.channel->center_freq; + rx_status->noise = sc->sc_ani.sc_noise_floor; + rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi; + rx_status->antenna = ds->ds_rxstat.rs_antenna; + + /* at 45 you will be able to use MCS 15 reliably. A more elaborate + * scheme can be used here but it requires tables of SNR/throughput for + * each possible mode used. */ + rx_status->qual = ds->ds_rxstat.rs_rssi * 100 / 45; + + /* rssi can be more than 45 though, anything above that + * should be considered at 100% */ + if (rx_status->qual > 100) + rx_status->qual = 100; + + rx_status->flag |= RX_FLAG_TSFT; + + return 1; +rx_next: + return 0; } static void ath_opmode_init(struct ath_softc *sc) @@ -498,11 +252,7 @@ static void ath_opmode_init(struct ath_softc *sc) /* calculate and install multicast filter */ mfilt[0] = mfilt[1] = ~0; - ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); - DPRINTF(sc, ATH_DBG_CONFIG , - "%s: RX filter 0x%x, MC filter %08x:%08x\n", - __func__, rfilt, mfilt[0], mfilt[1]); } int ath_rx_init(struct ath_softc *sc, int nbufs) @@ -512,38 +262,29 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) int error = 0; do { - spin_lock_init(&sc->sc_rxflushlock); + spin_lock_init(&sc->rx.rxflushlock); sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_lock_init(&sc->sc_rxbuflock); + spin_lock_init(&sc->rx.rxbuflock); - /* - * Cisco's VPN software requires that drivers be able to - * receive encapsulated frames that are larger than the MTU. - * Since we can't be sure how large a frame we'll get, setup - * to handle the larges on possible. - */ - sc->sc_rxbufsize = roundup(IEEE80211_MAX_MPDU_LEN, + sc->rx.bufsize = roundup(IEEE80211_MAX_MPDU_LEN, min(sc->sc_cachelsz, (u16)64)); - DPRINTF(sc, ATH_DBG_CONFIG, "%s: cachelsz %u rxbufsize %u\n", - __func__, sc->sc_cachelsz, sc->sc_rxbufsize); + DPRINTF(sc, ATH_DBG_CONFIG, "cachelsz %u rxbufsize %u\n", + sc->sc_cachelsz, sc->rx.bufsize); /* Initialize rx descriptors */ - error = ath_descdma_setup(sc, &sc->sc_rxdma, &sc->sc_rxbuf, + error = ath_descdma_setup(sc, &sc->rx.rxdma, &sc->rx.rxbuf, "rx", nbufs, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: failed to allocate rx descriptors: %d\n", - __func__, error); + "failed to allocate rx descriptors: %d\n", error); break; } - /* Pre-allocate a wbuf for each rx buffer */ - - list_for_each_entry(bf, &sc->sc_rxbuf, list) { - skb = ath_rxbuf_alloc(sc, sc->sc_rxbufsize); + list_for_each_entry(bf, &sc->rx.rxbuf, list) { + skb = ath_rxbuf_alloc(sc, sc->rx.bufsize); if (skb == NULL) { error = -ENOMEM; break; @@ -551,12 +292,20 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) bf->bf_mpdu = skb; bf->bf_buf_addr = pci_map_single(sc->pdev, skb->data, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, + bf->bf_buf_addr))) { + dev_kfree_skb_any(skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on RX init\n"); + error = -ENOMEM; + break; + } bf->bf_dmacontext = bf->bf_buf_addr; - ATH_RX_CONTEXT(skb)->ctx_rxbuf = bf; } - sc->sc_rxlink = NULL; + sc->rx.rxlink = NULL; } while (0); @@ -566,23 +315,19 @@ int ath_rx_init(struct ath_softc *sc, int nbufs) return error; } -/* Reclaim all rx queue resources */ - void ath_rx_cleanup(struct ath_softc *sc) { struct sk_buff *skb; struct ath_buf *bf; - list_for_each_entry(bf, &sc->sc_rxbuf, list) { + list_for_each_entry(bf, &sc->rx.rxbuf, list) { skb = bf->bf_mpdu; if (skb) dev_kfree_skb(skb); } - /* cleanup rx descriptors */ - - if (sc->sc_rxdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->sc_rxdma, &sc->sc_rxbuf); + if (sc->rx.rxdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->rx.rxdma, &sc->rx.rxbuf); } /* @@ -615,201 +360,115 @@ u32 ath_calcrxfilter(struct ath_softc *sc) | ATH9K_RX_FILTER_MCAST; /* If not a STA, enable processing of Probe Requests */ - if (sc->sc_ah->ah_opmode != ATH9K_M_STA) + if (sc->sc_ah->ah_opmode != NL80211_IFTYPE_STATION) rfilt |= ATH9K_RX_FILTER_PROBEREQ; /* Can't set HOSTAP into promiscous mode */ - if (((sc->sc_ah->ah_opmode != ATH9K_M_HOSTAP) && - (sc->rx_filter & FIF_PROMISC_IN_BSS)) || - (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR)) { + if (((sc->sc_ah->ah_opmode != NL80211_IFTYPE_AP) && + (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) || + (sc->sc_ah->ah_opmode == NL80211_IFTYPE_MONITOR)) { rfilt |= ATH9K_RX_FILTER_PROM; /* ??? To prevent from sending ACK */ rfilt &= ~ATH9K_RX_FILTER_UCAST; } - if (((sc->sc_ah->ah_opmode == ATH9K_M_STA) && - (sc->rx_filter & FIF_BCN_PRBRESP_PROMISC)) || - (sc->sc_ah->ah_opmode == ATH9K_M_IBSS)) + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_STATION || + sc->sc_ah->ah_opmode == NL80211_IFTYPE_ADHOC) rfilt |= ATH9K_RX_FILTER_BEACON; /* If in HOSTAP mode, want to enable reception of PSPOLL frames & beacon frames */ - if (sc->sc_ah->ah_opmode == ATH9K_M_HOSTAP) + if (sc->sc_ah->ah_opmode == NL80211_IFTYPE_AP) rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL); + return rfilt; #undef RX_FILTER_PRESERVE } -/* Enable the receive h/w following a reset. */ - int ath_startrecv(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf, *tbf; - spin_lock_bh(&sc->sc_rxbuflock); - if (list_empty(&sc->sc_rxbuf)) + spin_lock_bh(&sc->rx.rxbuflock); + if (list_empty(&sc->rx.rxbuf)) goto start_recv; - sc->sc_rxlink = NULL; - list_for_each_entry_safe(bf, tbf, &sc->sc_rxbuf, list) { - if (bf->bf_status & ATH_BUFSTATUS_STALE) { - /* restarting h/w, no need for holding descriptors */ - bf->bf_status &= ~ATH_BUFSTATUS_STALE; - /* - * Upper layer may not be done with the frame yet so - * we can't just re-queue it to hardware. Remove it - * from h/w queue. It'll be re-queued when upper layer - * returns the frame and ath_rx_requeue_mpdu is called. - */ - if (!(bf->bf_status & ATH_BUFSTATUS_FREE)) { - list_del(&bf->list); - continue; - } - } - /* chain descriptors */ + sc->rx.rxlink = NULL; + list_for_each_entry_safe(bf, tbf, &sc->rx.rxbuf, list) { ath_rx_buf_link(sc, bf); } /* We could have deleted elements so the list may be empty now */ - if (list_empty(&sc->sc_rxbuf)) + if (list_empty(&sc->rx.rxbuf)) goto start_recv; - bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list); + bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); ath9k_hw_putrxbuf(ah, bf->bf_daddr); - ath9k_hw_rxena(ah); /* enable recv descriptors */ + ath9k_hw_rxena(ah); start_recv: - spin_unlock_bh(&sc->sc_rxbuflock); - ath_opmode_init(sc); /* set filters, etc. */ - ath9k_hw_startpcureceive(ah); /* re-enable PCU/DMA engine */ + spin_unlock_bh(&sc->rx.rxbuflock); + ath_opmode_init(sc); + ath9k_hw_startpcureceive(ah); + return 0; } -/* Disable the receive h/w in preparation for a reset. */ - bool ath_stoprecv(struct ath_softc *sc) { struct ath_hal *ah = sc->sc_ah; - u64 tsf; bool stopped; - ath9k_hw_stoppcurecv(ah); /* disable PCU */ - ath9k_hw_setrxfilter(ah, 0); /* clear recv filter */ - stopped = ath9k_hw_stopdmarecv(ah); /* disable DMA engine */ - mdelay(3); /* 3ms is long enough for 1 frame */ - tsf = ath9k_hw_gettsf64(ah); - sc->sc_rxlink = NULL; /* just in case */ + ath9k_hw_stoppcurecv(ah); + ath9k_hw_setrxfilter(ah, 0); + stopped = ath9k_hw_stopdmarecv(ah); + mdelay(3); /* 3ms is long enough for 1 frame */ + sc->rx.rxlink = NULL; + return stopped; } -/* Flush receive queue */ - void ath_flushrecv(struct ath_softc *sc) { - /* - * ath_rx_tasklet may be used to handle rx interrupt and flush receive - * queue at the same time. Use a lock to serialize the access of rx - * queue. - * ath_rx_tasklet cannot hold the spinlock while indicating packets. - * Instead, do not claim the spinlock but check for a flush in - * progress (see references to sc_rxflush) - */ - spin_lock_bh(&sc->sc_rxflushlock); + spin_lock_bh(&sc->rx.rxflushlock); sc->sc_flags |= SC_OP_RXFLUSH; - ath_rx_tasklet(sc, 1); - sc->sc_flags &= ~SC_OP_RXFLUSH; - spin_unlock_bh(&sc->sc_rxflushlock); + spin_unlock_bh(&sc->rx.rxflushlock); } -/* Process an individual frame */ - -int ath_rx_input(struct ath_softc *sc, - struct ath_node *an, - int is_ampdu, - struct sk_buff *skb, - struct ath_recv_status *rx_status, - enum ATH_RX_TYPE *status) -{ - if (is_ampdu && (sc->sc_flags & SC_OP_RXAGGR)) { - *status = ATH_RX_CONSUMED; - return ath_ampdu_input(sc, an, skb, rx_status); - } else { - *status = ATH_RX_NON_CONSUMED; - return -1; - } -} - -/* Process receive queue, as well as LED, etc. */ - int ath_rx_tasklet(struct ath_softc *sc, int flush) { #define PA2DESC(_sc, _pa) \ - ((struct ath_desc *)((caddr_t)(_sc)->sc_rxdma.dd_desc + \ - ((_pa) - (_sc)->sc_rxdma.dd_desc_paddr))) + ((struct ath_desc *)((caddr_t)(_sc)->rx.rxdma.dd_desc + \ + ((_pa) - (_sc)->rx.rxdma.dd_desc_paddr))) - struct ath_buf *bf, *bf_held = NULL; + struct ath_buf *bf; struct ath_desc *ds; - struct ieee80211_hdr *hdr; - struct sk_buff *skb = NULL; - struct ath_recv_status rx_status; + struct sk_buff *skb = NULL, *requeue_skb; + struct ieee80211_rx_status rx_status; struct ath_hal *ah = sc->sc_ah; - int type, rx_processed = 0; - u32 phyerr; - u8 chainreset = 0; - int retval; - __le16 fc; + struct ieee80211_hdr *hdr; + int hdrlen, padsize, retval; + bool decrypt_error = false; + u8 keyix; + + spin_lock_bh(&sc->rx.rxbuflock); do { /* If handling rx interrupt and flush is in progress => exit */ if ((sc->sc_flags & SC_OP_RXFLUSH) && (flush == 0)) break; - spin_lock_bh(&sc->sc_rxbuflock); - if (list_empty(&sc->sc_rxbuf)) { - sc->sc_rxlink = NULL; - spin_unlock_bh(&sc->sc_rxbuflock); + if (list_empty(&sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; break; } - bf = list_first_entry(&sc->sc_rxbuf, struct ath_buf, list); - - /* - * There is a race condition that BH gets scheduled after sw - * writes RxE and before hw re-load the last descriptor to get - * the newly chained one. Software must keep the last DONE - * descriptor as a holding descriptor - software does so by - * marking it with the STALE flag. - */ - if (bf->bf_status & ATH_BUFSTATUS_STALE) { - bf_held = bf; - if (list_is_last(&bf_held->list, &sc->sc_rxbuf)) { - /* - * The holding descriptor is the last - * descriptor in queue. It's safe to - * remove the last holding descriptor - * in BH context. - */ - list_del(&bf_held->list); - bf_held->bf_status &= ~ATH_BUFSTATUS_STALE; - sc->sc_rxlink = NULL; - - if (bf_held->bf_status & ATH_BUFSTATUS_FREE) { - list_add_tail(&bf_held->list, - &sc->sc_rxbuf); - ath_rx_buf_link(sc, bf_held); - } - spin_unlock_bh(&sc->sc_rxbuflock); - break; - } - bf = list_entry(bf->list.next, struct ath_buf, list); - } - + bf = list_first_entry(&sc->rx.rxbuf, struct ath_buf, list); ds = bf->bf_desc; - ++rx_processed; /* * Must provide the virtual address of the current @@ -822,8 +481,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) * on. All this is necessary because of our use of * a self-linked list to avoid rx overruns. */ - retval = ath9k_hw_rxprocdesc(ah, - ds, + retval = ath9k_hw_rxprocdesc(ah, ds, bf->bf_daddr, PA2DESC(sc, ds->ds_link), 0); @@ -831,8 +489,8 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) struct ath_buf *tbf; struct ath_desc *tds; - if (list_is_last(&bf->list, &sc->sc_rxbuf)) { - spin_unlock_bh(&sc->sc_rxbuflock); + if (list_is_last(&bf->list, &sc->rx.rxbuf)) { + sc->rx.rxlink = NULL; break; } @@ -850,451 +508,127 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush) */ tds = tbf->bf_desc; - retval = ath9k_hw_rxprocdesc(ah, - tds, tbf->bf_daddr, - PA2DESC(sc, tds->ds_link), 0); + retval = ath9k_hw_rxprocdesc(ah, tds, tbf->bf_daddr, + PA2DESC(sc, tds->ds_link), 0); if (retval == -EINPROGRESS) { - spin_unlock_bh(&sc->sc_rxbuflock); break; } } - /* XXX: we do not support frames spanning - * multiple descriptors */ - bf->bf_status |= ATH_BUFSTATUS_DONE; - skb = bf->bf_mpdu; - if (skb == NULL) { /* XXX ??? can this happen */ - spin_unlock_bh(&sc->sc_rxbuflock); + if (!skb) continue; - } + /* - * Now we know it's a completed frame, we can indicate the - * frame. Remove the previous holding descriptor and leave - * this one in the queue as the new holding descriptor. + * Synchronize the DMA transfer with CPU before + * 1. accessing the frame + * 2. requeueing the same buffer to h/w */ - if (bf_held) { - list_del(&bf_held->list); - bf_held->bf_status &= ~ATH_BUFSTATUS_STALE; - if (bf_held->bf_status & ATH_BUFSTATUS_FREE) { - list_add_tail(&bf_held->list, &sc->sc_rxbuf); - /* try to requeue this descriptor */ - ath_rx_buf_link(sc, bf_held); - } - } + pci_dma_sync_single_for_cpu(sc->pdev, bf->bf_buf_addr, + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); - bf->bf_status |= ATH_BUFSTATUS_STALE; - bf_held = bf; /* - * Release the lock here in case ieee80211_input() return - * the frame immediately by calling ath_rx_mpdu_requeue(). + * If we're asked to flush receive queue, directly + * chain it back at the queue without processing it. */ - spin_unlock_bh(&sc->sc_rxbuflock); + if (flush) + goto requeue; - if (flush) { - /* - * If we're asked to flush receive queue, directly - * chain it back at the queue without processing it. - */ - goto rx_next; - } + if (!ds->ds_rxstat.rs_datalen) + goto requeue; - hdr = (struct ieee80211_hdr *)skb->data; - fc = hdr->frame_control; - memset(&rx_status, 0, sizeof(struct ath_recv_status)); + /* The status portion of the descriptor could get corrupted. */ + if (sc->rx.bufsize < ds->ds_rxstat.rs_datalen) + goto requeue; - if (ds->ds_rxstat.rs_more) { - /* - * Frame spans multiple descriptors; this - * cannot happen yet as we don't support - * jumbograms. If not in monitor mode, - * discard the frame. - */ -#ifndef ERROR_FRAMES - /* - * Enable this if you want to see - * error frames in Monitor mode. - */ - if (sc->sc_ah->ah_opmode != ATH9K_M_MONITOR) - goto rx_next; -#endif - /* fall thru for monitor mode handling... */ - } else if (ds->ds_rxstat.rs_status != 0) { - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_CRC) - rx_status.flags |= ATH_RX_FCS_ERROR; - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_PHY) { - phyerr = ds->ds_rxstat.rs_phyerr & 0x1f; - goto rx_next; - } + if (!ath_rx_prepare(skb, ds, &rx_status, &decrypt_error, sc)) + goto requeue; + + /* Ensure we always have an skb to requeue once we are done + * processing the current buffer's skb */ + requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize); + + /* If there is no memory we ignore the current RX'd frame, + * tell hardware it can give us a new frame using the old + * skb and put it at the tail of the sc->rx.rxbuf list for + * processing. */ + if (!requeue_skb) + goto requeue; + + /* Unmap the frame */ + pci_unmap_single(sc->pdev, bf->bf_buf_addr, + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); - if (ds->ds_rxstat.rs_status & ATH9K_RXERR_DECRYPT) { - /* - * Decrypt error. We only mark packet status - * here and always push up the frame up to let - * mac80211 handle the actual error case, be - * it no decryption key or real decryption - * error. This let us keep statistics there. - */ - rx_status.flags |= ATH_RX_DECRYPT_ERROR; - } else if (ds->ds_rxstat.rs_status & ATH9K_RXERR_MIC) { - /* - * Demic error. We only mark frame status here - * and always push up the frame up to let - * mac80211 handle the actual error case. This - * let us keep statistics there. Hardware may - * post a false-positive MIC error. - */ - if (ieee80211_is_ctl(fc)) - /* - * Sometimes, we get invalid - * MIC failures on valid control frames. - * Remove these mic errors. - */ - ds->ds_rxstat.rs_status &= - ~ATH9K_RXERR_MIC; - else - rx_status.flags |= ATH_RX_MIC_ERROR; - } - /* - * Reject error frames with the exception of - * decryption and MIC failures. For monitor mode, - * we also ignore the CRC error. - */ - if (sc->sc_ah->ah_opmode == ATH9K_M_MONITOR) { - if (ds->ds_rxstat.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | - ATH9K_RXERR_CRC)) - goto rx_next; - } else { - if (ds->ds_rxstat.rs_status & - ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { - goto rx_next; - } - } - } - /* - * The status portion of the descriptor could get corrupted. - */ - if (sc->sc_rxbufsize < ds->ds_rxstat.rs_datalen) - goto rx_next; - /* - * Sync and unmap the frame. At this point we're - * committed to passing the sk_buff somewhere so - * clear buf_skb; this means a new sk_buff must be - * allocated when the rx descriptor is setup again - * to receive another frame. - */ skb_put(skb, ds->ds_rxstat.rs_datalen); skb->protocol = cpu_to_be16(ETH_P_CONTROL); - rx_status.tsf = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp); - rx_status.rateieee = - sc->sc_hwmap[ds->ds_rxstat.rs_rate].ieeerate; - rx_status.rateKbps = - sc->sc_hwmap[ds->ds_rxstat.rs_rate].rateKbps; - rx_status.ratecode = ds->ds_rxstat.rs_rate; - /* HT rate */ - if (rx_status.ratecode & 0x80) { - /* TODO - add table to avoid division */ - if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) { - rx_status.flags |= ATH_RX_40MHZ; - rx_status.rateKbps = - (rx_status.rateKbps * 27) / 13; - } - if (ds->ds_rxstat.rs_flags & ATH9K_RX_GI) - rx_status.rateKbps = - (rx_status.rateKbps * 10) / 9; - else - rx_status.flags |= ATH_RX_SHORT_GI; + /* see if any padding is done by the hw and remove it */ + hdr = (struct ieee80211_hdr *)skb->data; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + + /* The MAC header is padded to have 32-bit boundary if the + * packet payload is non-zero. The general calculation for + * padsize would take into account odd header lengths: + * padsize = (4 - hdrlen % 4) % 4; However, since only + * even-length headers are used, padding can only be 0 or 2 + * bytes and we can optimize this a bit. In addition, we must + * not try to remove padding from short control frames that do + * not have payload. */ + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); } - /* sc_noise_floor is only available when the station - attaches to an AP, so we use a default value - if we are not yet attached. */ - rx_status.abs_rssi = - ds->ds_rxstat.rs_rssi + sc->sc_ani.sc_noise_floor; - - pci_dma_sync_single_for_cpu(sc->pdev, - bf->bf_buf_addr, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); - pci_unmap_single(sc->pdev, - bf->bf_buf_addr, - sc->sc_rxbufsize, - PCI_DMA_FROMDEVICE); + keyix = ds->ds_rxstat.rs_keyix; - /* XXX: Ah! make me more readable, use a helper */ - if (ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) { - if (ds->ds_rxstat.rs_moreaggr == 0) { - rx_status.rssictl[0] = - ds->ds_rxstat.rs_rssi_ctl0; - rx_status.rssictl[1] = - ds->ds_rxstat.rs_rssi_ctl1; - rx_status.rssictl[2] = - ds->ds_rxstat.rs_rssi_ctl2; - rx_status.rssi = ds->ds_rxstat.rs_rssi; - if (ds->ds_rxstat.rs_flags & ATH9K_RX_2040) { - rx_status.rssiextn[0] = - ds->ds_rxstat.rs_rssi_ext0; - rx_status.rssiextn[1] = - ds->ds_rxstat.rs_rssi_ext1; - rx_status.rssiextn[2] = - ds->ds_rxstat.rs_rssi_ext2; - rx_status.flags |= - ATH_RX_RSSI_EXTN_VALID; - } - rx_status.flags |= ATH_RX_RSSI_VALID | - ATH_RX_CHAIN_RSSI_VALID; - } - } else { - /* - * Need to insert the "combined" rssi into the - * status structure for upper layer processing - */ - rx_status.rssi = ds->ds_rxstat.rs_rssi; - rx_status.flags |= ATH_RX_RSSI_VALID; + if (!(keyix == ATH9K_RXKEYIX_INVALID) && !decrypt_error) { + rx_status.flag |= RX_FLAG_DECRYPTED; + } else if ((le16_to_cpu(hdr->frame_control) & IEEE80211_FCTL_PROTECTED) + && !decrypt_error && skb->len >= hdrlen + 4) { + keyix = skb->data[hdrlen + 3] >> 6; + + if (test_bit(keyix, sc->sc_keymap)) + rx_status.flag |= RX_FLAG_DECRYPTED; } - /* Pass frames up to the stack. */ + /* Send the frame to mac80211 */ + __ieee80211_rx(sc->hw, skb, &rx_status); - type = ath_rx_indicate(sc, skb, - &rx_status, ds->ds_rxstat.rs_keyix); + /* We will now give hardware our shiny new allocated skb */ + bf->bf_mpdu = requeue_skb; + bf->bf_buf_addr = pci_map_single(sc->pdev, requeue_skb->data, + sc->rx.bufsize, + PCI_DMA_FROMDEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, + bf->bf_buf_addr))) { + dev_kfree_skb_any(requeue_skb); + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on RX\n"); + break; + } + bf->bf_dmacontext = bf->bf_buf_addr; /* * change the default rx antenna if rx diversity chooses the * other antenna 3 times in a row. */ - if (sc->sc_defant != ds->ds_rxstat.rs_antenna) { - if (++sc->sc_rxotherant >= 3) - ath_setdefantenna(sc, - ds->ds_rxstat.rs_antenna); + if (sc->rx.defant != ds->ds_rxstat.rs_antenna) { + if (++sc->rx.rxotherant >= 3) + ath_setdefantenna(sc, ds->ds_rxstat.rs_antenna); } else { - sc->sc_rxotherant = 0; + sc->rx.rxotherant = 0; } +requeue: + list_move_tail(&bf->list, &sc->rx.rxbuf); + ath_rx_buf_link(sc, bf); + } while (1); -#ifdef CONFIG_SLOW_ANT_DIV - if ((rx_status.flags & ATH_RX_RSSI_VALID) && - ieee80211_is_beacon(fc)) { - ath_slow_ant_div(&sc->sc_antdiv, hdr, &ds->ds_rxstat); - } -#endif - /* - * For frames successfully indicated, the buffer will be - * returned to us by upper layers by calling - * ath_rx_mpdu_requeue, either synchronusly or asynchronously. - * So we don't want to do it here in this loop. - */ - continue; - -rx_next: - bf->bf_status |= ATH_BUFSTATUS_FREE; - } while (TRUE); - - if (chainreset) { - DPRINTF(sc, ATH_DBG_CONFIG, - "%s: Reset rx chain mask. " - "Do internal reset\n", __func__); - ASSERT(flush == 0); - ath_reset(sc, false); - } + spin_unlock_bh(&sc->rx.rxbuflock); return 0; #undef PA2DESC } - -/* Process ADDBA request in per-TID data structure */ - -int ath_rx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn) -{ - struct ath_arx_tid *rxtid; - struct ath_node *an; - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_supported_band *sband; - u16 buffersize = 0; - - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Node not found to initialize RX aggregation\n", - __func__); - return -1; - } - - sband = hw->wiphy->bands[hw->conf.channel->band]; - buffersize = IEEE80211_MIN_AMPDU_BUF << - sband->ht_info.ampdu_factor; /* FIXME */ - - rxtid = &an->an_aggr.rx.tid[tid]; - - spin_lock_bh(&rxtid->tidlock); - if (sc->sc_flags & SC_OP_RXAGGR) { - /* Allow aggregation reception - * Adjust rx BA window size. Peer might indicate a - * zero buffer size for a _dont_care_ condition. - */ - if (buffersize) - rxtid->baw_size = min(buffersize, rxtid->baw_size); - - /* set rx sequence number */ - rxtid->seq_next = *ssn; - - /* Allocate the receive buffers for this TID */ - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Allcating rxbuffer for TID %d\n", __func__, tid); - - if (rxtid->rxbuf == NULL) { - /* - * If the rxbuff is not NULL at this point, we *probably* - * already allocated the buffer on a previous ADDBA, - * and this is a subsequent ADDBA that got through. - * Don't allocate, but use the value in the pointer, - * we zero it out when we de-allocate. - */ - rxtid->rxbuf = kmalloc(ATH_TID_MAX_BUFS * - sizeof(struct ath_rxbuf), GFP_ATOMIC); - } - if (rxtid->rxbuf == NULL) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Unable to allocate RX buffer, " - "refusing ADDBA\n", __func__); - } else { - /* Ensure the memory is zeroed out (all internal - * pointers are null) */ - memset(rxtid->rxbuf, 0, ATH_TID_MAX_BUFS * - sizeof(struct ath_rxbuf)); - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Allocated @%p\n", __func__, rxtid->rxbuf); - - /* Allow aggregation reception */ - rxtid->addba_exchangecomplete = 1; - } - } - spin_unlock_bh(&rxtid->tidlock); - - return 0; -} - -/* Process DELBA */ - -int ath_rx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid) -{ - struct ath_node *an; - - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: RX aggr stop for non-existent node\n", __func__); - return -1; - } - - ath_rx_aggr_teardown(sc, an, tid); - return 0; -} - -/* Rx aggregation tear down */ - -void ath_rx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tid) -{ - struct ath_arx_tid *rxtid = &an->an_aggr.rx.tid[tid]; - - if (!rxtid->addba_exchangecomplete) - return; - - del_timer_sync(&rxtid->timer); - ath_rx_flush_tid(sc, rxtid, 0); - rxtid->addba_exchangecomplete = 0; - - /* De-allocate the receive buffer array allocated when addba started */ - - if (rxtid->rxbuf) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Deallocating TID %d rxbuff @%p\n", - __func__, tid, rxtid->rxbuf); - kfree(rxtid->rxbuf); - - /* Set pointer to null to avoid reuse*/ - rxtid->rxbuf = NULL; - } -} - -/* Initialize per-node receive state */ - -void ath_rx_node_init(struct ath_softc *sc, struct ath_node *an) -{ - if (sc->sc_flags & SC_OP_RXAGGR) { - struct ath_arx_tid *rxtid; - int tidno; - - /* Init per tid rx state */ - for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, rxtid++) { - rxtid->an = an; - rxtid->seq_reset = 1; - rxtid->seq_next = 0; - rxtid->baw_size = WME_MAX_BA; - rxtid->baw_head = rxtid->baw_tail = 0; - - /* - * Ensure the buffer pointer is null at this point - * (needs to be allocated when addba is received) - */ - - rxtid->rxbuf = NULL; - setup_timer(&rxtid->timer, ath_rx_timer, - (unsigned long)rxtid); - spin_lock_init(&rxtid->tidlock); - - /* ADDBA state */ - rxtid->addba_exchangecomplete = 0; - } - } -} - -void ath_rx_node_cleanup(struct ath_softc *sc, struct ath_node *an) -{ - if (sc->sc_flags & SC_OP_RXAGGR) { - struct ath_arx_tid *rxtid; - int tidno, i; - - /* Init per tid rx state */ - for (tidno = 0, rxtid = &an->an_aggr.rx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, rxtid++) { - - if (!rxtid->addba_exchangecomplete) - continue; - - /* must cancel timer first */ - del_timer_sync(&rxtid->timer); - - /* drop any pending sub-frames */ - ath_rx_flush_tid(sc, rxtid, 1); - - for (i = 0; i < ATH_TID_MAX_BUFS; i++) - ASSERT(rxtid->rxbuf[i].rx_wbuf == NULL); - - rxtid->addba_exchangecomplete = 0; - } - } - -} - -/* Cleanup per-node receive state */ - -void ath_rx_node_free(struct ath_softc *sc, struct ath_node *an) -{ - ath_rx_node_cleanup(sc, an); -} diff --git a/drivers/net/wireless/ath9k/reg.h b/drivers/net/wireless/ath9k/reg.h index 60617ae66209964890623a63b6c021d1fe3c3bcb..9fedb4911bc30b859ca87d907bdb8357c7a80178 100644 --- a/drivers/net/wireless/ath9k/reg.h +++ b/drivers/net/wireless/ath9k/reg.h @@ -671,7 +671,11 @@ #define AR_RC_APB 0x00000002 #define AR_RC_HOSTIF 0x00000100 -#define AR_WA 0x4004 +#define AR_WA 0x4004 +#define AR9285_WA_DEFAULT 0x004a05cb +#define AR9280_WA_DEFAULT 0x0040073f +#define AR_WA_DEFAULT 0x0000073f + #define AR_PM_STATE 0x4008 #define AR_PM_STATE_PME_D3COLD_VAUX 0x00100000 @@ -738,6 +742,8 @@ #define AR_SREV_REVISION_9280_21 2 #define AR_SREV_VERSION_9285 0xC0 #define AR_SREV_REVISION_9285_10 0 +#define AR_SREV_REVISION_9285_11 1 +#define AR_SREV_REVISION_9285_12 2 #define AR_SREV_9100_OR_LATER(_ah) \ (((_ah)->ah_macVersion >= AR_SREV_VERSION_5416_PCIE)) @@ -768,6 +774,16 @@ #define AR_SREV_9285(_ah) (((_ah)->ah_macVersion == AR_SREV_VERSION_9285)) #define AR_SREV_9285_10_OR_LATER(_ah) \ (((_ah)->ah_macVersion >= AR_SREV_VERSION_9285)) +#define AR_SREV_9285_11(_ah) \ + (AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_11)) +#define AR_SREV_9285_11_OR_LATER(_ah) \ + (((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \ + (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_11))) +#define AR_SREV_9285_12(_ah) \ + (AR_SREV_9280(ah) && ((_ah)->ah_macRev == AR_SREV_REVISION_9285_12)) +#define AR_SREV_9285_12_OR_LATER(_ah) \ + (((_ah)->ah_macVersion > AR_SREV_VERSION_9285) || \ + (AR_SREV_9285(ah) && ((_ah)->ah_macRev >= AR_SREV_REVISION_9285_12))) #define AR_RADIO_SREV_MAJOR 0xf0 #define AR_RAD5133_SREV_MAJOR 0xc0 @@ -1017,6 +1033,97 @@ enum { #define AR_AN_SYNTH9_REFDIVA 0xf8000000 #define AR_AN_SYNTH9_REFDIVA_S 27 +#define AR9285_AN_RF2G1 0x7820 +#define AR9285_AN_RF2G1_ENPACAL 0x00000800 +#define AR9285_AN_RF2G1_ENPACAL_S 11 +#define AR9285_AN_RF2G1_PDPADRV1 0x02000000 +#define AR9285_AN_RF2G1_PDPADRV1_S 25 +#define AR9285_AN_RF2G1_PDPADRV2 0x01000000 +#define AR9285_AN_RF2G1_PDPADRV2_S 24 +#define AR9285_AN_RF2G1_PDPAOUT 0x00800000 +#define AR9285_AN_RF2G1_PDPAOUT_S 23 + + +#define AR9285_AN_RF2G2 0x7824 +#define AR9285_AN_RF2G2_OFFCAL 0x00001000 +#define AR9285_AN_RF2G2_OFFCAL_S 12 + +#define AR9285_AN_RF2G3 0x7828 +#define AR9285_AN_RF2G3_PDVCCOMP 0x02000000 +#define AR9285_AN_RF2G3_PDVCCOMP_S 25 +#define AR9285_AN_RF2G3_OB_0 0x00E00000 +#define AR9285_AN_RF2G3_OB_0_S 21 +#define AR9285_AN_RF2G3_OB_1 0x001C0000 +#define AR9285_AN_RF2G3_OB_1_S 18 +#define AR9285_AN_RF2G3_OB_2 0x00038000 +#define AR9285_AN_RF2G3_OB_2_S 15 +#define AR9285_AN_RF2G3_OB_3 0x00007000 +#define AR9285_AN_RF2G3_OB_3_S 12 +#define AR9285_AN_RF2G3_OB_4 0x00000E00 +#define AR9285_AN_RF2G3_OB_4_S 9 + +#define AR9285_AN_RF2G3_DB1_0 0x000001C0 +#define AR9285_AN_RF2G3_DB1_0_S 6 +#define AR9285_AN_RF2G3_DB1_1 0x00000038 +#define AR9285_AN_RF2G3_DB1_1_S 3 +#define AR9285_AN_RF2G3_DB1_2 0x00000007 +#define AR9285_AN_RF2G3_DB1_2_S 0 +#define AR9285_AN_RF2G4 0x782C +#define AR9285_AN_RF2G4_DB1_3 0xE0000000 +#define AR9285_AN_RF2G4_DB1_3_S 29 +#define AR9285_AN_RF2G4_DB1_4 0x1C000000 +#define AR9285_AN_RF2G4_DB1_4_S 26 + +#define AR9285_AN_RF2G4_DB2_0 0x03800000 +#define AR9285_AN_RF2G4_DB2_0_S 23 +#define AR9285_AN_RF2G4_DB2_1 0x00700000 +#define AR9285_AN_RF2G4_DB2_1_S 20 +#define AR9285_AN_RF2G4_DB2_2 0x000E0000 +#define AR9285_AN_RF2G4_DB2_2_S 17 +#define AR9285_AN_RF2G4_DB2_3 0x0001C000 +#define AR9285_AN_RF2G4_DB2_3_S 14 +#define AR9285_AN_RF2G4_DB2_4 0x00003800 +#define AR9285_AN_RF2G4_DB2_4_S 11 + +#define AR9285_AN_RF2G6 0x7834 +#define AR9285_AN_RF2G6_CCOMP 0x00007800 +#define AR9285_AN_RF2G6_CCOMP_S 11 +#define AR9285_AN_RF2G6_OFFS 0x03f00000 +#define AR9285_AN_RF2G6_OFFS_S 20 + +#define AR9285_AN_RF2G7 0x7838 +#define AR9285_AN_RF2G7_PWDDB 0x00000002 +#define AR9285_AN_RF2G7_PWDDB_S 1 +#define AR9285_AN_RF2G7_PADRVGN2TAB0 0xE0000000 +#define AR9285_AN_RF2G7_PADRVGN2TAB0_S 29 + +#define AR9285_AN_RF2G8 0x783C +#define AR9285_AN_RF2G8_PADRVGN2TAB0 0x0001C000 +#define AR9285_AN_RF2G8_PADRVGN2TAB0_S 14 + + +#define AR9285_AN_RF2G9 0x7840 +#define AR9285_AN_RXTXBB1 0x7854 +#define AR9285_AN_RXTXBB1_PDRXTXBB1 0x00000020 +#define AR9285_AN_RXTXBB1_PDRXTXBB1_S 5 +#define AR9285_AN_RXTXBB1_PDV2I 0x00000080 +#define AR9285_AN_RXTXBB1_PDV2I_S 7 +#define AR9285_AN_RXTXBB1_PDDACIF 0x00000100 +#define AR9285_AN_RXTXBB1_PDDACIF_S 8 +#define AR9285_AN_RXTXBB1_SPARE9 0x00000001 +#define AR9285_AN_RXTXBB1_SPARE9_S 0 + +#define AR9285_AN_TOP2 0x7868 + +#define AR9285_AN_TOP3 0x786c +#define AR9285_AN_TOP3_XPABIAS_LVL 0x0000000C +#define AR9285_AN_TOP3_XPABIAS_LVL_S 2 +#define AR9285_AN_TOP3_PWDDAC 0x00800000 +#define AR9285_AN_TOP3_PWDDAC_S 23 + +#define AR9285_AN_TOP4 0x7870 +#define AR9285_AN_TOP4_DEFAULT 0x10142c00 + #define AR_STA_ID0 0x8000 #define AR_STA_ID1 0x8004 #define AR_STA_ID1_SADH_MASK 0x0000FFFF diff --git a/drivers/net/wireless/ath9k/regd.c b/drivers/net/wireless/ath9k/regd.c index 62e28887ccd3661dcffe155d57c54d8c9e27aaaa..64043e99facff0faef1838b01ca214c2d2f7c9b8 100644 --- a/drivers/net/wireless/ath9k/regd.c +++ b/drivers/net/wireless/ath9k/regd.c @@ -42,7 +42,7 @@ ath9k_regd_sort(void *a, u32 n, u32 size, ath_hal_cmp_t *cmp) u8 *u = t - size; if (cmp(u, t) <= 0) break; - swap(u, t, size); + swap_array(u, t, size); } } @@ -78,8 +78,7 @@ static bool ath9k_regd_is_eeprom_valid(struct ath_hal *ah) return true; } DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid regulatory domain/country code 0x%x\n", - __func__, rd); + "invalid regulatory domain/country code 0x%x\n", rd); return false; } @@ -107,13 +106,12 @@ static bool ath9k_regd_is_ccode_valid(struct ath_hal *ah, return true; rd = ath9k_regd_get_eepromRD(ah); - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: EEPROM regdomain 0x%x\n", - __func__, rd); + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "EEPROM regdomain 0x%x\n", rd); if (rd & COUNTRY_ERD_FLAG) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: EEPROM setting is country code %u\n", - __func__, rd & ~COUNTRY_ERD_FLAG); + "EEPROM setting is country code %u\n", + rd & ~COUNTRY_ERD_FLAG); return cc == (rd & ~COUNTRY_ERD_FLAG); } @@ -290,8 +288,7 @@ ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn, } if (!found) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Failed to find reg domain pair %u\n", - __func__, regDmn); + "Failed to find reg domain pair %u\n", regDmn); return false; } if (!(channelFlag & CHANNEL_2GHZ)) { @@ -307,8 +304,7 @@ ath9k_regd_get_wmode_regdomain(struct ath_hal *ah, int regDmn, found = ath9k_regd_is_valid_reg_domain(regDmn, rd); if (!found) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Failed to find unitary reg domain %u\n", - __func__, regDmn); + "Failed to find unitary reg domain %u\n", regDmn); return false; } else { rd->pscan &= regPair->pscanMask; @@ -430,30 +426,27 @@ ath9k_regd_add_channel(struct ath_hal *ah, if (!(c_lo <= c && c <= c_hi)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: c %u out of range [%u..%u]\n", - __func__, c, c_lo, c_hi); + "c %u out of range [%u..%u]\n", + c, c_lo, c_hi); return false; } if ((fband->channelBW == CHANNEL_HALF_BW) && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_HALFRATE)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %u half rate channel\n", - __func__, c); + "Skipping %u half rate channel\n", c); return false; } if ((fband->channelBW == CHANNEL_QUARTER_BW) && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_CHAN_QUARTERRATE)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %u quarter rate channel\n", - __func__, c); + "Skipping %u quarter rate channel\n", c); return false; } if (((c + fband->channelSep) / 2) > (maxChan + HALF_MAXCHANBW)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: c %u > maxChan %u\n", - __func__, c, maxChan); + "c %u > maxChan %u\n", c, maxChan); return false; } @@ -463,7 +456,7 @@ ath9k_regd_add_channel(struct ath_hal *ah, return false; } - if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == ATH9K_M_HOSTAP)) { + if ((rd->flags & NO_HOSTAP) && (ah->ah_opmode == NL80211_IFTYPE_AP)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "Skipping HOSTAP channel\n"); return false; @@ -606,8 +599,7 @@ static bool ath9k_regd_japan_check(struct ath_hal *ah, } DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Skipping %d freq band\n", - __func__, j_bandcheck[i].freqbandbit); + "Skipping %d freq band\n", j_bandcheck[i].freqbandbit); return skipband; } @@ -632,20 +624,19 @@ ath9k_regd_init_channels(struct ath_hal *ah, unsigned long *modes_avail; DECLARE_BITMAP(modes_allowed, ATH9K_MODE_MAX); - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: cc %u %s %s\n", - __func__, cc, + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "cc %u %s %s\n", cc, enableOutdoor ? "Enable outdoor" : "", enableExtendedChannels ? "Enable ecm" : ""); if (!ath9k_regd_is_ccode_valid(ah, cc)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid country code %d\n", __func__, cc); + "Invalid country code %d\n", cc); return false; } if (!ath9k_regd_is_eeprom_valid(ah)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: invalid EEPROM contents\n", __func__); + "Invalid EEPROM contents\n"); return false; } @@ -693,9 +684,9 @@ ath9k_regd_init_channels(struct ath_hal *ah, ~CHANNEL_2GHZ, &rd5GHz)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary " + "Couldn't find unitary " "5GHz reg domain for country %u\n", - __func__, ah->ah_countryCode); + ah->ah_countryCode); return false; } if (!ath9k_regd_get_wmode_regdomain(ah, @@ -703,9 +694,9 @@ ath9k_regd_init_channels(struct ath_hal *ah, CHANNEL_2GHZ, &rd2GHz)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary 2GHz " + "Couldn't find unitary 2GHz " "reg domain for country %u\n", - __func__, ah->ah_countryCode); + ah->ah_countryCode); return false; } @@ -717,9 +708,9 @@ ath9k_regd_init_channels(struct ath_hal *ah, ~CHANNEL_2GHZ, &rd5GHz)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: couldn't find unitary 5GHz " + "Couldn't find unitary 5GHz " "reg domain for country %u\n", - __func__, ah->ah_countryCode); + ah->ah_countryCode); return false; } } @@ -749,15 +740,14 @@ ath9k_regd_init_channels(struct ath_hal *ah, if (!test_bit(cm->mode, modes_avail)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: !avail mode %d flags 0x%x\n", - __func__, cm->mode, cm->flags); + "!avail mode %d flags 0x%x\n", + cm->mode, cm->flags); continue; } if (!ath9k_get_channel_edges(ah, cm->flags, &c_lo, &c_hi)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channels 0x%x not supported " - "by hardware\n", - __func__, cm->flags); + "channels 0x%x not supported " + "by hardware\n", cm->flags); continue; } @@ -788,8 +778,7 @@ ath9k_regd_init_channels(struct ath_hal *ah, break; default: DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: Unknown HAL mode 0x%x\n", __func__, - cm->mode); + "Unknown HAL mode 0x%x\n", cm->mode); continue; } @@ -841,9 +830,8 @@ ath9k_regd_init_channels(struct ath_hal *ah, if (next >= maxchans) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: too many channels " - "for channel table\n", - __func__); + "too many channels " + "for channel table\n"); goto done; } if (ath9k_regd_add_channel(ah, @@ -869,9 +857,8 @@ done: if (next > ARRAY_SIZE(ah->ah_channels)) { DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: too many channels %u; truncating to %u\n", - __func__, next, - (int) ARRAY_SIZE(ah->ah_channels)); + "too many channels %u; truncating to %u\n", + next, (int) ARRAY_SIZE(ah->ah_channels)); next = ARRAY_SIZE(ah->ah_channels); } #ifdef ATH_NF_PER_CHAN @@ -919,7 +906,7 @@ ath9k_regd_check_channel(struct ath_hal *ah, int n, lim; DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channel %u/0x%x (0x%x) requested\n", __func__, + "channel %u/0x%x (0x%x) requested\n", c->channel, c->channelFlags, flags); cc = ah->ah_curchan; @@ -950,15 +937,15 @@ ath9k_regd_check_channel(struct ath_hal *ah, d = flags - (cc->channelFlags & CHAN_FLAGS); } DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, - "%s: channel %u/0x%x d %d\n", __func__, + "channel %u/0x%x d %d\n", cc->channel, cc->channelFlags, d); if (d > 0) { base = cc + 1; lim--; } } - DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "%s: no match for %u/0x%x\n", - __func__, c->channel, c->channelFlags); + DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY, "no match for %u/0x%x\n", + c->channel, c->channelFlags); return NULL; } diff --git a/drivers/net/wireless/ath9k/regd.h b/drivers/net/wireless/ath9k/regd.h index 0ecd344fbd988e3592624b90bb86ced5a32e30ae..512d990aa7ea352e44452158cb04742689add545 100644 --- a/drivers/net/wireless/ath9k/regd.h +++ b/drivers/net/wireless/ath9k/regd.h @@ -125,7 +125,7 @@ #define CHAN_FLAGS (CHANNEL_ALL|CHANNEL_HALF|CHANNEL_QUARTER) -#define swap(_a, _b, _size) { \ +#define swap_array(_a, _b, _size) { \ u8 *s = _b; \ int i = _size; \ do { \ diff --git a/drivers/net/wireless/ath9k/xmit.c b/drivers/net/wireless/ath9k/xmit.c index 3a4757942b3fa80f5454bebffd468b4dc0103e76..3bfc3b90f2569013092e82959a03bfebdf39b979 100644 --- a/drivers/net/wireless/ath9k/xmit.c +++ b/drivers/net/wireless/ath9k/xmit.c @@ -14,10 +14,6 @@ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ -/* - * Implementation of transmit path. - */ - #include "core.h" #define BITS_PER_BYTE 8 @@ -65,11 +61,12 @@ static u32 bits_per_symbol[][2] = { * NB: must be called with txq lock held */ -static void ath_tx_txqaddbuf(struct ath_softc *sc, - struct ath_txq *txq, struct list_head *head) +static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq, + struct list_head *head) { struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf; + /* * Insert the frame on the outbound list and * pass it on to the hardware. @@ -86,18 +83,16 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, txq->axq_linkbuf = list_entry(txq->axq_q.prev, struct ath_buf, list); DPRINTF(sc, ATH_DBG_QUEUE, - "%s: txq depth = %d\n", __func__, txq->axq_depth); + "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth); if (txq->axq_link == NULL) { ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr); DPRINTF(sc, ATH_DBG_XMIT, - "%s: TXDP[%u] = %llx (%p)\n", - __func__, txq->axq_qnum, - ito64(bf->bf_daddr), bf->bf_desc); + "TXDP[%u] = %llx (%p)\n", + txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc); } else { *txq->axq_link = bf->bf_daddr; - DPRINTF(sc, ATH_DBG_XMIT, "%s: link[%u] (%p)=%llx (%p)\n", - __func__, + DPRINTF(sc, ATH_DBG_XMIT, "link[%u] (%p)=%llx (%p)\n", txq->axq_qnum, txq->axq_link, ito64(bf->bf_daddr), bf->bf_desc); } @@ -105,46 +100,94 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, ath9k_hw_txstart(ah, txq->axq_qnum); } -/* Get transmit rate index using rate in Kbps */ - -static int ath_tx_findindex(const struct ath9k_rate_table *rt, int rate) +static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb, + struct ath_xmit_status *tx_status) { - int i; - int ndx = 0; + struct ieee80211_hw *hw = sc->hw; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + int hdrlen, padsize; - for (i = 0; i < rt->rateCount; i++) { - if (rt->info[i].rateKbps == rate) { - ndx = i; - break; - } + DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb); + + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK || + tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) { + kfree(tx_info_priv); + tx_info->rate_driver_data[0] = NULL; + } + + if (tx_status->flags & ATH_TX_BAR) { + tx_info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; + tx_status->flags &= ~ATH_TX_BAR; + } + + if (!(tx_status->flags & (ATH_TX_ERROR | ATH_TX_XRETRY))) { + /* Frame was ACKed */ + tx_info->flags |= IEEE80211_TX_STAT_ACK; + } + + tx_info->status.rates[0].count = tx_status->retries; + if (tx_info->status.rates[0].flags & IEEE80211_TX_RC_MCS) { + /* Change idx from internal table index to MCS index */ + int idx = tx_info->status.rates[0].idx; + struct ath_rate_table *rate_table = sc->cur_rate_table; + if (idx >= 0 && idx < rate_table->rate_cnt) + tx_info->status.rates[0].idx = + rate_table->info[idx].ratecode & 0x7f; + } + + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + padsize = hdrlen & 3; + if (padsize && hdrlen >= 24) { + /* + * Remove MAC header padding before giving the frame back to + * mac80211. + */ + memmove(skb->data + padsize, skb->data, hdrlen); + skb_pull(skb, padsize); } - return ndx; + ieee80211_tx_status(hw, skb); } /* Check if it's okay to send out aggregates */ -static int ath_aggr_query(struct ath_softc *sc, - struct ath_node *an, u8 tidno) +static int ath_aggr_query(struct ath_softc *sc, struct ath_node *an, u8 tidno) { struct ath_atx_tid *tid; tid = ATH_AN_2_TID(an, tidno); - if (tid->addba_exchangecomplete || tid->addba_exchangeinprogress) + if (tid->state & AGGR_ADDBA_COMPLETE || + tid->state & AGGR_ADDBA_PROGRESS) return 1; else return 0; } -static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr) +static void ath_get_beaconconfig(struct ath_softc *sc, int if_id, + struct ath_beacon_config *conf) +{ + struct ieee80211_hw *hw = sc->hw; + + /* fill in beacon config data */ + + conf->beacon_interval = hw->conf.beacon_int; + conf->listen_interval = 100; + conf->dtim_count = 1; + conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval; +} + +/* Calculate Atheros packet type from IEEE80211 packet header */ + +static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb) { + struct ieee80211_hdr *hdr; enum ath9k_pkt_type htype; __le16 fc; + hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - /* Calculate Atheros packet type from IEEE80211 packet header */ - if (ieee80211_is_beacon(fc)) htype = ATH9K_PKT_TYPE_BEACON; else if (ieee80211_is_probe_resp(fc)) @@ -159,232 +202,123 @@ static enum ath9k_pkt_type get_hal_packet_type(struct ieee80211_hdr *hdr) return htype; } -static void fill_min_rates(struct sk_buff *skb, struct ath_tx_control *txctl) +static bool is_pae(struct sk_buff *skb) { struct ieee80211_hdr *hdr; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv; __le16 fc; hdr = (struct ieee80211_hdr *)skb->data; fc = hdr->frame_control; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) { - txctl->use_minrate = 1; - txctl->min_rate = tx_info_priv->min_rate; - } else if (ieee80211_is_data(fc)) { + if (ieee80211_is_data(fc)) { if (ieee80211_is_nullfunc(fc) || - /* Port Access Entity (IEEE 802.1X) */ - (skb->protocol == cpu_to_be16(0x888E))) { - txctl->use_minrate = 1; - txctl->min_rate = tx_info_priv->min_rate; + /* Port Access Entity (IEEE 802.1X) */ + (skb->protocol == cpu_to_be16(ETH_P_PAE))) { + return true; } - if (is_multicast_ether_addr(hdr->addr1)) - txctl->mcast_rate = tx_info_priv->min_rate; } + return false; } -/* This function will setup additional txctl information, mostly rate stuff */ -/* FIXME: seqno, ps */ -static int ath_tx_prepare(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_tx_control *txctl) +static int get_hw_crypto_keytype(struct sk_buff *skb) { - struct ieee80211_hw *hw = sc->hw; - struct ieee80211_hdr *hdr; - struct ath_rc_series *rcs; - struct ath_txq *txq = NULL; - const struct ath9k_rate_table *rt; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - struct ath_tx_info_priv *tx_info_priv; - int hdrlen; - u8 rix, antenna; - __le16 fc; - u8 *qc; - - txctl->dev = sc; - hdr = (struct ieee80211_hdr *)skb->data; - hdrlen = ieee80211_get_hdrlen_from_skb(skb); - fc = hdr->frame_control; - - rt = sc->sc_currates; - BUG_ON(!rt); - - /* Fill misc fields */ - - spin_lock_bh(&sc->node_lock); - txctl->an = ath_node_get(sc, hdr->addr1); - /* create a temp node, if the node is not there already */ - if (!txctl->an) - txctl->an = ath_node_attach(sc, hdr->addr1, 0); - spin_unlock_bh(&sc->node_lock); - - if (ieee80211_is_data_qos(fc)) { - qc = ieee80211_get_qos_ctl(hdr); - txctl->tidno = qc[0] & 0xf; - } - - txctl->if_id = 0; - txctl->frmlen = skb->len + FCS_LEN - (hdrlen & 3); - txctl->txpower = MAX_RATE_POWER; /* FIXME */ - - /* Fill Key related fields */ - - txctl->keytype = ATH9K_KEY_TYPE_CLEAR; - txctl->keyix = ATH9K_TXKEYIX_INVALID; if (tx_info->control.hw_key) { - txctl->keyix = tx_info->control.hw_key->hw_key_idx; - txctl->frmlen += tx_info->control.hw_key->icv_len; - if (tx_info->control.hw_key->alg == ALG_WEP) - txctl->keytype = ATH9K_KEY_TYPE_WEP; + return ATH9K_KEY_TYPE_WEP; else if (tx_info->control.hw_key->alg == ALG_TKIP) - txctl->keytype = ATH9K_KEY_TYPE_TKIP; + return ATH9K_KEY_TYPE_TKIP; else if (tx_info->control.hw_key->alg == ALG_CCMP) - txctl->keytype = ATH9K_KEY_TYPE_AES; - } - - /* Fill packet type */ - - txctl->atype = get_hal_packet_type(hdr); - - /* Fill qnum */ - - if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) { - txctl->qnum = 0; - txq = sc->sc_cabq; - } else { - txctl->qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); - txq = &sc->sc_txq[txctl->qnum]; - } - spin_lock_bh(&txq->axq_lock); - - /* Try to avoid running out of descriptors */ - if (txq->axq_depth >= (ATH_TXBUF - 20) && - !(txctl->flags & ATH9K_TXDESC_CAB)) { - DPRINTF(sc, ATH_DBG_FATAL, - "%s: TX queue: %d is full, depth: %d\n", - __func__, - txctl->qnum, - txq->axq_depth); - ieee80211_stop_queue(hw, skb_get_queue_mapping(skb)); - txq->stopped = 1; - spin_unlock_bh(&txq->axq_lock); - return -1; + return ATH9K_KEY_TYPE_AES; } - spin_unlock_bh(&txq->axq_lock); - - /* Fill rate */ - - fill_min_rates(skb, txctl); + return ATH9K_KEY_TYPE_CLEAR; +} - /* Fill flags */ +/* Called only when tx aggregation is enabled and HT is supported */ - txctl->flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ +static void assign_aggr_tid_seqno(struct sk_buff *skb, + struct ath_buf *bf) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ieee80211_hdr *hdr; + struct ath_node *an; + struct ath_atx_tid *tid; + __le16 fc; + u8 *qc; - if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) - txctl->flags |= ATH9K_TXDESC_NOACK; - if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) - txctl->flags |= ATH9K_TXDESC_RTSENA; + if (!tx_info->control.sta) + return; - /* - * Setup for rate calculations. - */ - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - rcs = tx_info_priv->rcs; + an = (struct ath_node *)tx_info->control.sta->drv_priv; + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; - if (ieee80211_is_data(fc) && !txctl->use_minrate) { + /* Get tidno */ - /* Enable HT only for DATA frames and not for EAPOL */ - txctl->ht = (hw->conf.ht_conf.ht_supported && - (tx_info->flags & IEEE80211_TX_CTL_AMPDU)); + if (ieee80211_is_data_qos(fc)) { + qc = ieee80211_get_qos_ctl(hdr); + bf->bf_tidno = qc[0] & 0xf; + } - if (is_multicast_ether_addr(hdr->addr1)) { - rcs[0].rix = (u8) - ath_tx_findindex(rt, txctl->mcast_rate); + /* Get seqno */ - /* - * mcast packets are not re-tried. - */ - rcs[0].tries = 1; - } + if (ieee80211_is_data(fc) && !is_pae(skb)) { /* For HT capable stations, we save tidno for later use. * We also override seqno set by upper layer with the one * in tx aggregation state. * - * First, the fragmentation stat is determined. * If fragmentation is on, the sequence number is * not overridden, since it has been * incremented by the fragmentation routine. + * + * FIXME: check if the fragmentation threshold exceeds + * IEEE80211 max. */ - if (likely(!(txctl->flags & ATH9K_TXDESC_FRAG_IS_ON)) && - txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { - struct ath_atx_tid *tid; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + hdr->seq_ctrl = cpu_to_le16(tid->seq_next << + IEEE80211_SEQ_SEQ_SHIFT); + bf->bf_seqno = tid->seq_next; + INCR(tid->seq_next, IEEE80211_SEQ_MAX); + } +} - tid = ATH_AN_2_TID(txctl->an, txctl->tidno); +static int setup_tx_flags(struct ath_softc *sc, struct sk_buff *skb, + struct ath_txq *txq) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + int flags = 0; - hdr->seq_ctrl = cpu_to_le16(tid->seq_next << - IEEE80211_SEQ_SEQ_SHIFT); - txctl->seqno = tid->seq_next; - INCR(tid->seq_next, IEEE80211_SEQ_MAX); - } - } else { - /* for management and control frames, - * or for NULL and EAPOL frames */ - if (txctl->min_rate) - rcs[0].rix = ath_rate_findrateix(sc, txctl->min_rate); - else - rcs[0].rix = 0; - rcs[0].tries = ATH_MGT_TXMAXTRY; - } - rix = rcs[0].rix; + flags |= ATH9K_TXDESC_CLRDMASK; /* needed for crypto errors */ + flags |= ATH9K_TXDESC_INTREQ; - if (ieee80211_has_morefrags(fc) || - (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { - /* - ** Force hardware to use computed duration for next - ** fragment by disabling multi-rate retry, which - ** updates duration based on the multi-rate - ** duration table. - */ - rcs[1].tries = rcs[2].tries = rcs[3].tries = 0; - rcs[1].rix = rcs[2].rix = rcs[3].rix = 0; - /* reset tries but keep rate index */ - rcs[0].tries = ATH_TXMAXTRY; - } + if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK) + flags |= ATH9K_TXDESC_NOACK; + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) + flags |= ATH9K_TXDESC_RTSENA; - /* - * Determine if a tx interrupt should be generated for - * this descriptor. We take a tx interrupt to reap - * descriptors when the h/w hits an EOL condition or - * when the descriptor is specifically marked to generate - * an interrupt. We periodically mark descriptors in this - * way to insure timely replenishing of the supply needed - * for sending frames. Defering interrupts reduces system - * load and potentially allows more concurrent work to be - * done but if done to aggressively can cause senders to - * backup. - * - * NB: use >= to deal with sc_txintrperiod changing - * dynamically through sysctl. - */ - spin_lock_bh(&txq->axq_lock); - if ((++txq->axq_intrcnt >= sc->sc_txintrperiod)) { - txctl->flags |= ATH9K_TXDESC_INTREQ; - txq->axq_intrcnt = 0; - } - spin_unlock_bh(&txq->axq_lock); + return flags; +} + +static struct ath_buf *ath_tx_get_buffer(struct ath_softc *sc) +{ + struct ath_buf *bf = NULL; - if (is_multicast_ether_addr(hdr->addr1)) { - antenna = sc->sc_mcastantenna + 1; - sc->sc_mcastantenna = (sc->sc_mcastantenna + 1) & 0x1; + spin_lock_bh(&sc->tx.txbuflock); + + if (unlikely(list_empty(&sc->tx.txbuf))) { + spin_unlock_bh(&sc->tx.txbuflock); + return NULL; } - return 0; + bf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); + list_del(&bf->list); + + spin_unlock_bh(&sc->tx.txbuflock); + + return bf; } /* To complete a chain of buffers associated a frame */ @@ -396,6 +330,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, { struct sk_buff *skb = bf->bf_mpdu; struct ath_xmit_status tx_status; + unsigned long flags; /* * Set retry information. @@ -414,20 +349,21 @@ static void ath_tx_complete_buf(struct ath_softc *sc, if (bf_isxretried(bf)) tx_status.flags |= ATH_TX_XRETRY; } + /* Unmap this frame */ pci_unmap_single(sc->pdev, bf->bf_dmacontext, skb->len, PCI_DMA_TODEVICE); /* complete this frame */ - ath_tx_complete(sc, skb, &tx_status, bf->bf_node); + ath_tx_complete(sc, skb, &tx_status); /* * Return the list of ath_buf of this mpdu to free queue */ - spin_lock_bh(&sc->sc_txbuflock); - list_splice_tail_init(bf_q, &sc->sc_txbuf); - spin_unlock_bh(&sc->sc_txbuflock); + spin_lock_irqsave(&sc->tx.txbuflock, flags); + list_splice_tail_init(bf_q, &sc->tx.txbuf); + spin_unlock_irqrestore(&sc->tx.txbuflock, flags); } /* @@ -468,7 +404,7 @@ static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid) static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; spin_lock_bh(&txq->axq_lock); @@ -481,7 +417,7 @@ static void ath_tx_pause_tid(struct ath_softc *sc, struct ath_atx_tid *tid) void ath_tx_resume_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; ASSERT(tid->paused > 0); spin_lock_bh(&txq->axq_lock); @@ -505,11 +441,9 @@ unlock: /* Compute the number of bad frames */ -static int ath_tx_num_badfrms(struct ath_softc *sc, - struct ath_buf *bf, int txok) +static int ath_tx_num_badfrms(struct ath_softc *sc, struct ath_buf *bf, + int txok) { - struct ath_node *an = bf->bf_node; - int isnodegone = (an->an_flags & ATH_NODE_CLEAN); struct ath_buf *bf_last = bf->bf_lastbf; struct ath_desc *ds = bf_last->bf_desc; u16 seq_st = 0; @@ -518,7 +452,7 @@ static int ath_tx_num_badfrms(struct ath_softc *sc, int nbad = 0; int isaggr = 0; - if (isnodegone || ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) + if (ds->ds_txstat.ts_flags == ATH9K_TX_SW_ABORTED) return 0; isaggr = bf_isaggr(bf); @@ -553,8 +487,8 @@ static void ath_tx_set_retry(struct ath_softc *sc, struct ath_buf *bf) /* Update block ack window */ -static void ath_tx_update_baw(struct ath_softc *sc, - struct ath_atx_tid *tid, int seqno) +static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid, + int seqno) { int index, cindex; @@ -577,34 +511,23 @@ static void ath_tx_update_baw(struct ath_softc *sc, * width - 0 for 20 MHz, 1 for 40 MHz * half_gi - to use 4us v/s 3.6 us for symbol time */ - -static u32 ath_pkt_duration(struct ath_softc *sc, - u8 rix, - struct ath_buf *bf, - int width, - int half_gi, - bool shortPreamble) +static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, struct ath_buf *bf, + int width, int half_gi, bool shortPreamble) { - const struct ath9k_rate_table *rt = sc->sc_currates; + struct ath_rate_table *rate_table = sc->cur_rate_table; u32 nbits, nsymbits, duration, nsymbols; u8 rc; int streams, pktlen; pktlen = bf_isaggr(bf) ? bf->bf_al : bf->bf_frmlen; - rc = rt->info[rix].rateCode; + rc = rate_table->info[rix].ratecode; - /* - * for legacy rates, use old function to compute packet duration - */ + /* for legacy rates, use old function to compute packet duration */ if (!IS_HT_RATE(rc)) - return ath9k_hw_computetxtime(sc->sc_ah, - rt, - pktlen, - rix, - shortPreamble); - /* - * find number of symbols: PLCP + data - */ + return ath9k_hw_computetxtime(sc->sc_ah, rate_table, pktlen, + rix, shortPreamble); + + /* find number of symbols: PLCP + data */ nbits = (pktlen << 3) + OFDM_PLCP_BITS; nsymbits = bits_per_symbol[HT_RC_2_MCS(rc)][width]; nsymbols = (nbits + nsymbits - 1) / nsymbits; @@ -614,11 +537,10 @@ static u32 ath_pkt_duration(struct ath_softc *sc, else duration = SYMBOL_TIME_HALFGI(nsymbols); - /* - * addup duration for legacy/ht training and signal fields - */ + /* addup duration for legacy/ht training and signal fields */ streams = HT_RC_2_STREAMS(rc); duration += L_STF + L_LTF + L_SIG + HT_SIG + HT_STF + HT_LTF(streams); + return duration; } @@ -627,207 +549,127 @@ static u32 ath_pkt_duration(struct ath_softc *sc, static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) { struct ath_hal *ah = sc->sc_ah; - const struct ath9k_rate_table *rt; + struct ath_rate_table *rt; struct ath_desc *ds = bf->bf_desc; struct ath_desc *lastds = bf->bf_lastbf->bf_desc; struct ath9k_11n_rate_series series[4]; - int i, flags, rtsctsena = 0, dynamic_mimops = 0; + struct sk_buff *skb; + struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rates; + struct ieee80211_hdr *hdr; + int i, flags, rtsctsena = 0; u32 ctsduration = 0; u8 rix = 0, cix, ctsrate = 0; - u32 aggr_limit_with_rts = ah->ah_caps.rts_aggr_limit; - struct ath_node *an = (struct ath_node *) bf->bf_node; + __le16 fc; - /* - * get the cix for the lowest valid rix. - */ - rt = sc->sc_currates; - for (i = 4; i--;) { - if (bf->bf_rcs[i].tries) { - rix = bf->bf_rcs[i].rix; + memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); + + skb = (struct sk_buff *)bf->bf_mpdu; + hdr = (struct ieee80211_hdr *)skb->data; + fc = hdr->frame_control; + tx_info = IEEE80211_SKB_CB(skb); + rates = tx_info->control.rates; + + if (ieee80211_has_morefrags(fc) || + (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_FRAG)) { + rates[1].count = rates[2].count = rates[3].count = 0; + rates[1].idx = rates[2].idx = rates[3].idx = 0; + rates[0].count = ATH_TXMAXTRY; + } + + /* get the cix for the lowest valid rix */ + rt = sc->cur_rate_table; + for (i = 3; i >= 0; i--) { + if (rates[i].count && (rates[i].idx >= 0)) { + rix = rates[i].idx; break; } } + flags = (bf->bf_flags & (ATH9K_TXDESC_RTSENA | ATH9K_TXDESC_CTSENA)); - cix = rt->info[rix].controlRate; + cix = rt->info[rix].ctrl_rate; /* - * If 802.11g protection is enabled, determine whether - * to use RTS/CTS or just CTS. Note that this is only - * done for OFDM/HT unicast frames. + * If 802.11g protection is enabled, determine whether to use RTS/CTS or + * just CTS. Note that this is only done for OFDM/HT unicast frames. */ - if (sc->sc_protmode != PROT_M_NONE && - (rt->info[rix].phy == PHY_OFDM || - rt->info[rix].phy == PHY_HT) && - (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { + if (sc->sc_protmode != PROT_M_NONE && !(bf->bf_flags & ATH9K_TXDESC_NOACK) + && (rt->info[rix].phy == WLAN_RC_PHY_OFDM || + WLAN_RC_PHY_HT(rt->info[rix].phy))) { if (sc->sc_protmode == PROT_M_RTSCTS) flags = ATH9K_TXDESC_RTSENA; else if (sc->sc_protmode == PROT_M_CTSONLY) flags = ATH9K_TXDESC_CTSENA; - cix = rt->info[sc->sc_protrix].controlRate; + cix = rt->info[sc->sc_protrix].ctrl_rate; rtsctsena = 1; } - /* For 11n, the default behavior is to enable RTS for - * hw retried frames. We enable the global flag here and - * let rate series flags determine which rates will actually - * use RTS. + /* For 11n, the default behavior is to enable RTS for hw retried frames. + * We enable the global flag here and let rate series flags determine + * which rates will actually use RTS. */ if ((ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT) && bf_isdata(bf)) { - BUG_ON(!an); - /* - * 802.11g protection not needed, use our default behavior - */ + /* 802.11g protection not needed, use our default behavior */ if (!rtsctsena) flags = ATH9K_TXDESC_RTSENA; - /* - * For dynamic MIMO PS, RTS needs to precede the first aggregate - * and the second aggregate should have any protection at all. - */ - if (an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) { - if (!bf_isaggrburst(bf)) { - flags = ATH9K_TXDESC_RTSENA; - dynamic_mimops = 1; - } else { - flags = 0; - } - } } - /* - * Set protection if aggregate protection on - */ + /* Set protection if aggregate protection on */ if (sc->sc_config.ath_aggr_prot && (!bf_isaggr(bf) || (bf_isaggr(bf) && bf->bf_al < 8192))) { flags = ATH9K_TXDESC_RTSENA; - cix = rt->info[sc->sc_protrix].controlRate; + cix = rt->info[sc->sc_protrix].ctrl_rate; rtsctsena = 1; } - /* - * For AR5416 - RTS cannot be followed by a frame larger than 8K. - */ - if (bf_isaggr(bf) && (bf->bf_al > aggr_limit_with_rts)) { - /* - * Ensure that in the case of SM Dynamic power save - * while we are bursting the second aggregate the - * RTS is cleared. - */ + /* For AR5416 - RTS cannot be followed by a frame larger than 8K */ + if (bf_isaggr(bf) && (bf->bf_al > ah->ah_caps.rts_aggr_limit)) flags &= ~(ATH9K_TXDESC_RTSENA); - } /* - * CTS transmit rate is derived from the transmit rate - * by looking in the h/w rate table. We must also factor - * in whether or not a short preamble is to be used. + * CTS transmit rate is derived from the transmit rate by looking in the + * h/w rate table. We must also factor in whether or not a short + * preamble is to be used. NB: cix is set above where RTS/CTS is enabled */ - /* NB: cix is set above where RTS/CTS is enabled */ - BUG_ON(cix == 0xff); - ctsrate = rt->info[cix].rateCode | - (bf_isshpreamble(bf) ? rt->info[cix].shortPreamble : 0); - - /* - * Setup HAL rate series - */ - memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4); + ctsrate = rt->info[cix].ratecode | + (bf_isshpreamble(bf) ? rt->info[cix].short_preamble : 0); for (i = 0; i < 4; i++) { - if (!bf->bf_rcs[i].tries) + if (!rates[i].count || (rates[i].idx < 0)) continue; - rix = bf->bf_rcs[i].rix; + rix = rates[i].idx; - series[i].Rate = rt->info[rix].rateCode | - (bf_isshpreamble(bf) ? rt->info[rix].shortPreamble : 0); + series[i].Rate = rt->info[rix].ratecode | + (bf_isshpreamble(bf) ? rt->info[rix].short_preamble : 0); - series[i].Tries = bf->bf_rcs[i].tries; + series[i].Tries = rates[i].count; series[i].RateFlags = ( - (bf->bf_rcs[i].flags & ATH_RC_RTSCTS_FLAG) ? + (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS) ? ATH9K_RATESERIES_RTS_CTS : 0) | - ((bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) ? + ((rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? ATH9K_RATESERIES_2040 : 0) | - ((bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG) ? + ((rates[i].flags & IEEE80211_TX_RC_SHORT_GI) ? ATH9K_RATESERIES_HALFGI : 0); - series[i].PktDuration = ath_pkt_duration( - sc, rix, bf, - (bf->bf_rcs[i].flags & ATH_RC_CW40_FLAG) != 0, - (bf->bf_rcs[i].flags & ATH_RC_SGI_FLAG), - bf_isshpreamble(bf)); + series[i].PktDuration = ath_pkt_duration(sc, rix, bf, + (rates[i].flags & IEEE80211_TX_RC_40_MHZ_WIDTH) != 0, + (rates[i].flags & IEEE80211_TX_RC_SHORT_GI), + bf_isshpreamble(bf)); - if ((an->an_smmode == ATH_SM_PWRSAV_STATIC) && - (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG) == 0) { - /* - * When sending to an HT node that has enabled static - * SM/MIMO power save, send at single stream rates but - * use maximum allowed transmit chains per user, - * hardware, regulatory, or country limits for - * better range. - */ - series[i].ChSel = sc->sc_tx_chainmask; - } else { - if (bf_isht(bf)) - series[i].ChSel = - ath_chainmask_sel_logic(sc, an); - else - series[i].ChSel = sc->sc_tx_chainmask; - } + series[i].ChSel = sc->sc_tx_chainmask; if (rtsctsena) series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; - - /* - * Set RTS for all rates if node is in dynamic powersave - * mode and we are using dual stream rates. - */ - if (dynamic_mimops && (bf->bf_rcs[i].flags & ATH_RC_DS_FLAG)) - series[i].RateFlags |= ATH9K_RATESERIES_RTS_CTS; - } - - /* - * For non-HT devices, calculate RTS/CTS duration in software - * and disable multi-rate retry. - */ - if (flags && !(ah->ah_caps.hw_caps & ATH9K_HW_CAP_HT)) { - /* - * Compute the transmit duration based on the frame - * size and the size of an ACK frame. We call into the - * HAL to do the computation since it depends on the - * characteristics of the actual PHY being used. - * - * NB: CTS is assumed the same size as an ACK so we can - * use the precalculated ACK durations. - */ - if (flags & ATH9K_TXDESC_RTSENA) { /* SIFS + CTS */ - ctsduration += bf_isshpreamble(bf) ? - rt->info[cix].spAckDuration : - rt->info[cix].lpAckDuration; - } - - ctsduration += series[0].PktDuration; - - if ((bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { /* SIFS + ACK */ - ctsduration += bf_isshpreamble(bf) ? - rt->info[rix].spAckDuration : - rt->info[rix].lpAckDuration; - } - - /* - * Disable multi-rate retry when using RTS/CTS by clearing - * series 1, 2 and 3. - */ - memset(&series[1], 0, sizeof(struct ath9k_11n_rate_series) * 3); } - /* - * set dur_update_en for l-sig computation except for PS-Poll frames - */ - ath9k_hw_set11n_ratescenario(ah, ds, lastds, - !bf_ispspoll(bf), - ctsrate, - ctsduration, + /* set dur_update_en for l-sig computation except for PS-Poll frames */ + ath9k_hw_set11n_ratescenario(ah, ds, lastds, !bf_ispspoll(bf), + ctsrate, ctsduration, series, 4, flags); + if (sc->sc_config.ath_aggr_prot && flags) ath9k_hw_set11n_burstduration(ah, ds, 8192); } @@ -836,27 +678,18 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf) * Function to send a normal HT (non-AMPDU) frame * NB: must be called with txq lock held */ - static int ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_head) { struct ath_buf *bf; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ath_tx_info_priv *tx_info_priv; BUG_ON(list_empty(bf_head)); bf = list_first_entry(bf_head, struct ath_buf, list); bf->bf_state.bf_type &= ~BUF_AMPDU; /* regular HT frame */ - skb = (struct sk_buff *)bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); - /* update starting sequence number for subsequent ADDBA request */ INCR(tid->seq_start, IEEE80211_SEQ_MAX); @@ -873,7 +706,7 @@ static int ath_tx_send_normal(struct ath_softc *sc, static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid) { - struct ath_txq *txq = &sc->sc_txq[tid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[tid->ac->qnum]; struct ath_buf *bf; struct list_head bf_head; INIT_LIST_HEAD(&bf_head); @@ -906,8 +739,10 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, struct list_head *bf_q, int txok) { - struct ath_node *an = bf->bf_node; - struct ath_atx_tid *tid = ATH_AN_2_TID(an, bf->bf_tidno); + struct ath_node *an = NULL; + struct sk_buff *skb; + struct ieee80211_tx_info *tx_info; + struct ath_atx_tid *tid = NULL; struct ath_buf *bf_last = bf->bf_lastbf; struct ath_desc *ds = bf_last->bf_desc; struct ath_buf *bf_next, *bf_lastq = NULL; @@ -915,7 +750,14 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, u16 seq_st = 0; u32 ba[WME_BA_BMP_SIZE >> 5]; int isaggr, txfail, txpending, sendbar = 0, needreset = 0; - int isnodegone = (an->an_flags & ATH_NODE_CLEAN); + + skb = (struct sk_buff *)bf->bf_mpdu; + tx_info = IEEE80211_SKB_CB(skb); + + if (tx_info->control.sta) { + an = (struct ath_node *)tx_info->control.sta->drv_priv; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + } isaggr = bf_isaggr(bf); if (isaggr) { @@ -939,7 +781,8 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, * when perform internal reset in this routine. * Only enable reset in STA mode for now. */ - if (sc->sc_ah->ah_opmode == ATH9K_M_STA) + if (sc->sc_ah->ah_opmode == + NL80211_IFTYPE_STATION) needreset = 1; } } else { @@ -961,7 +804,7 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, /* transmit completion */ } else { - if (!tid->cleanup_inprogress && !isnodegone && + if (!(tid->state & AGGR_CLEANUP) && ds->ds_txstat.ts_flags != ATH9K_TX_SW_ABORTED) { if (bf->bf_retries < ATH_MAX_SW_RETRIES) { ath_tx_set_retry(sc, bf); @@ -1038,18 +881,17 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, struct ath_buf *tbf; /* allocate new descriptor */ - spin_lock_bh(&sc->sc_txbuflock); - ASSERT(!list_empty((&sc->sc_txbuf))); - tbf = list_first_entry(&sc->sc_txbuf, + spin_lock_bh(&sc->tx.txbuflock); + ASSERT(!list_empty((&sc->tx.txbuf))); + tbf = list_first_entry(&sc->tx.txbuf, struct ath_buf, list); list_del(&tbf->list); - spin_unlock_bh(&sc->sc_txbuflock); + spin_unlock_bh(&sc->tx.txbuflock); ATH_TXBUF_RESET(tbf); /* copy descriptor content */ tbf->bf_mpdu = bf_last->bf_mpdu; - tbf->bf_node = bf_last->bf_node; tbf->bf_buf_addr = bf_last->bf_buf_addr; *(tbf->bf_desc) = *(bf_last->bf_desc); @@ -1090,25 +932,16 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, bf = bf_next; } - /* - * node is already gone. no more assocication - * with the node. the node might have been freed - * any node acces can result in panic.note tid - * is part of the node. - */ - if (isnodegone) - return; - - if (tid->cleanup_inprogress) { + if (tid->state & AGGR_CLEANUP) { /* check to see if we're done with cleaning the h/w queue */ spin_lock_bh(&txq->axq_lock); if (tid->baw_head == tid->baw_tail) { - tid->addba_exchangecomplete = 0; + tid->state &= ~AGGR_ADDBA_COMPLETE; tid->addba_exchangeattempts = 0; spin_unlock_bh(&txq->axq_lock); - tid->cleanup_inprogress = false; + tid->state &= ~AGGR_CLEANUP; /* send buffered frames as singles */ ath_tx_flush_tid(sc, tid); @@ -1136,29 +969,45 @@ static void ath_tx_complete_aggr_rifs(struct ath_softc *sc, return; } +static void ath_tx_rc_status(struct ath_buf *bf, struct ath_desc *ds, int nbad) +{ + struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info); + + tx_info_priv->update_rc = false; + if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) + tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + + if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && + (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { + if (bf_isdata(bf)) { + memcpy(&tx_info_priv->tx, &ds->ds_txstat, + sizeof(tx_info_priv->tx)); + tx_info_priv->n_frames = bf->bf_nframes; + tx_info_priv->n_bad_frames = nbad; + tx_info_priv->update_rc = true; + } + } +} + /* Process completed xmit descriptors from the specified queue */ -static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) +static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) { struct ath_hal *ah = sc->sc_ah; struct ath_buf *bf, *lastbf, *bf_held = NULL; struct list_head bf_head; - struct ath_desc *ds, *tmp_ds; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ath_tx_info_priv *tx_info_priv; - int nacked, txok, nbad = 0, isrifs = 0; + struct ath_desc *ds; + int txok, nbad = 0; int status; - DPRINTF(sc, ATH_DBG_QUEUE, - "%s: tx queue %d (%x), link %p\n", __func__, + DPRINTF(sc, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n", txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum), txq->axq_link); - nacked = 0; for (;;) { spin_lock_bh(&txq->axq_lock); - txq->axq_intrcnt = 0; /* reset periodic desc intr count */ if (list_empty(&txq->axq_q)) { txq->axq_link = NULL; txq->axq_linkbuf = NULL; @@ -1229,9 +1078,9 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) if (bf_held) { list_del(&bf_held->list); - spin_lock_bh(&sc->sc_txbuflock); - list_add_tail(&bf_held->list, &sc->sc_txbuf); - spin_unlock_bh(&sc->sc_txbuflock); + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf_held->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); } if (!bf_isampdu(bf)) { @@ -1246,29 +1095,8 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) } else { nbad = ath_tx_num_badfrms(sc, bf, txok); } - skb = bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *) - tx_info->driver_data[0]; - if (ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) - tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; - if ((ds->ds_txstat.ts_status & ATH9K_TXERR_FILT) == 0 && - (bf->bf_flags & ATH9K_TXDESC_NOACK) == 0) { - if (ds->ds_txstat.ts_status == 0) - nacked++; - - if (bf_isdata(bf)) { - if (isrifs) - tmp_ds = bf->bf_rifslast->bf_desc; - else - tmp_ds = ds; - memcpy(&tx_info_priv->tx, - &tmp_ds->ds_txstat, - sizeof(tx_info_priv->tx)); - tx_info_priv->n_frames = bf->bf_nframes; - tx_info_priv->n_bad_frames = nbad; - } - } + + ath_tx_rc_status(bf, ds, nbad); /* * Complete this transmit unit @@ -1299,7 +1127,6 @@ static int ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq) ath_txq_schedule(sc, txq); spin_unlock_bh(&txq->axq_lock); } - return nacked; } static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) @@ -1307,9 +1134,9 @@ static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) struct ath_hal *ah = sc->sc_ah; (void) ath9k_hw_stoptxdma(ah, txq->axq_qnum); - DPRINTF(sc, ATH_DBG_XMIT, "%s: tx queue [%u] %x, link %p\n", - __func__, txq->axq_qnum, - ath9k_hw_gettxbuf(ah, txq->axq_qnum), txq->axq_link); + DPRINTF(sc, ATH_DBG_XMIT, "tx queue [%u] %x, link %p\n", + txq->axq_qnum, ath9k_hw_gettxbuf(ah, txq->axq_qnum), + txq->axq_link); } /* Drain only the data queues */ @@ -1317,40 +1144,33 @@ static void ath_tx_stopdma(struct ath_softc *sc, struct ath_txq *txq) static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) { struct ath_hal *ah = sc->sc_ah; - int i; - int npend = 0; + int i, status, npend = 0; - /* XXX return value */ if (!(sc->sc_flags & SC_OP_INVALID)) { for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { - ath_tx_stopdma(sc, &sc->sc_txq[i]); - + ath_tx_stopdma(sc, &sc->tx.txq[i]); /* The TxDMA may not really be stopped. * Double check the hal tx pending count */ npend += ath9k_hw_numtxpending(ah, - sc->sc_txq[i].axq_qnum); + sc->tx.txq[i].axq_qnum); } } } if (npend) { - int status; - /* TxDMA not stopped, reset the hal */ - DPRINTF(sc, ATH_DBG_XMIT, - "%s: Unable to stop TxDMA. Reset HAL!\n", __func__); + DPRINTF(sc, ATH_DBG_XMIT, "Unable to stop TxDMA. Reset HAL!\n"); spin_lock_bh(&sc->sc_resetlock); if (!ath9k_hw_reset(ah, sc->sc_ah->ah_curchan, - sc->sc_ht_info.tx_chan_width, + sc->tx_chan_width, sc->sc_tx_chainmask, sc->sc_rx_chainmask, sc->sc_ht_extprotspacing, true, &status)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to reset hardware; hal status %u\n", - __func__, + "Unable to reset hardware; hal status %u\n", status); } spin_unlock_bh(&sc->sc_resetlock); @@ -1358,7 +1178,7 @@ static void ath_drain_txdataq(struct ath_softc *sc, bool retry_tx) for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) - ath_tx_draintxq(sc, &sc->sc_txq[i], retry_tx); + ath_tx_draintxq(sc, &sc->tx.txq[i], retry_tx); } } @@ -1390,24 +1210,17 @@ static void ath_tx_addto_baw(struct ath_softc *sc, * Function to send an A-MPDU * NB: must be called with txq lock held */ - static int ath_tx_send_ampdu(struct ath_softc *sc, - struct ath_txq *txq, struct ath_atx_tid *tid, struct list_head *bf_head, struct ath_tx_control *txctl) { struct ath_buf *bf; - struct sk_buff *skb; - struct ieee80211_tx_info *tx_info; - struct ath_tx_info_priv *tx_info_priv; BUG_ON(list_empty(bf_head)); bf = list_first_entry(bf_head, struct ath_buf, list); bf->bf_state.bf_type |= BUF_AMPDU; - bf->bf_seqno = txctl->seqno; /* save seqno and tidno in buffer */ - bf->bf_tidno = txctl->tidno; /* * Do not queue to h/w when any of the following conditions is true: @@ -1418,21 +1231,16 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, */ if (!list_empty(&tid->buf_q) || tid->paused || !BAW_WITHIN(tid->seq_start, tid->baw_size, bf->bf_seqno) || - txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { + txctl->txq->axq_depth >= ATH_AGGR_MIN_QDEPTH) { /* * Add this frame to software queue for scheduling later * for aggregation. */ list_splice_tail_init(bf_head, &tid->buf_q); - ath_tx_queue_tid(txq, tid); + ath_tx_queue_tid(txctl->txq, tid); return 0; } - skb = (struct sk_buff *)bf->bf_mpdu; - tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - memcpy(bf->bf_rcs, tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); - /* Add sub-frame to BAW */ ath_tx_addto_baw(sc, tid, bf); @@ -1440,7 +1248,8 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, bf->bf_nframes = 1; bf->bf_lastbf = bf->bf_lastfrm; /* one single frame */ ath_buf_set_rate(sc, bf); - ath_tx_txqaddbuf(sc, txq, bf_head); + ath_tx_txqaddbuf(sc, txctl->txq, bf_head); + return 0; } @@ -1448,25 +1257,24 @@ static int ath_tx_send_ampdu(struct ath_softc *sc, * looks up the rate * returns aggr limit based on lowest of the rates */ - static u32 ath_lookup_rate(struct ath_softc *sc, - struct ath_buf *bf) + struct ath_buf *bf, + struct ath_atx_tid *tid) { - const struct ath9k_rate_table *rt = sc->sc_currates; + struct ath_rate_table *rate_table = sc->cur_rate_table; struct sk_buff *skb; struct ieee80211_tx_info *tx_info; + struct ieee80211_tx_rate *rates; struct ath_tx_info_priv *tx_info_priv; u32 max_4ms_framelen, frame_length; u16 aggr_limit, legacy = 0, maxampdu; int i; - skb = (struct sk_buff *)bf->bf_mpdu; tx_info = IEEE80211_SKB_CB(skb); - tx_info_priv = (struct ath_tx_info_priv *) - tx_info->driver_data[0]; - memcpy(bf->bf_rcs, - tx_info_priv->rcs, 4 * sizeof(tx_info_priv->rcs[0])); + rates = tx_info->control.rates; + tx_info_priv = + (struct ath_tx_info_priv *)tx_info->rate_driver_data[0]; /* * Find the lowest frame length among the rate series that will have a @@ -1476,14 +1284,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc, max_4ms_framelen = ATH_AMPDU_LIMIT_MAX; for (i = 0; i < 4; i++) { - if (bf->bf_rcs[i].tries) { - frame_length = bf->bf_rcs[i].max_4ms_framelen; - - if (rt->info[bf->bf_rcs[i].rix].phy != PHY_HT) { + if (rates[i].count) { + if (!WLAN_RC_PHY_HT(rate_table->info[rates[i].idx].phy)) { legacy = 1; break; } + frame_length = + rate_table->info[rates[i].idx].max_4ms_framelen; max_4ms_framelen = min(max_4ms_framelen, frame_length); } } @@ -1504,7 +1312,7 @@ static u32 ath_lookup_rate(struct ath_softc *sc, * The IE, however can hold upto 65536, which shows up here * as zero. Ignore 65536 since we are constrained by hw. */ - maxampdu = sc->sc_ht_info.maxampdu; + maxampdu = tid->an->maxampdu; if (maxampdu) aggr_limit = min(aggr_limit, maxampdu); @@ -1516,12 +1324,14 @@ static u32 ath_lookup_rate(struct ath_softc *sc, * meet the minimum required mpdudensity. * caller should make sure that the rate is HT rate . */ - static int ath_compute_num_delims(struct ath_softc *sc, + struct ath_atx_tid *tid, struct ath_buf *bf, u16 frmlen) { - const struct ath9k_rate_table *rt = sc->sc_currates; + struct ath_rate_table *rt = sc->cur_rate_table; + struct sk_buff *skb = bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); u32 nsymbits, nsymbols, mpdudensity; u16 minlen; u8 rc, flags, rix; @@ -1545,7 +1355,7 @@ static int ath_compute_num_delims(struct ath_softc *sc, * required minimum length for subframe. Take into account * whether high rate is 20 or 40Mhz and half or full GI. */ - mpdudensity = sc->sc_ht_info.mpdudensity; + mpdudensity = tid->an->mpdudensity; /* * If there is no mpdu density restriction, no further calculation @@ -1554,11 +1364,11 @@ static int ath_compute_num_delims(struct ath_softc *sc, if (mpdudensity == 0) return ndelim; - rix = bf->bf_rcs[0].rix; - flags = bf->bf_rcs[0].flags; - rc = rt->info[rix].rateCode; - width = (flags & ATH_RC_CW40_FLAG) ? 1 : 0; - half_gi = (flags & ATH_RC_SGI_FLAG) ? 1 : 0; + rix = tx_info->control.rates[0].idx; + flags = tx_info->control.rates[0].flags; + rc = rt->info[rix].ratecode; + width = (flags & IEEE80211_TX_RC_40_MHZ_WIDTH) ? 1 : 0; + half_gi = (flags & IEEE80211_TX_RC_SHORT_GI) ? 1 : 0; if (half_gi) nsymbols = NUM_SYMBOLS_PER_USEC_HALFGI(mpdudensity); @@ -1585,7 +1395,6 @@ static int ath_compute_num_delims(struct ath_softc *sc, * For aggregation from software buffer queue. * NB: must be called with txq lock held */ - static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, struct ath_atx_tid *tid, struct list_head *bf_q, @@ -1600,7 +1409,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, u16 aggr_limit = 0, al = 0, bpad = 0, al_delta, h_baw = tid->baw_size / 2; enum ATH_AGGR_STATUS status = ATH_AGGR_DONE; - int prev_al = 0, is_ds_rate = 0; + int prev_al = 0; INIT_LIST_HEAD(&bf_head); BUG_ON(list_empty(&tid->buf_q)); @@ -1619,13 +1428,8 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, } if (!rl) { - aggr_limit = ath_lookup_rate(sc, bf); + aggr_limit = ath_lookup_rate(sc, bf, tid); rl = 1; - /* - * Is rate dual stream - */ - is_ds_rate = - (bf->bf_rcs[0].flags & ATH_RC_DS_FLAG) ? 1 : 0; } /* @@ -1657,7 +1461,7 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, * Get the delimiters needed to meet the MPDU * density for this node. */ - ndelim = ath_compute_num_delims(sc, bf_first, bf->bf_frmlen); + ndelim = ath_compute_num_delims(sc, tid, bf_first, bf->bf_frmlen); bpad = PADBYTES(al_delta) + (ndelim << 2); @@ -1713,7 +1517,6 @@ static enum ATH_AGGR_STATUS ath_tx_form_aggr(struct ath_softc *sc, * process pending frames possibly doing a-mpdu aggregation * NB: must be called with txq lock held */ - static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq, struct ath_atx_tid *tid) { @@ -1799,8 +1602,8 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq, - struct ath_atx_tid *tid, - bool bh_flag) + struct ath_atx_tid *tid) + { struct ath_buf *bf; struct list_head bf_head; @@ -1821,18 +1624,12 @@ static void ath_tid_drain(struct ath_softc *sc, * do not indicate packets while holding txq spinlock. * unlock is intentional here */ - if (likely(bh_flag)) - spin_unlock_bh(&txq->axq_lock); - else - spin_unlock(&txq->axq_lock); + spin_unlock(&txq->axq_lock); /* complete this sub-frame */ ath_tx_complete_buf(sc, bf, &bf_head, 0, 0); - if (likely(bh_flag)) - spin_lock_bh(&txq->axq_lock); - else - spin_lock(&txq->axq_lock); + spin_lock(&txq->axq_lock); } /* @@ -1849,10 +1646,8 @@ static void ath_tid_drain(struct ath_softc *sc, * Drain all pending buffers * NB: must be called with txq lock held */ - static void ath_txq_drain_pending_buffers(struct ath_softc *sc, - struct ath_txq *txq, - bool bh_flag) + struct ath_txq *txq) { struct ath_atx_ac *ac, *ac_tmp; struct ath_atx_tid *tid, *tid_tmp; @@ -1863,51 +1658,33 @@ static void ath_txq_drain_pending_buffers(struct ath_softc *sc, list_for_each_entry_safe(tid, tid_tmp, &ac->tid_q, list) { list_del(&tid->list); tid->sched = false; - ath_tid_drain(sc, txq, tid, bh_flag); + ath_tid_drain(sc, txq, tid); } } } -static int ath_tx_start_dma(struct ath_softc *sc, - struct sk_buff *skb, - struct scatterlist *sg, - u32 n_sg, - struct ath_tx_control *txctl) +static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf, + struct sk_buff *skb, + struct ath_tx_control *txctl) { - struct ath_node *an = txctl->an; - struct ath_buf *bf = NULL; - struct list_head bf_head; - struct ath_desc *ds; - struct ath_hal *ah = sc->sc_ah; - struct ath_txq *txq; - struct ath_tx_info_priv *tx_info_priv; - struct ath_rc_series *rcs; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); - __le16 fc = hdr->frame_control; - - if (unlikely(txctl->flags & ATH9K_TXDESC_CAB)) - txq = sc->sc_cabq; - else - txq = &sc->sc_txq[txctl->qnum]; + struct ath_tx_info_priv *tx_info_priv; + int hdrlen; + __le16 fc; - /* For each sglist entry, allocate an ath_buf for DMA */ - INIT_LIST_HEAD(&bf_head); - spin_lock_bh(&sc->sc_txbuflock); - if (unlikely(list_empty(&sc->sc_txbuf))) { - spin_unlock_bh(&sc->sc_txbuflock); + tx_info_priv = kzalloc(sizeof(*tx_info_priv), GFP_ATOMIC); + if (unlikely(!tx_info_priv)) return -ENOMEM; - } + tx_info->rate_driver_data[0] = tx_info_priv; + hdrlen = ieee80211_get_hdrlen_from_skb(skb); + fc = hdr->frame_control; - bf = list_first_entry(&sc->sc_txbuf, struct ath_buf, list); - list_del(&bf->list); - spin_unlock_bh(&sc->sc_txbuflock); + ATH_TXBUF_RESET(bf); - list_add_tail(&bf->list, &bf_head); + /* Frame type */ - /* set up this buffer */ - ATH_TXBUF_RESET(bf); - bf->bf_frmlen = txctl->frmlen; + bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3); ieee80211_is_data(fc) ? (bf->bf_state.bf_type |= BUF_DATA) : @@ -1921,120 +1698,158 @@ static int ath_tx_start_dma(struct ath_softc *sc, (sc->sc_flags & SC_OP_PREAMBLE_SHORT) ? (bf->bf_state.bf_type |= BUF_SHORT_PREAMBLE) : (bf->bf_state.bf_type &= ~BUF_SHORT_PREAMBLE); + (sc->hw->conf.ht.enabled && !is_pae(skb) && + (tx_info->flags & IEEE80211_TX_CTL_AMPDU)) ? + (bf->bf_state.bf_type |= BUF_HT) : + (bf->bf_state.bf_type &= ~BUF_HT); + + bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq); + + /* Crypto */ + + bf->bf_keytype = get_hw_crypto_keytype(skb); + + if (bf->bf_keytype != ATH9K_KEY_TYPE_CLEAR) { + bf->bf_frmlen += tx_info->control.hw_key->icv_len; + bf->bf_keyix = tx_info->control.hw_key->hw_key_idx; + } else { + bf->bf_keyix = ATH9K_TXKEYIX_INVALID; + } + + /* Assign seqno, tidno */ + + if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR)) + assign_aggr_tid_seqno(skb, bf); + + /* DMA setup */ - bf->bf_flags = txctl->flags; - bf->bf_keytype = txctl->keytype; - tx_info_priv = (struct ath_tx_info_priv *)tx_info->driver_data[0]; - rcs = tx_info_priv->rcs; - bf->bf_rcs[0] = rcs[0]; - bf->bf_rcs[1] = rcs[1]; - bf->bf_rcs[2] = rcs[2]; - bf->bf_rcs[3] = rcs[3]; - bf->bf_node = an; bf->bf_mpdu = skb; - bf->bf_buf_addr = sg_dma_address(sg); + + bf->bf_dmacontext = pci_map_single(sc->pdev, skb->data, + skb->len, PCI_DMA_TODEVICE); + if (unlikely(pci_dma_mapping_error(sc->pdev, bf->bf_dmacontext))) { + bf->bf_mpdu = NULL; + DPRINTF(sc, ATH_DBG_CONFIG, + "pci_dma_mapping_error() on TX\n"); + return -ENOMEM; + } + + bf->bf_buf_addr = bf->bf_dmacontext; + return 0; +} + +/* FIXME: tx power */ +static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf, + struct ath_tx_control *txctl) +{ + struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu; + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); + struct ath_node *an = NULL; + struct list_head bf_head; + struct ath_desc *ds; + struct ath_atx_tid *tid; + struct ath_hal *ah = sc->sc_ah; + int frm_type; + + frm_type = get_hw_packet_type(skb); + + INIT_LIST_HEAD(&bf_head); + list_add_tail(&bf->list, &bf_head); /* setup descriptor */ + ds = bf->bf_desc; ds->ds_link = 0; ds->ds_data = bf->bf_buf_addr; - /* - * Save the DMA context in the first ath_buf - */ - bf->bf_dmacontext = txctl->dmacontext; + /* Formulate first tx descriptor with tx controls */ - /* - * Formulate first tx descriptor with tx controls. - */ - ath9k_hw_set11n_txdesc(ah, - ds, - bf->bf_frmlen, /* frame length */ - txctl->atype, /* Atheros packet type */ - min(txctl->txpower, (u16)60), /* txpower */ - txctl->keyix, /* key cache index */ - txctl->keytype, /* key type */ - txctl->flags); /* flags */ - ath9k_hw_filltxdesc(ah, - ds, - sg_dma_len(sg), /* segment length */ - true, /* first segment */ - (n_sg == 1) ? true : false, /* last segment */ - ds); /* first descriptor */ + ath9k_hw_set11n_txdesc(ah, ds, bf->bf_frmlen, frm_type, MAX_RATE_POWER, + bf->bf_keyix, bf->bf_keytype, bf->bf_flags); + + ath9k_hw_filltxdesc(ah, ds, + skb->len, /* segment length */ + true, /* first segment */ + true, /* last segment */ + ds); /* first descriptor */ bf->bf_lastfrm = bf; - (txctl->ht) ? - (bf->bf_state.bf_type |= BUF_HT) : - (bf->bf_state.bf_type &= ~BUF_HT); - spin_lock_bh(&txq->axq_lock); + spin_lock_bh(&txctl->txq->axq_lock); - if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { - struct ath_atx_tid *tid = ATH_AN_2_TID(an, txctl->tidno); - if (ath_aggr_query(sc, an, txctl->tidno)) { + if (bf_isht(bf) && (sc->sc_flags & SC_OP_TXAGGR) && + tx_info->control.sta) { + an = (struct ath_node *)tx_info->control.sta->drv_priv; + tid = ATH_AN_2_TID(an, bf->bf_tidno); + + if (ath_aggr_query(sc, an, bf->bf_tidno)) { /* * Try aggregation if it's a unicast data frame * and the destination is HT capable. */ - ath_tx_send_ampdu(sc, txq, tid, &bf_head, txctl); + ath_tx_send_ampdu(sc, tid, &bf_head, txctl); } else { /* - * Send this frame as regular when ADDBA exchange - * is neither complete nor pending. + * Send this frame as regular when ADDBA + * exchange is neither complete nor pending. */ - ath_tx_send_normal(sc, txq, tid, &bf_head); + ath_tx_send_normal(sc, txctl->txq, + tid, &bf_head); } } else { bf->bf_lastbf = bf; bf->bf_nframes = 1; - ath_buf_set_rate(sc, bf); - - if (ieee80211_is_back_req(fc)) { - /* This is required for resuming tid - * during BAR completion */ - bf->bf_tidno = txctl->tidno; - } - ath_tx_txqaddbuf(sc, txq, &bf_head); + ath_buf_set_rate(sc, bf); + ath_tx_txqaddbuf(sc, txctl->txq, &bf_head); } - spin_unlock_bh(&txq->axq_lock); - return 0; + + spin_unlock_bh(&txctl->txq->axq_lock); } -static void xmit_map_sg(struct ath_softc *sc, - struct sk_buff *skb, - struct ath_tx_control *txctl) +/* Upon failure caller should free skb */ +int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb, + struct ath_tx_control *txctl) { - struct ath_xmit_status tx_status; - struct ath_atx_tid *tid; - struct scatterlist sg; + struct ath_buf *bf; + int r; - txctl->dmacontext = pci_map_single(sc->pdev, skb->data, - skb->len, PCI_DMA_TODEVICE); + /* Check if a tx buffer is available */ - /* setup S/G list */ - memset(&sg, 0, sizeof(struct scatterlist)); - sg_dma_address(&sg) = txctl->dmacontext; - sg_dma_len(&sg) = skb->len; + bf = ath_tx_get_buffer(sc); + if (!bf) { + DPRINTF(sc, ATH_DBG_XMIT, "TX buffers are full\n"); + return -1; + } - if (ath_tx_start_dma(sc, skb, &sg, 1, txctl) != 0) { - /* - * We have to do drop frame here. - */ - pci_unmap_single(sc->pdev, txctl->dmacontext, - skb->len, PCI_DMA_TODEVICE); + r = ath_tx_setup_buffer(sc, bf, skb, txctl); + if (unlikely(r)) { + struct ath_txq *txq = txctl->txq; - tx_status.retries = 0; - tx_status.flags = ATH_TX_ERROR; + DPRINTF(sc, ATH_DBG_FATAL, "TX mem alloc failure\n"); - if (txctl->ht && (sc->sc_flags & SC_OP_TXAGGR)) { - /* Reclaim the seqno. */ - tid = ATH_AN_2_TID((struct ath_node *) - txctl->an, txctl->tidno); - DECR(tid->seq_next, IEEE80211_SEQ_MAX); + /* upon ath_tx_processq() this TX queue will be resumed, we + * guarantee this will happen by knowing beforehand that + * we will at least have to run TX completionon one buffer + * on the queue */ + spin_lock_bh(&txq->axq_lock); + if (ath_txq_depth(sc, txq->axq_qnum) > 1) { + ieee80211_stop_queue(sc->hw, + skb_get_queue_mapping(skb)); + txq->stopped = 1; } - ath_tx_complete(sc, skb, &tx_status, txctl->an); + spin_unlock_bh(&txq->axq_lock); + + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); + + return r; } + + ath_tx_start_dma(sc, bf, txctl); + + return 0; } /* Initialize TX queue and h/w */ @@ -2044,26 +1859,25 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) int error = 0; do { - spin_lock_init(&sc->sc_txbuflock); + spin_lock_init(&sc->tx.txbuflock); /* Setup tx descriptors */ - error = ath_descdma_setup(sc, &sc->sc_txdma, &sc->sc_txbuf, + error = ath_descdma_setup(sc, &sc->tx.txdma, &sc->tx.txbuf, "tx", nbufs, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: failed to allocate tx descriptors: %d\n", - __func__, error); + "Failed to allocate tx descriptors: %d\n", + error); break; } /* XXX allocate beacon state together with vap */ - error = ath_descdma_setup(sc, &sc->sc_bdma, &sc->sc_bbuf, + error = ath_descdma_setup(sc, &sc->beacon.bdma, &sc->beacon.bbuf, "beacon", ATH_BCBUF, 1); if (error != 0) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: failed to allocate " - "beacon descripotrs: %d\n", - __func__, error); + "Failed to allocate beacon descriptors: %d\n", + error); break; } @@ -2080,12 +1894,12 @@ int ath_tx_init(struct ath_softc *sc, int nbufs) int ath_tx_cleanup(struct ath_softc *sc) { /* cleanup beacon descriptors */ - if (sc->sc_bdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->sc_bdma, &sc->sc_bbuf); + if (sc->beacon.bdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->beacon.bdma, &sc->beacon.bbuf); /* cleanup tx descriptors */ - if (sc->sc_txdma.dd_desc_len != 0) - ath_descdma_cleanup(sc, &sc->sc_txdma, &sc->sc_txbuf); + if (sc->tx.txdma.dd_desc_len != 0) + ath_descdma_cleanup(sc, &sc->tx.txdma, &sc->tx.txbuf); return 0; } @@ -2133,15 +1947,15 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) */ return NULL; } - if (qnum >= ARRAY_SIZE(sc->sc_txq)) { + if (qnum >= ARRAY_SIZE(sc->tx.txq)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: hal qnum %u out of range, max %u!\n", - __func__, qnum, (unsigned int)ARRAY_SIZE(sc->sc_txq)); + "qnum %u out of range, max %u!\n", + qnum, (unsigned int)ARRAY_SIZE(sc->tx.txq)); ath9k_hw_releasetxqueue(ah, qnum); return NULL; } if (!ATH_TXQ_SETUP(sc, qnum)) { - struct ath_txq *txq = &sc->sc_txq[qnum]; + struct ath_txq *txq = &sc->tx.txq[qnum]; txq->axq_qnum = qnum; txq->axq_link = NULL; @@ -2151,11 +1965,10 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) txq->axq_depth = 0; txq->axq_aggr_depth = 0; txq->axq_totalqueued = 0; - txq->axq_intrcnt = 0; txq->axq_linkbuf = NULL; - sc->sc_txqsetup |= 1<tx.txqsetup |= 1<sc_txq[qnum]; + return &sc->tx.txq[qnum]; } /* Reclaim resources for a setup queue */ @@ -2163,7 +1976,7 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype) void ath_tx_cleanupq(struct ath_softc *sc, struct ath_txq *txq) { ath9k_hw_releasetxqueue(sc->sc_ah, txq->axq_qnum); - sc->sc_txqsetup &= ~(1<axq_qnum); + sc->tx.txqsetup &= ~(1<axq_qnum); } /* @@ -2180,15 +1993,15 @@ int ath_tx_setup(struct ath_softc *sc, int haltype) { struct ath_txq *txq; - if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) { + if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: HAL AC %u out of range, max %zu!\n", - __func__, haltype, ARRAY_SIZE(sc->sc_haltype2q)); + "HAL AC %u out of range, max %zu!\n", + haltype, ARRAY_SIZE(sc->tx.hwq_map)); return 0; } txq = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, haltype); if (txq != NULL) { - sc->sc_haltype2q[haltype] = txq->axq_qnum; + sc->tx.hwq_map[haltype] = txq->axq_qnum; return 1; } else return 0; @@ -2200,20 +2013,19 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) switch (qtype) { case ATH9K_TX_QUEUE_DATA: - if (haltype >= ARRAY_SIZE(sc->sc_haltype2q)) { + if (haltype >= ARRAY_SIZE(sc->tx.hwq_map)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: HAL AC %u out of range, max %zu!\n", - __func__, - haltype, ARRAY_SIZE(sc->sc_haltype2q)); + "HAL AC %u out of range, max %zu!\n", + haltype, ARRAY_SIZE(sc->tx.hwq_map)); return -1; } - qnum = sc->sc_haltype2q[haltype]; + qnum = sc->tx.hwq_map[haltype]; break; case ATH9K_TX_QUEUE_BEACON: - qnum = sc->sc_bhalq; + qnum = sc->beacon.beaconq; break; case ATH9K_TX_QUEUE_CAB: - qnum = sc->sc_cabq->axq_qnum; + qnum = sc->beacon.cabq->axq_qnum; break; default: qnum = -1; @@ -2221,6 +2033,34 @@ int ath_tx_get_qnum(struct ath_softc *sc, int qtype, int haltype) return qnum; } +/* Get a transmit queue, if available */ + +struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb) +{ + struct ath_txq *txq = NULL; + int qnum; + + qnum = ath_get_hal_qnum(skb_get_queue_mapping(skb), sc); + txq = &sc->tx.txq[qnum]; + + spin_lock_bh(&txq->axq_lock); + + /* Try to avoid running out of descriptors */ + if (txq->axq_depth >= (ATH_TXBUF - 20)) { + DPRINTF(sc, ATH_DBG_FATAL, + "TX queue: %d is full, depth: %d\n", + qnum, txq->axq_depth); + ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb)); + txq->stopped = 1; + spin_unlock_bh(&txq->axq_lock); + return NULL; + } + + spin_unlock_bh(&txq->axq_lock); + + return txq; +} + /* Update parameters for a transmit queue */ int ath_txq_update(struct ath_softc *sc, int qnum, @@ -2230,17 +2070,17 @@ int ath_txq_update(struct ath_softc *sc, int qnum, int error = 0; struct ath9k_tx_queue_info qi; - if (qnum == sc->sc_bhalq) { + if (qnum == sc->beacon.beaconq) { /* * XXX: for beacon queue, we just save the parameter. * It will be picked up by ath_beaconq_config when * it's necessary. */ - sc->sc_beacon_qi = *qinfo; + sc->beacon.beacon_qi = *qinfo; return 0; } - ASSERT(sc->sc_txq[qnum].axq_qnum == qnum); + ASSERT(sc->tx.txq[qnum].axq_qnum == qnum); ath9k_hw_get_txq_props(ah, qnum, &qi); qi.tqi_aifs = qinfo->tqi_aifs; @@ -2251,8 +2091,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { DPRINTF(sc, ATH_DBG_FATAL, - "%s: unable to update hardware queue %u!\n", - __func__, qnum); + "Unable to update hardware queue %u!\n", qnum); error = -EIO; } else { ath9k_hw_resettxqueue(ah, qnum); /* push to h/w */ @@ -2264,7 +2103,7 @@ int ath_txq_update(struct ath_softc *sc, int qnum, int ath_cabq_update(struct ath_softc *sc) { struct ath9k_tx_queue_info qi; - int qnum = sc->sc_cabq->axq_qnum; + int qnum = sc->beacon.cabq->axq_qnum; struct ath_beacon_config conf; ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi); @@ -2284,27 +2123,6 @@ int ath_cabq_update(struct ath_softc *sc) return 0; } -int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb) -{ - struct ath_tx_control txctl; - int error = 0; - - memset(&txctl, 0, sizeof(struct ath_tx_control)); - error = ath_tx_prepare(sc, skb, &txctl); - if (error == 0) - /* - * Start DMA mapping. - * ath_tx_start_dma() will be called either synchronously - * or asynchrounsly once DMA is complete. - */ - xmit_map_sg(sc, skb, &txctl); - else - ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); - - /* failed packets will be dropped by the caller */ - return error; -} - /* Deferred processing of transmit interrupt */ void ath_tx_tasklet(struct ath_softc *sc) @@ -2319,7 +2137,7 @@ void ath_tx_tasklet(struct ath_softc *sc) */ for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i) && (qcumask & (1 << i))) - ath_tx_processq(sc, &sc->sc_txq[i]); + ath_tx_processq(sc, &sc->tx.txq[i]); } } @@ -2351,9 +2169,9 @@ void ath_tx_draintxq(struct ath_softc *sc, list_del(&bf->list); spin_unlock_bh(&txq->axq_lock); - spin_lock_bh(&sc->sc_txbuflock); - list_add_tail(&bf->list, &sc->sc_txbuf); - spin_unlock_bh(&sc->sc_txbuflock); + spin_lock_bh(&sc->tx.txbuflock); + list_add_tail(&bf->list, &sc->tx.txbuf); + spin_unlock_bh(&sc->tx.txbuflock); continue; } @@ -2378,8 +2196,7 @@ void ath_tx_draintxq(struct ath_softc *sc, if (sc->sc_flags & SC_OP_TXAGGR) { if (!retry_tx) { spin_lock_bh(&txq->axq_lock); - ath_txq_drain_pending_buffers(sc, txq, - ATH9K_BH_STATUS_CHANGE); + ath_txq_drain_pending_buffers(sc, txq); spin_unlock_bh(&txq->axq_lock); } } @@ -2392,9 +2209,9 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx) /* stop beacon queue. The beacon will be freed when * we go to INIT state */ if (!(sc->sc_flags & SC_OP_INVALID)) { - (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->sc_bhalq); - DPRINTF(sc, ATH_DBG_XMIT, "%s: beacon queue %x\n", __func__, - ath9k_hw_gettxbuf(sc->sc_ah, sc->sc_bhalq)); + (void) ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq); + DPRINTF(sc, ATH_DBG_XMIT, "beacon queue %x\n", + ath9k_hw_gettxbuf(sc->sc_ah, sc->beacon.beaconq)); } ath_drain_txdataq(sc, retry_tx); @@ -2402,72 +2219,47 @@ void ath_draintxq(struct ath_softc *sc, bool retry_tx) u32 ath_txq_depth(struct ath_softc *sc, int qnum) { - return sc->sc_txq[qnum].axq_depth; + return sc->tx.txq[qnum].axq_depth; } u32 ath_txq_aggr_depth(struct ath_softc *sc, int qnum) { - return sc->sc_txq[qnum].axq_aggr_depth; + return sc->tx.txq[qnum].axq_aggr_depth; } -/* Check if an ADDBA is required. A valid node must be passed. */ -enum ATH_AGGR_CHECK ath_tx_aggr_check(struct ath_softc *sc, - struct ath_node *an, - u8 tidno) +bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno) { struct ath_atx_tid *txtid; - DECLARE_MAC_BUF(mac); if (!(sc->sc_flags & SC_OP_TXAGGR)) - return AGGR_NOT_REQUIRED; + return false; - /* ADDBA exchange must be completed before sending aggregates */ txtid = ATH_AN_2_TID(an, tidno); - if (txtid->addba_exchangecomplete) - return AGGR_EXCHANGE_DONE; - - if (txtid->cleanup_inprogress) - return AGGR_CLEANUP_PROGRESS; - - if (txtid->addba_exchangeinprogress) - return AGGR_EXCHANGE_PROGRESS; - - if (!txtid->addba_exchangecomplete) { - if (!txtid->addba_exchangeinprogress && + if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { + if (!(txtid->state & AGGR_ADDBA_PROGRESS) && (txtid->addba_exchangeattempts < ADDBA_EXCHANGE_ATTEMPTS)) { txtid->addba_exchangeattempts++; - return AGGR_REQUIRED; + return true; } } - return AGGR_NOT_REQUIRED; + return false; } /* Start TX aggregation */ -int ath_tx_aggr_start(struct ath_softc *sc, - const u8 *addr, - u16 tid, - u16 *ssn) +int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta, + u16 tid, u16 *ssn) { struct ath_atx_tid *txtid; struct ath_node *an; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); - - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: Node not found to initialize " - "TX aggregation\n", __func__); - return -1; - } + an = (struct ath_node *)sta->drv_priv; if (sc->sc_flags & SC_OP_TXAGGR) { txtid = ATH_AN_2_TID(an, tid); - txtid->addba_exchangeinprogress = 1; + txtid->state |= AGGR_ADDBA_PROGRESS; ath_tx_pause_tid(sc, txtid); } @@ -2476,24 +2268,31 @@ int ath_tx_aggr_start(struct ath_softc *sc, /* Stop tx aggregation */ -int ath_tx_aggr_stop(struct ath_softc *sc, - const u8 *addr, - u16 tid) +int ath_tx_aggr_stop(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) { + struct ath_node *an = (struct ath_node *)sta->drv_priv; + + ath_tx_aggr_teardown(sc, an, tid); + return 0; +} + +/* Resume tx aggregation */ + +void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid) +{ + struct ath_atx_tid *txtid; struct ath_node *an; - spin_lock_bh(&sc->node_lock); - an = ath_node_find(sc, (u8 *) addr); - spin_unlock_bh(&sc->node_lock); + an = (struct ath_node *)sta->drv_priv; - if (!an) { - DPRINTF(sc, ATH_DBG_AGGR, - "%s: TX aggr stop for non-existent node\n", __func__); - return -1; + if (sc->sc_flags & SC_OP_TXAGGR) { + txtid = ATH_AN_2_TID(an, tid); + txtid->baw_size = + IEEE80211_MIN_AMPDU_BUF << sta->ht_cap.ampdu_factor; + txtid->state |= AGGR_ADDBA_COMPLETE; + txtid->state &= ~AGGR_ADDBA_PROGRESS; + ath_tx_resume_tid(sc, txtid); } - - ath_tx_aggr_teardown(sc, an, tid); - return 0; } /* @@ -2503,21 +2302,18 @@ int ath_tx_aggr_stop(struct ath_softc *sc, * - Discard all retry frames from the s/w queue. */ -void ath_tx_aggr_teardown(struct ath_softc *sc, - struct ath_node *an, u8 tid) +void ath_tx_aggr_teardown(struct ath_softc *sc, struct ath_node *an, u8 tid) { struct ath_atx_tid *txtid = ATH_AN_2_TID(an, tid); - struct ath_txq *txq = &sc->sc_txq[txtid->ac->qnum]; + struct ath_txq *txq = &sc->tx.txq[txtid->ac->qnum]; struct ath_buf *bf; struct list_head bf_head; INIT_LIST_HEAD(&bf_head); - DPRINTF(sc, ATH_DBG_AGGR, "%s: teardown TX aggregation\n", __func__); - - if (txtid->cleanup_inprogress) /* cleanup is in progress */ + if (txtid->state & AGGR_CLEANUP) /* cleanup is in progress */ return; - if (!txtid->addba_exchangecomplete) { + if (!(txtid->state & AGGR_ADDBA_COMPLETE)) { txtid->addba_exchangeattempts = 0; return; } @@ -2547,9 +2343,9 @@ void ath_tx_aggr_teardown(struct ath_softc *sc, if (txtid->baw_head != txtid->baw_tail) { spin_unlock_bh(&txq->axq_lock); - txtid->cleanup_inprogress = true; + txtid->state |= AGGR_CLEANUP; } else { - txtid->addba_exchangecomplete = 0; + txtid->state &= ~AGGR_ADDBA_COMPLETE; txtid->addba_exchangeattempts = 0; spin_unlock_bh(&txq->axq_lock); ath_tx_flush_tid(sc, txtid); @@ -2591,10 +2387,8 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) if (tid->paused) /* check next tid to keep h/w busy */ continue; - if (!(tid->an->an_smmode == ATH_SM_PWRSAV_DYNAMIC) || - ((txq->axq_depth % 2) == 0)) { + if ((txq->axq_depth % 2) == 0) ath_tx_sched_aggr(sc, txq, tid); - } /* * add tid to round-robin queue if more frames @@ -2625,72 +2419,67 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq) void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an) { - if (sc->sc_flags & SC_OP_TXAGGR) { - struct ath_atx_tid *tid; - struct ath_atx_ac *ac; - int tidno, acno; - - sc->sc_ht_info.maxampdu = ATH_AMPDU_LIMIT_DEFAULT; + struct ath_atx_tid *tid; + struct ath_atx_ac *ac; + int tidno, acno; - /* - * Init per tid tx state - */ - for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, tid++) { - tid->an = an; - tid->tidno = tidno; - tid->seq_start = tid->seq_next = 0; - tid->baw_size = WME_MAX_BA; - tid->baw_head = tid->baw_tail = 0; - tid->sched = false; - tid->paused = false; - tid->cleanup_inprogress = false; - INIT_LIST_HEAD(&tid->buf_q); - - acno = TID_TO_WME_AC(tidno); - tid->ac = &an->an_aggr.tx.ac[acno]; - - /* ADDBA state */ - tid->addba_exchangecomplete = 0; - tid->addba_exchangeinprogress = 0; - tid->addba_exchangeattempts = 0; - } + /* + * Init per tid tx state + */ + for (tidno = 0, tid = &an->tid[tidno]; + tidno < WME_NUM_TID; + tidno++, tid++) { + tid->an = an; + tid->tidno = tidno; + tid->seq_start = tid->seq_next = 0; + tid->baw_size = WME_MAX_BA; + tid->baw_head = tid->baw_tail = 0; + tid->sched = false; + tid->paused = false; + tid->state &= ~AGGR_CLEANUP; + INIT_LIST_HEAD(&tid->buf_q); + + acno = TID_TO_WME_AC(tidno); + tid->ac = &an->ac[acno]; + + /* ADDBA state */ + tid->state &= ~AGGR_ADDBA_COMPLETE; + tid->state &= ~AGGR_ADDBA_PROGRESS; + tid->addba_exchangeattempts = 0; + } - /* - * Init per ac tx state - */ - for (acno = 0, ac = &an->an_aggr.tx.ac[acno]; - acno < WME_NUM_AC; acno++, ac++) { - ac->sched = false; - INIT_LIST_HEAD(&ac->tid_q); - - switch (acno) { - case WME_AC_BE: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); - break; - case WME_AC_BK: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK); - break; - case WME_AC_VI: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI); - break; - case WME_AC_VO: - ac->qnum = ath_tx_get_qnum(sc, - ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO); - break; - } + /* + * Init per ac tx state + */ + for (acno = 0, ac = &an->ac[acno]; + acno < WME_NUM_AC; acno++, ac++) { + ac->sched = false; + INIT_LIST_HEAD(&ac->tid_q); + + switch (acno) { + case WME_AC_BE: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BE); + break; + case WME_AC_BK: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_BK); + break; + case WME_AC_VI: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VI); + break; + case WME_AC_VO: + ac->qnum = ath_tx_get_qnum(sc, + ATH9K_TX_QUEUE_DATA, ATH9K_WME_AC_VO); + break; } } } /* Cleanupthe pending buffers for the node. */ -void ath_tx_node_cleanup(struct ath_softc *sc, - struct ath_node *an, bool bh_flag) +void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_node *an) { int i; struct ath_atx_ac *ac, *ac_tmp; @@ -2698,12 +2487,9 @@ void ath_tx_node_cleanup(struct ath_softc *sc, struct ath_txq *txq; for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++) { if (ATH_TXQ_SETUP(sc, i)) { - txq = &sc->sc_txq[i]; + txq = &sc->tx.txq[i]; - if (likely(bh_flag)) - spin_lock_bh(&txq->axq_lock); - else - spin_lock(&txq->axq_lock); + spin_lock(&txq->axq_lock); list_for_each_entry_safe(ac, ac_tmp, &txq->axq_acq, list) { @@ -2718,36 +2504,14 @@ void ath_tx_node_cleanup(struct ath_softc *sc, tid_tmp, &ac->tid_q, list) { list_del(&tid->list); tid->sched = false; - ath_tid_drain(sc, txq, tid, bh_flag); - tid->addba_exchangecomplete = 0; + ath_tid_drain(sc, txq, tid); + tid->state &= ~AGGR_ADDBA_COMPLETE; tid->addba_exchangeattempts = 0; - tid->cleanup_inprogress = false; + tid->state &= ~AGGR_CLEANUP; } } - if (likely(bh_flag)) - spin_unlock_bh(&txq->axq_lock); - else - spin_unlock(&txq->axq_lock); - } - } -} - -/* Cleanup per node transmit state */ - -void ath_tx_node_free(struct ath_softc *sc, struct ath_node *an) -{ - if (sc->sc_flags & SC_OP_TXAGGR) { - struct ath_atx_tid *tid; - int tidno, i; - - /* Init per tid rx state */ - for (tidno = 0, tid = &an->an_aggr.tx.tid[tidno]; - tidno < WME_NUM_TID; - tidno++, tid++) { - - for (i = 0; i < ATH_TID_MAX_BUFS; i++) - ASSERT(tid->tx_buf[i] == NULL); + spin_unlock(&txq->axq_lock); } } } @@ -2758,6 +2522,8 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct ath_tx_control txctl; + memset(&txctl, 0, sizeof(struct ath_tx_control)); + /* * As a temporary workaround, assign seq# here; this will likely need * to be cleaned up to work better with Beacon transmission and virtual @@ -2766,9 +2532,9 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - sc->seq_no += 0x10; + sc->tx.seq_no += 0x10; hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - hdr->seq_ctrl |= cpu_to_le16(sc->seq_no); + hdr->seq_ctrl |= cpu_to_le16(sc->tx.seq_no); } /* Add the padding after the header if this is not already done */ @@ -2776,8 +2542,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) if (hdrlen & 3) { padsize = hdrlen % 4; if (skb_headroom(skb) < padsize) { - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ padding " - "failed\n", __func__); + DPRINTF(sc, ATH_DBG_XMIT, "TX CABQ padding failed\n"); dev_kfree_skb_any(skb); return; } @@ -2785,23 +2550,16 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb) memmove(skb->data, skb->data + padsize, hdrlen); } - DPRINTF(sc, ATH_DBG_XMIT, "%s: transmitting CABQ packet, skb: %p\n", - __func__, - skb); + txctl.txq = sc->beacon.cabq; - memset(&txctl, 0, sizeof(struct ath_tx_control)); - txctl.flags = ATH9K_TXDESC_CAB; - if (ath_tx_prepare(sc, skb, &txctl) == 0) { - /* - * Start DMA mapping. - * ath_tx_start_dma() will be called either synchronously - * or asynchrounsly once DMA is complete. - */ - xmit_map_sg(sc, skb, &txctl); - } else { - ath_node_put(sc, txctl.an, ATH9K_BH_STATUS_CHANGE); - DPRINTF(sc, ATH_DBG_XMIT, "%s: TX CABQ failed\n", __func__); - dev_kfree_skb_any(skb); + DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb); + + if (ath_tx_start(sc, skb, &txctl) != 0) { + DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n"); + goto exit; } -} + return; +exit: + dev_kfree_skb_any(skb); +} diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c index ecb02bdaab5be183821287d1d540a1eaad872d22..350157fcd080ae0bec9cc9734d7e65b05897caa0 100644 --- a/drivers/net/wireless/atmel.c +++ b/drivers/net/wireless/atmel.c @@ -67,7 +67,7 @@ #include #include #include -#include +#include #include "atmel.h" #define DRIVER_MAJOR 0 @@ -569,7 +569,7 @@ static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data); static void atmel_command_irq(struct atmel_private *priv); static int atmel_validate_channel(struct atmel_private *priv, int channel); static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 frame_len, u8 rssi); static void atmel_management_timer(u_long a); static void atmel_send_command(struct atmel_private *priv, int command, @@ -577,7 +577,7 @@ static void atmel_send_command(struct atmel_private *priv, int command, static int atmel_send_command_wait(struct atmel_private *priv, int command, void *cmd, int cmd_size); static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u8 *body, int body_len); static u8 atmel_get_mib8(struct atmel_private *priv, u8 type, u8 index); @@ -785,7 +785,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) { static const u8 SNAP_RFC1024[6] = { 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 }; struct atmel_private *priv = netdev_priv(dev); - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; unsigned long flags; u16 buff, frame_ctl, len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN; @@ -823,7 +823,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) frame_ctl = IEEE80211_FTYPE_DATA; header.duration_id = 0; - header.seq_ctl = 0; + header.seq_ctrl = 0; if (priv->wep_is_on) frame_ctl |= IEEE80211_FCTL_PROTECTED; if (priv->operating_mode == IW_MODE_ADHOC) { @@ -840,7 +840,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) if (priv->use_wpa) memcpy(&header.addr4, SNAP_RFC1024, 6); - header.frame_ctl = cpu_to_le16(frame_ctl); + header.frame_control = cpu_to_le16(frame_ctl); /* Copy the wireless header into the card */ atmel_copy_to_card(dev, buff, (unsigned char *)&header, DATA_FRAME_WS_HEADER_SIZE); /* Copy the packet sans its 802.3 header addresses which have been replaced */ @@ -860,7 +860,7 @@ static int start_tx(struct sk_buff *skb, struct net_device *dev) } static void atmel_transmit_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u8 *body, int body_len) { u16 buff; @@ -876,7 +876,7 @@ static void atmel_transmit_management_frame(struct atmel_private *priv, } static void fast_rx_path(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc) { /* fast path: unfragmented packet copy directly into skbuf */ @@ -914,12 +914,11 @@ static void fast_rx_path(struct atmel_private *priv, } memcpy(skbp, header->addr1, 6); /* destination address */ - if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) + if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) memcpy(&skbp[6], header->addr3, 6); else memcpy(&skbp[6], header->addr2, 6); /* source address */ - priv->dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); @@ -950,7 +949,7 @@ static int probe_crc(struct atmel_private *priv, u16 packet_loc, u16 msdu_size) } static void frag_rx_path(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 msdu_size, u16 rx_packet_loc, u32 crc, u16 seq_no, u8 frag_no, int more_frags) { @@ -958,7 +957,7 @@ static void frag_rx_path(struct atmel_private *priv, u8 source[6]; struct sk_buff *skb; - if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) + if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) memcpy(source, header->addr3, 6); else memcpy(source, header->addr2, 6); @@ -1026,7 +1025,6 @@ static void frag_rx_path(struct atmel_private *priv, memcpy(skb_put(skb, priv->frag_len + 12), priv->rx_buf, priv->frag_len + 12); - priv->dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, priv->dev); skb->ip_summed = CHECKSUM_NONE; netif_rx(skb); @@ -1041,7 +1039,7 @@ static void frag_rx_path(struct atmel_private *priv, static void rx_done_irq(struct atmel_private *priv) { int i; - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; for (i = 0; atmel_rmem8(priv, atmel_rx(priv, RX_DESC_FLAGS_OFFSET, priv->rx_desc_head)) == RX_DESC_FLAG_VALID && @@ -1068,10 +1066,10 @@ static void rx_done_irq(struct atmel_private *priv) goto next; } - /* Get header as far as end of seq_ctl */ + /* Get header as far as end of seq_ctrl */ atmel_copy_to_host(priv->dev, (char *)&header, rx_packet_loc, 24); - frame_ctl = le16_to_cpu(header.frame_ctl); - seq_control = le16_to_cpu(header.seq_ctl); + frame_ctl = le16_to_cpu(header.frame_control); + seq_control = le16_to_cpu(header.seq_ctrl); /* probe for CRC use here if needed once five packets have arrived with the same crc status, we assume we know what's @@ -1479,7 +1477,6 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, struct net_device *dev; struct atmel_private *priv; int rc; - DECLARE_MAC_BUF(mac); /* Create the network device object. */ dev = alloc_etherdev(sizeof(*priv)); @@ -1591,8 +1588,8 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port, if (!ent) printk(KERN_WARNING "atmel: unable to create /proc entry.\n"); - printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %s\n", - dev->name, DRIVER_MAJOR, DRIVER_MINOR, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: Atmel at76c50x. Version %d.%d. MAC %pM\n", + dev->name, DRIVER_MAJOR, DRIVER_MINOR, dev->dev_addr); return dev; @@ -1822,7 +1819,7 @@ static int atmel_set_encodeext(struct net_device *dev, /* Determine and validate the key index */ idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if (idx < 1 || idx > WEP_KEYS) + if (idx < 1 || idx > 4) return -EINVAL; idx--; } else @@ -1885,7 +1882,7 @@ static int atmel_get_encodeext(struct net_device *dev, idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if (idx < 1 || idx > WEP_KEYS) + if (idx < 1 || idx > 4) return -EINVAL; idx--; } else @@ -2800,7 +2797,7 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, u8 channel) { int rejoin = 0; - int new = capability & MFIE_TYPE_POWER_CONSTRAINT ? + int new = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? SHORT_PREAMBLE : LONG_PREAMBLE; if (priv->preamble != new) { @@ -2829,19 +2826,19 @@ static void handle_beacon_probe(struct atmel_private *priv, u16 capability, static void send_authentication_request(struct atmel_private *priv, u16 system, u8 *challenge, int challenge_len) { - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; struct auth_body auth; - header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); + header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_AUTH); header.duration_id = cpu_to_le16(0x8000); - header.seq_ctl = 0; + header.seq_ctrl = 0; memcpy(header.addr1, priv->CurrentBSSID, 6); memcpy(header.addr2, priv->dev->dev_addr, 6); memcpy(header.addr3, priv->CurrentBSSID, 6); if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1) /* no WEP for authentication frames with TrSeqNo 1 */ - header.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); + header.frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); auth.alg = cpu_to_le16(system); @@ -2864,7 +2861,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) { u8 *ssid_el_p; int bodysize; - struct ieee80211_hdr_4addr header; + struct ieee80211_hdr header; struct ass_req_format { __le16 capability; __le16 listen_interval; @@ -2877,10 +2874,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) u8 rates[4]; } body; - header.frame_ctl = cpu_to_le16(IEEE80211_FTYPE_MGMT | + header.frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | (is_reassoc ? IEEE80211_STYPE_REASSOC_REQ : IEEE80211_STYPE_ASSOC_REQ)); header.duration_id = cpu_to_le16(0x8000); - header.seq_ctl = 0; + header.seq_ctrl = 0; memcpy(header.addr1, priv->CurrentBSSID, 6); memcpy(header.addr2, priv->dev->dev_addr, 6); @@ -2890,7 +2887,7 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) if (priv->wep_is_on) body.capability |= cpu_to_le16(WLAN_CAPABILITY_PRIVACY); if (priv->preamble == SHORT_PREAMBLE) - body.capability |= cpu_to_le16(MFIE_TYPE_POWER_CONSTRAINT); + body.capability |= cpu_to_le16(WLAN_CAPABILITY_SHORT_PREAMBLE); body.listen_interval = cpu_to_le16(priv->listen_interval * priv->beacon_period); @@ -2904,10 +2901,10 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) bodysize = 12 + priv->SSID_size; } - ssid_el_p[0] = MFIE_TYPE_SSID; + ssid_el_p[0] = WLAN_EID_SSID; ssid_el_p[1] = priv->SSID_size; memcpy(ssid_el_p + 2, priv->SSID, priv->SSID_size); - ssid_el_p[2 + priv->SSID_size] = MFIE_TYPE_RATES; + ssid_el_p[2 + priv->SSID_size] = WLAN_EID_SUPP_RATES; ssid_el_p[3 + priv->SSID_size] = 4; /* len of suported rates */ memcpy(ssid_el_p + 4 + priv->SSID_size, atmel_basic_rates, 4); @@ -2915,9 +2912,9 @@ static void send_association_request(struct atmel_private *priv, int is_reassoc) } static int is_frame_from_current_bss(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header) + struct ieee80211_hdr *header) { - if (le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_FROMDS) + if (le16_to_cpu(header->frame_control) & IEEE80211_FCTL_FROMDS) return memcmp(header->addr3, priv->CurrentBSSID, 6) == 0; else return memcmp(header->addr2, priv->CurrentBSSID, 6) == 0; @@ -2965,7 +2962,7 @@ static int retrieve_bss(struct atmel_private *priv) } static void store_bss_info(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, u16 capability, + struct ieee80211_hdr *header, u16 capability, u16 beacon_period, u8 channel, u8 rssi, u8 ssid_len, u8 *ssid, int is_beacon) { @@ -3004,7 +3001,7 @@ static void store_bss_info(struct atmel_private *priv, else if (capability & WLAN_CAPABILITY_ESS) priv->BSSinfo[index].BSStype =IW_MODE_INFRA; - priv->BSSinfo[index].preamble = capability & MFIE_TYPE_POWER_CONSTRAINT ? + priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ? SHORT_PREAMBLE : LONG_PREAMBLE; } @@ -3040,7 +3037,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len) } } else if (system == WLAN_AUTH_SHARED_KEY) { if (trans_seq_no == 0x0002 && - auth->el_id == MFIE_TYPE_CHALLENGE) { + auth->el_id == WLAN_EID_CHALLENGE) { send_authentication_request(priv, system, auth->chall_text, auth->chall_text_len); return; } else if (trans_seq_no == 0x0004) { @@ -3183,7 +3180,7 @@ static void associate(struct atmel_private *priv, u16 frame_len, u16 subtype) } } -void atmel_join_bss(struct atmel_private *priv, int bss_index) +static void atmel_join_bss(struct atmel_private *priv, int bss_index) { struct bss_info *bss = &priv->BSSinfo[bss_index]; @@ -3291,12 +3288,12 @@ static void atmel_smooth_qual(struct atmel_private *priv) /* deals with incoming managment frames. */ static void atmel_management_frame(struct atmel_private *priv, - struct ieee80211_hdr_4addr *header, + struct ieee80211_hdr *header, u16 frame_len, u8 rssi) { u16 subtype; - subtype = le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_STYPE; + subtype = le16_to_cpu(header->frame_control) & IEEE80211_FCTL_STYPE; switch (subtype) { case IEEE80211_STYPE_BEACON: case IEEE80211_STYPE_PROBE_RESP: diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 427b8203e3f96af2d8367d5ef1e8b2fa0386ab4a..a53c378e74844ebdca86dd83fb3b5c9104511b27 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h @@ -718,7 +718,6 @@ struct b43_wldev { bool bad_frames_preempt; /* Use "Bad Frames Preemption" (default off) */ bool dfq_valid; /* Directed frame queue valid (IBSS PS mode, ATIM) */ - 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 */ diff --git a/drivers/net/wireless/b43/debugfs.c b/drivers/net/wireless/b43/debugfs.c index 06a01da801604c91dcf92408871f622e2ccd947d..e04fc91f569ea573f3c9d3dfad8551b710d98c32 100644 --- a/drivers/net/wireless/b43/debugfs.c +++ b/drivers/net/wireless/b43/debugfs.c @@ -731,6 +731,7 @@ static void b43_add_dynamic_debug(struct b43_wldev *dev) add_dyn_dbg("debug_pwork_stop", B43_DBG_PWORK_STOP, 0); add_dyn_dbg("debug_lo", B43_DBG_LO, 0); add_dyn_dbg("debug_firmware", B43_DBG_FIRMWARE, 0); + add_dyn_dbg("debug_keys", B43_DBG_KEYS, 0); #undef add_dyn_dbg } diff --git a/drivers/net/wireless/b43/debugfs.h b/drivers/net/wireless/b43/debugfs.h index 22ffd02ba554806a8625319b5c2fd2aeae1cdcba..7886cbe2d1d19276f22e3a974dd4d7e44a55347b 100644 --- a/drivers/net/wireless/b43/debugfs.h +++ b/drivers/net/wireless/b43/debugfs.h @@ -12,6 +12,7 @@ enum b43_dyndbg { /* Dynamic debugging features */ B43_DBG_PWORK_STOP, B43_DBG_LO, B43_DBG_FIRMWARE, + B43_DBG_KEYS, __B43_NR_DYNDBG, }; diff --git a/drivers/net/wireless/b43/dma.c b/drivers/net/wireless/b43/dma.c index 098f886976f658fe636c39aa8a9f3810d227e25f..6d65a02b7052cdfa0d754a029038dcb66d96c788 100644 --- a/drivers/net/wireless/b43/dma.c +++ b/drivers/net/wireless/b43/dma.c @@ -1387,13 +1387,11 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev, info = IEEE80211_SKB_CB(meta->skb); - memset(&info->status, 0, sizeof(info->status)); - /* * Call back to inform the ieee80211 subsystem about * the status of the transmission. */ - frame_succeed = b43_fill_txstatus_report(info, status); + frame_succeed = b43_fill_txstatus_report(dev, info, status); #ifdef CONFIG_B43_DEBUG if (frame_succeed) ring->nr_succeed_tx_packets++; diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 14c44df584d0973a383729955d8c4089a48f5e8d..7b31a327b24a33e643be1021360af7fdcb8273da 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c @@ -703,13 +703,11 @@ static void b43_set_slot_time(struct b43_wldev *dev, u16 slot_time) static void b43_short_slot_timing_enable(struct b43_wldev *dev) { b43_set_slot_time(dev, 9); - dev->short_slot = 1; } static void b43_short_slot_timing_disable(struct b43_wldev *dev) { b43_set_slot_time(dev, 20); - dev->short_slot = 0; } /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. @@ -994,6 +992,52 @@ static void b43_clear_keys(struct b43_wldev *dev) b43_key_clear(dev, i); } +static void b43_dump_keymemory(struct b43_wldev *dev) +{ + unsigned int i, index, offset; + DECLARE_MAC_BUF(macbuf); + u8 mac[ETH_ALEN]; + u16 algo; + u32 rcmta0; + u16 rcmta1; + u64 hf; + struct b43_key *key; + + if (!b43_debug(dev, B43_DBG_KEYS)) + return; + + hf = b43_hf_read(dev); + b43dbg(dev->wl, "Hardware key memory dump: USEDEFKEYS=%u\n", + !!(hf & B43_HF_USEDEFKEYS)); + for (index = 0; index < dev->max_nr_keys; index++) { + key = &(dev->key[index]); + printk(KERN_DEBUG "Key slot %02u: %s", + index, (key->keyconf == NULL) ? " " : "*"); + offset = dev->ktp + (index * B43_SEC_KEYSIZE); + for (i = 0; i < B43_SEC_KEYSIZE; i += 2) { + u16 tmp = b43_shm_read16(dev, B43_SHM_SHARED, offset + i); + printk("%02X%02X", (tmp & 0xFF), ((tmp >> 8) & 0xFF)); + } + + algo = b43_shm_read16(dev, B43_SHM_SHARED, + B43_SHM_SH_KEYIDXBLOCK + (index * 2)); + printk(" Algo: %04X/%02X", algo, key->algorithm); + + if (index >= 4) { + rcmta0 = b43_shm_read32(dev, B43_SHM_RCMTA, + ((index - 4) * 2) + 0); + rcmta1 = b43_shm_read16(dev, B43_SHM_RCMTA, + ((index - 4) * 2) + 1); + *((__le32 *)(&mac[0])) = cpu_to_le32(rcmta0); + *((__le16 *)(&mac[4])) = cpu_to_le16(rcmta1); + printk(" MAC: %s", + print_mac(macbuf, mac)); + } else + printk(" DEFAULT KEY"); + printk("\n"); + } +} + void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags) { u32 macctl; @@ -1339,25 +1383,6 @@ u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev, return antenna_nr; } -static int b43_antenna_from_ieee80211(struct b43_wldev *dev, u8 antenna) -{ - antenna = b43_ieee80211_antenna_sanitize(dev, antenna); - switch (antenna) { - case 0: /* default/diversity */ - return B43_ANTENNA_DEFAULT; - case 1: /* Antenna 0 */ - return B43_ANTENNA0; - case 2: /* Antenna 1 */ - return B43_ANTENNA1; - case 3: /* Antenna 2 */ - return B43_ANTENNA2; - case 4: /* Antenna 3 */ - return B43_ANTENNA3; - default: - return B43_ANTENNA_DEFAULT; - } -} - /* Convert a b43 antenna number value to the PHY TX control value. */ static u16 b43_antenna_to_phyctl(int antenna) { @@ -1399,7 +1424,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, len, ram_offset, shm_size_offset, rate); /* Write the PHY TX control parameters. */ - antenna = b43_antenna_from_ieee80211(dev, info->antenna_sel_tx); + antenna = B43_ANTENNA_DEFAULT; antenna = b43_antenna_to_phyctl(antenna); ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); /* We can't send beacons with short preamble. Would get PHY errors. */ @@ -1693,25 +1718,6 @@ static void b43_update_templates(struct b43_wl *wl) queue_work(wl->hw->workqueue, &wl->beacon_update_trigger); } -static void b43_set_ssid(struct b43_wldev *dev, const u8 * ssid, u8 ssid_len) -{ - u32 tmp; - u16 i, len; - - len = min((u16) ssid_len, (u16) 0x100); - for (i = 0; i < len; i += sizeof(u32)) { - tmp = (u32) (ssid[i + 0]); - if (i + 1 < len) - tmp |= (u32) (ssid[i + 1]) << 8; - if (i + 2 < len) - tmp |= (u32) (ssid[i + 2]) << 16; - if (i + 3 < len) - tmp |= (u32) (ssid[i + 3]) << 24; - b43_shm_write32(dev, B43_SHM_SHARED, 0x380 + i, tmp); - } - b43_shm_write16(dev, B43_SHM_SHARED, 0x48, len); -} - static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int) { b43_time_lock(dev); @@ -3339,15 +3345,31 @@ init_failure: return err; } -static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +/* Write the short and long frame retry limit values. */ +static void b43_set_retry_limits(struct b43_wldev *dev, + unsigned int short_retry, + unsigned int long_retry) +{ + /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. */ + short_retry = min(short_retry, (unsigned int)0xF); + long_retry = min(long_retry, (unsigned int)0xF); + + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, + short_retry); + b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, + long_retry); +} + +static int b43_op_config(struct ieee80211_hw *hw, u32 changed) { struct b43_wl *wl = hw_to_b43_wl(hw); struct b43_wldev *dev; struct b43_phy *phy; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int antenna; int err = 0; - u32 savedirqs; mutex_lock(&wl->mutex); @@ -3358,33 +3380,20 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) dev = wl->current_dev; phy = &dev->phy; - /* Disable IRQs while reconfiguring the device. - * This makes it possible to drop the spinlock throughout - * the reconfiguration process. */ - spin_lock_irqsave(&wl->irq_lock, flags); - if (b43_status(dev) < B43_STAT_STARTED) { - spin_unlock_irqrestore(&wl->irq_lock, flags); - goto out_unlock_mutex; - } - savedirqs = b43_interrupt_disable(dev, B43_IRQ_ALL); - spin_unlock_irqrestore(&wl->irq_lock, flags); - b43_synchronize_irq(dev); + b43_mac_suspend(dev); + + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + b43_set_retry_limits(dev, conf->short_frame_max_tx_count, + conf->long_frame_max_tx_count); + changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS; + if (!changed) + goto out_mac_enable; /* Switch to the requested channel. * The firmware takes care of races with the TX handler. */ if (conf->channel->hw_value != phy->channel) b43_switch_channel(dev, conf->channel->hw_value); - /* Enable/Disable ShortSlot timing. */ - if ((!!(conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME)) != - dev->short_slot) { - B43_WARN_ON(phy->type != B43_PHYTYPE_G); - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) - b43_short_slot_timing_enable(dev); - else - b43_short_slot_timing_disable(dev); - } - dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); /* Adjust the desired TX power level. */ @@ -3399,9 +3408,9 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) } /* Antennas for RX and management frame TX. */ - antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_tx); + antenna = B43_ANTENNA_DEFAULT; b43_mgmtframe_txantenna(dev, antenna); - antenna = b43_antenna_from_ieee80211(dev, conf->antenna_sel_rx); + antenna = B43_ANTENNA_DEFAULT; if (phy->ops->set_rx_antenna) phy->ops->set_rx_antenna(dev, antenna); @@ -3425,16 +3434,91 @@ static int b43_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) } } - spin_lock_irqsave(&wl->irq_lock, flags); - b43_interrupt_enable(dev, savedirqs); - mmiowb(); - spin_unlock_irqrestore(&wl->irq_lock, flags); - out_unlock_mutex: +out_mac_enable: + b43_mac_enable(dev); +out_unlock_mutex: mutex_unlock(&wl->mutex); return err; } +static void b43_update_basic_rates(struct b43_wldev *dev, u64 brates) +{ + struct ieee80211_supported_band *sband = + dev->wl->hw->wiphy->bands[b43_current_band(dev->wl)]; + struct ieee80211_rate *rate; + int i; + u16 basic, direct, offset, basic_offset, rateptr; + + for (i = 0; i < sband->n_bitrates; i++) { + rate = &sband->bitrates[i]; + + if (b43_is_cck_rate(rate->hw_value)) { + direct = B43_SHM_SH_CCKDIRECT; + basic = B43_SHM_SH_CCKBASIC; + offset = b43_plcp_get_ratecode_cck(rate->hw_value); + offset &= 0xF; + } else { + direct = B43_SHM_SH_OFDMDIRECT; + basic = B43_SHM_SH_OFDMBASIC; + offset = b43_plcp_get_ratecode_ofdm(rate->hw_value); + offset &= 0xF; + } + + rate = ieee80211_get_response_rate(sband, brates, rate->bitrate); + + if (b43_is_cck_rate(rate->hw_value)) { + basic_offset = b43_plcp_get_ratecode_cck(rate->hw_value); + basic_offset &= 0xF; + } else { + basic_offset = b43_plcp_get_ratecode_ofdm(rate->hw_value); + basic_offset &= 0xF; + } + + /* + * Get the pointer that we need to point to + * from the direct map + */ + rateptr = b43_shm_read16(dev, B43_SHM_SHARED, + direct + 2 * basic_offset); + /* and write it to the basic map */ + b43_shm_write16(dev, B43_SHM_SHARED, basic + 2 * offset, + rateptr); + } +} + +static void b43_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changed) +{ + struct b43_wl *wl = hw_to_b43_wl(hw); + struct b43_wldev *dev; + + mutex_lock(&wl->mutex); + + dev = wl->current_dev; + if (!dev || b43_status(dev) < B43_STAT_STARTED) + goto out_unlock_mutex; + b43_mac_suspend(dev); + + if (changed & BSS_CHANGED_BASIC_RATES) + b43_update_basic_rates(dev, conf->basic_rates); + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (conf->use_short_slot) + b43_short_slot_timing_enable(dev); + else + b43_short_slot_timing_disable(dev); + } + + b43_mac_enable(dev); +out_unlock_mutex: + mutex_unlock(&wl->mutex); + + return; +} + static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) @@ -3445,7 +3529,6 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, u8 algorithm; u8 index; int err; - DECLARE_MAC_BUF(mac); if (modparam_nohwcrypt) return -ENOSPC; /* User disabled HW-crypto */ @@ -3528,15 +3611,18 @@ static int b43_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, default: B43_WARN_ON(1); } + out_unlock: - spin_unlock_irqrestore(&wl->irq_lock, flags); - mutex_unlock(&wl->mutex); if (!err) { b43dbg(wl, "%s hardware based encryption for keyidx: %d, " - "mac: %s\n", + "mac: %pM\n", cmd == SET_KEY ? "Using" : "Disabling", key->keyidx, - print_mac(mac, addr)); + addr); + b43_dump_keymemory(dev); } + spin_unlock_irqrestore(&wl->irq_lock, flags); + mutex_unlock(&wl->mutex); + return err; } @@ -3598,8 +3684,6 @@ static int b43_op_config_interface(struct ieee80211_hw *hw, if (b43_is_mode(wl, NL80211_IFTYPE_AP) || b43_is_mode(wl, NL80211_IFTYPE_MESH_POINT)) { B43_WARN_ON(vif->type != wl->if_type); - if (conf->changed & IEEE80211_IFCC_SSID) - b43_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->changed & IEEE80211_IFCC_BEACON) b43_update_templates(wl); } else if (b43_is_mode(wl, NL80211_IFTYPE_ADHOC)) { @@ -3878,22 +3962,6 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev) #endif /* CONFIG_SSB_DRIVER_PCICORE */ } -/* Write the short and long frame retry limit values. */ -static void b43_set_retry_limits(struct b43_wldev *dev, - unsigned int short_retry, - unsigned int long_retry) -{ - /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. */ - short_retry = min(short_retry, (unsigned int)0xF); - long_retry = min(long_retry, (unsigned int)0xF); - - b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_SRLIMIT, - short_retry); - b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_LRLIMIT, - long_retry); -} - static void b43_set_synth_pu_delay(struct b43_wldev *dev, bool idle) { u16 pu_delay; @@ -4214,26 +4282,6 @@ static void b43_op_stop(struct ieee80211_hw *hw) cancel_work_sync(&(wl->txpower_adjust_work)); } -static int b43_op_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry_limit, u32 long_retry_limit) -{ - struct b43_wl *wl = hw_to_b43_wl(hw); - struct b43_wldev *dev; - int err = 0; - - mutex_lock(&wl->mutex); - dev = wl->current_dev; - if (unlikely(!dev || (b43_status(dev) < B43_STAT_INITIALIZED))) { - err = -ENODEV; - goto out_unlock; - } - b43_set_retry_limits(dev, short_retry_limit, long_retry_limit); -out_unlock: - mutex_unlock(&wl->mutex); - - return err; -} - static int b43_op_beacon_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { @@ -4263,6 +4311,7 @@ static const struct ieee80211_ops b43_hw_ops = { .add_interface = b43_op_add_interface, .remove_interface = b43_op_remove_interface, .config = b43_op_config, + .bss_info_changed = b43_op_bss_info_changed, .config_interface = b43_op_config_interface, .configure_filter = b43_op_configure_filter, .set_key = b43_op_set_key, @@ -4270,7 +4319,6 @@ static const struct ieee80211_ops b43_hw_ops = { .get_tx_stats = b43_op_get_tx_stats, .start = b43_op_start, .stop = b43_op_stop, - .set_retry_limit = b43_op_set_retry_limit, .set_tim = b43_op_beacon_set_tim, .sta_notify = b43_op_sta_notify, }; @@ -4588,7 +4636,7 @@ static int b43_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_ADHOC); hw->queues = b43_modparam_qos ? 4 : 1; - hw->max_altrates = 1; + hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); diff --git a/drivers/net/wireless/b43/phy_a.c b/drivers/net/wireless/b43/phy_a.c index 0f1a84c9de6162c41a83c823cc0c0f59492e9594..7fe9d1701624b01051518199ca5574c6663f9c24 100644 --- a/drivers/net/wireless/b43/phy_a.c +++ b/drivers/net/wireless/b43/phy_a.c @@ -77,7 +77,7 @@ static s8 b43_aphy_estimate_power_out(struct b43_wldev *dev, s8 tssi) } #endif -void b43_radio_set_tx_iq(struct b43_wldev *dev) +static void b43_radio_set_tx_iq(struct b43_wldev *dev) { static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; @@ -147,7 +147,7 @@ static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel) //FIXME b43_phy_xmitpower(dev); } -void b43_radio_init2060(struct b43_wldev *dev) +static void b43_radio_init2060(struct b43_wldev *dev) { b43_radio_write16(dev, 0x0004, 0x00C0); b43_radio_write16(dev, 0x0005, 0x0008); diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c index af37abccccb39e4f3ca7f7c1bcd465ef5fc10ac1..026b61c03fb9fb4432492bc8ddad32a617d72b6a 100644 --- a/drivers/net/wireless/b43/phy_common.c +++ b/drivers/net/wireless/b43/phy_common.c @@ -178,13 +178,27 @@ void b43_phy_unlock(struct b43_wldev *dev) b43_power_saving_ctl_bits(dev, 0); } +static inline void assert_mac_suspended(struct b43_wldev *dev) +{ + if (!B43_DEBUG) + return; + if ((b43_status(dev) >= B43_STAT_INITIALIZED) && + (dev->mac_suspended <= 0)) { + b43dbg(dev->wl, "PHY/RADIO register access with " + "enabled MAC.\n"); + dump_stack(); + } +} + u16 b43_radio_read(struct b43_wldev *dev, u16 reg) { + assert_mac_suspended(dev); return dev->phy.ops->radio_read(dev, reg); } void b43_radio_write(struct b43_wldev *dev, u16 reg, u16 value) { + assert_mac_suspended(dev); dev->phy.ops->radio_write(dev, reg, value); } @@ -208,11 +222,13 @@ void b43_radio_maskset(struct b43_wldev *dev, u16 offset, u16 mask, u16 set) u16 b43_phy_read(struct b43_wldev *dev, u16 reg) { + assert_mac_suspended(dev); return dev->phy.ops->phy_read(dev, reg); } void b43_phy_write(struct b43_wldev *dev, u16 reg, u16 value) { + assert_mac_suspended(dev); dev->phy.ops->phy_write(dev, reg, value); } @@ -280,8 +296,10 @@ void b43_software_rfkill(struct b43_wldev *dev, enum rfkill_state state) state = RFKILL_STATE_SOFT_BLOCKED; } + b43_mac_suspend(dev); phy->ops->software_rfkill(dev, state); phy->radio_on = (state == RFKILL_STATE_UNBLOCKED); + b43_mac_enable(dev); } /** diff --git a/drivers/net/wireless/b43/phy_g.c b/drivers/net/wireless/b43/phy_g.c index 232181f6333c453eb6d0f030c07d60da1d0f2c73..caac4a45f0bf799bcf576c4ec0ede550008bc6ad 100644 --- a/drivers/net/wireless/b43/phy_g.c +++ b/drivers/net/wireless/b43/phy_g.c @@ -54,7 +54,7 @@ static const s8 b43_tssi2dbm_g_table[] = { -20, -20, -20, -20, }; -const u8 b43_radio_channel_codes_bg[] = { +static const u8 b43_radio_channel_codes_bg[] = { 12, 17, 22, 27, 32, 37, 42, 47, 52, 57, 62, 67, @@ -215,9 +215,9 @@ void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev, } /* Adjust the transmission power output (G-PHY) */ -void b43_set_txpower_g(struct b43_wldev *dev, - const struct b43_bbatt *bbatt, - const struct b43_rfatt *rfatt, u8 tx_control) +static void b43_set_txpower_g(struct b43_wldev *dev, + const struct b43_bbatt *bbatt, + const struct b43_rfatt *rfatt, u8 tx_control) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; @@ -383,14 +383,14 @@ static void b43_set_original_gains(struct b43_wldev *dev) } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) +static void b43_nrssi_hw_write(struct b43_wldev *dev, u16 offset, s16 val) { b43_phy_write(dev, B43_PHY_NRSSILT_CTRL, offset); b43_phy_write(dev, B43_PHY_NRSSILT_DATA, (u16) val); } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) +static s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) { u16 val; @@ -401,7 +401,7 @@ s16 b43_nrssi_hw_read(struct b43_wldev *dev, u16 offset) } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) +static void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) { u16 i; s16 tmp; @@ -415,7 +415,7 @@ void b43_nrssi_hw_update(struct b43_wldev *dev, u16 val) } /* http://bcm-specs.sipsolutions.net/NRSSILookupTable */ -void b43_nrssi_mem_update(struct b43_wldev *dev) +static void b43_nrssi_mem_update(struct b43_wldev *dev) { struct b43_phy_g *gphy = dev->phy.g; s16 i, delta; @@ -589,7 +589,7 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev) b43_phy_write(dev, 0x0811, backup[1]); } -void b43_calc_nrssi_slope(struct b43_wldev *dev) +static void b43_calc_nrssi_slope(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; @@ -1354,7 +1354,7 @@ struct init2050_saved_values { u16 phy_syncctl; }; -u16 b43_radio_init2050(struct b43_wldev *dev) +static u16 b43_radio_init2050(struct b43_wldev *dev) { struct b43_phy *phy = &dev->phy; struct init2050_saved_values sav; @@ -3047,6 +3047,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) int rfatt, bbatt; u8 tx_control; + b43_mac_suspend(dev); + spin_lock_irq(&dev->wl->irq_lock); /* Calculate the new attenuation values. */ @@ -3103,6 +3105,8 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev) gphy->tx_control); b43_radio_unlock(dev); b43_phy_unlock(dev); + + b43_mac_enable(dev); } static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev, @@ -3215,9 +3219,9 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) struct b43_phy *phy = &dev->phy; struct b43_phy_g *gphy = phy->g; + b43_mac_suspend(dev); //TODO: update_aci_moving_average if (gphy->aci_enable && gphy->aci_wlan_automatic) { - b43_mac_suspend(dev); if (!gphy->aci_enable && 1 /*TODO: not scanning? */ ) { if (0 /*TODO: bunch of conditions */ ) { phy->ops->interf_mitigation(dev, @@ -3227,12 +3231,12 @@ static void b43_gphy_op_pwork_15sec(struct b43_wldev *dev) if (/*(aci_average > 1000) &&*/ !b43_gphy_aci_scan(dev)) phy->ops->interf_mitigation(dev, B43_INTERFMODE_NONE); } - b43_mac_enable(dev); } else if (gphy->interfmode == B43_INTERFMODE_NONWLAN && phy->rev == 1) { //TODO: implement rev1 workaround } b43_lo_g_maintanance_work(dev); + b43_mac_enable(dev); } static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev) diff --git a/drivers/net/wireless/b43/pio.c b/drivers/net/wireless/b43/pio.c index 4015912675922f4a5e9f8e6249885f70d364c8b1..1036bef8c4cc398e0fe72c16e09c4b43f67c45a3 100644 --- a/drivers/net/wireless/b43/pio.c +++ b/drivers/net/wireless/b43/pio.c @@ -587,9 +587,8 @@ void b43_pio_handle_txstatus(struct b43_wldev *dev, spin_lock(&q->lock); /* IRQs are already disabled. */ info = IEEE80211_SKB_CB(pack->skb); - memset(&info->status, 0, sizeof(info->status)); - b43_fill_txstatus_report(info, status); + b43_fill_txstatus_report(dev, info, status); total_len = pack->skb->len + b43_txhdr_size(dev); total_len = roundup(total_len, 4); diff --git a/drivers/net/wireless/b43/xmit.c b/drivers/net/wireless/b43/xmit.c index 2fabcf8f0474253bba1dca6fb46fa7b7afd4584c..eae9b8052658c3c28de328df9016a0bb82917ff8 100644 --- a/drivers/net/wireless/b43/xmit.c +++ b/drivers/net/wireless/b43/xmit.c @@ -46,7 +46,6 @@ static int b43_plcp_get_bitrate_idx_cck(struct b43_plcp_hdr6 *plcp) case 0x6E: return 3; } - B43_WARN_ON(1); return -1; } @@ -73,7 +72,6 @@ static u8 b43_plcp_get_bitrate_idx_ofdm(struct b43_plcp_hdr6 *plcp, bool aphy) case 0xC: return base + 7; } - B43_WARN_ON(1); return -1; } @@ -185,7 +183,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 *_txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { struct b43_txhdr *txhdr = (struct b43_txhdr *)_txhdr; @@ -202,6 +200,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u16 phy_ctl = 0; u8 extra_ft = 0; struct ieee80211_rate *txrate; + struct ieee80211_tx_rate *rates; memset(txhdr, 0, sizeof(*txhdr)); @@ -291,7 +290,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, phy_ctl |= B43_TXH_PHY_ENC_OFDM; else phy_ctl |= B43_TXH_PHY_ENC_CCK; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43_TXH_PHY_SHORTPRMBL; switch (b43_ieee80211_antenna_sanitize(dev, info->antenna_sel_tx)) { @@ -314,6 +313,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, B43_WARN_ON(1); } + rates = info->control.rates; /* MAC control */ if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43_TXH_MAC_ACK; @@ -324,12 +324,22 @@ int b43_generate_txhdr(struct b43_wldev *dev, mac_ctl |= B43_TXH_MAC_STMSDU; if (phy->type == B43_PHYTYPE_A) mac_ctl |= B43_TXH_MAC_5GHZ; - if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + + /* Overwrite rates[0].count to make the retry calculation + * in the tx status easier. need the actual retry limit to + * detect whether the fallback rate was used. + */ + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) { + rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count; mac_ctl |= B43_TXH_MAC_LONGFRAME; + } else { + rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count; + } /* Generate the RTS or CTS-to-self frame */ - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate, rts_rate_fb; @@ -344,7 +354,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, rts_rate_fb = b43_calc_fallback_rate(rts_rate); rts_rate_fb_ofdm = b43_is_ofdm_rate(rts_rate_fb); - if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { struct ieee80211_cts *cts; if (b43_is_old_txhdr_format(dev)) { @@ -596,6 +606,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr) phytype == B43_PHYTYPE_A); else status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp); + if (unlikely(status.rate_idx == -1)) + goto drop; status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT); /* @@ -687,10 +699,18 @@ void b43_handle_txstatus(struct b43_wldev *dev, /* Fill out the mac80211 TXstatus report based on the b43-specific * txstatus report data. This returns a boolean whether the frame was * successfully transmitted. */ -bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, +bool b43_fill_txstatus_report(struct b43_wldev *dev, + struct ieee80211_tx_info *report, const struct b43_txstatus *status) { bool frame_success = 1; + int retry_limit; + + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = report->status.rates[0].count; + ieee80211_tx_info_clear_status(report); if (status->acked) { /* The frame was ACKed. */ @@ -700,14 +720,32 @@ bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, if (!(report->flags & IEEE80211_TX_CTL_NO_ACK)) { /* ...but we expected an ACK. */ frame_success = 0; - report->status.excessive_retries = 1; } } if (status->frame_count == 0) { /* The frame was not transmitted at all. */ - report->status.retry_count = 0; - } else - report->status.retry_count = status->frame_count - 1; + report->status.rates[0].count = 0; + } else if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + report->status.rates[0].count = 0; + report->status.rates[1].count = status->frame_count; + } else { + if (status->frame_count > retry_limit) { + report->status.rates[0].count = retry_limit; + report->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + report->status.rates[0].count = status->frame_count; + report->status.rates[1].idx = -1; + } + } return frame_success; } diff --git a/drivers/net/wireless/b43/xmit.h b/drivers/net/wireless/b43/xmit.h index 0215faf4754181cb6069b4878349d3d4c48e88d6..4fb2a190f7a74fc8f1a8cd9b44a27beff263281f 100644 --- a/drivers/net/wireless/b43/xmit.h +++ b/drivers/net/wireless/b43/xmit.h @@ -178,7 +178,7 @@ int b43_generate_txhdr(struct b43_wldev *dev, u8 * txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *txctl, u16 cookie); + struct ieee80211_tx_info *txctl, u16 cookie); /* Transmit Status */ struct b43_txstatus { @@ -294,7 +294,8 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr); void b43_handle_txstatus(struct b43_wldev *dev, const struct b43_txstatus *status); -bool b43_fill_txstatus_report(struct ieee80211_tx_info *report, +bool b43_fill_txstatus_report(struct b43_wldev *dev, + struct ieee80211_tx_info *report, const struct b43_txstatus *status); void b43_tx_suspend(struct b43_wldev *dev); diff --git a/drivers/net/wireless/b43legacy/b43legacy.h b/drivers/net/wireless/b43legacy/b43legacy.h index c40078e1fff9f3efabfa92f787dcb7217018669d..97b0e06dfe219bf6a4614bcabed70efaa67521b4 100644 --- a/drivers/net/wireless/b43legacy/b43legacy.h +++ b/drivers/net/wireless/b43legacy/b43legacy.h @@ -145,6 +145,10 @@ #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 */ +#define B43legacy_SHM_SH_OFDMDIRECT 0x0480 /* Pointer to OFDM direct map */ +#define B43legacy_SHM_SH_OFDMBASIC 0x04A0 /* Pointer to OFDM basic rate map */ +#define B43legacy_SHM_SH_CCKDIRECT 0x04C0 /* Pointer to CCK direct map */ +#define B43legacy_SHM_SH_CCKBASIC 0x04E0 /* Pointer to CCK basic rate map */ /* SHM_SHARED microcode soft registers */ #define B43legacy_SHM_SH_UCODEREV 0x0000 /* Microcode revision */ #define B43legacy_SHM_SH_UCODEPATCH 0x0002 /* Microcode patchlevel */ @@ -663,7 +667,6 @@ struct b43legacy_wldev { bool bad_frames_preempt;/* Use "Bad Frames Preemption". */ 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. */ /* PHY/Radio device. */ diff --git a/drivers/net/wireless/b43legacy/debugfs.c b/drivers/net/wireless/b43legacy/debugfs.c index 03ce0821a60eb86e9f327675c9069bc1b64ecb1b..1f85ac569fec0065868fb4341971dfec9c83480f 100644 --- a/drivers/net/wireless/b43legacy/debugfs.c +++ b/drivers/net/wireless/b43legacy/debugfs.c @@ -211,7 +211,7 @@ static ssize_t b43legacy_debugfs_read(struct file *file, char __user *userbuf, struct b43legacy_dfs_file *dfile; ssize_t uninitialized_var(ret); char *buf; - const size_t bufsize = 1024 * 128; + const size_t bufsize = 1024 * 16; /* 16 KiB buffer */ const size_t buforder = get_order(bufsize); int err = 0; diff --git a/drivers/net/wireless/b43legacy/dma.c b/drivers/net/wireless/b43legacy/dma.c index fb6819e40f383442a7c73ceb254f866e1dc6eb9b..3649fc3670988219cd99185fc3acfbec6e162b3e 100644 --- a/drivers/net/wireless/b43legacy/dma.c +++ b/drivers/net/wireless/b43legacy/dma.c @@ -919,7 +919,7 @@ struct b43legacy_dmaring *b43legacy_setup_dmaring(struct b43legacy_wldev *dev, if (!ring->txhdr_cache) goto err_kfree_meta; - dma_test = ssb_dma_map_single(dev->dev, + dma_test = ssb_dma_map_single(dev->dev, ring->txhdr_cache, sizeof(struct b43legacy_txhdr_fw3), DMA_TO_DEVICE); @@ -1411,6 +1411,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, struct b43legacy_dmaring *ring; struct b43legacy_dmadesc_generic *desc; struct b43legacy_dmadesc_meta *meta; + int retry_limit; int slot; ring = parse_cookie(dev, status->cookie, &slot); @@ -1437,25 +1438,42 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev, struct ieee80211_tx_info *info; BUG_ON(!meta->skb); info = IEEE80211_SKB_CB(meta->skb); - /* Call back to inform the ieee80211 subsystem about the - * status of the transmission. - * Some fields of txstat are already filled in dma_tx(). - */ - memset(&info->status, 0, sizeof(info->status)); + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = info->status.rates[0].count; + ieee80211_tx_info_clear_status(info); - if (status->acked) { + if (status->acked) info->flags |= IEEE80211_TX_STAT_ACK; + + if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + info->status.rates[0].count = 0; + info->status.rates[1].count = status->frame_count; } else { - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) - info->status.excessive_retries = 1; + if (status->frame_count > retry_limit) { + info->status.rates[0].count = retry_limit; + info->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + info->status.rates[0].count = status->frame_count; + info->status.rates[1].idx = -1; + } } - if (status->frame_count == 0) { - /* The frame was not transmitted at all. */ - info->status.retry_count = 0; - } else - info->status.retry_count = status->frame_count - - 1; + + /* Call back to inform the ieee80211 subsystem about the + * status of the transmission. + * Some fields of txstat are already filled in dma_tx(). + */ ieee80211_tx_status_irqsafe(dev->wl->hw, meta->skb); /* skb is freed by ieee80211_tx_status_irqsafe() */ meta->skb = NULL; diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c index c66d57560e7ceb97af514a8c4bc05e07f03e9971..c1324e31d2f6465e0260e4df84e6e85c49c35e28 100644 --- a/drivers/net/wireless/b43legacy/main.c +++ b/drivers/net/wireless/b43legacy/main.c @@ -576,13 +576,11 @@ static void b43legacy_set_slot_time(struct b43legacy_wldev *dev, static void b43legacy_short_slot_timing_enable(struct b43legacy_wldev *dev) { b43legacy_set_slot_time(dev, 9); - dev->short_slot = 1; } static void b43legacy_short_slot_timing_disable(struct b43legacy_wldev *dev) { b43legacy_set_slot_time(dev, 20); - dev->short_slot = 0; } /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable. @@ -1160,29 +1158,6 @@ static void b43legacy_update_templates(struct b43legacy_wl *wl) wl->beacon1_uploaded = 0; } -static void b43legacy_set_ssid(struct b43legacy_wldev *dev, - const u8 *ssid, u8 ssid_len) -{ - u32 tmp; - u16 i; - u16 len; - - len = min((u16)ssid_len, (u16)0x100); - for (i = 0; i < len; i += sizeof(u32)) { - tmp = (u32)(ssid[i + 0]); - if (i + 1 < len) - tmp |= (u32)(ssid[i + 1]) << 8; - if (i + 2 < len) - tmp |= (u32)(ssid[i + 2]) << 16; - if (i + 3 < len) - tmp |= (u32)(ssid[i + 3]) << 24; - b43legacy_shm_write32(dev, B43legacy_SHM_SHARED, - 0x380 + i, tmp); - } - b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, - 0x48, len); -} - static void b43legacy_set_beacon_int(struct b43legacy_wldev *dev, u16 beacon_int) { @@ -2556,26 +2531,27 @@ init_failure: return err; } -static int b43legacy_antenna_from_ieee80211(u8 antenna) +/* Write the short and long frame retry limit values. */ +static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev, + unsigned int short_retry, + unsigned int long_retry) { - switch (antenna) { - case 0: /* default/diversity */ - return B43legacy_ANTENNA_DEFAULT; - case 1: /* Antenna 0 */ - return B43legacy_ANTENNA0; - case 2: /* Antenna 1 */ - return B43legacy_ANTENNA1; - default: - return B43legacy_ANTENNA_DEFAULT; - } + /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing + * the chip-internal counter. */ + short_retry = min(short_retry, (unsigned int)0xF); + long_retry = min(long_retry, (unsigned int)0xF); + + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry); + b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry); } static int b43legacy_op_dev_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) + u32 changed) { struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); struct b43legacy_wldev *dev; struct b43legacy_phy *phy; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; unsigned int new_phymode = 0xFFFF; int antenna_tx; @@ -2583,13 +2559,21 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, int err = 0; u32 savedirqs; - antenna_tx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_tx); - antenna_rx = b43legacy_antenna_from_ieee80211(conf->antenna_sel_rx); + antenna_tx = B43legacy_ANTENNA_DEFAULT; + antenna_rx = B43legacy_ANTENNA_DEFAULT; mutex_lock(&wl->mutex); dev = wl->current_dev; phy = &dev->phy; + if (changed & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + b43legacy_set_retry_limits(dev, + conf->short_frame_max_tx_count, + conf->long_frame_max_tx_count); + changed &= ~IEEE80211_CONF_CHANGE_RETRY_LIMITS; + if (!changed) + goto out_unlock_mutex; + /* Switch the PHY mode (if necessary). */ switch (conf->channel->band) { case IEEE80211_BAND_2GHZ: @@ -2622,16 +2606,6 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw, 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)) - != dev->short_slot) { - B43legacy_WARN_ON(phy->type != B43legacy_PHYTYPE_G); - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) - b43legacy_short_slot_timing_enable(dev); - else - b43legacy_short_slot_timing_disable(dev); - } - dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP); /* Adjust the desired TX power level. */ @@ -2676,6 +2650,104 @@ out_unlock_mutex: return err; } +static void b43legacy_update_basic_rates(struct b43legacy_wldev *dev, u64 brates) +{ + struct ieee80211_supported_band *sband = + dev->wl->hw->wiphy->bands[IEEE80211_BAND_2GHZ]; + struct ieee80211_rate *rate; + int i; + u16 basic, direct, offset, basic_offset, rateptr; + + for (i = 0; i < sband->n_bitrates; i++) { + rate = &sband->bitrates[i]; + + if (b43legacy_is_cck_rate(rate->hw_value)) { + direct = B43legacy_SHM_SH_CCKDIRECT; + basic = B43legacy_SHM_SH_CCKBASIC; + offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value); + offset &= 0xF; + } else { + direct = B43legacy_SHM_SH_OFDMDIRECT; + basic = B43legacy_SHM_SH_OFDMBASIC; + offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value); + offset &= 0xF; + } + + rate = ieee80211_get_response_rate(sband, brates, rate->bitrate); + + if (b43legacy_is_cck_rate(rate->hw_value)) { + basic_offset = b43legacy_plcp_get_ratecode_cck(rate->hw_value); + basic_offset &= 0xF; + } else { + basic_offset = b43legacy_plcp_get_ratecode_ofdm(rate->hw_value); + basic_offset &= 0xF; + } + + /* + * Get the pointer that we need to point to + * from the direct map + */ + rateptr = b43legacy_shm_read16(dev, B43legacy_SHM_SHARED, + direct + 2 * basic_offset); + /* and write it to the basic map */ + b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, + basic + 2 * offset, rateptr); + } +} + +static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *conf, + u32 changed) +{ + struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); + struct b43legacy_wldev *dev; + struct b43legacy_phy *phy; + unsigned long flags; + u32 savedirqs; + + mutex_lock(&wl->mutex); + + dev = wl->current_dev; + phy = &dev->phy; + + /* Disable IRQs while reconfiguring the device. + * This makes it possible to drop the spinlock throughout + * the reconfiguration process. */ + spin_lock_irqsave(&wl->irq_lock, flags); + if (b43legacy_status(dev) < B43legacy_STAT_STARTED) { + spin_unlock_irqrestore(&wl->irq_lock, flags); + goto out_unlock_mutex; + } + savedirqs = b43legacy_interrupt_disable(dev, B43legacy_IRQ_ALL); + spin_unlock_irqrestore(&wl->irq_lock, flags); + b43legacy_synchronize_irq(dev); + + b43legacy_mac_suspend(dev); + + if (changed & BSS_CHANGED_BASIC_RATES) + b43legacy_update_basic_rates(dev, conf->basic_rates); + + if (changed & BSS_CHANGED_ERP_SLOT) { + if (conf->use_short_slot) + b43legacy_short_slot_timing_enable(dev); + else + b43legacy_short_slot_timing_disable(dev); + } + + b43legacy_mac_enable(dev); + + spin_lock_irqsave(&wl->irq_lock, flags); + b43legacy_interrupt_enable(dev, savedirqs); + /* XXX: why? */ + mmiowb(); + spin_unlock_irqrestore(&wl->irq_lock, flags); + out_unlock_mutex: + mutex_unlock(&wl->mutex); + + return; +} + static void b43legacy_op_configure_filter(struct ieee80211_hw *hw, unsigned int changed, unsigned int *fflags, @@ -2735,7 +2807,6 @@ static int b43legacy_op_config_interface(struct ieee80211_hw *hw, if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) { if (b43legacy_is_mode(wl, NL80211_IFTYPE_AP)) { B43legacy_WARN_ON(vif->type != NL80211_IFTYPE_AP); - b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len); if (conf->changed & IEEE80211_IFCC_BEACON) b43legacy_update_templates(wl); } else if (b43legacy_is_mode(wl, NL80211_IFTYPE_ADHOC)) { @@ -3002,20 +3073,6 @@ static void b43legacy_imcfglo_timeouts_workaround(struct b43legacy_wldev *dev) #endif /* CONFIG_SSB_DRIVER_PCICORE */ } -/* Write the short and long frame retry limit values. */ -static void b43legacy_set_retry_limits(struct b43legacy_wldev *dev, - unsigned int short_retry, - unsigned int long_retry) -{ - /* The retry limit is a 4-bit counter. Enforce this to avoid overflowing - * the chip-internal counter. */ - short_retry = min(short_retry, (unsigned int)0xF); - long_retry = min(long_retry, (unsigned int)0xF); - - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0006, short_retry); - b43legacy_shm_write16(dev, B43legacy_SHM_WIRELESS, 0x0007, long_retry); -} - static void b43legacy_set_synth_pu_delay(struct b43legacy_wldev *dev, bool idle) { u16 pu_delay = 1050; @@ -3380,28 +3437,6 @@ static void b43legacy_op_stop(struct ieee80211_hw *hw) mutex_unlock(&wl->mutex); } -static int b43legacy_op_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry_limit, - u32 long_retry_limit) -{ - struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); - struct b43legacy_wldev *dev; - int err = 0; - - mutex_lock(&wl->mutex); - dev = wl->current_dev; - if (unlikely(!dev || - (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED))) { - err = -ENODEV; - goto out_unlock; - } - b43legacy_set_retry_limits(dev, short_retry_limit, long_retry_limit); -out_unlock: - mutex_unlock(&wl->mutex); - - return err; -} - static int b43legacy_op_beacon_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, bool set) { @@ -3421,13 +3456,13 @@ static const struct ieee80211_ops b43legacy_hw_ops = { .add_interface = b43legacy_op_add_interface, .remove_interface = b43legacy_op_remove_interface, .config = b43legacy_op_dev_config, + .bss_info_changed = b43legacy_op_bss_info_changed, .config_interface = b43legacy_op_config_interface, .configure_filter = b43legacy_op_configure_filter, .get_stats = b43legacy_op_get_stats, .get_tx_stats = b43legacy_op_get_tx_stats, .start = b43legacy_op_start, .stop = b43legacy_op_stop, - .set_retry_limit = b43legacy_op_set_retry_limit, .set_tim = b43legacy_op_beacon_set_tim, }; @@ -3710,7 +3745,7 @@ static int b43legacy_wireless_init(struct ssb_device *dev) BIT(NL80211_IFTYPE_WDS) | BIT(NL80211_IFTYPE_ADHOC); hw->queues = 1; /* FIXME: hardware has more queues */ - hw->max_altrates = 1; + hw->max_rates = 2; SET_IEEE80211_DEV(hw, dev->dev); if (is_valid_ether_addr(sprom->et1mac)) SET_IEEE80211_PERM_ADDR(hw, sprom->et1mac); diff --git a/drivers/net/wireless/b43legacy/phy.c b/drivers/net/wireless/b43legacy/phy.c index 4c9442b16f3fb51ce9505ac5ac013d2d453d6f49..11319ec2d64a75d0788a3e6ea97357973b766da5 100644 --- a/drivers/net/wireless/b43legacy/phy.c +++ b/drivers/net/wireless/b43legacy/phy.c @@ -1296,12 +1296,10 @@ void b43legacy_lo_write(struct b43legacy_wldev *dev, /* Sanity check. */ if (pair->low < -8 || pair->low > 8 || pair->high < -8 || pair->high > 8) { - struct b43legacy_phy *phy = &dev->phy; b43legacydbg(dev->wl, "WARNING: Writing invalid LOpair " - "(low: %d, high: %d, index: %lu)\n", - pair->low, pair->high, - (unsigned long)(pair - phy->_lo_pairs)); + "(low: %d, high: %d)\n", + pair->low, pair->high); dump_stack(); } #endif diff --git a/drivers/net/wireless/b43legacy/pio.c b/drivers/net/wireless/b43legacy/pio.c index a86c7647fa2d62caec9027d316f3ddd648f156a6..746d5361bba017b56838c6cf5b5c54add2cd0317 100644 --- a/drivers/net/wireless/b43legacy/pio.c +++ b/drivers/net/wireless/b43legacy/pio.c @@ -491,6 +491,7 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, struct b43legacy_pioqueue *queue; struct b43legacy_pio_txpacket *packet; struct ieee80211_tx_info *info; + int retry_limit; queue = parse_cookie(dev, status->cookie, &packet); B43legacy_WARN_ON(!queue); @@ -503,11 +504,37 @@ void b43legacy_pio_handle_txstatus(struct b43legacy_wldev *dev, sizeof(struct b43legacy_txhdr_fw3)); info = IEEE80211_SKB_CB(packet->skb); - memset(&info->status, 0, sizeof(info->status)); + + /* preserve the confiured retry limit before clearing the status + * The xmit function has overwritten the rc's value with the actual + * retry limit done by the hardware */ + retry_limit = info->status.rates[0].count; + ieee80211_tx_info_clear_status(info); if (status->acked) info->flags |= IEEE80211_TX_STAT_ACK; - info->status.retry_count = status->frame_count - 1; + + if (status->rts_count > dev->wl->hw->conf.short_frame_max_tx_count) { + /* + * If the short retries (RTS, not data frame) have exceeded + * the limit, the hw will not have tried the selected rate, + * but will have used the fallback rate instead. + * Don't let the rate control count attempts for the selected + * rate in this case, otherwise the statistics will be off. + */ + info->status.rates[0].count = 0; + info->status.rates[1].count = status->frame_count; + } else { + if (status->frame_count > retry_limit) { + info->status.rates[0].count = retry_limit; + info->status.rates[1].count = status->frame_count - + retry_limit; + + } else { + info->status.rates[0].count = status->frame_count; + info->status.rates[1].idx = -1; + } + } ieee80211_tx_status_irqsafe(dev->wl->hw, packet->skb); packet->skb = NULL; diff --git a/drivers/net/wireless/b43legacy/xmit.c b/drivers/net/wireless/b43legacy/xmit.c index 65e833781608ecda0629e85dd6755dcf9104847c..12fca99f7578d28744eb8a815fac0b7a2adcddcd 100644 --- a/drivers/net/wireless/b43legacy/xmit.c +++ b/drivers/net/wireless/b43legacy/xmit.c @@ -188,7 +188,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, struct b43legacy_txhdr_fw3 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { const struct ieee80211_hdr *wlhdr; @@ -201,6 +201,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, u32 mac_ctl = 0; u16 phy_ctl = 0; struct ieee80211_rate *tx_rate; + struct ieee80211_tx_rate *rates; wlhdr = (const struct ieee80211_hdr *)fragment_data; @@ -274,7 +275,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, /* PHY TX Control word */ if (rate_ofdm) phy_ctl |= B43legacy_TX4_PHY_OFDM; - if (dev->short_preamble) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) phy_ctl |= B43legacy_TX4_PHY_SHORTPRMBL; switch (info->antenna_sel_tx) { case 0: @@ -291,6 +292,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, } /* MAC control */ + rates = info->control.rates; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) mac_ctl |= B43legacy_TX4_MAC_ACK; if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) @@ -299,12 +301,22 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, mac_ctl |= B43legacy_TX4_MAC_STMSDU; if (rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_FALLBACKOFDM; - if (info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + + /* Overwrite rates[0].count to make the retry calculation + * in the tx status easier. need the actual retry limit to + * detect whether the fallback rate was used. + */ + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].count <= dev->wl->hw->conf.long_frame_max_tx_count)) { + rates[0].count = dev->wl->hw->conf.long_frame_max_tx_count; mac_ctl |= B43legacy_TX4_MAC_LONGFRAME; + } else { + rates[0].count = dev->wl->hw->conf.short_frame_max_tx_count; + } /* Generate the RTS or CTS-to-self frame */ - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { + if ((rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) { unsigned int len; struct ieee80211_hdr *hdr; int rts_rate; @@ -319,7 +331,7 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev, if (rts_rate_fb_ofdm) mac_ctl |= B43legacy_TX4_MAC_CTSFALLBACKOFDM; - if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + if (rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { ieee80211_ctstoself_get(dev->wl->hw, info->control.vif, fragment_data, @@ -362,7 +374,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie) { return generate_txhdr_fw3(dev, (struct b43legacy_txhdr_fw3 *)txhdr, diff --git a/drivers/net/wireless/b43legacy/xmit.h b/drivers/net/wireless/b43legacy/xmit.h index e56777e0feabf7f0e4552449e29daf91c8b11577..62e09d02788fb74648b13bfe324c35588ee50d87 100644 --- a/drivers/net/wireless/b43legacy/xmit.h +++ b/drivers/net/wireless/b43legacy/xmit.h @@ -80,7 +80,7 @@ int b43legacy_generate_txhdr(struct b43legacy_wldev *dev, u8 *txhdr, const unsigned char *fragment_data, unsigned int fragment_len, - const struct ieee80211_tx_info *info, + struct ieee80211_tx_info *info, u16 cookie); diff --git a/drivers/net/wireless/hostap/Kconfig b/drivers/net/wireless/hostap/Kconfig index 1fef33169fdd0c133c995bb2d173851674c3848c..932d207bce231955548e6e68adbc1585bb1e4b59 100644 --- a/drivers/net/wireless/hostap/Kconfig +++ b/drivers/net/wireless/hostap/Kconfig @@ -2,8 +2,17 @@ config HOSTAP tristate "IEEE 802.11 for Host AP (Prism2/2.5/3 and WEP/TKIP/CCMP)" depends on WLAN_80211 select WIRELESS_EXT - select IEEE80211 - select IEEE80211_CRYPT_WEP + select CRYPTO + select CRYPTO_ARC4 + select CRYPTO_ECB + select CRYPTO_AES + select CRYPTO_MICHAEL_MIC + select CRYPTO_ECB + select CRC32 + select LIB80211 + select LIB80211_CRYPT_WEP + select LIB80211_CRYPT_TKIP + select LIB80211_CRYPT_CCMP ---help--- Shared driver code for IEEE 802.11b wireless cards based on Intersil Prism2/2.5/3 chipset. This driver supports so called diff --git a/drivers/net/wireless/hostap/hostap.h b/drivers/net/wireless/hostap/hostap.h index 3a386a636cca4a0f2aad3f24cf259908fa1729ef..2453deaa3e009e03faab3f92850d012f6f808bbf 100644 --- a/drivers/net/wireless/hostap/hostap.h +++ b/drivers/net/wireless/hostap/hostap.h @@ -63,7 +63,7 @@ void ap_control_flush_macs(struct mac_restrictions *mac_restrictions); int ap_control_kick_mac(struct ap_data *ap, struct net_device *dev, u8 *mac); void ap_control_kickall(struct ap_data *ap); void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct ieee80211_crypt_data ***crypt); + struct lib80211_crypt_data ***crypt); int prism2_ap_get_sta_qual(local_info_t *local, struct sockaddr addr[], struct iw_quality qual[], int buf_size, int aplist); diff --git a/drivers/net/wireless/hostap/hostap_80211.h b/drivers/net/wireless/hostap/hostap_80211.h index 3694b1eba521cbca531bb56574abb643da79f9a8..3a9474d9a90780b7bbde1b83e2c91f14cd3b27bd 100644 --- a/drivers/net/wireless/hostap/hostap_80211.h +++ b/drivers/net/wireless/hostap/hostap_80211.h @@ -2,7 +2,7 @@ #define HOSTAP_80211_H #include -#include +#include struct hostap_ieee80211_mgmt { __le16 frame_control; diff --git a/drivers/net/wireless/hostap/hostap_80211_rx.c b/drivers/net/wireless/hostap/hostap_80211_rx.c index f106bc1585a45bbeacb1c1a6f2716e2ac8dfc1b0..19b1bf0478bd62ae4e34c23a44f6cfb9a7c947f8 100644 --- a/drivers/net/wireless/hostap/hostap_80211_rx.c +++ b/drivers/net/wireless/hostap/hostap_80211_rx.c @@ -1,5 +1,5 @@ #include -#include +#include #include "hostap_80211.h" #include "hostap.h" @@ -19,7 +19,6 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, { struct ieee80211_hdr_4addr *hdr; u16 fc; - DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; @@ -45,11 +44,11 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb, printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), le16_to_cpu(hdr->seq_ctl)); - printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1)); - printk(" A2=%s", print_mac(mac, hdr->addr2)); - printk(" A3=%s", print_mac(mac, hdr->addr3)); + printk(KERN_DEBUG " A1=%pM", hdr->addr1); + printk(" A2=%pM", hdr->addr2); + printk(" A3=%pM", hdr->addr3); if (skb->len >= 30) - printk(" A4=%s", print_mac(mac, hdr->addr4)); + printk(" A4=%pM", hdr->addr4); printk("\n"); } @@ -68,7 +67,6 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb, iface = netdev_priv(dev); local = iface->local; - dev->last_rx = jiffies; if (dev->type == ARPHRD_IEEE80211_PRISM) { if (local->monitor_type == PRISM2_MONITOR_PRISM) { @@ -557,7 +555,6 @@ static int hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, u16 fc, struct net_device **wds) { - DECLARE_MAC_BUF(mac); /* FIX: is this really supposed to accept WDS frames only in Master * mode? What about Repeater or Managed with WDS frames? */ if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) != @@ -573,10 +570,10 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, hdr->addr1[4] != 0xff || hdr->addr1[5] != 0xff)) { /* RA (or BSSID) is not ours - drop */ PDEBUG(DEBUG_EXTRA2, "%s: received WDS frame with " - "not own or broadcast %s=%s\n", + "not own or broadcast %s=%pM\n", local->dev->name, fc & IEEE80211_FCTL_FROMDS ? "RA" : "BSSID", - print_mac(mac, hdr->addr1)); + hdr->addr1); return -1; } @@ -589,8 +586,8 @@ hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr, /* require that WDS link has been registered with TA or the * frame is from current AP when using 'AP client mode' */ PDEBUG(DEBUG_EXTRA, "%s: received WDS[4 addr] frame " - "from unknown TA=%s\n", - local->dev->name, print_mac(mac, hdr->addr2)); + "from unknown TA=%pM\n", + local->dev->name, hdr->addr2); if (local->ap && local->ap->autom_ap_wds) hostap_wds_link_oper(local, hdr->addr2, WDS_ADD); return -1; @@ -652,7 +649,7 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb) /* Called only as a tasklet (software IRQ) */ static int hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) + struct lib80211_crypt_data *crypt) { struct ieee80211_hdr_4addr *hdr; int res, hdrlen; @@ -667,10 +664,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, strcmp(crypt->ops->name, "TKIP") == 0) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "received packet from " MAC_FMT "\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "received packet from %pM\n", + local->dev->name, hdr->addr2); } return -1; } @@ -679,12 +674,8 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { - printk(KERN_DEBUG "%s: decryption failed (SA=" MAC_FMT - ") res=%d\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - res); + printk(KERN_DEBUG "%s: decryption failed (SA=%pM) res=%d\n", + local->dev->name, hdr->addr2, res); local->comm_tallies.rx_discards_wep_undecryptable++; return -1; } @@ -696,11 +687,10 @@ hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb, /* Called only as a tasklet (software IRQ) */ static int hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, - int keyidx, struct ieee80211_crypt_data *crypt) + int keyidx, struct lib80211_crypt_data *crypt) { struct ieee80211_hdr_4addr *hdr; int res, hdrlen; - DECLARE_MAC_BUF(mac); if (crypt == NULL || crypt->ops->decrypt_msdu == NULL) return 0; @@ -713,8 +703,8 @@ hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb, atomic_dec(&crypt->refcnt); if (res < 0) { printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=%s keyidx=%d)\n", - local->dev->name, print_mac(mac, hdr->addr2), keyidx); + " (SA=%pM keyidx=%d)\n", + local->dev->name, hdr->addr2, keyidx); return -1; } @@ -743,7 +733,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, int from_assoc_ap = 0; u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; - struct ieee80211_crypt_data *crypt = NULL; + struct lib80211_crypt_data *crypt = NULL; void *sta = NULL; int keyidx = 0; @@ -795,7 +785,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, int idx = 0; if (skb->len >= hdrlen + 3) idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt[idx]; + crypt = local->crypt_info.crypt[idx]; sta = NULL; /* Use station specific key to override default keys if the @@ -822,10 +812,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, * frames silently instead of filling system log with * these reports. */ printk(KERN_DEBUG "%s: WEP decryption failed (not set)" - " (SA=" MAC_FMT ")\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + " (SA=%pM)\n", + local->dev->name, hdr->addr2); #endif local->comm_tallies.rx_discards_wep_undecryptable++; goto rx_dropped; @@ -839,9 +827,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0) { printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from " MAC_FMT "\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "from %pM\n", dev->name, hdr->addr2); /* TODO: could inform hostapd about this so that it * could send auth failure report */ goto rx_dropped; @@ -896,8 +882,6 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, from_assoc_ap = 1; } - dev->last_rx = jiffies; - if ((local->iw_mode == IW_MODE_MASTER || local->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) { @@ -1009,10 +993,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, "unencrypted EAPOL frame\n", local->dev->name); } else { printk(KERN_DEBUG "%s: encryption configured, but RX " - "frame not encrypted (SA=" MAC_FMT ")\n", - local->dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "frame not encrypted (SA=%pM)\n", + local->dev->name, hdr->addr2); goto rx_dropped; } } @@ -1021,10 +1003,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb, !hostap_is_eapol_frame(local, skb)) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: dropped unencrypted RX data " - "frame from " MAC_FMT " (drop_unencrypted=1)\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "frame from %pM (drop_unencrypted=1)\n", + dev->name, hdr->addr2); } goto rx_dropped; } diff --git a/drivers/net/wireless/hostap/hostap_80211_tx.c b/drivers/net/wireless/hostap/hostap_80211_tx.c index 921c984416f8b03270e57b199b2be839a6e61b50..078a010f39a0835c765d5e706f7f53600aa8d30a 100644 --- a/drivers/net/wireless/hostap/hostap_80211_tx.c +++ b/drivers/net/wireless/hostap/hostap_80211_tx.c @@ -17,7 +17,6 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) { struct ieee80211_hdr_4addr *hdr; u16 fc; - DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *) skb->data; @@ -41,11 +40,11 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb) printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id), le16_to_cpu(hdr->seq_ctl)); - printk(KERN_DEBUG " A1=%s", print_mac(mac, hdr->addr1)); - printk(" A2=%s", print_mac(mac, hdr->addr2)); - printk(" A3=%s", print_mac(mac, hdr->addr3)); + printk(KERN_DEBUG " A1=%pM", hdr->addr1); + printk(" A2=%pM", hdr->addr2); + printk(" A3=%pM", hdr->addr3); if (skb->len >= 30) - printk(" A4=%s", print_mac(mac, hdr->addr4)); + printk(" A4=%pM", hdr->addr4); printk("\n"); } @@ -307,7 +306,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev) /* Called only from software IRQ */ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) + struct lib80211_crypt_data *crypt) { struct hostap_interface *iface; local_info_t *local; @@ -328,10 +327,8 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb, hdr = (struct ieee80211_hdr_4addr *) skb->data; if (net_ratelimit()) { printk(KERN_DEBUG "%s: TKIP countermeasures: dropped " - "TX packet to " MAC_FMT "\n", - local->dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + "TX packet to %pM\n", + local->dev->name, hdr->addr1); } kfree_skb(skb); return NULL; @@ -408,7 +405,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (local->host_encrypt) { /* Set crypt to default algorithm and key; will be replaced in * AP code if STA has own alg/key */ - tx.crypt = local->crypt[local->tx_keyidx]; + tx.crypt = local->crypt_info.crypt[local->crypt_info.tx_keyidx]; tx.host_encrypt = 1; } else { tx.crypt = NULL; @@ -490,7 +487,9 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tx.crypt && (!tx.crypt->ops || !tx.crypt->ops->encrypt_mpdu)) tx.crypt = NULL; - else if ((tx.crypt || local->crypt[local->tx_keyidx]) && !no_encrypt) { + else if ((tx.crypt || + local->crypt_info.crypt[local->crypt_info.tx_keyidx]) && + !no_encrypt) { /* Add ISWEP flag both for firmware and host based encryption */ fc |= IEEE80211_FCTL_PROTECTED; diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c index af3d4ef2a80b75218b52f538e93e58e8215f5930..0903db786d5f94d565e67ed82d7a42216eb41cf9 100644 --- a/drivers/net/wireless/hostap/hostap_ap.c +++ b/drivers/net/wireless/hostap/hostap_ap.c @@ -94,7 +94,6 @@ static void ap_sta_hash_add(struct ap_data *ap, struct sta_info *sta) static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) { struct sta_info *s; - DECLARE_MAC_BUF(mac); s = ap->sta_hash[STA_HASH(sta->addr)]; if (s == NULL) return; @@ -109,20 +108,18 @@ static void ap_sta_hash_del(struct ap_data *ap, struct sta_info *sta) if (s->hnext != NULL) s->hnext = s->hnext->hnext; else - printk("AP: could not remove STA %s" - " from hash table\n", - print_mac(mac, sta->addr)); + printk("AP: could not remove STA %pM from hash table\n", + sta->addr); } static void ap_free_sta(struct ap_data *ap, struct sta_info *sta) { - DECLARE_MAC_BUF(mac); if (sta->ap && sta->local) hostap_event_expired_sta(sta->local->dev, sta); if (ap->proc != NULL) { char name[20]; - sprintf(name, "%s", print_mac(mac, sta->addr)); + sprintf(name, "%pM", sta->addr); remove_proc_entry(name, ap->proc); } @@ -185,7 +182,6 @@ static void ap_handle_timer(unsigned long data) struct ap_data *ap; unsigned long next_time = 0; int was_assoc; - DECLARE_MAC_BUF(mac); if (sta == NULL || sta->local == NULL || sta->local->ap == NULL) { PDEBUG(DEBUG_AP, "ap_handle_timer() called with NULL data\n"); @@ -242,8 +238,8 @@ static void ap_handle_timer(unsigned long data) if (sta->ap) { if (ap->autom_ap_wds) { PDEBUG(DEBUG_AP, "%s: removing automatic WDS " - "connection to AP %s\n", - local->dev->name, print_mac(mac, sta->addr)); + "connection to AP %pM\n", + local->dev->name, sta->addr); hostap_wds_link_oper(local, sta->addr, WDS_DEL); } } else if (sta->timeout_next == STA_NULLFUNC) { @@ -259,11 +255,11 @@ static void ap_handle_timer(unsigned long data) } else { int deauth = sta->timeout_next == STA_DEAUTH; __le16 resp; - PDEBUG(DEBUG_AP, "%s: sending %s info to STA %s" + PDEBUG(DEBUG_AP, "%s: sending %s info to STA %pM" "(last=%lu, jiffies=%lu)\n", local->dev->name, deauth ? "deauthentication" : "disassociation", - print_mac(mac, sta->addr), sta->last_rx, jiffies); + sta->addr, sta->last_rx, jiffies); resp = cpu_to_le16(deauth ? WLAN_REASON_PREV_AUTH_NOT_VALID : WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); @@ -275,10 +271,10 @@ static void ap_handle_timer(unsigned long data) if (sta->timeout_next == STA_DEAUTH) { if (sta->flags & WLAN_STA_PERM) { - PDEBUG(DEBUG_AP, "%s: STA %s" + PDEBUG(DEBUG_AP, "%s: STA %pM" " would have been removed, " "but it has 'perm' flag\n", - local->dev->name, print_mac(mac, sta->addr)); + local->dev->name, sta->addr); } else ap_free_sta(ap, sta); return; @@ -332,7 +328,6 @@ static int ap_control_proc_read(char *page, char **start, off_t off, struct ap_data *ap = (struct ap_data *) data; char *policy_txt; struct mac_entry *entry; - DECLARE_MAC_BUF(mac); if (off != 0) { *eof = 1; @@ -363,7 +358,7 @@ static int ap_control_proc_read(char *page, char **start, off_t off, break; } - p += sprintf(p, "%s\n", print_mac(mac, entry->addr)); + p += sprintf(p, "%pM\n", entry->addr); } spin_unlock_bh(&ap->mac_restrictions.lock); @@ -520,7 +515,6 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, struct ap_data *ap = (struct ap_data *) data; struct sta_info *sta; int i; - DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -533,8 +527,8 @@ static int prism2_ap_proc_read(char *page, char **start, off_t off, if (!sta->ap) continue; - p += sprintf(p, "%s %d %d %d %d '", - print_mac(mac, sta->addr), + p += sprintf(p, "%pM %d %d %d %d '", + sta->addr, sta->u.ap.channel, sta->last_rx_signal, sta->last_rx_silence, sta->last_rx_rate); for (i = 0; i < sta->u.ap.ssid_len; i++) @@ -683,11 +677,9 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data) if (sta) atomic_dec(&sta->users); if (txt) { - PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth_cb - alg=%d " + PDEBUG(DEBUG_AP, "%s: %pM auth_cb - alg=%d " "trans#=%d status=%d - %s\n", - dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], + dev->name, hdr->addr1, auth_alg, auth_transaction, status, txt); } dev_kfree_skb(skb); @@ -754,11 +746,8 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data) if (sta) atomic_dec(&sta->users); if (txt) { - PDEBUG(DEBUG_AP, "%s: " MAC_FMT " assoc_cb - %s\n", - dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], - txt); + PDEBUG(DEBUG_AP, "%s: %pM assoc_cb - %s\n", + dev->name, hdr->addr1, txt); } dev_kfree_skb(skb); } @@ -781,11 +770,9 @@ static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data) sta->flags &= ~WLAN_STA_PENDING_POLL; spin_unlock(&ap->sta_table_lock); } else { - PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT - " did not ACK activity poll frame\n", - ap->local->dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, + "%s: STA %pM did not ACK activity poll frame\n", + ap->local->dev->name, hdr->addr1); } fail: @@ -1002,7 +989,6 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, char *p = page; struct sta_info *sta = (struct sta_info *) data; int i; - DECLARE_MAC_BUF(mac); /* FIX: possible race condition.. the STA data could have just expired, * but proc entry was still here so that the read could have started; @@ -1013,11 +999,11 @@ static int prism2_sta_proc_read(char *page, char **start, off_t off, return 0; } - p += sprintf(p, "%s=%s\nusers=%d\naid=%d\n" + p += sprintf(p, "%s=%pM\nusers=%d\naid=%d\n" "flags=0x%04x%s%s%s%s%s%s%s\n" "capability=0x%02x\nlisten_interval=%d\nsupported_rates=", sta->ap ? "AP" : "STA", - print_mac(mac, sta->addr), atomic_read(&sta->users), sta->aid, + sta->addr, atomic_read(&sta->users), sta->aid, sta->flags, sta->flags & WLAN_STA_AUTH ? " AUTH" : "", sta->flags & WLAN_STA_ASSOC ? " ASSOC" : "", @@ -1078,7 +1064,6 @@ static void handle_add_proc_queue(struct work_struct *work) struct sta_info *sta; char name[20]; struct add_sta_proc_data *entry, *prev; - DECLARE_MAC_BUF(mac); entry = ap->add_sta_proc_entries; ap->add_sta_proc_entries = NULL; @@ -1091,7 +1076,7 @@ static void handle_add_proc_queue(struct work_struct *work) spin_unlock_bh(&ap->sta_table_lock); if (sta) { - sprintf(name, "%s", print_mac(mac, sta->addr)); + sprintf(name, "%pM", sta->addr); sta->proc = create_proc_read_entry( name, 0, ap->proc, prism2_sta_proc_read, sta); @@ -1221,7 +1206,7 @@ static void prism2_check_tx_rates(struct sta_info *sta) static void ap_crypt_init(struct ap_data *ap) { - ap->crypt = ieee80211_get_crypto_ops("WEP"); + ap->crypt = lib80211_get_crypto_ops("WEP"); if (ap->crypt) { if (ap->crypt->init) { @@ -1239,7 +1224,7 @@ static void ap_crypt_init(struct ap_data *ap) if (ap->crypt == NULL) { printk(KERN_WARNING "AP could not initialize WEP: load module " - "ieee80211_crypt_wep.ko\n"); + "lib80211_crypt_wep.ko\n"); } } @@ -1308,7 +1293,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, __le16 *pos; u16 resp = WLAN_STATUS_SUCCESS, fc; struct sta_info *sta = NULL; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; char *txt = ""; len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1318,9 +1303,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, if (len < 6) { PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload " - "(len=%d) from " MAC_FMT "\n", dev->name, len, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "(len=%d) from %pM\n", dev->name, len, hdr->addr2); return; } @@ -1336,7 +1319,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, int idx = 0; if (skb->len >= hdrlen + 3) idx = skb->data[hdrlen + 3] >> 6; - crypt = local->crypt[idx]; + crypt = local->crypt_info.crypt[idx]; } pos = (__le16 *) (skb->data + IEEE80211_MGMT_HDR_LEN); @@ -1385,10 +1368,8 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, if (time_after(jiffies, sta->u.ap.last_beacon + (10 * sta->listen_interval * HZ) / 1024)) { PDEBUG(DEBUG_AP, "%s: no beacons received for a while," - " assuming AP " MAC_FMT " is now STA\n", - dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5]); + " assuming AP %pM is now STA\n", + dev->name, sta->addr); sta->ap = 0; sta->flags = 0; sta->u.sta.challenge = NULL; @@ -1503,11 +1484,9 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb, } if (resp) { - PDEBUG(DEBUG_AP, "%s: " MAC_FMT " auth (alg=%d " + PDEBUG(DEBUG_AP, "%s: %pM auth (alg=%d " "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + dev->name, hdr->addr2, auth_alg, auth_transaction, status_code, len, fc, resp, txt); } @@ -1533,10 +1512,8 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, if (len < (reassoc ? 10 : 4)) { PDEBUG(DEBUG_AP, "%s: handle_assoc - too short payload " - "(len=%d, reassoc=%d) from " MAC_FMT "\n", - dev->name, len, reassoc, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5]); + "(len=%d, reassoc=%d) from %pM\n", + dev->name, len, reassoc, hdr->addr2); return; } @@ -1613,12 +1590,9 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, } if (left > 0) { - PDEBUG(DEBUG_AP, "%s: assoc from " MAC_FMT + PDEBUG(DEBUG_AP, "%s: assoc from %pM" " with extra data (%d bytes) [", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - left); + dev->name, hdr->addr2, left); while (left > 0) { PDEBUG2(DEBUG_AP, "<%02x>", *u); u++; left--; @@ -1717,14 +1691,12 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb, } #if 0 - PDEBUG(DEBUG_AP, "%s: " MAC_FMT" %sassoc (len=%d " - "prev_ap=" MAC_FMT") => %d(%d) (%s)\n", + PDEBUG(DEBUG_AP, "%s: %pM %sassoc (len=%d " + "prev_ap=%pM) => %d(%d) (%s)\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + hdr->addr2, reassoc ? "re" : "", len, - prev_ap[0], prev_ap[1], prev_ap[2], - prev_ap[3], prev_ap[4], prev_ap[5], + prev_ap, resp, send_deauth, txt); #endif } @@ -1741,7 +1713,6 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, u16 reason_code; __le16 *pos; struct sta_info *sta = NULL; - DECLARE_MAC_BUF(mac); len = skb->len - IEEE80211_MGMT_HDR_LEN; @@ -1753,10 +1724,8 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, pos = (__le16 *) body; reason_code = le16_to_cpu(*pos); - PDEBUG(DEBUG_AP, "%s: deauthentication: " MAC_FMT " len=%d, " - "reason_code=%d\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + PDEBUG(DEBUG_AP, "%s: deauthentication: %pM len=%d, " + "reason_code=%d\n", dev->name, hdr->addr2, len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); @@ -1768,11 +1737,9 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb, } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { - printk("%s: deauthentication from " MAC_FMT ", " + printk("%s: deauthentication from %pM, " "reason_code=%d, but STA not authenticated\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - reason_code); + hdr->addr2, reason_code); } } @@ -1799,10 +1766,8 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, pos = (__le16 *) body; reason_code = le16_to_cpu(*pos); - PDEBUG(DEBUG_AP, "%s: disassociation: " MAC_FMT " len=%d, " - "reason_code=%d\n", dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + PDEBUG(DEBUG_AP, "%s: disassociation: %pM len=%d, " + "reason_code=%d\n", dev->name, hdr->addr2, len, reason_code); spin_lock_bh(&local->ap->sta_table_lock); @@ -1814,12 +1779,9 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb, } spin_unlock_bh(&local->ap->sta_table_lock); if (sta == NULL) { - printk("%s: disassociation from " MAC_FMT ", " + printk("%s: disassociation from %pM, " "reason_code=%d, but STA not authenticated\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], - reason_code); + dev->name, hdr->addr2, reason_code); } } @@ -1909,19 +1871,14 @@ static void handle_pspoll(local_info_t *local, u16 aid; struct sk_buff *skb; - PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=" MAC_FMT - ", TA=" MAC_FMT " PWRMGT=%d\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], - hdr->addr2[0], hdr->addr2[1], hdr->addr2[2], - hdr->addr2[3], hdr->addr2[4], hdr->addr2[5], + PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n", + hdr->addr1, hdr->addr2, !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM)); if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_pspoll - addr1(BSSID)=" MAC_FMT - " not own MAC\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, + "handle_pspoll - addr1(BSSID)=%pM not own MAC\n", + hdr->addr1); return; } @@ -2007,11 +1964,10 @@ static void handle_wds_oper_queue(struct work_struct *work) while (entry) { PDEBUG(DEBUG_AP, "%s: %s automatic WDS connection " - "to AP " MAC_FMT "\n", + "to AP %pM\n", local->dev->name, entry->type == WDS_ADD ? "adding" : "removing", - entry->addr[0], entry->addr[1], entry->addr[2], - entry->addr[3], entry->addr[4], entry->addr[5]); + entry->addr); if (entry->type == WDS_ADD) prism2_wds_add(local, entry->addr, 0); else if (entry->type == WDS_DEL) @@ -2215,10 +2171,8 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, } if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=" - MAC_FMT " not own MAC\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, "handle_ap_item - addr1(BSSID)=%pM" + " not own MAC\n", hdr->addr1); goto done; } @@ -2254,18 +2208,14 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb, } if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=" MAC_FMT - " not own MAC\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + PDEBUG(DEBUG_AP, "handle_ap_item - addr1(DA)=%pM" + " not own MAC\n", hdr->addr1); goto done; } if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN)) { - PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=" MAC_FMT - " not own MAC\n", - hdr->addr3[0], hdr->addr3[1], hdr->addr3[2], - hdr->addr3[3], hdr->addr3[4], hdr->addr3[5]); + PDEBUG(DEBUG_AP, "handle_ap_item - addr3(BSSID)=%pM" + " not own MAC\n", hdr->addr3); goto done; } @@ -2366,10 +2316,9 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta) memcpy(hdr->addr2, sta->addr, ETH_ALEN); hdr->duration_id = cpu_to_le16(sta->aid | BIT(15) | BIT(14)); - PDEBUG(DEBUG_PS2, "%s: Scheduling buffered packet delivery for STA " - MAC_FMT "\n", local->dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5]); + PDEBUG(DEBUG_PS2, + "%s: Scheduling buffered packet delivery for STA %pM\n", + local->dev->name, sta->addr); skb->dev = local->dev; @@ -2723,12 +2672,8 @@ static int ap_update_sta_tx_rate(struct sta_info *sta, struct net_device *dev) case 3: sta->tx_rate = 110; break; default: sta->tx_rate = 0; break; } - PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT - " TX rate raised to %d\n", - dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5], - sta->tx_rate); + PDEBUG(DEBUG_AP, "%s: STA %pM TX rate raised to %d\n", + dev->name, sta->addr, sta->tx_rate); } sta->tx_since_last_failure = 0; } @@ -2781,9 +2726,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) * print out any errors here. */ if (net_ratelimit()) { printk(KERN_DEBUG "AP: drop packet to non-associated " - "STA " MAC_FMT "\n", - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5]); + "STA %pM\n", hdr->addr1); } #endif local->ap->tx_drop_nonassoc++; @@ -2821,11 +2764,9 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx) } if (skb_queue_len(&sta->tx_buf) >= STA_MAX_TX_BUFFER) { - PDEBUG(DEBUG_PS, "%s: No more space in STA (" MAC_FMT - ")'s PS mode buffer\n", - local->dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5]); + PDEBUG(DEBUG_PS, "%s: No more space in STA (%pM)'s" + "PS mode buffer\n", + local->dev->name, sta->addr); /* Make sure that TIM is set for the station (it might not be * after AP wlan hw reset). */ /* FIX: should fix hw reset to restore bits based on STA @@ -2897,12 +2838,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) sta = ap_get_sta(local->ap, hdr->addr1); if (!sta) { spin_unlock(&local->ap->sta_table_lock); - PDEBUG(DEBUG_AP, "%s: Could not find STA " MAC_FMT + PDEBUG(DEBUG_AP, "%s: Could not find STA %pM" " for this TX error (@%lu)\n", - local->dev->name, - hdr->addr1[0], hdr->addr1[1], hdr->addr1[2], - hdr->addr1[3], hdr->addr1[4], hdr->addr1[5], - jiffies); + local->dev->name, hdr->addr1, jiffies); return; } @@ -2929,12 +2867,9 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) case 3: sta->tx_rate = 110; break; default: sta->tx_rate = 0; break; } - PDEBUG(DEBUG_AP, "%s: STA " MAC_FMT - " TX rate lowered to %d\n", - local->dev->name, - sta->addr[0], sta->addr[1], sta->addr[2], - sta->addr[3], sta->addr[4], sta->addr[5], - sta->tx_rate); + PDEBUG(DEBUG_AP, + "%s: STA %pM TX rate lowered to %d\n", + local->dev->name, sta->addr, sta->tx_rate); } sta->tx_consecutive_exc = 0; } @@ -2945,17 +2880,16 @@ void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb) static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta, int pwrmgt, int type, int stype) { - DECLARE_MAC_BUF(mac); if (pwrmgt && !(sta->flags & WLAN_STA_PS)) { sta->flags |= WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %s changed to use PS " + PDEBUG(DEBUG_PS2, "STA %pM changed to use PS " "mode (type=0x%02X, stype=0x%02X)\n", - print_mac(mac, sta->addr), type >> 2, stype >> 4); + sta->addr, type >> 2, stype >> 4); } else if (!pwrmgt && (sta->flags & WLAN_STA_PS)) { sta->flags &= ~WLAN_STA_PS; - PDEBUG(DEBUG_PS2, "STA %s changed to not use " + PDEBUG(DEBUG_PS2, "STA %pM changed to not use " "PS mode (type=0x%02X, stype=0x%02X)\n", - print_mac(mac, sta->addr), type >> 2, stype >> 4); + sta->addr, type >> 2, stype >> 4); if (type != IEEE80211_FTYPE_CTL || stype != IEEE80211_STYPE_PSPOLL) schedule_packet_send(local, sta); @@ -3029,13 +2963,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT } else { printk(KERN_DEBUG "%s: dropped received packet" - " from non-associated STA " - MAC_FMT + " from non-associated STA %pM" " (type=0x%02x, subtype=0x%02x)\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5], + dev->name, hdr->addr2, type >> 2, stype >> 4); hostap_rx(dev, skb, rx_stats); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ @@ -3068,13 +2998,9 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, * after being unavailable for some time. Speed up * re-association by informing the station about it not * being associated. */ - printk(KERN_DEBUG "%s: rejected received nullfunc " - "frame without ToDS from not associated STA " - MAC_FMT "\n", - dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5]); + printk(KERN_DEBUG "%s: rejected received nullfunc frame" + " without ToDS from not associated STA %pM\n", + dev->name, hdr->addr2); hostap_rx(dev, skb, rx_stats); #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ } @@ -3090,13 +3016,10 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, * broadcast frame from an IBSS network. Drop it silently. * If BSSID is own, report the dropping of this frame. */ if (memcmp(hdr->addr3, dev->dev_addr, ETH_ALEN) == 0) { - printk(KERN_DEBUG "%s: dropped received packet from " - MAC_FMT " with no ToDS flag " + printk(KERN_DEBUG "%s: dropped received packet from %pM" + " with no ToDS flag " "(type=0x%02x, subtype=0x%02x)\n", dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5], - type >> 2, stype >> 4); + hdr->addr2, type >> 2, stype >> 4); hostap_dump_rx_80211(dev->name, skb, rx_stats); } ret = AP_RX_DROP; @@ -3142,7 +3065,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, /* Called only as a tasklet (software IRQ) */ int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr, - struct ieee80211_crypt_data **crypt, + struct lib80211_crypt_data **crypt, void **sta_ptr) { struct sta_info *sta; @@ -3290,7 +3213,7 @@ void hostap_update_rates(local_info_t *local) void * ap_crypt_get_ptrs(struct ap_data *ap, u8 *addr, int permanent, - struct ieee80211_crypt_data ***crypt) + struct lib80211_crypt_data ***crypt) { struct sta_info *sta; diff --git a/drivers/net/wireless/hostap/hostap_ap.h b/drivers/net/wireless/hostap/hostap_ap.h index 2fa2452b6b07de6d6c06f76b2e4b0742c90e7dc2..d36e4b17533615462c9694332764abdc15eba7d3 100644 --- a/drivers/net/wireless/hostap/hostap_ap.h +++ b/drivers/net/wireless/hostap/hostap_ap.h @@ -74,7 +74,7 @@ struct sta_info { u32 tx_since_last_failure; u32 tx_consecutive_exc; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; int ap; /* whether this station is an AP */ @@ -209,7 +209,7 @@ struct ap_data { /* WEP operations for generating challenges to be used with shared key * authentication */ - struct ieee80211_crypto_ops *crypt; + struct lib80211_crypto_ops *crypt; void *crypt_priv; #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */ }; @@ -229,7 +229,7 @@ typedef enum { struct hostap_tx_data { struct sk_buff *skb; int host_encrypt; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; void *sta_ptr; }; ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx); @@ -244,7 +244,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev, struct hostap_80211_rx_status *rx_stats, int wds); int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr, - struct ieee80211_crypt_data **crypt, + struct lib80211_crypt_data **crypt, void **sta_ptr); int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr); int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr); diff --git a/drivers/net/wireless/hostap/hostap_common.h b/drivers/net/wireless/hostap/hostap_common.h index b470c743c2d1923d5214fe0507ebb6d3fbf3aba2..90b64b09200716c31cb9af9a4e2761ba0ba7100d 100644 --- a/drivers/net/wireless/hostap/hostap_common.h +++ b/drivers/net/wireless/hostap/hostap_common.h @@ -6,19 +6,6 @@ /* IEEE 802.11 defines */ -/* Information Element IDs */ -#define WLAN_EID_SSID 0 -#define WLAN_EID_SUPP_RATES 1 -#define WLAN_EID_FH_PARAMS 2 -#define WLAN_EID_DS_PARAMS 3 -#define WLAN_EID_CF_PARAMS 4 -#define WLAN_EID_TIM 5 -#define WLAN_EID_IBSS_PARAMS 6 -#define WLAN_EID_CHALLENGE 16 -#define WLAN_EID_RSN 48 -#define WLAN_EID_GENERIC 221 - - /* HFA384X Configuration RIDs */ #define HFA384X_RID_CNFPORTTYPE 0xFC00 #define HFA384X_RID_CNFOWNMACADDR 0xFC01 diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c index 3153fe9d7ce09dc32bf8764bc6437569c270ba14..0f27059bbe85a88d20aacc0ec127e63a12fe475f 100644 --- a/drivers/net/wireless/hostap/hostap_hw.c +++ b/drivers/net/wireless/hostap/hostap_hw.c @@ -47,7 +47,7 @@ #include #include #include -#include +#include #include #include "hostap_80211.h" @@ -2335,10 +2335,6 @@ static void prism2_txexc(local_info_t *local) int show_dump, res; char *payload = NULL; struct hfa384x_tx_frame txdesc; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR; local->stats.tx_errors++; @@ -2404,9 +2400,9 @@ static void prism2_txexc(local_info_t *local) WLAN_FC_GET_STYPE(fc) >> 4, fc & IEEE80211_FCTL_TODS ? " ToDS" : "", fc & IEEE80211_FCTL_FROMDS ? " FromDS" : ""); - PDEBUG(DEBUG_EXTRA, " A1=%s A2=%s A3=%s A4=%s\n", - print_mac(mac, txdesc.addr1), print_mac(mac2, txdesc.addr2), - print_mac(mac3, txdesc.addr3), print_mac(mac4, txdesc.addr4)); + PDEBUG(DEBUG_EXTRA, " A1=%pM A2=%pM A3=%pM A4=%pM\n", + txdesc.addr1, txdesc.addr2, + txdesc.addr3, txdesc.addr4); } @@ -2792,45 +2788,6 @@ static void prism2_check_sta_fw_version(local_info_t *local) } -static void prism2_crypt_deinit_entries(local_info_t *local, int force) -{ - struct list_head *ptr, *n; - struct ieee80211_crypt_data *entry; - - for (ptr = local->crypt_deinit_list.next, n = ptr->next; - ptr != &local->crypt_deinit_list; ptr = n, n = ptr->next) { - entry = list_entry(ptr, struct ieee80211_crypt_data, list); - - if (atomic_read(&entry->refcnt) != 0 && !force) - continue; - - list_del(ptr); - - if (entry->ops) - entry->ops->deinit(entry->priv); - kfree(entry); - } -} - - -static void prism2_crypt_deinit_handler(unsigned long data) -{ - local_info_t *local = (local_info_t *) data; - unsigned long flags; - - spin_lock_irqsave(&local->lock, flags); - prism2_crypt_deinit_entries(local, 0); - if (!list_empty(&local->crypt_deinit_list)) { - printk(KERN_DEBUG "%s: entries remaining in delayed crypt " - "deletion list\n", local->dev->name); - local->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&local->crypt_deinit_timer); - } - spin_unlock_irqrestore(&local->lock, flags); - -} - - static void hostap_passive_scan(unsigned long data) { local_info_t *local = (local_info_t *) data; @@ -3254,10 +3211,8 @@ while (0) INIT_LIST_HEAD(&local->cmd_queue); init_waitqueue_head(&local->hostscan_wq); - INIT_LIST_HEAD(&local->crypt_deinit_list); - init_timer(&local->crypt_deinit_timer); - local->crypt_deinit_timer.data = (unsigned long) local; - local->crypt_deinit_timer.function = prism2_crypt_deinit_handler; + + lib80211_crypt_info_init(&local->crypt_info, dev->name, &local->lock); init_timer(&local->passive_scan_timer); local->passive_scan_timer.data = (unsigned long) local; @@ -3358,9 +3313,7 @@ static void prism2_free_local_data(struct net_device *dev) flush_scheduled_work(); - if (timer_pending(&local->crypt_deinit_timer)) - del_timer(&local->crypt_deinit_timer); - prism2_crypt_deinit_entries(local, 1); + lib80211_crypt_info_free(&local->crypt_info); if (timer_pending(&local->passive_scan_timer)) del_timer(&local->passive_scan_timer); @@ -3377,16 +3330,6 @@ static void prism2_free_local_data(struct net_device *dev) if (local->dev_enabled) prism2_callback(local, PRISM2_CALLBACK_DISABLE); - for (i = 0; i < WEP_KEYS; i++) { - struct ieee80211_crypt_data *crypt = local->crypt[i]; - if (crypt) { - if (crypt->ops) - crypt->ops->deinit(crypt->priv); - kfree(crypt); - local->crypt[i] = NULL; - } - } - if (local->ap != NULL) hostap_free_data(local->ap); diff --git a/drivers/net/wireless/hostap/hostap_info.c b/drivers/net/wireless/hostap/hostap_info.c index 7cd3fb79230e51d12f5b226049e64a474d562eb3..99b4cf41edf2c59d5d5d2ea2baa5273a21d28d43 100644 --- a/drivers/net/wireless/hostap/hostap_info.c +++ b/drivers/net/wireless/hostap/hostap_info.c @@ -166,7 +166,6 @@ static void prism2_host_roaming(local_info_t *local) struct hfa384x_hostscan_result *selected, *entry; int i; unsigned long flags; - DECLARE_MAC_BUF(mac); if (local->last_join_time && time_before(jiffies, local->last_join_time + 10 * HZ)) { @@ -199,9 +198,8 @@ static void prism2_host_roaming(local_info_t *local) local->preferred_ap[2] || local->preferred_ap[3] || local->preferred_ap[4] || local->preferred_ap[5]) { /* Try to find preferred AP */ - PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID " - "%s\n", - dev->name, print_mac(mac, local->preferred_ap)); + PDEBUG(DEBUG_EXTRA, "%s: Preferred AP BSSID %pM\n", + dev->name, local->preferred_ap); for (i = 0; i < local->last_scan_results_count; i++) { entry = &local->last_scan_results[i]; if (memcmp(local->preferred_ap, entry->bssid, 6) == 0) @@ -218,9 +216,9 @@ static void prism2_host_roaming(local_info_t *local) req.channel = selected->chid; spin_unlock_irqrestore(&local->lock, flags); - PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%s" + PDEBUG(DEBUG_EXTRA, "%s: JoinRequest: BSSID=%pM" " channel=%d\n", - dev->name, print_mac(mac, req.bssid), le16_to_cpu(req.channel)); + dev->name, req.bssid, le16_to_cpu(req.channel)); if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, sizeof(req))) { printk(KERN_DEBUG "%s: JoinRequest failed\n", dev->name); @@ -413,7 +411,6 @@ static void handle_info_queue_linkstatus(local_info_t *local) int val = local->prev_link_status; int connected; union iwreq_data wrqu; - DECLARE_MAC_BUF(mac); connected = val == HFA384X_LINKSTATUS_CONNECTED || @@ -425,10 +422,9 @@ static void handle_info_queue_linkstatus(local_info_t *local) printk(KERN_DEBUG "%s: could not read CURRENTBSSID after " "LinkStatus event\n", local->dev->name); } else { - PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=" - "%s\n", + PDEBUG(DEBUG_EXTRA, "%s: LinkStatus: BSSID=%pM\n", local->dev->name, - print_mac(mac, (unsigned char *) local->bssid)); + (unsigned char *) local->bssid); if (local->wds_type & HOSTAP_WDS_AP_CLIENT) hostap_add_sta(local->ap, local->bssid); } diff --git a/drivers/net/wireless/hostap/hostap_ioctl.c b/drivers/net/wireless/hostap/hostap_ioctl.c index 3f8b1d7036e51467879b1dcaf44a895223325c11..c40fdf4c79de8af8193c78d7c8340641b1ddf724 100644 --- a/drivers/net/wireless/hostap/hostap_ioctl.c +++ b/drivers/net/wireless/hostap/hostap_ioctl.c @@ -2,7 +2,7 @@ #include #include -#include +#include #include "hostap_wlan.h" #include "hostap.h" @@ -116,32 +116,6 @@ static int prism2_get_name(struct net_device *dev, } -static void prism2_crypt_delayed_deinit(local_info_t *local, - struct ieee80211_crypt_data **crypt) -{ - struct ieee80211_crypt_data *tmp; - unsigned long flags; - - tmp = *crypt; - *crypt = NULL; - - if (tmp == NULL) - return; - - /* must not run ops->deinit() while there may be pending encrypt or - * decrypt operations. Use a list of delayed deinits to avoid needing - * locking. */ - - spin_lock_irqsave(&local->lock, flags); - list_add(&tmp->list, &local->crypt_deinit_list); - if (!timer_pending(&local->crypt_deinit_timer)) { - local->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&local->crypt_deinit_timer); - } - spin_unlock_irqrestore(&local->lock, flags); -} - - static int prism2_ioctl_siwencode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *keybuf) @@ -149,47 +123,47 @@ static int prism2_ioctl_siwencode(struct net_device *dev, struct hostap_interface *iface; local_info_t *local; int i; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypt_data **crypt; iface = netdev_priv(dev); local = iface->local; i = erq->flags & IW_ENCODE_INDEX; if (i < 1 || i > 4) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; if (i < 0 || i >= WEP_KEYS) return -EINVAL; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; if (erq->flags & IW_ENCODE_DISABLED) { if (*crypt) - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); goto done; } if (*crypt != NULL && (*crypt)->ops != NULL && strcmp((*crypt)->ops->name, "WEP") != 0) { /* changing to use WEP; deinit previously used algorithm */ - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); } if (*crypt == NULL) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + new_crypt->ops = lib80211_get_crypto_ops("WEP"); if (!new_crypt->ops) { - request_module("ieee80211_crypt_wep"); - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + request_module("lib80211_crypt_wep"); + new_crypt->ops = lib80211_get_crypto_ops("WEP"); } - if (new_crypt->ops) + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) new_crypt->priv = new_crypt->ops->init(i); if (!new_crypt->ops || !new_crypt->priv) { kfree(new_crypt); @@ -210,16 +184,16 @@ static int prism2_ioctl_siwencode(struct net_device *dev, memset(keybuf + erq->length, 0, len - erq->length); (*crypt)->ops->set_key(keybuf, len, NULL, (*crypt)->priv); for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt[j]) { + if (j != i && local->crypt_info.crypt[j]) { first = 0; break; } } if (first) - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } else { /* No key data - just set the default TX key index */ - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } done: @@ -252,20 +226,20 @@ static int prism2_ioctl_giwencode(struct net_device *dev, local_info_t *local; int i, len; u16 val; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; iface = netdev_priv(dev); local = iface->local; i = erq->flags & IW_ENCODE_INDEX; if (i < 1 || i > 4) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; if (i < 0 || i >= WEP_KEYS) return -EINVAL; - crypt = local->crypt[i]; + crypt = local->crypt_info.crypt[i]; erq->flags = i + 1; if (crypt == NULL || crypt->ops == NULL) { @@ -664,7 +638,6 @@ static int hostap_join_ap(struct net_device *dev) unsigned long flags; int i; struct hfa384x_hostscan_result *entry; - DECLARE_MAC_BUF(mac); iface = netdev_priv(dev); local = iface->local; @@ -686,14 +659,13 @@ static int hostap_join_ap(struct net_device *dev) if (local->func->set_rid(dev, HFA384X_RID_JOINREQUEST, &req, sizeof(req))) { - printk(KERN_DEBUG "%s: JoinRequest %s" - " failed\n", - dev->name, print_mac(mac, local->preferred_ap)); + printk(KERN_DEBUG "%s: JoinRequest %pM failed\n", + dev->name, local->preferred_ap); return -1; } - printk(KERN_DEBUG "%s: Trying to join BSSID %s\n", - dev->name, print_mac(mac, local->preferred_ap)); + printk(KERN_DEBUG "%s: Trying to join BSSID %pM\n", + dev->name, local->preferred_ap); return 0; } @@ -3229,8 +3201,8 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, local_info_t *local = iface->local; struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; int i, ret = 0; - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; void *sta_ptr; u8 *addr; const char *alg, *module; @@ -3239,7 +3211,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if (i > WEP_KEYS) return -EINVAL; if (i < 1 || i > WEP_KEYS) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; if (i < 0 || i >= WEP_KEYS) @@ -3249,7 +3221,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { sta_ptr = NULL; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; } else { if (i != 0) return -EINVAL; @@ -3262,7 +3234,7 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, * is emulated by using default key idx 0. */ i = 0; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; } else return -EINVAL; } @@ -3271,22 +3243,22 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if ((erq->flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE) { if (*crypt) - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); goto done; } switch (ext->alg) { case IW_ENCODE_ALG_WEP: alg = "WEP"; - module = "ieee80211_crypt_wep"; + module = "lib80211_crypt_wep"; break; case IW_ENCODE_ALG_TKIP: alg = "TKIP"; - module = "ieee80211_crypt_tkip"; + module = "lib80211_crypt_tkip"; break; case IW_ENCODE_ALG_CCMP: alg = "CCMP"; - module = "ieee80211_crypt_ccmp"; + module = "lib80211_crypt_ccmp"; break; default: printk(KERN_DEBUG "%s: unsupported algorithm %d\n", @@ -3295,10 +3267,10 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, goto done; } - ops = ieee80211_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); if (ops == NULL) { request_module(module); - ops = ieee80211_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); } if (ops == NULL) { printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", @@ -3317,18 +3289,19 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, } if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) { ret = -ENOMEM; goto done; } new_crypt->ops = ops; - new_crypt->priv = new_crypt->ops->init(i); + if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) + new_crypt->priv = new_crypt->ops->init(i); if (new_crypt->priv == NULL) { kfree(new_crypt); ret = -EINVAL; @@ -3356,20 +3329,20 @@ static int prism2_ioctl_siwencodeext(struct net_device *dev, if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { if (!sta_ptr) - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } if (sta_ptr == NULL && ext->key_len > 0) { int first = 1, j; for (j = 0; j < WEP_KEYS; j++) { - if (j != i && local->crypt[j]) { + if (j != i && local->crypt_info.crypt[j]) { first = 0; break; } } if (first) - local->tx_keyidx = i; + local->crypt_info.tx_keyidx = i; } done: @@ -3401,7 +3374,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, { struct hostap_interface *iface = netdev_priv(dev); local_info_t *local = iface->local; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypt_data **crypt; void *sta_ptr; int max_key_len, i; struct iw_encode_ext *ext = (struct iw_encode_ext *) extra; @@ -3413,7 +3386,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, i = erq->flags & IW_ENCODE_INDEX; if (i < 1 || i > WEP_KEYS) - i = local->tx_keyidx; + i = local->crypt_info.tx_keyidx; else i--; @@ -3421,7 +3394,7 @@ static int prism2_ioctl_giwencodeext(struct net_device *dev, if (addr[0] == 0xff && addr[1] == 0xff && addr[2] == 0xff && addr[3] == 0xff && addr[4] == 0xff && addr[5] == 0xff) { sta_ptr = NULL; - crypt = &local->crypt[i]; + crypt = &local->crypt_info.crypt[i]; } else { i = 0; sta_ptr = ap_crypt_get_ptrs(local->ap, addr, 0, &crypt); @@ -3470,8 +3443,8 @@ static int prism2_ioctl_set_encryption(local_info_t *local, int param_len) { int ret = 0; - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; void *sta_ptr; param->u.crypt.err = 0; @@ -3488,7 +3461,7 @@ static int prism2_ioctl_set_encryption(local_info_t *local, if (param->u.crypt.idx >= WEP_KEYS) return -EINVAL; sta_ptr = NULL; - crypt = &local->crypt[param->u.crypt.idx]; + crypt = &local->crypt_info.crypt[param->u.crypt.idx]; } else { if (param->u.crypt.idx) return -EINVAL; @@ -3505,20 +3478,20 @@ static int prism2_ioctl_set_encryption(local_info_t *local, if (strcmp(param->u.crypt.alg, "none") == 0) { if (crypt) - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); goto done; } - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); if (ops == NULL && strcmp(param->u.crypt.alg, "WEP") == 0) { - request_module("ieee80211_crypt_wep"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + request_module("lib80211_crypt_wep"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); } else if (ops == NULL && strcmp(param->u.crypt.alg, "TKIP") == 0) { - request_module("ieee80211_crypt_tkip"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + request_module("lib80211_crypt_tkip"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); } else if (ops == NULL && strcmp(param->u.crypt.alg, "CCMP") == 0) { - request_module("ieee80211_crypt_ccmp"); - ops = ieee80211_get_crypto_ops(param->u.crypt.alg); + request_module("lib80211_crypt_ccmp"); + ops = lib80211_get_crypto_ops(param->u.crypt.alg); } if (ops == NULL) { printk(KERN_DEBUG "%s: unknown crypto alg '%s'\n", @@ -3533,11 +3506,11 @@ static int prism2_ioctl_set_encryption(local_info_t *local, local->host_decrypt = local->host_encrypt = 1; if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; - prism2_crypt_delayed_deinit(local, crypt); + lib80211_crypt_delayed_deinit(&local->crypt_info, crypt); - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) { ret = -ENOMEM; @@ -3570,7 +3543,7 @@ static int prism2_ioctl_set_encryption(local_info_t *local, if (param->u.crypt.flags & HOSTAP_CRYPT_FLAG_SET_TX_KEY) { if (!sta_ptr) - local->tx_keyidx = param->u.crypt.idx; + local->crypt_info.tx_keyidx = param->u.crypt.idx; else if (param->u.crypt.idx) { printk(KERN_DEBUG "%s: TX key idx setting failed\n", local->dev->name); @@ -3606,7 +3579,7 @@ static int prism2_ioctl_get_encryption(local_info_t *local, struct prism2_hostapd_param *param, int param_len) { - struct ieee80211_crypt_data **crypt; + struct lib80211_crypt_data **crypt; void *sta_ptr; int max_key_len; @@ -3622,8 +3595,8 @@ static int prism2_ioctl_get_encryption(local_info_t *local, param->sta_addr[4] == 0xff && param->sta_addr[5] == 0xff) { sta_ptr = NULL; if (param->u.crypt.idx >= WEP_KEYS) - param->u.crypt.idx = local->tx_keyidx; - crypt = &local->crypt[param->u.crypt.idx]; + param->u.crypt.idx = local->crypt_info.tx_keyidx; + crypt = &local->crypt_info.crypt[param->u.crypt.idx]; } else { param->u.crypt.idx = 0; sta_ptr = ap_crypt_get_ptrs(local->ap, param->sta_addr, 0, @@ -3701,10 +3674,8 @@ static int prism2_ioctl_set_assoc_ap_addr(local_info_t *local, struct prism2_hostapd_param *param, int param_len) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%ssta: associated as client with AP " - "%s\n", - local->dev->name, print_mac(mac, param->sta_addr)); + printk(KERN_DEBUG "%ssta: associated as client with AP %pM\n", + local->dev->name, param->sta_addr); memcpy(local->assoc_ap_addr, param->sta_addr, ETH_ALEN); return 0; } diff --git a/drivers/net/wireless/hostap/hostap_main.c b/drivers/net/wireless/hostap/hostap_main.c index 756ab56c1f4034de12c77b2ba067987aebbcd555..02a312ca860752ad7c4324570499ee139a771d66 100644 --- a/drivers/net/wireless/hostap/hostap_main.c +++ b/drivers/net/wireless/hostap/hostap_main.c @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include "hostap_wlan.h" @@ -343,10 +343,11 @@ int hostap_set_encryption(local_info_t *local) char keybuf[WEP_KEY_LEN + 1]; enum { NONE, WEP, OTHER } encrypt_type; - idx = local->tx_keyidx; - if (local->crypt[idx] == NULL || local->crypt[idx]->ops == NULL) + idx = local->crypt_info.tx_keyidx; + if (local->crypt_info.crypt[idx] == NULL || + local->crypt_info.crypt[idx]->ops == NULL) encrypt_type = NONE; - else if (strcmp(local->crypt[idx]->ops->name, "WEP") == 0) + else if (strcmp(local->crypt_info.crypt[idx]->ops->name, "WEP") == 0) encrypt_type = WEP; else encrypt_type = OTHER; @@ -394,17 +395,17 @@ int hostap_set_encryption(local_info_t *local) /* 104-bit support seems to require that all the keys are set to the * same keylen */ keylen = 6; /* first 5 octets */ - len = local->crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), - NULL, local->crypt[idx]->priv); + len = local->crypt_info.crypt[idx]->ops->get_key(keybuf, sizeof(keybuf), NULL, + local->crypt_info.crypt[idx]->priv); if (idx >= 0 && idx < WEP_KEYS && len > 5) keylen = WEP_KEY_LEN + 1; /* first 13 octets */ for (i = 0; i < WEP_KEYS; i++) { memset(keybuf, 0, sizeof(keybuf)); - if (local->crypt[i]) { - (void) local->crypt[i]->ops->get_key( + if (local->crypt_info.crypt[i]) { + (void) local->crypt_info.crypt[i]->ops->get_key( keybuf, sizeof(keybuf), - NULL, local->crypt[i]->priv); + NULL, local->crypt_info.crypt[i]->priv); } if (local->func->set_rid(local->dev, HFA384X_RID_CNFDEFAULTKEY0 + i, @@ -530,10 +531,6 @@ int hostap_set_auth_algs(local_info_t *local) void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) { u16 status, fc; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); status = __le16_to_cpu(rx->status); @@ -552,12 +549,11 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n", - print_mac(mac, rx->addr1), print_mac(mac2, rx->addr2), - print_mac(mac3, rx->addr3), print_mac(mac4, rx->addr4)); + printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", + rx->addr1, rx->addr2, rx->addr3, rx->addr4); - printk(KERN_DEBUG " dst=%s src=%s len=%d\n", - print_mac(mac, rx->dst_addr), print_mac(mac2, rx->src_addr), + printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", + rx->dst_addr, rx->src_addr, __be16_to_cpu(rx->len)); } @@ -565,10 +561,6 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx) void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) { u16 fc; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); printk(KERN_DEBUG "%s: TX status=0x%04x retry_count=%d tx_rate=%d " "tx_control=0x%04x; jiffies=%ld\n", @@ -584,12 +576,11 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx) fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "", fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : ""); - printk(KERN_DEBUG " A1=%s A2=%s A3=%s A4=%s\n", - print_mac(mac, tx->addr1), print_mac(mac2, tx->addr2), - print_mac(mac3, tx->addr3), print_mac(mac4, tx->addr4)); + printk(KERN_DEBUG " A1=%pM A2=%pM A3=%pM A4=%pM\n", + tx->addr1, tx->addr2, tx->addr3, tx->addr4); - printk(KERN_DEBUG " dst=%s src=%s len=%d\n", - print_mac(mac, tx->dst_addr), print_mac(mac2, tx->src_addr), + printk(KERN_DEBUG " dst=%pM src=%pM len=%d\n", + tx->dst_addr, tx->src_addr, __be16_to_cpu(tx->len)); } diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c index 3a874fc621d386a3c7ccfb160c54d443ec2c664d..8fdd41f4b4f2121a65f70d322bfe3951d1e233e0 100644 --- a/drivers/net/wireless/hostap/hostap_pci.c +++ b/drivers/net/wireless/hostap/hostap_pci.c @@ -312,7 +312,7 @@ static int prism2_pci_probe(struct pci_dev *pdev, goto err_out_disable; } - mem = ioremap(phymem, pci_resource_len(pdev, 0)); + mem = pci_ioremap_bar(pdev, 0); if (mem == NULL) { printk(KERN_ERR "prism2: Cannot remap PCI memory region\n") ; goto fail; diff --git a/drivers/net/wireless/hostap/hostap_proc.c b/drivers/net/wireless/hostap/hostap_proc.c index b03536008ad98df43218fe8a9aef9e7b05fb0fe2..005ff25a405f2bfde34adf66d4e9e85f85c44f2a 100644 --- a/drivers/net/wireless/hostap/hostap_proc.c +++ b/drivers/net/wireless/hostap/hostap_proc.c @@ -2,7 +2,7 @@ #include #include -#include +#include #include "hostap_wlan.h" #include "hostap.h" @@ -36,9 +36,10 @@ static int prism2_debug_proc_read(char *page, char **start, off_t off, p += sprintf(p, "dev_enabled=%d\n", local->dev_enabled); p += sprintf(p, "sw_tick_stuck=%d\n", local->sw_tick_stuck); for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt[i] && local->crypt[i]->ops) { - p += sprintf(p, "crypt[%d]=%s\n", - i, local->crypt[i]->ops->name); + if (local->crypt_info.crypt[i] && + local->crypt_info.crypt[i]->ops) { + p += sprintf(p, "crypt[%d]=%s\n", i, + local->crypt_info.crypt[i]->ops->name); } } p += sprintf(p, "pri_only=%d\n", local->pri_only); @@ -106,7 +107,6 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off, local_info_t *local = (local_info_t *) data; struct list_head *ptr; struct hostap_interface *iface; - DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -118,9 +118,9 @@ static int prism2_wds_proc_read(char *page, char **start, off_t off, iface = list_entry(ptr, struct hostap_interface, list); if (iface->type != HOSTAP_INTERFACE_WDS) continue; - p += sprintf(p, "%s\t%s\n", + p += sprintf(p, "%s\t%pM\n", iface->dev->name, - print_mac(mac, iface->u.wds.remote_addr)); + iface->u.wds.remote_addr); if ((p - page) > PROC_LIMIT) { printk(KERN_DEBUG "%s: wds proc did not fit\n", local->dev->name); @@ -148,7 +148,6 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off, struct list_head *ptr; struct hostap_bss_info *bss; int i; - DECLARE_MAC_BUF(mac); if (off > PROC_LIMIT) { *eof = 1; @@ -160,8 +159,8 @@ static int prism2_bss_list_proc_read(char *page, char **start, off_t off, spin_lock_bh(&local->lock); list_for_each(ptr, &local->bss_list) { bss = list_entry(ptr, struct hostap_bss_info, list); - p += sprintf(p, "%s\t%lu\t%u\t0x%x\t", - print_mac(mac, bss->bssid), bss->last_update, + p += sprintf(p, "%pM\t%lu\t%u\t0x%x\t", + bss->bssid, bss->last_update, bss->count, bss->capab_info); for (i = 0; i < bss->ssid_len; i++) { p += sprintf(p, "%c", @@ -208,12 +207,13 @@ static int prism2_crypt_proc_read(char *page, char **start, off_t off, return 0; } - p += sprintf(p, "tx_keyidx=%d\n", local->tx_keyidx); + p += sprintf(p, "tx_keyidx=%d\n", local->crypt_info.tx_keyidx); for (i = 0; i < WEP_KEYS; i++) { - if (local->crypt[i] && local->crypt[i]->ops && - local->crypt[i]->ops->print_stats) { - p = local->crypt[i]->ops->print_stats( - p, local->crypt[i]->priv); + if (local->crypt_info.crypt[i] && + local->crypt_info.crypt[i]->ops && + local->crypt_info.crypt[i]->ops->print_stats) { + p = local->crypt_info.crypt[i]->ops->print_stats( + p, local->crypt_info.crypt[i]->priv); } } @@ -314,7 +314,6 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, int entry, i, len, total = 0; struct hfa384x_hostscan_result *scanres; u8 *pos; - DECLARE_MAC_BUF(mac); p += sprintf(p, "CHID ANL SL BcnInt Capab Rate BSSID ATIM SupRates " "SSID\n"); @@ -332,14 +331,14 @@ static int prism2_scan_results_proc_read(char *page, char **start, off_t off, if ((p - page) > (PAGE_SIZE - 200)) break; - p += sprintf(p, "%d %d %d %d 0x%02x %d %s %d ", + p += sprintf(p, "%d %d %d %d 0x%02x %d %pM %d ", le16_to_cpu(scanres->chid), (s16) le16_to_cpu(scanres->anl), (s16) le16_to_cpu(scanres->sl), le16_to_cpu(scanres->beacon_interval), le16_to_cpu(scanres->capability), le16_to_cpu(scanres->rate), - print_mac(mac, scanres->bssid), + scanres->bssid, le16_to_cpu(scanres->atim)); pos = scanres->sup_rates; diff --git a/drivers/net/wireless/hostap/hostap_wlan.h b/drivers/net/wireless/hostap/hostap_wlan.h index a68f97c3935947a59990d188f7d95d05b19c600c..4d8d51a353cd3cf02395e7ab6c1eaf4333314303 100644 --- a/drivers/net/wireless/hostap/hostap_wlan.h +++ b/drivers/net/wireless/hostap/hostap_wlan.h @@ -6,6 +6,7 @@ #include #include #include +#include #include "hostap_config.h" #include "hostap_common.h" @@ -763,10 +764,7 @@ struct local_info { #define WEP_KEYS 4 #define WEP_KEY_LEN 13 - struct ieee80211_crypt_data *crypt[WEP_KEYS]; - int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ - struct timer_list crypt_deinit_timer; - struct list_head crypt_deinit_list; + struct lib80211_crypt_info crypt_info; int open_wep; /* allow unencrypted frames */ int host_encrypt; @@ -822,7 +820,7 @@ struct local_info { int last_scan_results_count; enum { PRISM2_SCAN, PRISM2_HOSTSCAN } last_scan_type; struct work_struct info_queue; - long pending_info; /* bit field of pending info_queue items */ + unsigned long pending_info; /* bit field of pending info_queue items */ #define PRISM2_INFO_PENDING_LINKSTATUS 0 #define PRISM2_INFO_PENDING_SCANRESULTS 1 int prev_link_status; /* previous received LinkStatus info */ diff --git a/drivers/net/wireless/ipw2x00/Kconfig b/drivers/net/wireless/ipw2x00/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..3d5cc4463d4d5e641601aa3fbc4eb3438007da0f --- /dev/null +++ b/drivers/net/wireless/ipw2x00/Kconfig @@ -0,0 +1,191 @@ +# +# Intel Centrino wireless drivers +# + +config IPW2100 + tristate "Intel PRO/Wireless 2100 Network Connection" + depends on PCI && WLAN_80211 + select WIRELESS_EXT + select FW_LOADER + select LIB80211 + select LIBIPW + ---help--- + A driver for the Intel PRO/Wireless 2100 Network + Connection 802.11b wireless network adapter. + + See for information on + the capabilities currently enabled in this driver and for tips + for debugging issues and problems. + + In order to use this driver, you will need a firmware image for it. + You can obtain the firmware from + . Once you have the firmware image, you + will need to place it in /lib/firmware. + + You will also very likely need the Wireless Tools in order to + configure your card: + + . + + 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 IPW2100_MONITOR + bool "Enable promiscuous mode" + depends on IPW2100 + ---help--- + Enables promiscuous/monitor mode support for the ipw2100 driver. + With this feature compiled into the driver, you can switch to + promiscuous mode via the Wireless Tool's Monitor mode. While in this + mode, no packets can be sent. + +config IPW2100_DEBUG + bool "Enable full debugging output in IPW2100 module." + depends on IPW2100 + ---help--- + This option will enable debug tracing output for the IPW2100. + + This will result in the kernel module being ~60k larger. You can + control which debug output is sent to the kernel log by setting the + value in + + /sys/bus/pci/drivers/ipw2100/debug_level + + This entry will only exist if this option is enabled. + + If you are not trying to debug or develop the IPW2100 driver, you + most likely want to say N here. + +config IPW2200 + tristate "Intel PRO/Wireless 2200BG and 2915ABG Network Connection" + depends on PCI && WLAN_80211 + select WIRELESS_EXT + select FW_LOADER + select LIB80211 + select LIBIPW + ---help--- + A driver for the Intel PRO/Wireless 2200BG and 2915ABG Network + Connection adapters. + + See for + information on the capabilities currently enabled in this + driver and for tips for debugging issues and problems. + + In order to use this driver, you will need a firmware image for it. + You can obtain the firmware from + . See the above referenced README.ipw2200 + for information on where to install the firmware images. + + You will also very likely need the Wireless Tools in order to + configure your card: + + . + + 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" + depends on IPW2200 + ---help--- + Enables promiscuous/monitor mode support for the ipw2200 driver. + With this feature compiled into the driver, you can switch to + promiscuous mode via the Wireless Tool's Monitor mode. While in this + mode, no packets can be sent. + +config IPW2200_RADIOTAP + bool "Enable radiotap format 802.11 raw packet support" + depends on IPW2200_MONITOR + +config IPW2200_PROMISCUOUS + bool "Enable creation of a RF radiotap promiscuous interface" + depends on IPW2200_MONITOR + select IPW2200_RADIOTAP + ---help--- + Enables the creation of a second interface prefixed 'rtap'. + This second interface will provide every received in radiotap + format. + + This is useful for performing wireless network analysis while + maintaining an active association. + + Example usage: + + % modprobe ipw2200 rtap_iface=1 + % ifconfig rtap0 up + % tethereal -i rtap0 + + If you do not specify 'rtap_iface=1' as a module parameter then + the rtap interface will not be created and you will need to turn + it on via sysfs: + + % echo 1 > /sys/bus/pci/drivers/ipw2200/*/rtap_iface + +config IPW2200_QOS + bool "Enable QoS support" + depends on IPW2200 && EXPERIMENTAL + +config IPW2200_DEBUG + bool "Enable full debugging output in IPW2200 module." + depends on IPW2200 + ---help--- + This option will enable low level debug tracing output for IPW2200. + + Note, normal debug code is already compiled in. This low level + debug option enables debug on hot paths (e.g Tx, Rx, ISR) and + will result in the kernel module being ~70 larger. Most users + will typically not need this high verbosity debug information. + + If you are not sure, say N here. + +config LIBIPW + tristate + select WIRELESS_EXT + select CRYPTO + select CRYPTO_ARC4 + select CRYPTO_ECB + select CRYPTO_AES + select CRYPTO_MICHAEL_MIC + select CRYPTO_ECB + select CRC32 + select LIB80211 + select LIB80211_CRYPT_WEP + select LIB80211_CRYPT_TKIP + select LIB80211_CRYPT_CCMP + ---help--- + This option enables the hardware independent IEEE 802.11 + networking stack. This component is deprecated in favor of the + mac80211 component. + +config LIBIPW_DEBUG + bool "Full debugging output for the LIBIPW component" + depends on LIBIPW + ---help--- + This option will enable debug tracing output for the + libipw component. + + This will result in the kernel module being ~70k larger. You + can control which debug output is sent to the kernel log by + setting the value in + + /proc/net/ieee80211/debug_level + + For example: + + % echo 0x00000FFO > /proc/net/ieee80211/debug_level + + For a list of values you can assign to debug_level, you + can look at the bit mask values in + + If you are not trying to debug or develop the libipw + component, you most likely want to say N here. diff --git a/drivers/net/wireless/ipw2x00/Makefile b/drivers/net/wireless/ipw2x00/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..aecd2cff462bda30f0419aeff80f8b31c4e5a517 --- /dev/null +++ b/drivers/net/wireless/ipw2x00/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for the Intel Centrino wireless drivers +# + +obj-$(CONFIG_IPW2100) += ipw2100.o +obj-$(CONFIG_IPW2200) += ipw2200.o + +obj-$(CONFIG_LIBIPW) += libipw.o +libipw-objs := \ + libipw_module.o \ + libipw_tx.o \ + libipw_rx.o \ + libipw_wx.o \ + libipw_geo.o diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2x00/ipw2100.c similarity index 99% rename from drivers/net/wireless/ipw2100.c rename to drivers/net/wireless/ipw2x00/ipw2100.c index bca74811bc7ff34dd946d6ef0c5b852b54165935..1667065b86a7568b7212a26fb25d76924564ad21 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2x00/ipw2100.c @@ -163,6 +163,8 @@ that only one external action is invoked at a time. #include #include +#include + #include "ipw2100.h" #define IPW2100_VERSION "git-1.2.2" @@ -185,7 +187,7 @@ MODULE_LICENSE("GPL"); static int debug = 0; static int mode = 0; static int channel = 0; -static int associate = 1; +static int associate = 0; static int disable = 0; #ifdef CONFIG_PM static struct ipw2100_fw ipw2100_firmware; @@ -201,7 +203,7 @@ module_param(disable, int, 0444); MODULE_PARM_DESC(debug, "debug level"); MODULE_PARM_DESC(mode, "network mode (0=BSS,1=IBSS,2=Monitor)"); MODULE_PARM_DESC(channel, "channel"); -MODULE_PARM_DESC(associate, "auto associate when scanning (default on)"); +MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); static u32 ipw2100_debug_level = IPW_DL_NONE; @@ -1914,7 +1916,7 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) u32 chan; char *txratename; u8 bssid[ETH_ALEN]; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); /* * TBD: BSSID is usually 00:00:00:00:00:00 here and not @@ -1975,10 +1977,9 @@ static void isr_indicate_associated(struct ipw2100_priv *priv, u32 status) break; } - IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=" - "%s)\n", - priv->net_dev->name, escape_essid(essid, essid_len), - txratename, chan, print_mac(mac, bssid)); + IPW_DEBUG_INFO("%s: Associated with '%s' at %s, channel %d (BSSID=%pM)\n", + priv->net_dev->name, print_ssid(ssid, essid, essid_len), + txratename, chan, bssid); /* now we copy read ssid into dev */ if (!(priv->config & CFG_STATIC_ESSID)) { @@ -2004,8 +2005,9 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, .host_command_length = ssid_len }; int err; + DECLARE_SSID_BUF(ssid); - IPW_DEBUG_HC("SSID: '%s'\n", escape_essid(essid, ssid_len)); + IPW_DEBUG_HC("SSID: '%s'\n", print_ssid(ssid, essid, ssid_len)); if (ssid_len) memcpy(cmd.host_command_parameters, essid, ssid_len); @@ -2046,12 +2048,12 @@ static int ipw2100_set_essid(struct ipw2100_priv *priv, char *essid, static void isr_indicate_association_lost(struct ipw2100_priv *priv, u32 status) { - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' %s \n", - escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + "disassociated: '%s' %pM \n", + print_ssid(ssid, priv->essid, priv->essid_len), + priv->bssid); priv->status &= ~(STATUS_ASSOCIATED | STATUS_ASSOCIATING); @@ -4008,7 +4010,7 @@ static ssize_t show_internals(struct device *d, struct device_attribute *attr, else len += sprintf(buf + len, "not connected\n"); - DUMP_VAR(ieee->crypt[priv->ieee->tx_keyidx], "p"); + DUMP_VAR(ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx], "p"); DUMP_VAR(status, "08lx"); DUMP_VAR(config, "08lx"); DUMP_VAR(capability, "08lx"); @@ -4058,7 +4060,6 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, char *out = buf; int length; int ret; - DECLARE_MAC_BUF(mac); if (priv->status & STATUS_RF_KILL_MASK) return 0; @@ -4086,7 +4087,7 @@ static ssize_t show_bssinfo(struct device *d, struct device_attribute *attr, __LINE__); out += sprintf(out, "ESSID: %s\n", essid); - out += sprintf(out, "BSSID: %s\n", print_mac(mac, bssid)); + out += sprintf(out, "BSSID: %pM\n", bssid); out += sprintf(out, "Channel: %d\n", chan); return out - buf; @@ -4662,7 +4663,6 @@ static int ipw2100_read_mac_address(struct ipw2100_priv *priv) { u32 length = ETH_ALEN; u8 addr[ETH_ALEN]; - DECLARE_MAC_BUF(mac); int err; @@ -4673,8 +4673,7 @@ static int ipw2100_read_mac_address(struct ipw2100_priv *priv) } memcpy(priv->net_dev->dev_addr, addr, ETH_ALEN); - IPW_DEBUG_INFO("card MAC is %s\n", - print_mac(mac, priv->net_dev->dev_addr)); + IPW_DEBUG_INFO("card MAC is %pM\n", priv->net_dev->dev_addr); return 0; } @@ -5053,10 +5052,8 @@ static int ipw2100_set_mandatory_bssid(struct ipw2100_priv *priv, u8 * bssid, int err; #ifdef CONFIG_IPW2100_DEBUG - DECLARE_MAC_BUF(mac); if (bssid != NULL) - IPW_DEBUG_HC("MANDATORY_BSSID: %s\n", - print_mac(mac, bssid)); + IPW_DEBUG_HC("MANDATORY_BSSID: %pM\n", bssid); else IPW_DEBUG_HC("MANDATORY_BSSID: \n"); #endif @@ -5271,21 +5268,21 @@ static int ipw2100_set_ibss_beacon_interval(struct ipw2100_priv *priv, return 0; } -void ipw2100_queues_initialize(struct ipw2100_priv *priv) +static void ipw2100_queues_initialize(struct ipw2100_priv *priv) { ipw2100_tx_initialize(priv); ipw2100_rx_initialize(priv); ipw2100_msg_initialize(priv); } -void ipw2100_queues_free(struct ipw2100_priv *priv) +static void ipw2100_queues_free(struct ipw2100_priv *priv) { ipw2100_tx_free(priv); ipw2100_rx_free(priv); ipw2100_msg_free(priv); } -int ipw2100_queues_allocate(struct ipw2100_priv *priv) +static int ipw2100_queues_allocate(struct ipw2100_priv *priv) { if (ipw2100_tx_allocate(priv) || ipw2100_rx_allocate(priv) || ipw2100_msg_allocate(priv)) @@ -5517,7 +5514,7 @@ static int ipw2100_configure_security(struct ipw2100_priv *priv, int batch_mode) } } - ipw2100_set_key_index(priv, priv->ieee->tx_keyidx, 1); + ipw2100_set_key_index(priv, priv->ieee->crypt_info.tx_keyidx, 1); } /* Always enable privacy so the Host can filter WEP packets if @@ -6905,7 +6902,6 @@ static int ipw2100_wx_set_wap(struct net_device *dev, static const unsigned char off[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - DECLARE_MAC_BUF(mac); // sanity checks if (wrqu->ap_addr.sa_family != ARPHRD_ETHER) @@ -6931,8 +6927,7 @@ static int ipw2100_wx_set_wap(struct net_device *dev, err = ipw2100_set_mandatory_bssid(priv, wrqu->ap_addr.sa_data, 0); - IPW_DEBUG_WX("SET BSSID -> %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("SET BSSID -> %pM\n", wrqu->ap_addr.sa_data); done: mutex_unlock(&priv->action_mutex); @@ -6948,7 +6943,6 @@ static int ipw2100_wx_get_wap(struct net_device *dev, */ struct ipw2100_priv *priv = ieee80211_priv(dev); - DECLARE_MAC_BUF(mac); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -6958,8 +6952,7 @@ static int ipw2100_wx_get_wap(struct net_device *dev, } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - IPW_DEBUG_WX("Getting WAP BSSID: %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", wrqu->ap_addr.sa_data); return 0; } @@ -6971,6 +6964,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev, char *essid = ""; /* ANY */ int length = 0; int err = 0; + DECLARE_SSID_BUF(ssid); mutex_lock(&priv->action_mutex); if (!(priv->status & STATUS_INITIALIZED)) { @@ -7000,8 +6994,8 @@ static int ipw2100_wx_set_essid(struct net_device *dev, goto done; } - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(essid, length), - length); + IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", + print_ssid(ssid, essid, length), length); priv->essid_len = length; memcpy(priv->essid, essid, priv->essid_len); @@ -7022,12 +7016,13 @@ static int ipw2100_wx_get_essid(struct net_device *dev, */ struct ipw2100_priv *priv = ieee80211_priv(dev); + DECLARE_SSID_BUF(ssid); /* If we are associated, trying to associate, or have a statically * configured ESSID then return that; otherwise return ANY */ if (priv->config & CFG_STATIC_ESSID || priv->status & STATUS_ASSOCIATED) { IPW_DEBUG_WX("Getting essid: '%s'\n", - escape_essid(priv->essid, priv->essid_len)); + print_ssid(ssid, priv->essid, priv->essid_len)); memcpy(extra, priv->essid, priv->essid_len); wrqu->essid.length = priv->essid_len; wrqu->essid.flags = 1; /* active */ @@ -7625,7 +7620,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev, struct ipw2100_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; unsigned long flags; int ret = 0; @@ -7640,7 +7635,7 @@ static int ipw2100_wx_set_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) break; @@ -7717,7 +7712,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev, { struct ipw2100_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; int ret = 0; @@ -7733,7 +7728,7 @@ static int ipw2100_wx_get_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->get_flags) { IPW_DEBUG_WARNING("Can't get TKIP countermeasures: " "crypt not set!\n"); diff --git a/drivers/net/wireless/ipw2100.h b/drivers/net/wireless/ipw2x00/ipw2100.h similarity index 100% rename from drivers/net/wireless/ipw2100.h rename to drivers/net/wireless/ipw2x00/ipw2100.h diff --git a/drivers/net/wireless/ipw2200.c b/drivers/net/wireless/ipw2x00/ipw2200.c similarity index 97% rename from drivers/net/wireless/ipw2200.c rename to drivers/net/wireless/ipw2x00/ipw2200.c index 7a9f901d4ff6dee5cf15ae78d0f9bb763344bdd7..625f2cf99fa9f9a7bf4976aeb460523e18b1b920 100644 --- a/drivers/net/wireless/ipw2200.c +++ b/drivers/net/wireless/ipw2x00/ipw2200.c @@ -87,7 +87,7 @@ static int channel = 0; static int mode = 0; static u32 ipw_debug_level; -static int associate = 1; +static int associate; static int auto_create = 1; static int led = 0; static int disable = 0; @@ -2265,8 +2265,8 @@ static int ipw_send_adapter_address(struct ipw_priv *priv, u8 * mac) return -1; } - IPW_DEBUG_INFO("%s: Setting MAC to %s\n", - priv->net_dev->name, print_mac(mac, mac)); + IPW_DEBUG_INFO("%s: Setting MAC to %pM\n", + priv->net_dev->name, mac); return ipw_send_cmd_pdu(priv, IPW_CMD_ADAPTER_ADDRESS, ETH_ALEN, mac); } @@ -3812,7 +3812,6 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) { struct ipw_station_entry entry; int i; - DECLARE_MAC_BUF(mac); for (i = 0; i < priv->num_stations; i++) { if (!memcmp(priv->stations[i], bssid, ETH_ALEN)) { @@ -3829,7 +3828,7 @@ static u8 ipw_add_station(struct ipw_priv *priv, u8 * bssid) if (i == MAX_STATIONS) return IPW_INVALID_STATION; - IPW_DEBUG_SCAN("Adding AdHoc station: %s\n", print_mac(mac, bssid)); + IPW_DEBUG_SCAN("Adding AdHoc station: %pM\n", bssid); entry.reserved = 0; entry.support_mode = 0; @@ -3856,7 +3855,6 @@ static u8 ipw_find_station(struct ipw_priv *priv, u8 * bssid) static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) { int err; - DECLARE_MAC_BUF(mac); if (priv->status & STATUS_ASSOCIATING) { IPW_DEBUG_ASSOC("Disassociating while associating.\n"); @@ -3869,9 +3867,9 @@ static void ipw_send_disassociate(struct ipw_priv *priv, int quiet) return; } - IPW_DEBUG_ASSOC("Disassocation attempt from %s " + IPW_DEBUG_ASSOC("Disassocation attempt from %pM " "on channel %d.\n", - print_mac(mac, priv->assoc_request.bssid), + priv->assoc_request.bssid, priv->assoc_request.channel); priv->status &= ~(STATUS_ASSOCIATING | STATUS_ASSOCIATED); @@ -4347,7 +4345,8 @@ static void ipw_handle_missed_beacon(struct ipw_priv *priv, return; } - if (priv->status & STATUS_SCANNING) { + if (priv->status & STATUS_SCANNING && + missed_count > IPW_MB_SCAN_CANCEL_THRESHOLD) { /* Stop scan to keep fw from getting * stuck (only if we aren't roaming -- * otherwise we'll never scan more than 2 or 3 @@ -4398,7 +4397,7 @@ static void handle_scan_event(struct ipw_priv *priv) static void ipw_rx_notification(struct ipw_priv *priv, struct ipw_rx_notification *notif) { - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); u16 size = le16_to_cpu(notif->size); notif->size = le16_to_cpu(notif->size); @@ -4412,11 +4411,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, case CMAS_ASSOCIATED:{ IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "associated: '%s' %s" - " \n", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "associated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); switch (priv->ieee->iw_mode) { case IW_MODE_INFRA: @@ -4450,7 +4448,7 @@ static void ipw_rx_notification(struct ipw_priv *priv, #ifdef CONFIG_IPW2200_QOS #define IPW_GET_PACKET_STYPE(x) WLAN_FC_GET_STYPE( \ - le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_ctl)) + le16_to_cpu(((struct ieee80211_hdr *)(x))->frame_control)) if ((priv->status & STATUS_AUTH) && (IPW_GET_PACKET_STYPE(¬if->u.raw) == IEEE80211_STYPE_ASSOC_RESP)) { @@ -4493,13 +4491,14 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DL_STATE | IPW_DL_ASSOC, "deauthenticated: '%s' " - "%s" + "%pM" ": (0x%04X) - %s \n", - escape_essid(priv-> - essid, - priv-> - essid_len), - print_mac(mac, priv->bssid), + print_ssid(ssid, + priv-> + essid, + priv-> + essid_len), + priv->bssid, le16_to_cpu(auth->status), ipw_get_status_code (le16_to_cpu @@ -4516,11 +4515,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "authenticated: '%s' %s" - "\n", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "authenticated: '%s' %pM\n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); break; } @@ -4545,11 +4543,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "disassociated: '%s' %s" - " \n", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "disassociated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); priv->status &= ~(STATUS_DISASSOCIATING | @@ -4584,10 +4581,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, switch (auth->state) { case CMAS_AUTHENTICATED: IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE, - "authenticated: '%s' %s \n", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "authenticated: '%s' %pM \n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); priv->status |= STATUS_AUTH; break; @@ -4603,10 +4600,10 @@ static void ipw_rx_notification(struct ipw_priv *priv, } IPW_DEBUG(IPW_DL_NOTIF | IPW_DL_STATE | IPW_DL_ASSOC, - "deauthenticated: '%s' %s\n", - escape_essid(priv->essid, - priv->essid_len), - print_mac(mac, priv->bssid)); + "deauthenticated: '%s' %pM\n", + print_ssid(ssid, priv->essid, + priv->essid_len), + priv->bssid); priv->status &= ~(STATUS_ASSOCIATING | STATUS_AUTH | @@ -5430,27 +5427,17 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, int roaming) { struct ipw_supported_rates rates; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); + DECLARE_SSID_BUF(ssid); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ if ((priv->ieee->iw_mode == IW_MODE_ADHOC && !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded due to " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded due to " "capability mismatch.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); - return 0; - } - - /* If we do not have an ESSID for this AP, we can not associate with - * it */ - if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " - "because of hidden ESSID.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5460,11 +5447,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if ((network->ssid_len != match->network->ssid_len) || memcmp(network->ssid, match->network->ssid, network->ssid_len)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of non-network ESSID.\n", - escape_essid(network->ssid, - network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } } else { @@ -5477,13 +5464,14 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_essid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), sizeof(escaped)); - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of ESSID mismatch: '%s'.\n", - escaped, print_mac(mac, network->bssid), - escape_essid(priv->essid, - priv->essid_len)); + escaped, network->bssid, + print_ssid(ssid, priv->essid, + priv->essid_len)); return 0; } } @@ -5494,24 +5482,25 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if (network->time_stamp[0] < match->network->time_stamp[0]) { IPW_DEBUG_MERGE("Network '%s excluded because newer than " "current network.\n", - escape_essid(match->network->ssid, - match->network->ssid_len)); + print_ssid(ssid, match->network->ssid, + match->network->ssid_len)); return 0; } else if (network->time_stamp[1] < match->network->time_stamp[1]) { IPW_DEBUG_MERGE("Network '%s excluded because newer than " "current network.\n", - escape_essid(match->network->ssid, - match->network->ssid_len)); + print_ssid(ssid, match->network->ssid, + match->network->ssid_len)); return 0; } /* Now go through and see if the requested network is valid... */ if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of age: %ums.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5519,10 +5508,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_CHANNEL) && (network->channel != priv->channel)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of channel mismatch: %d != %d.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, network->channel, priv->channel); return 0; } @@ -5530,10 +5520,11 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Verify privacy compatability */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of privacy mismatch: %s != %s.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, priv-> capability & CAP_PRIVACY_ON ? "on" : "off", network-> @@ -5543,41 +5534,44 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, } if (!memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " - "because of the same BSSID match: %s" - ".\n", escape_essid(network->ssid, - network->ssid_len), - print_mac(mac, network->bssid), - print_mac(mac2, priv->bssid)); + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " + "because of the same BSSID match: %pM" + ".\n", print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, + priv->bssid); return 0; } /* Filter out any incompatible freq / mode combinations */ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } /* Ensure that the rates supported by the driver are compatible with * this AP, including verification of basic rates (mandatory) */ if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } if (rates.num_rates == 0) { - IPW_DEBUG_MERGE("Network '%s (%s)' excluded " + IPW_DEBUG_MERGE("Network '%s (%pM)' excluded " "because of no compatible rates.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5588,15 +5582,16 @@ static int ipw_find_adhoc_network(struct ipw_priv *priv, /* Set up 'new' AP to this network */ ipw_copy_rates(&match->rates, &rates); match->network = network; - IPW_DEBUG_MERGE("Network '%s (%s)' is a viable match.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + IPW_DEBUG_MERGE("Network '%s (%pM)' is a viable match.\n", + print_ssid(ssid, network->ssid, network->ssid_len), + network->bssid); return 1; } static void ipw_merge_adhoc_network(struct work_struct *work) { + DECLARE_SSID_BUF(ssid); struct ipw_priv *priv = container_of(work, struct ipw_priv, merge_networks); struct ieee80211_network *network = NULL; @@ -5627,8 +5622,8 @@ static void ipw_merge_adhoc_network(struct work_struct *work) mutex_lock(&priv->mutex); if ((priv->ieee->iw_mode == IW_MODE_ADHOC)) { IPW_DEBUG_MERGE("remove network %s\n", - escape_essid(priv->essid, - priv->essid_len)); + print_ssid(ssid, priv->essid, + priv->essid_len)); ipw_remove_current_network(priv); } @@ -5644,7 +5639,7 @@ static int ipw_best_network(struct ipw_priv *priv, struct ieee80211_network *network, int roaming) { struct ipw_supported_rates rates; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); /* Verify that this network's capability is compatible with the * current mode (AdHoc or Infrastructure) */ @@ -5652,20 +5647,11 @@ static int ipw_best_network(struct ipw_priv *priv, !(network->capability & WLAN_CAPABILITY_ESS)) || (priv->ieee->iw_mode == IW_MODE_ADHOC && !(network->capability & WLAN_CAPABILITY_IBSS))) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded due to " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded due to " "capability mismatch.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); - return 0; - } - - /* If we do not have an ESSID for this AP, we can not associate with - * it */ - if (network->flags & NETWORK_EMPTY_ESSID) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " - "because of hidden ESSID.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5675,11 +5661,11 @@ static int ipw_best_network(struct ipw_priv *priv, if ((network->ssid_len != match->network->ssid_len) || memcmp(network->ssid, match->network->ssid, network->ssid_len)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of non-network ESSID.\n", - escape_essid(network->ssid, - network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } } else { @@ -5691,13 +5677,14 @@ static int ipw_best_network(struct ipw_priv *priv, min(network->ssid_len, priv->essid_len)))) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_essid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, + network->ssid_len), sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of ESSID mismatch: '%s'.\n", - escaped, print_mac(mac, network->bssid), - escape_essid(priv->essid, - priv->essid_len)); + escaped, network->bssid, + print_ssid(ssid, priv->essid, + priv->essid_len)); return 0; } } @@ -5707,14 +5694,14 @@ static int ipw_best_network(struct ipw_priv *priv, if (match->network && match->network->stats.rssi > network->stats.rssi) { char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; strncpy(escaped, - escape_essid(network->ssid, network->ssid_len), + print_ssid(ssid, network->ssid, network->ssid_len), sizeof(escaped)); - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded because " - "'%s (%s)' has a stronger signal.\n", - escaped, print_mac(mac, network->bssid), - escape_essid(match->network->ssid, - match->network->ssid_len), - print_mac(mac, match->network->bssid)); + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded because " + "'%s (%pM)' has a stronger signal.\n", + escaped, network->bssid, + print_ssid(ssid, match->network->ssid, + match->network->ssid_len), + match->network->bssid); return 0; } @@ -5722,11 +5709,12 @@ static int ipw_best_network(struct ipw_priv *priv, * last 3 seconds, do not try and associate again... */ if (network->last_associate && time_after(network->last_associate + (HZ * 3UL), jiffies)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of storming (%ums since last " "assoc attempt).\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, jiffies_to_msecs(jiffies - network->last_associate)); return 0; @@ -5735,10 +5723,11 @@ static int ipw_best_network(struct ipw_priv *priv, /* Now go through and see if the requested network is valid... */ if (priv->ieee->scan_age != 0 && time_after(jiffies, network->last_scanned + priv->ieee->scan_age)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of age: %ums.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, jiffies_to_msecs(jiffies - network->last_scanned)); return 0; @@ -5746,10 +5735,11 @@ static int ipw_best_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_CHANNEL) && (network->channel != priv->channel)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of channel mismatch: %d != %d.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, network->channel, priv->channel); return 0; } @@ -5757,10 +5747,11 @@ static int ipw_best_network(struct ipw_priv *priv, /* Verify privacy compatability */ if (((priv->capability & CAP_PRIVACY_ON) ? 1 : 0) != ((network->capability & WLAN_CAPABILITY_PRIVACY) ? 1 : 0)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of privacy mismatch: %s != %s.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, priv->capability & CAP_PRIVACY_ON ? "on" : "off", network->capability & @@ -5770,48 +5761,53 @@ static int ipw_best_network(struct ipw_priv *priv, if ((priv->config & CFG_STATIC_BSSID) && memcmp(network->bssid, priv->bssid, ETH_ALEN)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " - "because of BSSID mismatch: %s.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid), print_mac(mac, priv->bssid)); + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " + "because of BSSID mismatch: %pM.\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, priv->bssid); return 0; } /* Filter out any incompatible freq / mode combinations */ if (!ieee80211_is_valid_mode(priv->ieee, network->mode)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid frequency/mode " "combination.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } /* Filter out invalid channel in current GEO */ if (!ieee80211_is_valid_channel(priv->ieee, network->channel)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of invalid channel in current GEO\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } /* Ensure that the rates supported by the driver are compatible with * this AP, including verification of basic rates (mandatory) */ if (!ipw_compatible_rates(priv, network, &rates)) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because configured rate mask excludes " "AP mandatory rate.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } if (rates.num_rates == 0) { - IPW_DEBUG_ASSOC("Network '%s (%s)' excluded " + IPW_DEBUG_ASSOC("Network '%s (%pM)' excluded " "because of no compatible rates.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 0; } @@ -5823,9 +5819,9 @@ static int ipw_best_network(struct ipw_priv *priv, ipw_copy_rates(&match->rates, &rates); match->network = network; - IPW_DEBUG_ASSOC("Network '%s (%s)' is a viable match.\n", - escape_essid(network->ssid, network->ssid_len), - print_mac(mac, network->bssid)); + IPW_DEBUG_ASSOC("Network '%s (%pM)' is a viable match.\n", + print_ssid(ssid, network->ssid, network->ssid_len), + network->bssid); return 1; } @@ -6067,7 +6063,7 @@ static void ipw_bg_adhoc_check(struct work_struct *work) static void ipw_debug_config(struct ipw_priv *priv) { - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); IPW_DEBUG_INFO("Scan completed, no valid APs matched " "[CFG 0x%08X]\n", priv->config); if (priv->config & CFG_STATIC_CHANNEL) @@ -6076,12 +6072,11 @@ static void ipw_debug_config(struct ipw_priv *priv) IPW_DEBUG_INFO("Channel unlocked.\n"); if (priv->config & CFG_STATIC_ESSID) IPW_DEBUG_INFO("ESSID locked to '%s'\n", - escape_essid(priv->essid, priv->essid_len)); + print_ssid(ssid, priv->essid, priv->essid_len)); else IPW_DEBUG_INFO("ESSID unlocked.\n"); if (priv->config & CFG_STATIC_BSSID) - IPW_DEBUG_INFO("BSSID locked to %s\n", - print_mac(mac, priv->bssid)); + IPW_DEBUG_INFO("BSSID locked to %pM\n", priv->bssid); else IPW_DEBUG_INFO("BSSID unlocked.\n"); if (priv->capability & CAP_PRIVACY_ON) @@ -6277,6 +6272,20 @@ static void ipw_add_scan_channels(struct ipw_priv *priv, } } +static int ipw_passive_dwell_time(struct ipw_priv *priv) +{ + /* staying on passive channels longer than the DTIM interval during a + * scan, while associated, causes the firmware to cancel the scan + * without notification. Hence, don't stay on passive channels longer + * than the beacon interval. + */ + if (priv->status & STATUS_ASSOCIATED + && priv->assoc_network->beacon_interval > 10) + return priv->assoc_network->beacon_interval - 10; + else + return 120; +} + static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) { struct ipw_scan_request_ext scan; @@ -6320,16 +6329,16 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) scan.full_scan_index = cpu_to_le32(ieee80211_get_scans(priv->ieee)); if (type == IW_SCAN_TYPE_PASSIVE) { - IPW_DEBUG_WX("use passive scanning\n"); - scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN; + IPW_DEBUG_WX("use passive scanning\n"); + scan_type = IPW_SCAN_PASSIVE_FULL_DWELL_SCAN; scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = - cpu_to_le16(120); + cpu_to_le16(ipw_passive_dwell_time(priv)); ipw_add_scan_channels(priv, &scan, scan_type); goto send_request; } /* Use active scan by default. */ - if (priv->config & CFG_SPEED_SCAN) + if (priv->config & CFG_SPEED_SCAN) scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_SCAN] = cpu_to_le16(30); else @@ -6339,7 +6348,8 @@ static int ipw_request_scan_helper(struct ipw_priv *priv, int type, int direct) scan.dwell_time[IPW_SCAN_ACTIVE_BROADCAST_AND_DIRECT_SCAN] = cpu_to_le16(20); - scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = cpu_to_le16(120); + scan.dwell_time[IPW_SCAN_PASSIVE_FULL_DWELL_SCAN] = + cpu_to_le16(ipw_passive_dwell_time(priv)); scan.dwell_time[IPW_SCAN_ACTIVE_DIRECT_SCAN] = cpu_to_le16(20); #ifdef CONFIG_IPW2200_MONITOR @@ -6607,7 +6617,7 @@ static int ipw_wx_set_auth(struct net_device *dev, struct ipw_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; struct iw_param *param = &wrqu->param; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; unsigned long flags; int ret = 0; @@ -6629,7 +6639,7 @@ static int ipw_wx_set_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->set_flags || !crypt->ops->get_flags) break; @@ -6706,7 +6716,7 @@ static int ipw_wx_get_auth(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); struct ieee80211_device *ieee = priv->ieee; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; struct iw_param *param = &wrqu->param; int ret = 0; @@ -6722,7 +6732,7 @@ static int ipw_wx_get_auth(struct net_device *dev, break; case IW_AUTH_TKIP_COUNTERMEASURES: - crypt = priv->ieee->crypt[priv->ieee->tx_keyidx]; + crypt = priv->ieee->crypt_info.crypt[priv->ieee->crypt_info.tx_keyidx]; if (!crypt || !crypt->ops->get_flags) break; @@ -6893,8 +6903,7 @@ static int ipw_qos_handle_probe_response(struct ipw_priv *priv, if ((priv->status & STATUS_ASSOCIATED) && (priv->ieee->iw_mode == IW_MODE_ADHOC) && (active_network == 0)) { if (memcmp(network->bssid, priv->bssid, ETH_ALEN)) - if ((network->capability & WLAN_CAPABILITY_IBSS) && - !(network->flags & NETWORK_EMPTY_ESSID)) + if (network->capability & WLAN_CAPABILITY_IBSS) if ((network->ssid_len == priv->assoc_network->ssid_len) && !memcmp(network->ssid, @@ -7296,7 +7305,7 @@ static int ipw_associate_network(struct ipw_priv *priv, struct ipw_supported_rates *rates, int roaming) { int err; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); if (priv->config & CFG_FIXED_RATE) ipw_set_fixed_rate(priv, network->mode); @@ -7365,7 +7374,7 @@ static int ipw_associate_network(struct ipw_priv *priv, IPW_DEBUG_ASSOC("%sssocation attempt: '%s', channel %d, " "802.11%c [%d], %s[:%s], enc=%s%s%s%c%c\n", roaming ? "Rea" : "A", - escape_essid(priv->essid, priv->essid_len), + print_ssid(ssid, priv->essid, priv->essid_len), network->channel, ipw_modes[priv->assoc_request.ieee_mode], rates->num_rates, @@ -7464,9 +7473,9 @@ static int ipw_associate_network(struct ipw_priv *priv, return err; } - IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %s \n", - escape_essid(priv->essid, priv->essid_len), - print_mac(mac, priv->bssid)); + IPW_DEBUG(IPW_DL_STATE, "associating: '%s' %pM \n", + print_ssid(ssid, priv->essid, priv->essid_len), + priv->bssid); return 0; } @@ -7556,6 +7565,7 @@ static int ipw_associate(void *data) struct ipw_supported_rates *rates; struct list_head *element; unsigned long flags; + DECLARE_SSID_BUF(ssid); if (priv->ieee->iw_mode == IW_MODE_MONITOR) { IPW_DEBUG_ASSOC("Not attempting association (monitor mode)\n"); @@ -7582,8 +7592,7 @@ static int ipw_associate(void *data) } if (!(priv->config & CFG_ASSOCIATE) && - !(priv->config & (CFG_STATIC_ESSID | - CFG_STATIC_CHANNEL | CFG_STATIC_BSSID))) { + !(priv->config & (CFG_STATIC_ESSID | CFG_STATIC_BSSID))) { IPW_DEBUG_ASSOC("Not attempting association (associate=0)\n"); return 0; } @@ -7605,7 +7614,6 @@ static int ipw_associate(void *data) if (list_empty(&priv->ieee->network_free_list)) { struct ieee80211_network *oldest = NULL; struct ieee80211_network *target; - DECLARE_MAC_BUF(mac); list_for_each_entry(target, &priv->ieee->network_list, list) { if ((oldest == NULL) || @@ -7616,11 +7624,11 @@ static int ipw_associate(void *data) /* If there are no more slots, expire the oldest */ list_del(&oldest->list); target = oldest; - IPW_DEBUG_ASSOC("Expired '%s' (%s) from " + IPW_DEBUG_ASSOC("Expired '%s' (%pM) from " "network list.\n", - escape_essid(target->ssid, - target->ssid_len), - print_mac(mac, target->bssid)); + print_ssid(ssid, target->ssid, + target->ssid_len), + target->bssid); list_add_tail(&target->list, &priv->ieee->network_free_list); } @@ -7673,12 +7681,12 @@ static void ipw_rebuild_decrypted_skb(struct ipw_priv *priv, u16 fc; hdr = (struct ieee80211_hdr *)skb->data; - fc = le16_to_cpu(hdr->frame_ctl); + fc = le16_to_cpu(hdr->frame_control); if (!(fc & IEEE80211_FCTL_PROTECTED)) return; fc &= ~IEEE80211_FCTL_PROTECTED; - hdr->frame_ctl = cpu_to_le16(fc); + hdr->frame_control = cpu_to_le16(fc); switch (priv->ieee->sec.level) { case SEC_LEVEL_3: /* Remove CCMP HDR */ @@ -7806,15 +7814,6 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv, memmove(rxb->skb->data + sizeof(struct ipw_rt_hdr), rxb->skb->data + IPW_RX_FRAME_SIZE, len); - /* Zero the radiotap static buffer ... We only need to zero the bytes NOT - * part of our real header, saves a little time. - * - * No longer necessary since we fill in all our data. Purge before merging - * patch officially. - * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, - * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); - */ - ipw_rt = (struct ipw_rt_hdr *)rxb->skb->data; ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; @@ -7990,17 +7989,17 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, } hdr = (void *)rxb->skb->data + IPW_RX_FRAME_SIZE; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) { + if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_MGMT) return; if (filter & IPW_PROM_MGMT_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_CTL) return; if (filter & IPW_PROM_CTL_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_DATA) return; if (filter & IPW_PROM_DATA_HEADER_ONLY) @@ -8018,19 +8017,10 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv, ipw_rt = (void *)skb->data; if (hdr_only) - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); memcpy(ipw_rt->payload, hdr, len); - /* Zero the radiotap static buffer ... We only need to zero the bytes - * NOT part of our real header, saves a little time. - * - * No longer necessary since we fill in all our data. Purge before - * merging patch officially. - * memset(rxb->skb->data + sizeof(struct ipw_rt_hdr), 0, - * IEEE80211_RADIOTAP_HDRLEN - sizeof(struct ipw_rt_hdr)); - */ - ipw_rt->rt_hdr.it_version = PKTHDR_RADIOTAP_VERSION; ipw_rt->rt_hdr.it_pad = 0; /* always good to zero */ ipw_rt->rt_hdr.it_len = cpu_to_le16(sizeof(*ipw_rt)); /* total header+data */ @@ -8238,7 +8228,7 @@ static int is_duplicate_packet(struct ipw_priv *priv, /* Comment this line now since we observed the card receives * duplicate packets but the FCTL_RETRY bit is not set in the * IBSS mode with fragmentation enabled. - BUG_ON(!(le16_to_cpu(header->frame_ctl) & IEEE80211_FCTL_RETRY)); */ + BUG_ON(!(le16_to_cpu(header->frame_control) & IEEE80211_FCTL_RETRY)); */ return 1; } @@ -8302,9 +8292,6 @@ static void ipw_rx(struct ipw_priv *priv) u32 r, w, i; u8 network_packet; u8 fill_rx = 0; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); r = ipw_read32(priv, IPW_RX_READ_INDEX); w = ipw_read32(priv, IPW_RX_WRITE_INDEX); @@ -8434,18 +8421,12 @@ static void ipw_rx(struct ipw_priv *priv) header))) { IPW_DEBUG_DROP("Dropping: " - "%s, " - "%s, " - "%s\n", - print_mac(mac, - header-> - addr1), - print_mac(mac2, - header-> - addr2), - print_mac(mac3, - header-> - addr3)); + "%pM, " + "%pM, " + "%pM\n", + header->addr1, + header->addr2, + header->addr3); break; } @@ -8984,7 +8965,6 @@ static int ipw_wx_set_wap(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - DECLARE_MAC_BUF(mac); static const unsigned char any[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff @@ -9015,8 +8995,8 @@ static int ipw_wx_set_wap(struct net_device *dev, return 0; } - IPW_DEBUG_WX("Setting mandatory BSSID to %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Setting mandatory BSSID to %pM\n", + wrqu->ap_addr.sa_data); memcpy(priv->bssid, wrqu->ap_addr.sa_data, ETH_ALEN); @@ -9034,7 +9014,6 @@ static int ipw_wx_get_wap(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); - DECLARE_MAC_BUF(mac); /* If we are associated, trying to associate, or have a statically * configured BSSID then return that; otherwise return ANY */ @@ -9046,8 +9025,8 @@ static int ipw_wx_get_wap(struct net_device *dev, } else memset(wrqu->ap_addr.sa_data, 0, ETH_ALEN); - IPW_DEBUG_WX("Getting WAP BSSID: %s\n", - print_mac(mac, wrqu->ap_addr.sa_data)); + IPW_DEBUG_WX("Getting WAP BSSID: %pM\n", + wrqu->ap_addr.sa_data); mutex_unlock(&priv->mutex); return 0; } @@ -9058,6 +9037,7 @@ static int ipw_wx_set_essid(struct net_device *dev, { struct ipw_priv *priv = ieee80211_priv(dev); int length; + DECLARE_SSID_BUF(ssid); mutex_lock(&priv->mutex); @@ -9082,8 +9062,8 @@ static int ipw_wx_set_essid(struct net_device *dev, return 0; } - IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", escape_essid(extra, length), - length); + IPW_DEBUG_WX("Setting ESSID: '%s' (%d)\n", + print_ssid(ssid, extra, length), length); priv->essid_len = length; memcpy(priv->essid, extra, priv->essid_len); @@ -9102,6 +9082,7 @@ static int ipw_wx_get_essid(struct net_device *dev, union iwreq_data *wrqu, char *extra) { struct ipw_priv *priv = ieee80211_priv(dev); + DECLARE_SSID_BUF(ssid); /* If we are associated, trying to associate, or have a statically * configured ESSID then return that; otherwise return ANY */ @@ -9109,7 +9090,7 @@ static int ipw_wx_get_essid(struct net_device *dev, if (priv->config & CFG_STATIC_ESSID || priv->status & (STATUS_ASSOCIATED | STATUS_ASSOCIATING)) { IPW_DEBUG_WX("Getting essid: '%s'\n", - escape_essid(priv->essid, priv->essid_len)); + print_ssid(ssid, priv->essid, priv->essid_len)); memcpy(extra, priv->essid, priv->essid_len); wrqu->essid.length = priv->essid_len; wrqu->essid.flags = 1; /* active */ @@ -10203,10 +10184,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, id = ipw_add_station(priv, hdr->addr1); if (id == IPW_INVALID_STATION) { IPW_WARNING("Attempt to send data to " - "invalid cell: " MAC_FMT "\n", - hdr->addr1[0], hdr->addr1[1], - hdr->addr1[2], hdr->addr1[3], - hdr->addr1[4], hdr->addr1[5]); + "invalid cell: %pM\n", + hdr->addr1); goto drop; } } @@ -10274,8 +10253,8 @@ static int ipw_tx_skb(struct ipw_priv *priv, struct ieee80211_txb *txb, case SEC_LEVEL_1: tfd->u.data.tfd.tfd_24.mchdr.frame_ctl |= cpu_to_le16(IEEE80211_FCTL_PROTECTED); - tfd->u.data.key_index = priv->ieee->tx_keyidx; - if (priv->ieee->sec.key_sizes[priv->ieee->tx_keyidx] <= + tfd->u.data.key_index = priv->ieee->crypt_info.tx_keyidx; + if (priv->ieee->sec.key_sizes[priv->ieee->crypt_info.tx_keyidx] <= 40) tfd->u.data.key_index |= DCT_WEP_KEY_64Bit; else @@ -10403,17 +10382,17 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, /* Filtering of fragment chains is done agains the first fragment */ hdr = (void *)txb->fragments[0]->data; - if (ieee80211_is_management(le16_to_cpu(hdr->frame_ctl))) { + if (ieee80211_is_management(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_MGMT) return; if (filter & IPW_PROM_MGMT_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_control(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_CTL) return; if (filter & IPW_PROM_CTL_HEADER_ONLY) hdr_only = 1; - } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_ctl))) { + } else if (ieee80211_is_data(le16_to_cpu(hdr->frame_control))) { if (filter & IPW_PROM_NO_DATA) return; if (filter & IPW_PROM_DATA_HEADER_ONLY) @@ -10428,13 +10407,13 @@ static void ipw_handle_promiscuous_tx(struct ipw_priv *priv, if (hdr_only) { hdr = (void *)src->data; - len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl)); + len = ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control)); } else len = src->len; - dst = alloc_skb( - len + IEEE80211_RADIOTAP_HDRLEN, GFP_ATOMIC); - if (!dst) continue; + dst = alloc_skb(len + sizeof(*rt_hdr), GFP_ATOMIC); + if (!dst) + continue; rt_hdr = (void *)skb_put(dst, sizeof(*rt_hdr)); @@ -10509,15 +10488,14 @@ static int ipw_net_set_mac_address(struct net_device *dev, void *p) { struct ipw_priv *priv = ieee80211_priv(dev); struct sockaddr *addr = p; - DECLARE_MAC_BUF(mac); if (!is_valid_ether_addr(addr->sa_data)) return -EADDRNOTAVAIL; mutex_lock(&priv->mutex); priv->config |= CFG_CUSTOM_MAC; memcpy(priv->mac_addr, addr->sa_data, ETH_ALEN); - printk(KERN_INFO "%s: Setting MAC to %s\n", - priv->net_dev->name, print_mac(mac, priv->mac_addr)); + printk(KERN_INFO "%s: Setting MAC to %pM\n", + priv->net_dev->name, priv->mac_addr); queue_work(priv->workqueue, &priv->adapter_restart); mutex_unlock(&priv->mutex); return 0; @@ -11652,7 +11630,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev, length = pci_resource_len(pdev, 0); priv->hw_len = length; - base = ioremap_nocache(pci_resource_start(pdev, 0), length); + base = pci_ioremap_bar(pdev, 0); if (!base) { err = -ENODEV; goto out_pci_release_regions; @@ -11944,7 +11922,7 @@ module_param(disable, int, 0444); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param(associate, int, 0444); -MODULE_PARM_DESC(associate, "auto associate when scanning (default on)"); +MODULE_PARM_DESC(associate, "auto associate when scanning (default off)"); module_param(auto_create, int, 0444); MODULE_PARM_DESC(auto_create, "auto create adhoc network (default on)"); diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2x00/ipw2200.h similarity index 99% rename from drivers/net/wireless/ipw2200.h rename to drivers/net/wireless/ipw2x00/ipw2200.h index 0bad1ec3e7e0af7c9594d6cdc2deb0cce002811a..277b274d4be5d10f6552d5273591895cc138a460 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2x00/ipw2200.h @@ -48,6 +48,7 @@ #include #include +#include #include #include @@ -244,6 +245,7 @@ enum connection_manager_assoc_states { #define HOST_NOTIFICATION_S36_MEASUREMENT_REFUSED 31 #define HOST_NOTIFICATION_STATUS_BEACON_MISSING 1 +#define IPW_MB_SCAN_CANCEL_THRESHOLD 3 #define IPW_MB_ROAMING_THRESHOLD_MIN 1 #define IPW_MB_ROAMING_THRESHOLD_DEFAULT 8 #define IPW_MB_ROAMING_THRESHOLD_MAX 30 diff --git a/net/ieee80211/ieee80211_geo.c b/drivers/net/wireless/ipw2x00/libipw_geo.c similarity index 100% rename from net/ieee80211/ieee80211_geo.c rename to drivers/net/wireless/ipw2x00/libipw_geo.c diff --git a/net/ieee80211/ieee80211_module.c b/drivers/net/wireless/ipw2x00/libipw_module.c similarity index 88% rename from net/ieee80211/ieee80211_module.c rename to drivers/net/wireless/ipw2x00/libipw_module.c index 949772a5a7dc15bd35152c3ada3df912681acfd7..a2f5616d5b095a2f80bea548871fbac24f05f751 100644 --- a/net/ieee80211/ieee80211_module.c +++ b/drivers/net/wireless/ipw2x00/libipw_module.c @@ -180,13 +180,10 @@ struct net_device *alloc_ieee80211(int sizeof_priv) ieee->host_open_frag = 1; ieee->ieee802_1x = 1; /* Default to supporting 802.1x */ - INIT_LIST_HEAD(&ieee->crypt_deinit_list); - setup_timer(&ieee->crypt_deinit_timer, ieee80211_crypt_deinit_handler, - (unsigned long)ieee); - ieee->crypt_quiesced = 0; - spin_lock_init(&ieee->lock); + lib80211_crypt_info_init(&ieee->crypt_info, dev->name, &ieee->lock); + ieee->wpa_enabled = 0; ieee->drop_unencrypted = 0; ieee->privacy_invoked = 0; @@ -203,23 +200,7 @@ void free_ieee80211(struct net_device *dev) { struct ieee80211_device *ieee = netdev_priv(dev); - int i; - - ieee80211_crypt_quiescing(ieee); - del_timer_sync(&ieee->crypt_deinit_timer); - ieee80211_crypt_deinit_entries(ieee, 1); - - for (i = 0; i < WEP_KEYS; i++) { - struct ieee80211_crypt_data *crypt = ieee->crypt[i]; - if (crypt) { - if (crypt->ops) { - crypt->ops->deinit(crypt->priv); - module_put(crypt->ops->owner); - } - kfree(crypt); - ieee->crypt[i] = NULL; - } - } + lib80211_crypt_info_free(&ieee->crypt_info); ieee80211_networks_free(ieee); free_netdev(dev); @@ -308,31 +289,5 @@ MODULE_PARM_DESC(debug, "debug output mask"); module_exit(ieee80211_exit); module_init(ieee80211_init); -const char *escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (ieee80211_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else { - *d++ = *s++; - } - } - *d = '\0'; - return escaped; -} - EXPORT_SYMBOL(alloc_ieee80211); EXPORT_SYMBOL(free_ieee80211); -EXPORT_SYMBOL(escape_essid); diff --git a/net/ieee80211/ieee80211_rx.c b/drivers/net/wireless/ipw2x00/libipw_rx.c similarity index 94% rename from net/ieee80211/ieee80211_rx.c rename to drivers/net/wireless/ipw2x00/libipw_rx.c index 69dbc342a4649271341946341b6231495e293c91..9c67dfae43200c0e0516abfc794e906be98539b9 100644 --- a/net/ieee80211/ieee80211_rx.c +++ b/drivers/net/wireless/ipw2x00/libipw_rx.c @@ -32,6 +32,7 @@ #include #include +#include #include static void ieee80211_monitor_rx(struct ieee80211_device *ieee, @@ -39,7 +40,7 @@ static void ieee80211_monitor_rx(struct ieee80211_device *ieee, struct ieee80211_rx_stats *rx_stats) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - u16 fc = le16_to_cpu(hdr->frame_ctl); + u16 fc = le16_to_cpu(hdr->frame_control); skb->dev = ieee->dev; skb_reset_mac_header(skb); @@ -267,7 +268,7 @@ static int ieee80211_is_eapol_frame(struct ieee80211_device *ieee, /* Called only as a tasklet (software IRQ), by ieee80211_rx */ static int ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, - struct ieee80211_crypt_data *crypt) + struct lib80211_crypt_data *crypt) { struct ieee80211_hdr_3addr *hdr; int res, hdrlen; @@ -282,12 +283,8 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, res = crypt->ops->decrypt_mpdu(skb, hdrlen, crypt->priv); atomic_dec(&crypt->refcnt); if (res < 0) { - IEEE80211_DEBUG_DROP("decryption failed (SA=" MAC_FMT - ") res=%d\n", - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5], - res); + IEEE80211_DEBUG_DROP("decryption failed (SA=%pM) res=%d\n", + hdr->addr2, res); if (res == -2) IEEE80211_DEBUG_DROP("Decryption failed ICV " "mismatch (key %d)\n", @@ -303,7 +300,7 @@ ieee80211_rx_frame_decrypt(struct ieee80211_device *ieee, struct sk_buff *skb, static int ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, struct sk_buff *skb, int keyidx, - struct ieee80211_crypt_data *crypt) + struct lib80211_crypt_data *crypt) { struct ieee80211_hdr_3addr *hdr; int res, hdrlen; @@ -319,11 +316,7 @@ ieee80211_rx_frame_decrypt_msdu(struct ieee80211_device *ieee, atomic_dec(&crypt->refcnt); if (res < 0) { printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed" - " (SA=" MAC_FMT " keyidx=%d)\n", - ieee->dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5], + " (SA=%pM keyidx=%d)\n", ieee->dev->name, hdr->addr2, keyidx); return -1; } @@ -355,10 +348,9 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, #endif u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; - struct ieee80211_crypt_data *crypt = NULL; + struct lib80211_crypt_data *crypt = NULL; int keyidx = 0; int can_be_decrypted = 0; - DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr_4addr *)skb->data; stats = &ieee->stats; @@ -439,7 +431,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * is only allowed 2-bits of storage, no value of keyidx can * be provided via above code that would result in keyidx * being out of range */ - crypt = ieee->crypt[keyidx]; + crypt = ieee->crypt_info.crypt[keyidx]; #ifdef NOT_YET sta = NULL; @@ -468,10 +460,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * frames silently instead of filling system log with * these reports. */ IEEE80211_DEBUG_DROP("Decryption failed (not set)" - " (SA=" MAC_FMT ")\n", - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5]); + " (SA=%pM)\n", hdr->addr2); ieee->ieee_stats.rx_discards_undecryptable++; goto rx_dropped; } @@ -482,10 +471,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, fc & IEEE80211_FCTL_PROTECTED && ieee->host_decrypt && (keyidx = hostap_rx_frame_decrypt(ieee, skb, crypt)) < 0) { printk(KERN_DEBUG "%s: failed to decrypt mgmt::auth " - "from " MAC_FMT "\n", dev->name, - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5]); + "from %pM\n", dev->name, hdr->addr2); /* TODO: could inform hostapd about this so that it * could send auth failure report */ goto rx_dropped; @@ -547,8 +533,6 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, } #endif - dev->last_rx = jiffies; - #ifdef NOT_YET if ((ieee->iw_mode == IW_MODE_MASTER || ieee->iw_mode == IW_MODE_REPEAT) && !from_assoc_ap) { @@ -663,11 +647,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, * configured */ } else { IEEE80211_DEBUG_DROP("encryption configured, but RX " - "frame not encrypted (SA=" - MAC_FMT ")\n", - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5]); + "frame not encrypted (SA=%pM)\n", + hdr->addr2); goto rx_dropped; } } @@ -675,11 +656,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb, if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !ieee->open_wep && !ieee80211_is_eapol_frame(ieee, skb)) { IEEE80211_DEBUG_DROP("dropped unencrypted RX data " - "frame from " MAC_FMT - " (drop_unencrypted=1)\n", - hdr->addr2[0], hdr->addr2[1], - hdr->addr2[2], hdr->addr2[3], - hdr->addr2[4], hdr->addr2[5]); + "frame from %pM (drop_unencrypted=1)\n", + hdr->addr2); goto rx_dropped; } @@ -1144,6 +1122,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element *info_element, u16 length, struct ieee80211_network *network) { + DECLARE_SSID_BUF(ssid); u8 i; #ifdef CONFIG_IEEE80211_DEBUG char rates_str[64]; @@ -1166,12 +1145,6 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element switch (info_element->id) { case MFIE_TYPE_SSID: - if (ieee80211_is_empty_essid(info_element->data, - info_element->len)) { - network->flags |= NETWORK_EMPTY_ESSID; - break; - } - network->ssid_len = min(info_element->len, (u8) IW_ESSID_MAX_SIZE); memcpy(network->ssid, info_element->data, @@ -1181,7 +1154,9 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element IW_ESSID_MAX_SIZE - network->ssid_len); IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n", - network->ssid, network->ssid_len); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->ssid_len); break; case MFIE_TYPE_RATES: @@ -1411,9 +1386,6 @@ static int ieee80211_handle_assoc_resp(struct ieee80211_device *ieee, struct iee network->mode |= IEEE_B; } - if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) - network->flags |= NETWORK_EMPTY_ESSID; - memcpy(&network->stats, stats, sizeof(network->stats)); if (ieee->handle_assoc_response != NULL) @@ -1429,7 +1401,7 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 struct ieee80211_network *network, struct ieee80211_rx_stats *stats) { - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); network->qos_data.active = 0; network->qos_data.supported = 0; @@ -1477,17 +1449,14 @@ static int ieee80211_network_init(struct ieee80211_device *ieee, struct ieee8021 } if (network->mode == 0) { - IEEE80211_DEBUG_SCAN("Filtered out '%s (%s)' " + IEEE80211_DEBUG_SCAN("Filtered out '%s (%pM)' " "network.\n", - escape_essid(network->ssid, - network->ssid_len), - print_mac(mac, network->bssid)); + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid); return 1; } - if (ieee80211_is_empty_essid(network->ssid, network->ssid_len)) - network->flags |= NETWORK_EMPTY_ESSID; - memcpy(&network->stats, stats, sizeof(network->stats)); return 0; @@ -1510,7 +1479,6 @@ static void update_network(struct ieee80211_network *dst, { int qos_active; u8 old_param; - DECLARE_MAC_BUF(mac); ieee80211_network_reset(dst); dst->ibss_dfs = src->ibss_dfs; @@ -1524,8 +1492,8 @@ static void update_network(struct ieee80211_network *dst, memcpy(&dst->stats, &src->stats, sizeof(struct ieee80211_rx_stats)); else - IEEE80211_DEBUG_SCAN("Network %s info received " - "off channel (%d vs. %d)\n", print_mac(mac, src->bssid), + IEEE80211_DEBUG_SCAN("Network %pM info received " + "off channel (%d vs. %d)\n", src->bssid, dst->channel, src->stats.received_channel); dst->capability = src->capability; @@ -1597,12 +1565,12 @@ static void ieee80211_process_probe_response(struct ieee80211_device struct ieee80211_info_element *info_element = beacon->info_element; #endif unsigned long flags; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); - IEEE80211_DEBUG_SCAN("'%s' (%s" + IEEE80211_DEBUG_SCAN("'%s' (%pM" "): %c%c%c%c %c%c%c%c-%c%c%c%c %c%c%c%c\n", - escape_essid(info_element->data, info_element->len), - print_mac(mac, beacon->header.addr3), + print_ssid(ssid, info_element->data, info_element->len), + beacon->header.addr3, (beacon->capability & cpu_to_le16(1 << 0xf)) ? '1' : '0', (beacon->capability & cpu_to_le16(1 << 0xe)) ? '1' : '0', (beacon->capability & cpu_to_le16(1 << 0xd)) ? '1' : '0', @@ -1621,10 +1589,10 @@ static void ieee80211_process_probe_response(struct ieee80211_device (beacon->capability & cpu_to_le16(1 << 0x0)) ? '1' : '0'); if (ieee80211_network_init(ieee, beacon, &network, stats)) { - IEEE80211_DEBUG_SCAN("Dropped '%s' (%s) via %s.\n", - escape_essid(info_element->data, - info_element->len), - print_mac(mac, beacon->header.addr3), + IEEE80211_DEBUG_SCAN("Dropped '%s' (%pM) via %s.\n", + print_ssid(ssid, info_element->data, + info_element->len), + beacon->header.addr3, is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); return; @@ -1658,11 +1626,11 @@ static void ieee80211_process_probe_response(struct ieee80211_device /* If there are no more slots, expire the oldest */ list_del(&oldest->list); target = oldest; - IEEE80211_DEBUG_SCAN("Expired '%s' (%s) from " + IEEE80211_DEBUG_SCAN("Expired '%s' (%pM) from " "network list.\n", - escape_essid(target->ssid, - target->ssid_len), - print_mac(mac, target->bssid)); + print_ssid(ssid, target->ssid, + target->ssid_len), + target->bssid); ieee80211_network_reset(target); } else { /* Otherwise just pull from the free list */ @@ -1672,10 +1640,10 @@ static void ieee80211_process_probe_response(struct ieee80211_device } #ifdef CONFIG_IEEE80211_DEBUG - IEEE80211_DEBUG_SCAN("Adding '%s' (%s) via %s.\n", - escape_essid(network.ssid, - network.ssid_len), - print_mac(mac, network.bssid), + IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n", + print_ssid(ssid, network.ssid, + network.ssid_len), + network.bssid, is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); #endif @@ -1683,10 +1651,10 @@ static void ieee80211_process_probe_response(struct ieee80211_device network.ibss_dfs = NULL; list_add_tail(&target->list, &ieee->network_list); } else { - IEEE80211_DEBUG_SCAN("Updating '%s' (%s) via %s.\n", - escape_essid(target->ssid, - target->ssid_len), - print_mac(mac, target->bssid), + IEEE80211_DEBUG_SCAN("Updating '%s' (%pM) via %s.\n", + print_ssid(ssid, target->ssid, + target->ssid_len), + target->bssid, is_beacon(beacon->header.frame_ctl) ? "BEACON" : "PROBE RESPONSE"); update_network(target, &network); diff --git a/net/ieee80211/ieee80211_tx.c b/drivers/net/wireless/ipw2x00/libipw_tx.c similarity index 98% rename from net/ieee80211/ieee80211_tx.c rename to drivers/net/wireless/ipw2x00/libipw_tx.c index d996547f7a629564aeb4fb99164054a41165c746..f78f57e8844a9c1eb2d08bbc9b3f4ba6a66b9b94 100644 --- a/net/ieee80211/ieee80211_tx.c +++ b/drivers/net/wireless/ipw2x00/libipw_tx.c @@ -152,7 +152,8 @@ static int ieee80211_copy_snap(u8 * data, __be16 h_proto) static int ieee80211_encrypt_fragment(struct ieee80211_device *ieee, struct sk_buff *frag, int hdr_len) { - struct ieee80211_crypt_data *crypt = ieee->crypt[ieee->tx_keyidx]; + struct lib80211_crypt_data *crypt = + ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; int res; if (crypt == NULL) @@ -270,7 +271,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) .qos_ctl = 0 }; u8 dest[ETH_ALEN], src[ETH_ALEN]; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; int priority = skb->priority; int snapped = 0; @@ -294,7 +295,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev) ether_type = ((struct ethhdr *)skb->data)->h_proto; - crypt = ieee->crypt[ieee->tx_keyidx]; + crypt = ieee->crypt_info.crypt[ieee->crypt_info.tx_keyidx]; encrypt = !(ether_type == htons(ETH_P_PAE) && ieee->ieee802_1x) && ieee->sec.encrypt; diff --git a/net/ieee80211/ieee80211_wx.c b/drivers/net/wireless/ipw2x00/libipw_wx.c similarity index 91% rename from net/ieee80211/ieee80211_wx.c rename to drivers/net/wireless/ipw2x00/libipw_wx.c index 973832dd7faf6a56c189290f89a1d33e87184871..31ea3abfc3277cb672d930007992dd504276186e 100644 --- a/net/ieee80211/ieee80211_wx.c +++ b/drivers/net/wireless/ipw2x00/libipw_wx.c @@ -34,6 +34,7 @@ #include #include +#include #include #include @@ -65,15 +66,9 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee, /* Add the ESSID */ iwe.cmd = SIOCGIWESSID; iwe.u.data.flags = 1; - if (network->flags & NETWORK_EMPTY_ESSID) { - iwe.u.data.length = sizeof(""); - start = iwe_stream_add_point(info, start, stop, - &iwe, ""); - } else { - iwe.u.data.length = min(network->ssid_len, (u8) 32); - start = iwe_stream_add_point(info, start, stop, - &iwe, network->ssid); - } + iwe.u.data.length = min(network->ssid_len, (u8) 32); + start = iwe_stream_add_point(info, start, stop, + &iwe, network->ssid); /* Add the protocol name */ iwe.cmd = SIOCGIWNAME; @@ -264,7 +259,7 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, char *ev = extra; char *stop = ev + wrqu->data.length; int i = 0; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); IEEE80211_DEBUG_WX("Getting scan\n"); @@ -283,10 +278,10 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee, info); else IEEE80211_DEBUG_SCAN("Not showing network '%s (" - "%s)' due to age (%dms).\n", - escape_essid(network->ssid, - network->ssid_len), - print_mac(mac, network->bssid), + "%pM)' due to age (%dms).\n", + print_ssid(ssid, network->ssid, + network->ssid_len), + network->bssid, jiffies_to_msecs(jiffies - network-> last_scanned)); @@ -312,8 +307,9 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, .flags = 0 }; int i, key, key_provided, len; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypt_data **crypt; int host_crypto = ieee->host_encrypt || ieee->host_decrypt || ieee->host_build_iv; + DECLARE_SSID_BUF(ssid); IEEE80211_DEBUG_WX("SET_ENCODE\n"); @@ -325,30 +321,30 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, key_provided = 1; } else { key_provided = 0; - key = ieee->tx_keyidx; + key = ieee->crypt_info.tx_keyidx; } IEEE80211_DEBUG_WX("Key: %d [%s]\n", key, key_provided ? "provided" : "default"); - crypt = &ieee->crypt[key]; + crypt = &ieee->crypt_info.crypt[key]; if (erq->flags & IW_ENCODE_DISABLED) { if (key_provided && *crypt) { IEEE80211_DEBUG_WX("Disabling encryption on key %d.\n", key); - ieee80211_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); } else IEEE80211_DEBUG_WX("Disabling encryption.\n"); /* Check all the keys to see if any are still configured, * and if no key index was provided, de-init them all */ for (i = 0; i < WEP_KEYS; i++) { - if (ieee->crypt[i] != NULL) { + if (ieee->crypt_info.crypt[i] != NULL) { if (key_provided) break; - ieee80211_crypt_delayed_deinit(ieee, - &ieee->crypt[i]); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, + &ieee->crypt_info.crypt[i]); } } @@ -370,21 +366,21 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, strcmp((*crypt)->ops->name, "WEP") != 0) { /* changing to use WEP; deinit previously used algorithm * on this key */ - ieee80211_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); } if (*crypt == NULL && host_crypto) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; /* take WEP into use */ - new_crypt = kzalloc(sizeof(struct ieee80211_crypt_data), + new_crypt = kzalloc(sizeof(struct lib80211_crypt_data), GFP_KERNEL); if (new_crypt == NULL) return -ENOMEM; - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + new_crypt->ops = lib80211_get_crypto_ops("WEP"); if (!new_crypt->ops) { - request_module("ieee80211_crypt_wep"); - new_crypt->ops = ieee80211_get_crypto_ops("WEP"); + request_module("lib80211_crypt_wep"); + new_crypt->ops = lib80211_get_crypto_ops("WEP"); } if (new_crypt->ops && try_module_get(new_crypt->ops->owner)) @@ -395,7 +391,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, new_crypt = NULL; printk(KERN_WARNING "%s: could not initialize WEP: " - "load module ieee80211_crypt_wep\n", dev->name); + "load module lib80211_crypt_wep\n", dev->name); return -EOPNOTSUPP; } *crypt = new_crypt; @@ -403,13 +399,17 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, /* If a new key was provided, set it up */ if (erq->length > 0) { +#ifdef CONFIG_IEEE80211_DEBUG + DECLARE_SSID_BUF(ssid); +#endif + len = erq->length <= 5 ? 5 : 13; memcpy(sec.keys[key], keybuf, erq->length); if (len > erq->length) memset(sec.keys[key] + erq->length, 0, len - erq->length); IEEE80211_DEBUG_WX("Setting key %d to '%s' (%d:%d bytes)\n", - key, escape_essid(sec.keys[key], len), + key, print_ssid(ssid, sec.keys[key], len), erq->length, len); sec.key_sizes[key] = len; if (*crypt) @@ -440,7 +440,7 @@ int ieee80211_wx_set_encode(struct ieee80211_device *ieee, if (key_provided) { IEEE80211_DEBUG_WX("Setting key %d to default Tx " "key.\n", key); - ieee->tx_keyidx = key; + ieee->crypt_info.tx_keyidx = key; sec.active_key = key; sec.flags |= SEC_ACTIVE_KEY; } @@ -485,7 +485,7 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, { struct iw_point *erq = &(wrqu->encoding); int len, key; - struct ieee80211_crypt_data *crypt; + struct lib80211_crypt_data *crypt; struct ieee80211_security *sec = &ieee->sec; IEEE80211_DEBUG_WX("GET_ENCODE\n"); @@ -496,9 +496,9 @@ int ieee80211_wx_get_encode(struct ieee80211_device *ieee, return -EINVAL; key--; } else - key = ieee->tx_keyidx; + key = ieee->crypt_info.tx_keyidx; - crypt = ieee->crypt[key]; + crypt = ieee->crypt_info.crypt[key]; erq->flags = key + 1; if (!sec->enabled) { @@ -531,8 +531,8 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, int i, idx, ret = 0; int group_key = 0; const char *alg, *module; - struct ieee80211_crypto_ops *ops; - struct ieee80211_crypt_data **crypt; + struct lib80211_crypto_ops *ops; + struct lib80211_crypt_data **crypt; struct ieee80211_security sec = { .flags = 0, @@ -544,17 +544,17 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, return -EINVAL; idx--; } else - idx = ieee->tx_keyidx; + idx = ieee->crypt_info.tx_keyidx; if (ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) { - crypt = &ieee->crypt[idx]; + crypt = &ieee->crypt_info.crypt[idx]; group_key = 1; } else { /* some Cisco APs use idx>0 for unicast in dynamic WEP */ if (idx != 0 && ext->alg != IW_ENCODE_ALG_WEP) return -EINVAL; if (ieee->iw_mode == IW_MODE_INFRA) - crypt = &ieee->crypt[idx]; + crypt = &ieee->crypt_info.crypt[idx]; else return -EINVAL; } @@ -563,10 +563,10 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, if ((encoding->flags & IW_ENCODE_DISABLED) || ext->alg == IW_ENCODE_ALG_NONE) { if (*crypt) - ieee80211_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); for (i = 0; i < WEP_KEYS; i++) - if (ieee->crypt[i] != NULL) + if (ieee->crypt_info.crypt[i] != NULL) break; if (i == WEP_KEYS) { @@ -589,15 +589,15 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, switch (ext->alg) { case IW_ENCODE_ALG_WEP: alg = "WEP"; - module = "ieee80211_crypt_wep"; + module = "lib80211_crypt_wep"; break; case IW_ENCODE_ALG_TKIP: alg = "TKIP"; - module = "ieee80211_crypt_tkip"; + module = "lib80211_crypt_tkip"; break; case IW_ENCODE_ALG_CCMP: alg = "CCMP"; - module = "ieee80211_crypt_ccmp"; + module = "lib80211_crypt_ccmp"; break; default: IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", @@ -606,10 +606,10 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, goto done; } - ops = ieee80211_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); if (ops == NULL) { request_module(module); - ops = ieee80211_get_crypto_ops(alg); + ops = lib80211_get_crypto_ops(alg); } if (ops == NULL) { IEEE80211_DEBUG_WX("%s: unknown crypto alg %d\n", @@ -619,9 +619,9 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, } if (*crypt == NULL || (*crypt)->ops != ops) { - struct ieee80211_crypt_data *new_crypt; + struct lib80211_crypt_data *new_crypt; - ieee80211_crypt_delayed_deinit(ieee, crypt); + lib80211_crypt_delayed_deinit(&ieee->crypt_info, crypt); new_crypt = kzalloc(sizeof(*new_crypt), GFP_KERNEL); if (new_crypt == NULL) { @@ -649,7 +649,7 @@ int ieee80211_wx_set_encodeext(struct ieee80211_device *ieee, skip_host_crypt: if (ext->ext_flags & IW_ENCODE_EXT_SET_TX_KEY) { - ieee->tx_keyidx = idx; + ieee->crypt_info.tx_keyidx = idx; sec.active_key = idx; sec.flags |= SEC_ACTIVE_KEY; } @@ -715,7 +715,7 @@ int ieee80211_wx_get_encodeext(struct ieee80211_device *ieee, return -EINVAL; idx--; } else - idx = ieee->tx_keyidx; + idx = ieee->crypt_info.tx_keyidx; if (!(ext->ext_flags & IW_ENCODE_EXT_GROUP_KEY) && ext->alg != IW_ENCODE_ALG_WEP) diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig index b0ac0ce3fb9f6dfb4c8d126ded42f4621d9e2877..47bee0ee0a7c3b1a040f477f450a2ecd4692e4ee 100644 --- a/drivers/net/wireless/iwlwifi/Kconfig +++ b/drivers/net/wireless/iwlwifi/Kconfig @@ -4,6 +4,7 @@ config IWLWIFI config IWLCORE tristate "Intel Wireless Wifi Core" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL + select LIB80211 select IWLWIFI select MAC80211_LEDS if IWLWIFI_LEDS select LEDS_CLASS if IWLWIFI_LEDS @@ -105,6 +106,7 @@ config IWL3945 tristate "Intel PRO/Wireless 3945ABG/BG Network Connection" depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL select FW_LOADER + select LIB80211 select IWLWIFI select MAC80211_LEDS if IWL3945_LEDS select LEDS_CLASS if IWL3945_LEDS diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile index 47aa28f6a5138993a7ad4d82000c8d50917f2c6f..0be9e6b66aa0f0187b8072dbf1c5879b0b3f8b58 100644 --- a/drivers/net/wireless/iwlwifi/Makefile +++ b/drivers/net/wireless/iwlwifi/Makefile @@ -5,9 +5,10 @@ iwlcore-objs += iwl-scan.o iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o +iwlcore-$(CONFIG_IWLAGN_SPECTRUM_MEASUREMENT) += iwl-spectrum.o obj-$(CONFIG_IWLAGN) += iwlagn.o -iwlagn-objs := iwl-agn.o iwl-agn-rs.o +iwlagn-objs := iwl-agn.o iwl-agn-rs.o iwl-agn-hcmd-check.o iwlagn-$(CONFIG_IWL4965) += iwl-4965.o iwlagn-$(CONFIG_IWL5000) += iwl-5000.o diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h index 817ece7736434f9645749c2e12940aca11f1106a..c6f4eb54a2b1d6d2fe0a6a88932a4ad06725527b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-commands.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -69,6 +69,12 @@ #ifndef __iwl_3945_commands_h__ #define __iwl_3945_commands_h__ +/* uCode version contains 4 values: Major/Minor/API/Serial */ +#define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) +#define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) +#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) +#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) + enum { REPLY_ALIVE = 0x1, REPLY_ERROR = 0x2, @@ -121,7 +127,7 @@ enum { REPLY_TX_PWR_TABLE_CMD = 0x97, MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ - /* Bluetooth device coexistance config command */ + /* Bluetooth device coexistence config command */ REPLY_BT_CONFIG = 0x9b, /* Statistics */ @@ -158,7 +164,7 @@ struct iwl3945_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ u8 flags; /* IWL_CMD_* */ /* - * The driver sets up the sequence number to values of its chosing. + * The driver sets up the sequence number to values of its choosing. * uCode does not use this value, but passes it back to the driver * when sending the response to each driver-originated command, so * the driver can match the response to the command. Since the values @@ -220,7 +226,7 @@ struct iwl3945_power_per_rate { * *****************************************************************************/ -#define UCODE_VALID_OK __constant_cpu_to_le32(0x1) +#define UCODE_VALID_OK cpu_to_le32(0x1) #define INITIALIZE_SUBTYPE (9) /* @@ -322,42 +328,42 @@ enum { /* rx_config flags */ /* band & modulation selection */ -#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0) -#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FLG_BAND_24G_MSK cpu_to_le32(1 << 0) +#define RXON_FLG_CCK_MSK cpu_to_le32(1 << 1) /* auto detection enable */ -#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FLG_AUTO_DETECT_MSK cpu_to_le32(1 << 2) /* TGg protection when tx */ -#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FLG_TGG_PROTECT_MSK cpu_to_le32(1 << 3) /* cck short slot & preamble */ -#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4) -#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FLG_SHORT_SLOT_MSK cpu_to_le32(1 << 4) +#define RXON_FLG_SHORT_PREAMBLE_MSK cpu_to_le32(1 << 5) /* antenna selection */ -#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7) -#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00) -#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define RXON_FLG_DIS_DIV_MSK cpu_to_le32(1 << 7) +#define RXON_FLG_ANT_SEL_MSK cpu_to_le32(0x0f00) +#define RXON_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define RXON_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* radar detection enable */ -#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12) -#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13) +#define RXON_FLG_RADAR_DETECT_MSK cpu_to_le32(1 << 12) +#define RXON_FLG_TGJ_NARROW_BAND_MSK cpu_to_le32(1 << 13) /* rx response to host with 8-byte TSF * (according to ON_AIR deassertion) */ -#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15) +#define RXON_FLG_TSF2HOST_MSK cpu_to_le32(1 << 15) /* rx_config filter flags */ /* accept all data frames */ -#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0) +#define RXON_FILTER_PROMISC_MSK cpu_to_le32(1 << 0) /* pass control & management to host */ -#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FILTER_CTL2HOST_MSK cpu_to_le32(1 << 1) /* accept multi-cast */ -#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FILTER_ACCEPT_GRP_MSK cpu_to_le32(1 << 2) /* don't decrypt uni-cast frames */ -#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FILTER_DIS_DECRYPT_MSK cpu_to_le32(1 << 3) /* don't decrypt multi-cast frames */ -#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4) +#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4) /* STA is associated */ -#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FILTER_ASSOC_MSK cpu_to_le32(1 << 5) /* transfer to host non bssid beacons in associated state */ -#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) +#define RXON_FILTER_BCON_AWARE_MSK cpu_to_le32(1 << 6) /** * REPLY_RXON = 0x10 (command, has simple generic response) @@ -471,9 +477,9 @@ struct iwl3945_ac_qos { } __attribute__ ((packed)); /* QoS flags defines */ -#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01) -#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) -#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) +#define QOS_PARAM_FLG_UPDATE_EDCA_MSK cpu_to_le32(0x01) +#define QOS_PARAM_FLG_TGN_MSK cpu_to_le32(0x02) +#define QOS_PARAM_FLG_TXOP_TYPE_MSK cpu_to_le32(0x10) /* Number of Access Categories (AC) (EDCA), queues 0..3 */ #define AC_NUM 4 @@ -508,27 +514,27 @@ struct iwl3945_qosparam_cmd { #define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 -#define STA_FLG_TX_RATE_MSK __constant_cpu_to_le32(1 << 2); -#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8); +#define STA_FLG_TX_RATE_MSK cpu_to_le32(1 << 2); +#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); /* Use in mode field. 1: modify existing entry, 0: add new station entry */ #define STA_CONTROL_MODIFY_MSK 0x01 /* key flags __le16*/ -#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_ENCRYPT_MSK cpu_to_le16(0x0007) +#define STA_KEY_FLG_NO_ENC cpu_to_le16(0x0000) +#define STA_KEY_FLG_WEP cpu_to_le16(0x0001) +#define STA_KEY_FLG_CCMP cpu_to_le16(0x0002) +#define STA_KEY_FLG_TKIP cpu_to_le16(0x0003) #define STA_KEY_FLG_KEYID_POS 8 -#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) +#define STA_KEY_FLG_INVALID 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) +#define STA_KEY_FLG_WEP_KEY_MAP_MSK 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) +#define STA_KEY_FLG_KEY_SIZE_MSK cpu_to_le16(0x1000) +#define STA_KEY_MULTICAST_MSK cpu_to_le16(0x4000) /* Flags indicate whether to modify vs. don't change various station params */ #define STA_MODIFY_KEY_MASK 0x01 @@ -666,14 +672,14 @@ struct iwl3945_rx_frame_hdr { 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 cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW 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 cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0) #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) @@ -733,57 +739,57 @@ struct iwl3945_rx_frame { /* 1: Use Request-To-Send protocol before this frame. * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ -#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1) +#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1) /* 1: Transmit Clear-To-Send to self before this frame. * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames. * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */ -#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2) +#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2) /* 1: Expect ACK from receiving station * 0: Don't expect ACK (MAC header's duration field s/b 0) * Set this for unicast frames, but not broadcast/multicast. */ -#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) +#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3) /* 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD). * Tx command's initial_rate_index indicates first rate to try; * uCode walks through table for additional Tx attempts. * 0: Use Tx rate/MCS from Tx command's rate_n_flags field. * This rate will be used for all Tx attempts; it will not be scaled. */ -#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) +#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4) /* 1: Expect immediate block-ack. * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ -#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) +#define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6) /* 1: Frame requires full Tx-Op protection. * Set this if either RTS or CTS Tx Flag gets set. */ -#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) +#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7) /* Tx antenna selection field; used only for 3945, reserved (0) for 4965. * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */ -#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) -#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00) +#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define TX_CMD_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* 1: Ignore Bluetooth priority for this frame. * 0: Delay Tx until Bluetooth device is done (normal usage). */ -#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) +#define TX_CMD_FLG_BT_DIS_MSK cpu_to_le32(1 << 12) /* 1: uCode overrides sequence control field in MAC header. * 0: Driver provides sequence control field in MAC header. * Set this for management frames, non-QOS data frames, non-unicast frames, * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */ -#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) +#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13) /* 1: This frame is non-last MPDU; more fragments are coming. * 0: Last fragment, or not using fragmentation. */ -#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) +#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14) /* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame. * 0: No TSF required in outgoing frame. * Set this for transmitting beacons and probe responses. */ -#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) +#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16) /* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword * alignment of frame's payload data field. @@ -791,10 +797,10 @@ struct iwl3945_rx_frame { * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4 * field (but not both). Driver must align frame data (i.e. data following * MAC header) to DWORD boundary. */ -#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) +#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20) /* HCCA-AP - disable duration overwriting. */ -#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) +#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25) /* * TX command security control @@ -991,7 +997,7 @@ struct iwl3945_rate_scaling_cmd { * * 3945 and 4965 support hardware handshake with Bluetooth device on * same platform. Bluetooth device alerts wireless device when it will Tx; - * wireless device can delay or kill its own Tx to accomodate. + * wireless device can delay or kill its own Tx to accommodate. */ struct iwl3945_bt_cmd { u8 flags; @@ -1158,9 +1164,9 @@ struct iwl3945_spectrum_notification { */ #define IWL_POWER_VEC_SIZE 5 -#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le32(1 << 0) -#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le32(1 << 2) -#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le32(1 << 3) +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le32(1 << 0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le32(1 << 2) +#define IWL_POWER_PCI_PM_MSK cpu_to_le32(1 << 3) struct iwl3945_powertable_cmd { __le32 flags; __le32 rx_data_timeout; @@ -1278,8 +1284,8 @@ struct iwl3945_ssid_ie { } __attribute__ ((packed)); #define PROBE_OPTION_MAX 0x4 -#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) -#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) +#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) +#define IWL_GOOD_CRC_TH cpu_to_le16(1) #define IWL_MAX_SCAN_SIZE 1024 /* @@ -1379,7 +1385,7 @@ struct iwl3945_scan_cmd { } __attribute__ ((packed)); /* Can abort will notify by complete notification with abort status. */ -#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1) +#define CAN_ABORT_STATUS cpu_to_le32(0x1) /* complete notification statuses */ #define ABORT_STATUS 0x2 @@ -1572,8 +1578,8 @@ struct statistics_general { * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself. */ -#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ -#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ +#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1) /* see above */ +#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */ struct iwl3945_statistics_cmd { __le32 configuration_flags; /* IWL_STATS_CONF_* */ } __attribute__ ((packed)); @@ -1593,8 +1599,8 @@ struct iwl3945_statistics_cmd { * appropriately so that each notification contains statistics for only the * one channel that has just been scanned. */ -#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) -#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) +#define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) +#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8) struct iwl3945_notif_statistics { __le32 flag; struct statistics_rx rx; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-core.h b/drivers/net/wireless/iwlwifi/iwl-3945-core.h index bc12f97ba0b1d82ab9087900840ff640593861df..6f463555402c7bb1b751d1ec9846730efca355bc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-core.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -71,9 +71,33 @@ #define IWL_SKU_G 0x1 #define IWL_SKU_A 0x2 +/** + * struct iwl_3945_cfg + * @fw_name_pre: Firmware filename prefix. The api version and extension + * (.ucode) will be added to filename before loading from disk. The + * filename is constructed as fw_name_pre.ucode. + * @ucode_api_max: Highest version of uCode API supported by driver. + * @ucode_api_min: Lowest version of uCode API supported by driver. + * + * We enable the driver to be backward compatible wrt API version. The + * driver specifies which APIs it supports (with @ucode_api_max being the + * highest and @ucode_api_min the lowest). Firmware will only be loaded if + * it has a supported API version. The firmware's API version will be + * stored in @iwl_priv, enabling the driver to make runtime changes based + * on firmware version used. + * + * For example, + * if (IWL_UCODE_API(priv->ucode_ver) >= 2) { + * Driver interacts with Firmware API version >= 2. + * } else { + * Driver interacts with Firmware API version 1. + * } + */ struct iwl_3945_cfg { const char *name; - const char *fw_name; + const char *fw_name_pre; + const unsigned int ucode_api_max; + const unsigned int ucode_api_min; unsigned int sku; }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h index 33016fb5e9b3c01d3e0e9af04bf023b239bab0c4..85eb778f9df1e0232a6d6cf16509ac5ab59fa9b3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-debug.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h index 644bd9e0805217f2b399260a073487537f3de918..94ea0e60c41076d9d5fa6a656595bc4bbda57cf8 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-hw.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -103,7 +103,6 @@ * 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 iwl_eeprom_channel.flags. @@ -321,6 +320,7 @@ struct iwl3945_eeprom { /* RSSR */ #define FH_RSSR_CTRL (FH_RSSR_TABLE+0x000) #define FH_RSSR_STATUS (FH_RSSR_TABLE+0x004) +#define FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE (0x01000000) /* TCSR */ #define FH_TCSR(_channel) (FH_TCSR_TABLE+(_channel)*0x20) #define FH_TCSR_CONFIG(_channel) (FH_TCSR(_channel)+0x00) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-io.h b/drivers/net/wireless/iwlwifi/iwl-3945-io.h index b3fe48de3ae7b819d17bffd7cd7d01013cd632b1..2440fd664dd59ad4dc88808d5f320c43b4c2b9c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-io.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -53,7 +53,7 @@ * _iwl3945_read32.) * * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguring of the hardware I/O. In combination with + * which result in misconfiguration of the hardware I/O. In combination with * git-bisect and the IO debug level you can quickly determine the specific * commit which breaks the IO sequence to the hardware. * @@ -93,7 +93,7 @@ static inline int _iwl3945_poll_bit(struct iwl3945_priv *priv, u32 addr, do { if ((_iwl3945_read32(priv, addr) & mask) == (bits & mask)) return i; - mdelay(10); + udelay(10); i += 10; } while (i < timeout); @@ -107,7 +107,7 @@ static inline int __iwl3945_poll_bit(const char *f, u32 l, int ret = _iwl3945_poll_bit(priv, addr, bits, mask, timeout); IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", addr, bits, mask, - unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l); + unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); return ret; } #define iwl3945_poll_bit(priv, addr, bits, mask, timeout) \ @@ -271,16 +271,7 @@ static inline void iwl3945_write_reg_buf(struct iwl3945_priv *priv, static inline int _iwl3945_poll_direct_bit(struct iwl3945_priv *priv, u32 addr, u32 mask, int timeout) { - int i = 0; - - do { - if ((_iwl3945_read_direct32(priv, addr) & mask) == mask) - return i; - mdelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; + return _iwl3945_poll_bit(priv, addr, mask, mask, timeout); } #ifdef CONFIG_IWL3945_DEBUG @@ -307,6 +298,7 @@ static inline int __iwl3945_poll_direct_bit(const char *f, u32 l, static inline u32 _iwl3945_read_prph(struct iwl3945_priv *priv, u32 reg) { _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + rmb(); return _iwl3945_read_direct32(priv, HBUS_TARG_PRPH_RDAT); } #ifdef CONFIG_IWL3945_DEBUG @@ -328,6 +320,7 @@ static inline void _iwl3945_write_prph(struct iwl3945_priv *priv, { _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WADDR, ((addr & 0x0000FFFF) | (3 << 24))); + wmb(); _iwl3945_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); } #ifdef CONFIG_IWL3945_DEBUG @@ -389,12 +382,14 @@ static inline void iwl3945_clear_bits_prph(struct iwl3945_priv static inline u32 iwl3945_read_targ_mem(struct iwl3945_priv *priv, u32 addr) { iwl3945_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); + rmb(); return iwl3945_read_direct32(priv, HBUS_TARG_MEM_RDAT); } static inline void iwl3945_write_targ_mem(struct iwl3945_priv *priv, u32 addr, u32 val) { iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); } @@ -402,6 +397,7 @@ static inline void iwl3945_write_targ_mem_buf(struct iwl3945_priv *priv, u32 add u32 len, u32 *values) { iwl3945_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); for (; 0 < len; len -= sizeof(u32), values++) iwl3945_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); } diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c index 705c65bed9fd7a719c22b355e8ad6fe7c8eee07c..4c638909a7db325bd6314c3f2f065824f8d66f0a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h index 2fbd126c13478b4b6a0cb6ad6be6037123c69b1c..749ac035fd6aa3a20d4a7c85b8778f2084dc11e1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c index 6fc5e7361f267dad0e01deb1a5c2a155cdc72bc6..9b60a0c5de5f3f55bf45bd7acf8594e3973f172a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -63,6 +63,9 @@ struct iwl3945_rs_sta { u8 ibss_sta_added; struct timer_list rate_scale_flush; struct iwl3945_rate_scale_data win[IWL_RATE_COUNT]; +#ifdef CONFIG_MAC80211_DEBUGFS + struct dentry *rs_sta_dbgfs_stats_table_file; +#endif /* used to be in sta_info */ int last_txrate_idx; @@ -114,9 +117,11 @@ static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = { }; #define IWL_RATE_MAX_WINDOW 62 -#define IWL_RATE_FLUSH (3*HZ/10) +#define IWL_RATE_FLUSH (3*HZ) #define IWL_RATE_WIN_FLUSH (HZ/2) #define IWL_RATE_HIGH_TH 11520 +#define IWL_SUCCESS_UP_TH 8960 +#define IWL_SUCCESS_DOWN_TH 10880 #define IWL_RATE_MIN_FAILURE_TH 8 #define IWL_RATE_MIN_SUCCESS_TH 8 #define IWL_RATE_DECREASE_TH 1920 @@ -203,6 +208,7 @@ static int iwl3945_rate_scale_flush_windows(struct iwl3945_rs_sta *rs_sta) #define IWL_RATE_FLUSH_MAX 5000 /* msec */ #define IWL_RATE_FLUSH_MIN 50 /* msec */ +#define IWL_AVERAGE_PACKETS 1500 static void iwl3945_bg_rate_scale_flush(unsigned long data) { @@ -217,8 +223,6 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) spin_lock_irqsave(&rs_sta->lock, flags); - rs_sta->flush_pending = 0; - /* Number of packets Rx'd since last time this timer ran */ packet_count = (rs_sta->tx_packets - rs_sta->last_tx_packets) + 1; @@ -227,7 +231,6 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) if (unflushed) { duration = jiffies_to_msecs(jiffies - rs_sta->last_partial_flush); -/* duration = jiffies_to_msecs(rs_sta->flush_time); */ IWL_DEBUG_RATE("Tx'd %d packets in %dms\n", packet_count, duration); @@ -239,9 +242,11 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) pps = 0; if (pps) { - duration = IWL_RATE_FLUSH_MAX / pps; + duration = (IWL_AVERAGE_PACKETS * 1000) / pps; if (duration < IWL_RATE_FLUSH_MIN) duration = IWL_RATE_FLUSH_MIN; + else if (duration > IWL_RATE_FLUSH_MAX) + duration = IWL_RATE_FLUSH_MAX; } else duration = IWL_RATE_FLUSH_MAX; @@ -254,8 +259,10 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) rs_sta->flush_time); rs_sta->last_partial_flush = jiffies; + } else { + rs_sta->flush_time = IWL_RATE_FLUSH; + rs_sta->flush_pending = 0; } - /* If there weren't any unflushed entries, we don't schedule the timer * to run again */ @@ -275,17 +282,18 @@ static void iwl3945_bg_rate_scale_flush(unsigned long data) */ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, struct iwl3945_rate_scale_data *window, - int success, int retries) + int success, int retries, int index) { unsigned long flags; + s32 fail_count; if (!retries) { IWL_DEBUG_RATE("leave: retries == 0 -- should be at least 1\n"); return; } + spin_lock_irqsave(&rs_sta->lock, flags); while (retries--) { - spin_lock_irqsave(&rs_sta->lock, flags); /* If we have filled up the window then subtract one from the * success counter if the high-bit is counting toward @@ -313,14 +321,25 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta, /* Tag this window as having been updated */ window->stamp = jiffies; - spin_unlock_irqrestore(&rs_sta->lock, flags); } + + fail_count = window->counter - window->success_counter; + if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) || + (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH)) + window->average_tpt = ((window->success_ratio * + rs_sta->expected_tpt[index] + 64) / 128); + else + window->average_tpt = IWL_INV_TPT; + + spin_unlock_irqrestore(&rs_sta->lock, flags); + } -static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband, +static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta) { struct iwl3945_rs_sta *rs_sta = priv_sta; + struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r; int i; IWL_DEBUG_RATE("enter\n"); @@ -330,16 +349,21 @@ static void rs_rate_init(void *priv, struct ieee80211_supported_band *sband, * previous packets? Need to have IEEE 802.1X auth succeed immediately * after assoc.. */ - for (i = IWL_RATE_COUNT - 1; i >= 0; i--) { + for (i = sband->n_bitrates - 1; i >= 0; i--) { if (sta->supp_rates[sband->band] & (1 << i)) { rs_sta->last_txrate_idx = i; break; } } + priv->sta_supp_rates = sta->supp_rates[sband->band]; /* For 5 GHz band it start at IWL_FIRST_OFDM_RATE */ - if (sband->band == IEEE80211_BAND_5GHZ) + if (sband->band == IEEE80211_BAND_5GHZ) { rs_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + priv->sta_supp_rates = priv->sta_supp_rates << + IWL_FIRST_OFDM_RATE; + } + IWL_DEBUG_RATE("leave\n"); } @@ -355,12 +379,6 @@ static void rs_free(void *priv) return; } -static void rs_clear(void *priv) -{ - return; -} - - static void *rs_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { struct iwl3945_rs_sta *rs_sta; @@ -422,34 +440,6 @@ static void rs_free_sta(void *priv, struct ieee80211_sta *sta, } -/* - * get ieee prev rate from rate scale table. - * for A and B mode we need to overright prev - * value - */ -static int rs_adjust_next_rate(struct iwl3945_priv *priv, int rate) -{ - int next_rate = iwl3945_get_prev_ieee_rate(rate); - - 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; - } - - return next_rate; -} /** * rs_tx_status - Update rate control values based on Tx results * @@ -460,7 +450,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb) { - u8 retries, current_count; + s8 retries = 0, current_count; int scale_rate_index, first_index, last_index; unsigned long flags; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_rate; @@ -469,8 +459,9 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband IWL_DEBUG_RATE("enter\n"); - retries = info->status.retry_count; - first_index = sband->bitrates[info->tx_rate_idx].hw_value; + retries = info->status.rates[0].count; + + first_index = sband->bitrates[info->status.rates[0].idx].hw_value; if ((first_index < 0) || (first_index >= IWL_RATE_COUNT)) { IWL_DEBUG_RATE("leave: Rate out of bounds: %d\n", first_index); return; @@ -496,13 +487,13 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband * at which the frame was finally transmitted (or failed if no * ACK) */ - while (retries > 0) { - if (retries < priv->retry_rate) { - current_count = retries; + while (retries > 1) { + if ((retries - 1) < priv->retry_rate) { + current_count = (retries - 1); last_index = scale_rate_index; } else { current_count = priv->retry_rate; - last_index = rs_adjust_next_rate(priv, + last_index = iwl3945_rs_next_rate(priv, scale_rate_index); } @@ -510,15 +501,13 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband * as was used for it (per current_count) */ iwl3945_collect_tx_data(rs_sta, &rs_sta->win[scale_rate_index], - 0, current_count); + 0, current_count, scale_rate_index); IWL_DEBUG_RATE("Update rate %d for %d retries.\n", scale_rate_index, current_count); retries -= current_count; - if (retries) - scale_rate_index = - rs_adjust_next_rate(priv, scale_rate_index); + scale_rate_index = last_index; } @@ -529,7 +518,7 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband "success" : "failure"); iwl3945_collect_tx_data(rs_sta, &rs_sta->win[last_index], - info->flags & IEEE80211_TX_STAT_ACK, 1); + info->flags & IEEE80211_TX_STAT_ACK, 1, last_index); /* We updated the rate scale window -- if its been more than * flush_time since the last run, schedule the flush @@ -537,9 +526,10 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband spin_lock_irqsave(&rs_sta->lock, flags); if (!rs_sta->flush_pending && - time_after(jiffies, rs_sta->last_partial_flush + + time_after(jiffies, rs_sta->last_flush + rs_sta->flush_time)) { + rs_sta->last_partial_flush = jiffies; rs_sta->flush_pending = 1; mod_timer(&rs_sta->rate_scale_flush, jiffies + rs_sta->flush_time); @@ -630,10 +620,11 @@ static u16 iwl3945_get_adjacent_rate(struct iwl3945_rs_sta *rs_sta, * rate table and must reference the driver allocated rate table * */ -static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, + void *priv_sta, struct ieee80211_tx_rate_control *txrc) { + struct ieee80211_supported_band *sband = txrc->sband; + struct sk_buff *skb = txrc->skb; u8 low = IWL_RATE_INVALID; u8 high = IWL_RATE_INVALID; u16 high_low; @@ -649,7 +640,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; u16 fc, rate_mask; struct iwl3945_priv *priv = (struct iwl3945_priv *)priv_r; - DECLARE_MAC_BUF(mac); + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); IWL_DEBUG_RATE("enter\n"); @@ -660,7 +651,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, is_multicast_ether_addr(hdr->addr1) || !sta || !priv_sta) { IWL_DEBUG_RATE("leave: No STA priv data to update!\n"); - sel->rate_idx = rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } @@ -675,8 +666,8 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, u8 sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_RATE("LQ: ADD station %pm\n", + hdr->addr1); sta_id = iwl3945_add_station(priv, hdr->addr1, 0, CMD_ASYNC); } @@ -686,8 +677,13 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, spin_lock_irqsave(&rs_sta->lock, flags); + /* for recent assoc, choose best rate regarding + * to rssi value + */ if (rs_sta->start_rate != IWL_RATE_INVALID) { - index = rs_sta->start_rate; + if (rs_sta->start_rate < index && + (rate_mask & (1 << rs_sta->start_rate))) + index = rs_sta->start_rate; rs_sta->start_rate = IWL_RATE_INVALID; } @@ -697,7 +693,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) && (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) { - window->average_tpt = IWL_INV_TPT; spin_unlock_irqrestore(&rs_sta->lock, flags); IWL_DEBUG_RATE("Invalid average_tpt on rate %d: " @@ -711,8 +706,6 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, } - window->average_tpt = ((window->success_ratio * - rs_sta->expected_tpt[index] + 64) / 128); current_tpt = window->average_tpt; high_low = iwl3945_get_adjacent_rate(rs_sta, index, rate_mask, @@ -760,13 +753,15 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, } } - if ((window->success_ratio > IWL_RATE_HIGH_TH) || - (current_tpt > window->average_tpt)) { - IWL_DEBUG_RATE("No action -- success_ratio [%d] > HIGH_TH or " - "current_tpt [%d] > average_tpt [%d]\n", - window->success_ratio, - current_tpt, window->average_tpt); - scale_action = 0; + if (scale_action == -1) { + if (window->success_ratio > IWL_SUCCESS_DOWN_TH) + scale_action = 0; + } else if (scale_action == 1) { + if (window->success_ratio < IWL_SUCCESS_UP_TH) { + IWL_DEBUG_RATE("No action -- success_ratio [%d] < " + "SUCCESS UP\n", window->success_ratio); + scale_action = 0; + } } switch (scale_action) { @@ -793,24 +788,83 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, rs_sta->last_txrate_idx = index; if (sband->band == IEEE80211_BAND_5GHZ) - sel->rate_idx = rs_sta->last_txrate_idx - IWL_FIRST_OFDM_RATE; + info->control.rates[0].idx = rs_sta->last_txrate_idx - + IWL_FIRST_OFDM_RATE; else - sel->rate_idx = rs_sta->last_txrate_idx; + info->control.rates[0].idx = rs_sta->last_txrate_idx; IWL_DEBUG_RATE("leave: %d\n", index); } +#ifdef CONFIG_MAC80211_DEBUGFS +static int iwl3945_open_file_generic(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + return 0; +} + +static ssize_t iwl3945_sta_dbgfs_stats_table_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + char buff[1024]; + int desc = 0; + int j; + struct iwl3945_rs_sta *lq_sta = file->private_data; + + desc += sprintf(buff + desc, "tx packets=%d last rate index=%d\n" + "rate=0x%X flush time %d\n", + lq_sta->tx_packets, + lq_sta->last_txrate_idx, + lq_sta->start_rate, jiffies_to_msecs(lq_sta->flush_time)); + for (j = 0; j < IWL_RATE_COUNT; j++) { + desc += sprintf(buff+desc, + "counter=%d success=%d %%=%d\n", + lq_sta->win[j].counter, + lq_sta->win[j].success_counter, + lq_sta->win[j].success_ratio); + } + return simple_read_from_buffer(user_buf, count, ppos, buff, desc); +} + +static const struct file_operations rs_sta_dbgfs_stats_table_ops = { + .read = iwl3945_sta_dbgfs_stats_table_read, + .open = iwl3945_open_file_generic, +}; + +static void iwl3945_add_debugfs(void *priv, void *priv_sta, + struct dentry *dir) +{ + struct iwl3945_rs_sta *lq_sta = priv_sta; + + lq_sta->rs_sta_dbgfs_stats_table_file = + debugfs_create_file("rate_stats_table", 0600, dir, + lq_sta, &rs_sta_dbgfs_stats_table_ops); + +} + +static void iwl3945_remove_debugfs(void *priv, void *priv_sta) +{ + struct iwl3945_rs_sta *lq_sta = priv_sta; + debugfs_remove(lq_sta->rs_sta_dbgfs_stats_table_file); +} +#endif + static struct rate_control_ops rs_ops = { .module = NULL, .name = RS_NAME, .tx_status = rs_tx_status, .get_rate = rs_get_rate, .rate_init = rs_rate_init, - .clear = rs_clear, .alloc = rs_alloc, .free = rs_free, .alloc_sta = rs_alloc_sta, .free_sta = rs_free_sta, +#ifdef CONFIG_MAC80211_DEBUGFS + .add_sta_debugfs = iwl3945_add_debugfs, + .remove_sta_debugfs = iwl3945_remove_debugfs, +#endif + }; void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) @@ -827,13 +881,12 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) rcu_read_lock(); sta = ieee80211_find_sta(hw, priv->stations[sta_id].sta.sta.addr); - psta = (void *) sta->drv_priv; - if (!sta || !psta) { - IWL_DEBUG_RATE("leave - no private rate data!\n"); + if (!sta) { rcu_read_unlock(); return; } + psta = (void *) sta->drv_priv; rs_sta = psta->rs_sta; spin_lock_irqsave(&rs_sta->lock, flags); @@ -857,7 +910,6 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) break; } - rcu_read_unlock(); spin_unlock_irqrestore(&rs_sta->lock, flags); rssi = priv->last_rx_rssi; @@ -871,6 +923,7 @@ void iwl3945_rate_scale_init(struct ieee80211_hw *hw, s32 sta_id) IWL_DEBUG_RATE("leave: rssi %d assign rate index: " "%d (plcp 0x%x)\n", rssi, rs_sta->start_rate, iwl3945_rates[rs_sta->start_rate].plcp); + rcu_read_unlock(); } int iwl3945_rate_control_register(void) diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h index 98b17ae6ef246d62720760cf4c5416e10300eb4d..b5a66135deddf0f1fcbd2b6f4c0d3f3b71287d02 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945-rs.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c index 7ca5627cc078bed3944190d36ab201c39b31c9e8..8fdb34222c0a4f3e3ba8c11644fc429ed6de7300 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.c +++ b/drivers/net/wireless/iwlwifi/iwl-3945.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -200,7 +200,7 @@ static int iwl3945_hwrate_to_plcp_idx(u8 plcp) * priv->eeprom is used to determine if antenna AUX/MAIN are reversed * priv->antenna specifies the antenna diversity mode: * - * IWL_ANTENNA_DIVERISTY - NIC selects best antenna by itself + * IWL_ANTENNA_DIVERSITY - NIC selects best antenna by itself * IWL_ANTENNA_MAIN - Force MAIN antenna * IWL_ANTENNA_AUX - Force AUX antenna */ @@ -261,6 +261,37 @@ static inline const char *iwl3945_get_tx_fail_reason(u32 status) } #endif +/* + * get ieee prev rate from rate scale table. + * for A and B mode we need to overright prev + * value + */ +int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate) +{ + int next_rate = iwl3945_get_prev_ieee_rate(rate); + + 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; + case IEEE80211_BAND_2GHZ: + if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) && + iwl3945_is_associated(priv)) { + if (rate == IWL_RATE_11M_INDEX) + next_rate = IWL_RATE_5M_INDEX; + } + break; + + default: + break; + } + + return next_rate; +} + /** * iwl3945_tx_queue_reclaim - Reclaim Tx queue entries already Tx'd @@ -308,6 +339,7 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, struct iwl3945_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->status); int rate_idx; + int fail; 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 " @@ -318,9 +350,18 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, } info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); + + /* Fill the MRR chain with some info about on-chip retransmissions */ + rate_idx = iwl3945_hwrate_to_plcp_idx(tx_resp->rate); + if (info->band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; + + fail = tx_resp->failure_frame; + + info->status.rates[0].idx = rate_idx; + info->status.rates[0].count = fail + 1; /* add final attempt */ - info->status.retry_count = tx_resp->failure_frame; /* tx_status->rts_retry_count = tx_resp->failure_rts; */ info->flags |= ((status & TX_STATUS_MSK) == TX_STATUS_SUCCESS) ? IEEE80211_TX_STAT_ACK : 0; @@ -329,10 +370,6 @@ static void iwl3945_rx_reply_tx(struct iwl3945_priv *priv, 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); - if (info->band == IEEE80211_BAND_5GHZ) - rate_idx -= IWL_FIRST_OFDM_RATE; - info->tx_rate_idx = rate_idx; IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); iwl3945_tx_queue_reclaim(priv, txq_id, index); @@ -756,13 +793,19 @@ int iwl3945_hw_txq_free_tfd(struct iwl3945_priv *priv, struct iwl3945_tx_queue * u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr) { - int i; + int i, start = IWL_AP_ID; int ret = IWL_INVALID_STATION; unsigned long flags; - DECLARE_MAC_BUF(mac); + + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || + (priv->iw_mode == NL80211_IFTYPE_AP)) + start = IWL_STA_ID; + + if (is_broadcast_ether_addr(addr)) + return priv->hw_setting.bcast_sta_id; spin_lock_irqsave(&priv->sta_lock, flags); - for (i = IWL_STA_ID; i < priv->hw_setting.max_stations; i++) + for (i = start; i < priv->hw_setting.max_stations; i++) if ((priv->stations[i].used) && (!compare_ether_addr (priv->stations[i].sta.sta.addr, addr))) { @@ -770,8 +813,8 @@ u8 iwl3945_hw_find_station(struct iwl3945_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_INFO("can not find STA %s (total %d)\n", - print_mac(mac, addr), priv->num_stations); + IWL_DEBUG_INFO("can not find STA %pM (total %d)\n", + addr, priv->num_stations); out: spin_unlock_irqrestore(&priv->sta_lock, flags); return ret; @@ -1060,9 +1103,8 @@ int iwl3945_hw_nic_init(struct iwl3945_priv *priv) CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + rc = iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (rc < 0) { spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("Failed to init the card\n"); @@ -1243,8 +1285,7 @@ int iwl3945_hw_nic_stop_master(struct iwl3945_priv *priv) IWL_DEBUG_INFO("Card in power save, master is already " "stopped\n"); else { - rc = iwl3945_poll_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, + rc = iwl3945_poll_direct_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); if (rc < 0) { spin_unlock_irqrestore(&priv->lock, flags); @@ -1269,9 +1310,8 @@ int iwl3945_hw_nic_reset(struct iwl3945_priv *priv) iwl3945_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET); - rc = iwl3945_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); rc = iwl3945_grab_nic_access(priv); if (!rc) { @@ -1830,7 +1870,7 @@ static int iwl3945_hw_reg_comp_txpower_temp(struct iwl3945_priv *priv) ref_temp = (s16)priv->eeprom.groups[ch_info->group_index]. temperature; - /* get power index adjustment based on curr and factory + /* get power index adjustment based on current and factory * temps */ delta_index = iwl3945_hw_reg_adjust_power_by_temp(temperature, ref_temp); @@ -2268,7 +2308,8 @@ int iwl3945_hw_rxq_stop(struct iwl3945_priv *priv) } iwl3945_write_direct32(priv, FH_RCSR_CONFIG(0), 0); - rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS, (1 << 24), 1000); + rc = iwl3945_poll_direct_bit(priv, FH_RSSR_STATUS, + FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); if (rc < 0) IWL_ERROR("Can't stop Rx DMA.\n"); @@ -2337,7 +2378,8 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) iwl3945_hw_set_rate_n_flags(iwl3945_rates[i].plcp, 0); table[index].try_cnt = priv->retry_rate; prev_index = iwl3945_get_prev_ieee_rate(i); - table[index].next_rate_index = iwl3945_rates[prev_index].table_rs_index; + table[index].next_rate_index = + iwl3945_rates[prev_index].table_rs_index; } switch (priv->band) { @@ -2345,11 +2387,14 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) 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 */ - for (i = IWL_RATE_1M_INDEX_TABLE; i <= IWL_RATE_11M_INDEX_TABLE; i++) - table[i].next_rate_index = iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; + for (i = IWL_RATE_1M_INDEX_TABLE; + i <= IWL_RATE_11M_INDEX_TABLE; i++) + table[i].next_rate_index = + iwl3945_rates[IWL_FIRST_OFDM_RATE].table_rs_index; /* Don't fall back to CCK rates */ - table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = IWL_RATE_9M_INDEX_TABLE; + table[IWL_RATE_12M_INDEX_TABLE].next_rate_index = + IWL_RATE_9M_INDEX_TABLE; /* Don't drop out of OFDM rates */ table[IWL_RATE_6M_INDEX_TABLE].next_rate_index = @@ -2360,11 +2405,20 @@ int iwl3945_init_hw_rate_table(struct iwl3945_priv *priv) 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++) - table[i].next_rate_index = iwl3945_rates[IWL_FIRST_CCK_RATE].table_rs_index; - /* CCK shouldn't fall back to OFDM... */ - table[IWL_RATE_11M_INDEX_TABLE].next_rate_index = IWL_RATE_5M_INDEX_TABLE; + if (!(priv->sta_supp_rates & IWL_OFDM_RATES_MASK) && + iwl3945_is_associated(priv)) { + + index = IWL_FIRST_CCK_RATE; + for (i = IWL_RATE_6M_INDEX_TABLE; + i <= IWL_RATE_54M_INDEX_TABLE; i++) + table[i].next_rate_index = + iwl3945_rates[index].table_rs_index; + + index = IWL_RATE_11M_INDEX_TABLE; + /* CCK shouldn't fall back to OFDM... */ + table[index].next_rate_index = IWL_RATE_5M_INDEX_TABLE; + } break; default: @@ -2428,7 +2482,6 @@ unsigned int iwl3945_hw_get_beacon_cmd(struct iwl3945_priv *priv, frame_size = iwl3945_fill_beacon_frame(priv, tx_beacon_cmd->frame, - iwl3945_broadcast_addr, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); BUG_ON(frame_size > MAX_MPDU_SIZE); @@ -2467,13 +2520,17 @@ void iwl3945_hw_cancel_deferred_work(struct iwl3945_priv *priv) static struct iwl_3945_cfg iwl3945_bg_cfg = { .name = "3945BG", - .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode", + .fw_name_pre = IWL3945_FW_PRE, + .ucode_api_max = IWL3945_UCODE_API_MAX, + .ucode_api_min = IWL3945_UCODE_API_MIN, .sku = IWL_SKU_G, }; static struct iwl_3945_cfg iwl3945_abg_cfg = { .name = "3945ABG", - .fw_name = "iwlwifi-3945" IWL3945_UCODE_API ".ucode", + .fw_name_pre = IWL3945_FW_PRE, + .ucode_api_max = IWL3945_UCODE_API_MAX, + .ucode_api_min = IWL3945_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, }; diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h index bdd32475b99ca6b0ca7ae1562f85b878edfa55fc..2c0ddc5110c6b1611e631239a8ef84a16c8e0539 100644 --- a/drivers/net/wireless/iwlwifi/iwl-3945.h +++ b/drivers/net/wireless/iwlwifi/iwl-3945.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -50,11 +50,15 @@ extern struct pci_device_id iwl3945_hw_card_ids[]; #include "iwl-3945-debug.h" #include "iwl-3945-led.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" +/* Highest firmware API version supported */ +#define IWL3945_UCODE_API_MAX 2 + +/* Lowest firmware API version supported */ +#define IWL3945_UCODE_API_MIN 1 + +#define IWL3945_FW_PRE "iwlwifi-3945-" +#define _IWL3945_MODULE_FIRMWARE(api) IWL3945_FW_PRE #api ".ucode" +#define IWL3945_MODULE_FIRMWARE(api) _IWL3945_MODULE_FIRMWARE(api) /* Default noise level to report when noise measurement is not available. * This may be because we're: @@ -401,12 +405,6 @@ struct iwl3945_rx_queue { #define SCAN_INTERVAL 100 -#define MAX_A_CHANNELS 252 -#define MIN_A_CHANNELS 7 - -#define MAX_B_CHANNELS 14 -#define MIN_B_CHANNELS 1 - #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ #define STATUS_HCMD_SYNC_ACTIVE 1 /* sync host command in progress */ #define STATUS_INT_ENABLED 2 @@ -472,7 +470,6 @@ union iwl3945_qos_capabity { /* QoS structures */ struct iwl3945_qos_info { - int qos_enable; int qos_active; union iwl3945_qos_capabity qos_cap; struct iwl3945_qosparam_cmd def_qos_parm; @@ -505,7 +502,7 @@ struct fw_desc { /* uCode file layout */ struct iwl3945_ucode { - __le32 ver; /* major/minor/subminor */ + __le32 ver; /* major/minor/API/serial */ __le32 inst_size; /* bytes of runtime instructions */ __le32 data_size; /* bytes of runtime data */ __le32 init_size; /* bytes of initialization instructions */ @@ -587,8 +584,7 @@ extern int iwl3945_send_cmd_pdu(struct iwl3945_priv *priv, u8 id, u16 len, extern int __must_check iwl3945_send_cmd(struct iwl3945_priv *priv, struct iwl3945_host_cmd *cmd); extern unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, - struct ieee80211_hdr *hdr, - const u8 *dest, int left); + struct ieee80211_hdr *hdr,int left); extern int iwl3945_rx_queue_update_write_ptr(struct iwl3945_priv *priv, struct iwl3945_rx_queue *q); extern int iwl3945_send_statistics_request(struct iwl3945_priv *priv); @@ -762,6 +758,8 @@ struct iwl3945_priv { void __iomem *hw_base; /* uCode images, save to reload in case of failure */ + u32 ucode_ver; /* ucode version, copy of + iwl3945_ucode.ver */ struct fw_desc ucode_code; /* runtime inst */ struct fw_desc ucode_data; /* runtime data original */ struct fw_desc ucode_data_backup; /* runtime data save/restore */ @@ -804,6 +802,8 @@ struct iwl3945_priv { u16 active_rate; u16 active_rate_basic; + u32 sta_supp_rates; + u8 call_post_assoc_from_beacon; /* Rate scaling data */ s8 data_retry_limit; @@ -828,8 +828,6 @@ struct iwl3945_priv { unsigned long last_statistics_time; /* context information */ - u8 essid[IW_ESSID_MAX_SIZE]; - u8 essid_len; u16 rates_mask; u32 power_mode; @@ -888,7 +886,6 @@ struct iwl3945_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; - struct work_struct set_monitor; struct tasklet_struct irq_tasklet; @@ -903,9 +900,6 @@ struct iwl3945_priv { s8 user_txpower_limit; s8 max_channel_txpower_limit; -#ifdef CONFIG_PM - u32 pm_state[16]; -#endif #ifdef CONFIG_IWL3945_DEBUG /* debugging info */ @@ -954,6 +948,8 @@ static inline int is_channel_ibss(const struct iwl3945_channel_info *ch) extern const struct iwl3945_channel_info *iwl3945_get_channel_info( const struct iwl3945_priv *priv, enum ieee80211_band band, u16 channel); +extern int iwl3945_rs_next_rate(struct iwl3945_priv *priv, int rate); + /* Requires full declaration of iwl3945_priv before including */ #include "iwl-3945-io.h" diff --git a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h index f4793a609443eca52ded350777ea0f0967deb130..6649f7b55650012ef01310bab088fc2f56455526 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-4965-hw.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -71,7 +71,7 @@ #include "iwl-fh.h" -/* EERPROM */ +/* EEPROM */ #define IWL4965_EEPROM_IMG_SIZE 1024 /* @@ -84,12 +84,6 @@ #define IWL_CMD_FIFO_NUM 4 #define IWL49_FIRST_AMPDU_QUEUE 7 -/* Tx rates */ -#define IWL_CCK_RATES 4 -#define IWL_OFDM_RATES 8 -#define IWL_HT_RATES 16 -#define IWL_MAX_RATES (IWL_CCK_RATES+IWL_OFDM_RATES+IWL_HT_RATES) - /* Time constants */ #define SHORT_SLOT_TIME 9 #define LONG_SLOT_TIME 20 @@ -111,7 +105,6 @@ #define PCI_CFG_CMD_REG_INT_DIS_MSK 0x04 #define PCI_CFG_PMC_PME_FROM_D3COLD_SUPPORT (0x80000000) -#define TFD_QUEUE_SIZE_MAX (256) #define IWL_NUM_SCAN_RATES (2) @@ -287,13 +280,13 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * that target txpower. * * - * 3) Determine (EEPROM) calibration subband for the target channel, by - * comparing against first and last channels in each subband + * 3) Determine (EEPROM) calibration sub band for the target channel, by + * comparing against first and last channels in each sub band * (see struct iwl4965_eeprom_calib_subband_info). * * * 4) Linearly interpolate (EEPROM) factory calibration measurement sets, - * referencing the 2 factory-measured (sample) channels within the subband. + * referencing the 2 factory-measured (sample) channels within the sub band. * * Interpolation is based on difference between target channel's frequency * and the sample channels' frequencies. Since channel numbers are based @@ -301,7 +294,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * to interpolating based on channel number differences. * * Note that the sample channels may or may not be the channels at the - * edges of the subband. The target channel may be "outside" of the + * edges of the sub band. The target channel may be "outside" of the * span of the sampled channels. * * Driver may choose the pair (for 2 Tx chains) of measurements (see @@ -345,7 +338,7 @@ static inline int iwl4965_hw_valid_rtc_data_addr(u32 addr) * "4965 temperature calculation". * * If current temperature is higher than factory temperature, driver must - * increase gain (lower gain table index), and vice versa. + * increase gain (lower gain table index), and vice verse. * * Temperature affects gain differently for different channels: * @@ -815,125 +808,14 @@ enum { * up to 7 DMA channels (FIFOs). Each Tx queue is supported by a circular array * in DRAM containing 256 Transmit Frame Descriptors (TFDs). */ -#define IWL49_MAX_WIN_SIZE 64 -#define IWL49_QUEUE_SIZE 256 #define IWL49_NUM_FIFOS 7 #define IWL49_CMD_FIFO_NUM 4 #define IWL49_NUM_QUEUES 16 #define IWL49_NUM_AMPDU_QUEUES 8 -/** - * struct iwl_tfd_frame_data - * - * Describes up to 2 buffers containing (contiguous) portions of a Tx frame. - * Each buffer must be on dword boundary. - * Up to 10 iwl_tfd_frame_data structures, describing up to 20 buffers, - * may be filled within a TFD (iwl_tfd_frame). - * - * Bit fields in tb1_addr: - * 31- 0: Tx buffer 1 address bits [31:0] - * - * Bit fields in val1: - * 31-16: Tx buffer 2 address bits [15:0] - * 15- 4: Tx buffer 1 length (bytes) - * 3- 0: Tx buffer 1 address bits [32:32] - * - * Bit fields in val2: - * 31-20: Tx buffer 2 length (bytes) - * 19- 0: Tx buffer 2 address bits [35:16] - */ -struct iwl_tfd_frame_data { - __le32 tb1_addr; - - __le32 val1; - /* __le32 ptb1_32_35:4; */ -#define IWL_tb1_addr_hi_POS 0 -#define IWL_tb1_addr_hi_LEN 4 -#define IWL_tb1_addr_hi_SYM val1 - /* __le32 tb_len1:12; */ -#define IWL_tb1_len_POS 4 -#define IWL_tb1_len_LEN 12 -#define IWL_tb1_len_SYM val1 - /* __le32 ptb2_0_15:16; */ -#define IWL_tb2_addr_lo16_POS 16 -#define IWL_tb2_addr_lo16_LEN 16 -#define IWL_tb2_addr_lo16_SYM val1 - - __le32 val2; - /* __le32 ptb2_16_35:20; */ -#define IWL_tb2_addr_hi20_POS 0 -#define IWL_tb2_addr_hi20_LEN 20 -#define IWL_tb2_addr_hi20_SYM val2 - /* __le32 tb_len2:12; */ -#define IWL_tb2_len_POS 20 -#define IWL_tb2_len_LEN 12 -#define IWL_tb2_len_SYM val2 -} __attribute__ ((packed)); - /** - * struct iwl_tfd_frame - * - * Transmit Frame Descriptor (TFD) - * - * 4965 supports up to 16 Tx queues resident in host DRAM. - * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. - * Both driver and device share these circular buffers, each of which must be - * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes for 4965. - * - * Driver must indicate the physical address of the base of each - * circular buffer via the 4965's FH_MEM_CBBC_QUEUE registers. - * - * Each TFD contains pointer/size information for up to 20 data buffers - * in host DRAM. These buffers collectively contain the (one) frame described - * by the TFD. Each buffer must be a single contiguous block of memory within - * itself, but buffers may be scattered in host DRAM. Each buffer has max size - * of (4K - 4). The 4965 concatenates all of a TFD's buffers into a single - * Tx frame, up to 8 KBytes in size. - * - * Bit fields in the control dword (val0): - * 31-30: # dwords (0-3) of padding required at end of frame for 16-byte bound - * 29: reserved - * 28-24: # Transmit Buffer Descriptors in TFD - * 23- 0: reserved - * - * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. - */ -struct iwl_tfd_frame { - __le32 val0; - /* __le32 rsvd1:24; */ - /* __le32 num_tbs:5; */ -#define IWL_num_tbs_POS 24 -#define IWL_num_tbs_LEN 5 -#define IWL_num_tbs_SYM val0 - /* __le32 rsvd2:1; */ - /* __le32 padding:2; */ - struct iwl_tfd_frame_data pa[10]; - __le32 reserved; -} __attribute__ ((packed)); - - -/** - * struct iwl4965_queue_byte_cnt_entry - * - * Byte Count Table Entry - * - * Bit fields: - * 15-12: reserved - * 11- 0: total to-be-transmitted byte count of frame (does not include command) - */ -struct iwl4965_queue_byte_cnt_entry { - __le16 val; - /* __le16 byte_cnt:12; */ -#define IWL_byte_cnt_POS 0 -#define IWL_byte_cnt_LEN 12 -#define IWL_byte_cnt_SYM val - /* __le16 rsvd:4; */ -} __attribute__ ((packed)); - - -/** - * struct iwl4965_sched_queue_byte_cnt_tbl + * struct iwl4965_schedq_bc_tbl * * Byte Count table * @@ -947,71 +829,12 @@ struct iwl4965_queue_byte_cnt_entry { * count table for the chosen Tx queue. If the TFD index is 0-63, the driver * must duplicate the byte count entry in corresponding index 256-319. * - * "dont_care" padding puts each byte count table on a 1024-byte boundary; + * padding puts each byte count table on a 1024-byte boundary; * 4965 assumes tables are separated by 1024 bytes. */ -struct iwl4965_sched_queue_byte_cnt_tbl { - struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL49_QUEUE_SIZE + - IWL49_MAX_WIN_SIZE]; - u8 dont_care[1024 - - (IWL49_QUEUE_SIZE + IWL49_MAX_WIN_SIZE) * - sizeof(__le16)]; -} __attribute__ ((packed)); - - -/** - * struct iwl4965_shared - handshake area for Tx and Rx - * - * For convenience in allocating memory, this structure combines 2 areas of - * DRAM which must be shared between driver and 4965. These do not need to - * be combined, if better allocation would result from keeping them separate: - * - * 1) The Tx byte count tables occupy 1024 bytes each (16 KBytes total for - * 16 queues). Driver uses SCD_DRAM_BASE_ADDR to tell 4965 where to find - * the first of these tables. 4965 assumes tables are 1024 bytes apart. - * - * 2) The Rx status (val0 and val1) occupies only 8 bytes. Driver uses - * FH_RSCSR_CHNL0_STTS_WPTR_REG to tell 4965 where to find this area. - * Driver reads val0 to determine the latest Receive Buffer Descriptor (RBD) - * that has been filled by the 4965. - * - * Bit fields val0: - * 31-12: Not used - * 11- 0: Index of last filled Rx buffer descriptor (4965 writes, driver reads) - * - * Bit fields val1: - * 31- 0: Not used - */ -struct iwl4965_shared { - struct iwl4965_sched_queue_byte_cnt_tbl - queues_byte_cnt_tbls[IWL49_NUM_QUEUES]; - __le32 rb_closed; - - /* __le32 rb_closed_stts_rb_num:12; */ -#define IWL_rb_closed_stts_rb_num_POS 0 -#define IWL_rb_closed_stts_rb_num_LEN 12 -#define IWL_rb_closed_stts_rb_num_SYM rb_closed - /* __le32 rsrv1:4; */ - /* __le32 rb_closed_stts_rx_frame_num:12; */ -#define IWL_rb_closed_stts_rx_frame_num_POS 16 -#define IWL_rb_closed_stts_rx_frame_num_LEN 12 -#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed - /* __le32 rsrv2:4; */ - - __le32 frm_finished; - /* __le32 frame_finished_stts_rb_num:12; */ -#define IWL_frame_finished_stts_rb_num_POS 0 -#define IWL_frame_finished_stts_rb_num_LEN 12 -#define IWL_frame_finished_stts_rb_num_SYM frm_finished - /* __le32 rsrv3:4; */ - /* __le32 frame_finished_stts_rx_frame_num:12; */ -#define IWL_frame_finished_stts_rx_frame_num_POS 16 -#define IWL_frame_finished_stts_rx_frame_num_LEN 12 -#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished - /* __le32 rsrv4:4; */ - - __le32 padding1; /* so that allocation will be aligned to 16B */ - __le32 padding2; +struct iwl4965_scd_bc_tbl { + __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; + u8 pad[1024 - (TFD_QUEUE_BC_SIZE) * sizeof(__le16)]; } __attribute__ ((packed)); -#endif /* __iwl4965_4965_hw_h__ */ +#endif /* !__iwl_4965_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c index 9838de5f436918762c0fafdca82102ea01993094..5a72bc0377ded292dcfd7048b9fbfc86373eab4e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-4965.c +++ b/drivers/net/wireless/iwlwifi/iwl-4965.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -48,18 +48,21 @@ static int iwl4965_send_tx_power(struct iwl_priv *priv); static int iwl4965_hw_get_temperature(const struct iwl_priv *priv); -/* 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 "-2" +/* Highest firmware API version supported */ +#define IWL4965_UCODE_API_MAX 2 + +/* Lowest firmware API version supported */ +#define IWL4965_UCODE_API_MIN 2 + +#define IWL4965_FW_PRE "iwlwifi-4965-" +#define _IWL4965_MODULE_FIRMWARE(api) IWL4965_FW_PRE #api ".ucode" +#define IWL4965_MODULE_FIRMWARE(api) _IWL4965_MODULE_FIRMWARE(api) /* module parameters */ static struct iwl_mod_params iwl4965_mod_params = { .num_of_queues = IWL49_NUM_QUEUES, .num_of_ampdu_queues = IWL49_NUM_AMPDU_QUEUES, - .enable_qos = 1, .amsdu_size_8K = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -246,7 +249,7 @@ static int iwl4965_set_ucode_ptrs(struct iwl_priv *priv) iwl_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, priv->ucode_data.len); - /* Inst bytecount must be last to set up, bit 31 signals uCode + /* Inst byte count must be last to set up, bit 31 signals uCode * that all new ptr/size info is in place */ iwl_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); @@ -318,31 +321,13 @@ static int is_fat_channel(__le32 rxon_flags) /* * EEPROM handlers */ - -static int iwl4965_eeprom_check_version(struct iwl_priv *priv) +static u16 iwl4965_eeprom_calib_version(struct iwl_priv *priv) { - u16 eeprom_ver; - u16 calib_ver; - - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - - calib_ver = iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET); - - if (eeprom_ver < EEPROM_4965_EEPROM_VERSION || - calib_ver < EEPROM_4965_TX_POWER_VERSION) - goto err; - - return 0; -err: - IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", - eeprom_ver, EEPROM_4965_EEPROM_VERSION, - calib_ver, EEPROM_4965_TX_POWER_VERSION); - return -EINVAL; - + return iwl_eeprom_query16(priv, EEPROM_4965_CALIB_VERSION_OFFSET); } /* - * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask + * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask * must be called under priv->lock and mac access */ static void iwl4965_txq_set_sched(struct iwl_priv *priv, u32 mask) @@ -366,9 +351,8 @@ static int iwl4965_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO("Failed to init the card\n"); goto out; @@ -414,7 +398,7 @@ static void iwl4965_nic_config(struct iwl_priv *priv) /* L1 is enabled by BIOS */ if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) - /* diable L0S disabled L1A enabled */ + /* disable L0S disabled L1A enabled */ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); else /* L0S enabled L1A disabled */ @@ -442,7 +426,6 @@ static void iwl4965_nic_config(struct iwl_priv *priv) static int iwl4965_apm_stop_master(struct iwl_priv *priv) { - int ret = 0; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); @@ -450,17 +433,13 @@ static int iwl4965_apm_stop_master(struct iwl_priv *priv) /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, - CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - if (ret < 0) - goto out; + iwl_poll_direct_bit(priv, CSR_RESET, + CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); -out: spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("stop master\n"); - return ret; + return 0; } static void iwl4965_apm_stop(struct iwl_priv *priv) @@ -496,11 +475,9 @@ static int iwl4965_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - ret = iwl_poll_bit(priv, CSR_RESET, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25); - - if (ret) + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (ret < 0) goto out; udelay(10); @@ -537,10 +514,10 @@ static void iwl4965_chain_noise_reset(struct iwl_priv *priv) struct iwl_chain_noise_data *data = &(priv->chain_noise_data); if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { - struct iwl4965_calibration_cmd cmd; + struct iwl_calib_diff_gain_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; cmd.diff_gain_a = 0; cmd.diff_gain_b = 0; cmd.diff_gain_c = 0; @@ -587,11 +564,11 @@ static void iwl4965_gain_computation(struct iwl_priv *priv, /* Differential gain gets sent to uCode only once */ if (!data->radio_write) { - struct iwl4965_calibration_cmd cmd; + struct iwl_calib_diff_gain_cmd cmd; data->radio_write = 1; memset(&cmd, 0, sizeof(cmd)); - cmd.opCode = PHY_CALIBRATE_DIFF_GAIN_CMD; + cmd.hdr.op_code = IWL_PHY_CALIBRATE_DIFF_GAIN_CMD; cmd.diff_gain_a = data->delta_gain_code[0]; cmd.diff_gain_b = data->delta_gain_code[1]; cmd.diff_gain_c = data->delta_gain_code[2]; @@ -619,10 +596,10 @@ static void iwl4965_gain_computation(struct iwl_priv *priv, static void iwl4965_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags) { - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { *tx_flags |= TX_CMD_FLG_RTS_MSK; *tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { *tx_flags &= ~TX_CMD_FLG_RTS_MSK; *tx_flags |= TX_CMD_FLG_CTS_MSK; } @@ -643,7 +620,7 @@ static void iwl4965_bg_txpower_work(struct work_struct *work) mutex_lock(&priv->mutex); - /* Regardless of if we are assocaited, we must reconfigure the + /* Regardless of if we are associated, we must reconfigure the * TX power since frames can be sent on non-radar channels while * not associated */ iwl4965_send_tx_power(priv); @@ -679,7 +656,7 @@ static void iwl4965_tx_queue_set_status(struct iwl_priv *priv, int txq_id = txq->q.id; /* Find out whether to activate Tx queue */ - int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; + int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0; /* Set up and activate */ iwl_write_prph(priv, IWL49_SCD_QUEUE_STATUS_BITS(txq_id), @@ -709,9 +686,10 @@ static const u16 default_queue_to_tx_fifo[] = { static int iwl4965_alive_notify(struct iwl_priv *priv) { u32 a; - int i = 0; unsigned long flags; int ret; + int i, chan; + u32 reg_val; spin_lock_irqsave(&priv->lock, flags); @@ -733,8 +711,18 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) /* Tel 4965 where to find Tx byte count tables */ iwl_write_prph(priv, IWL49_SCD_DRAM_BASE_ADDR, - (priv->shared_phys + - offsetof(struct iwl4965_shared, queues_byte_cnt_tbls)) >> 10); + priv->scd_bc_tbls.dma >> 10); + + /* Enable DMA channel */ + for (chan = 0; chan < FH49_TCSR_CHNL_NUM ; chan++) + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); + + /* Update FH chicken bits */ + reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG); + iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG, + reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); /* Disable chain mode for all queues */ iwl_write_prph(priv, IWL49_SCD_QUEUECHAIN_SEL, 0); @@ -766,7 +754,7 @@ static int iwl4965_alive_notify(struct iwl_priv *priv) (1 << priv->hw_params.max_txq_num) - 1); /* Activate all Tx DMA/FIFO channels */ - priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7)); + priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 6)); iwl4965_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); @@ -822,7 +810,9 @@ static int iwl4965_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; - priv->hw_params.first_ampdu_q = IWL49_FIRST_AMPDU_QUEUE; + priv->hw_params.dma_chnl_num = FH49_TCSR_CHNL_NUM; + priv->hw_params.scd_bc_tbls_size = + IWL49_NUM_QUEUES * sizeof(struct iwl4965_scd_bc_tbl); priv->hw_params.max_stations = IWL4965_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL4965_BROADCAST_ID; priv->hw_params.max_data_size = IWL49_RTC_DATA_SIZE; @@ -1650,36 +1640,6 @@ static int iwl4965_hw_channel_switch(struct iwl_priv *priv, u16 channel) } #endif -static int iwl4965_shared_mem_rx_idx(struct iwl_priv *priv) -{ - struct iwl4965_shared *s = priv->shared_virt; - return le32_to_cpu(s->rb_closed) & 0xFFF; -} - -static int iwl4965_alloc_shared_mem(struct iwl_priv *priv) -{ - priv->shared_virt = pci_alloc_consistent(priv->pci_dev, - sizeof(struct iwl4965_shared), - &priv->shared_phys); - if (!priv->shared_virt) - return -ENOMEM; - - memset(priv->shared_virt, 0, sizeof(struct iwl4965_shared)); - - priv->rb_closed_offset = offsetof(struct iwl4965_shared, rb_closed); - - return 0; -} - -static void iwl4965_free_shared_mem(struct iwl_priv *priv) -{ - if (priv->shared_virt) - pci_free_consistent(priv->pci_dev, - sizeof(struct iwl4965_shared), - priv->shared_virt, - priv->shared_phys); -} - /** * iwl4965_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ @@ -1687,21 +1647,22 @@ static void iwl4965_txq_update_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt) { - int len; + struct iwl4965_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int txq_id = txq->q.id; - struct iwl4965_shared *shared_data = priv->shared_virt; + int write_ptr = txq->q.write_ptr; + int len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + __le16 bc_ent; - len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); + bc_ent = cpu_to_le16(len & 0xFFF); /* Set up byte count within first 256 entries */ - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[txq->q.write_ptr], byte_cnt, len); + scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; /* If within first 64 entries, duplicate at end */ - if (txq->q.write_ptr < IWL49_MAX_WIN_SIZE) - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL49_QUEUE_SIZE + txq->q.write_ptr], - byte_cnt, len); + if (write_ptr < TFD_QUEUE_SIZE_BC_DUP) + scd_bc_tbl[txq_id]. + tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } /** @@ -1956,7 +1917,7 @@ static int iwl4965_txq_agg_enable(struct iwl_priv *priv, int txq_id, ra_tid = BUILD_RAxTID(sta_id, tid); /* Modify device's station table to Tx this TID */ - iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); + iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); ret = iwl_grab_nic_access(priv); @@ -2037,7 +1998,7 @@ static inline u32 iwl4965_get_scd_ssn(struct iwl4965_tx_resp *tx_resp) } /** - * iwl4965_tx_status_reply_tx - Handle Tx rspnse for frames in aggregation queue + * iwl4965_tx_status_reply_tx - Handle Tx response for frames in aggregation queue */ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, struct iwl_ht_agg *agg, @@ -2059,7 +2020,7 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, agg->rate_n_flags = rate_n_flags; agg->bitmap = 0; - /* # frames attempted by Tx command */ + /* num frames attempted by Tx command */ if (agg->frame_count == 1) { /* Only one frame was attempted; no block-ack will arrive */ status = le16_to_cpu(frame_status[0].status); @@ -2070,9 +2031,9 @@ static int iwl4965_tx_status_reply_tx(struct iwl_priv *priv, agg->frame_count, agg->start_idx, idx); info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_is_tx_success(status)? + info->flags |= iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, rate_n_flags, info); /* FIXME: code repetition end */ @@ -2158,12 +2119,13 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, int txq_id = SEQ_TO_QUEUE(sequence); int index = SEQ_TO_INDEX(sequence); struct iwl_tx_queue *txq = &priv->txq[txq_id]; + struct ieee80211_hdr *hdr; struct ieee80211_tx_info *info; struct iwl4965_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le32_to_cpu(tx_resp->u.status); - int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; - __le16 fc; - struct ieee80211_hdr *hdr; + int tid = MAX_TID_COUNT; + int sta_id; + int freed; u8 *qc = NULL; if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { @@ -2178,8 +2140,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, memset(&info->status, 0, sizeof(info->status)); hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); - fc = hdr->frame_control; - if (ieee80211_is_data_qos(fc)) { + if (ieee80211_is_data_qos(hdr->frame_control)) { qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; } @@ -2194,8 +2155,7 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, const u32 scd_ssn = iwl4965_get_scd_ssn(tx_resp); struct iwl_ht_agg *agg = NULL; - if (!qc) - return; + WARN_ON(!qc); agg = &priv->stations[sta_id].tid[tid].agg; @@ -2206,54 +2166,49 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv, info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; if (txq->q.read_ptr != (scd_ssn & 0xff)) { - int freed, ampdu_q; 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); freed = iwl_tx_queue_reclaim(priv, txq_id, index); priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - txq_id >= 0 && priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { - /* calculate mac80211 ampdu sw queue to wake */ - ampdu_q = txq_id - IWL49_FIRST_AMPDU_QUEUE + - priv->hw->queues; + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark) && + (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { if (agg->state == IWL_AGG_OFF) ieee80211_wake_queue(priv->hw, txq_id); else - ieee80211_wake_queue(priv->hw, ampdu_q); + ieee80211_wake_queue(priv->hw, + txq->swq_id); } - iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { - info->status.retry_count = tx_resp->failure_frame; - info->flags |= - iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + info->status.rates[0].count = tx_resp->failure_frame + 1; + info->flags |= iwl_is_tx_success(status) ? + IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags " - "0x%x retries %d\n", txq_id, - iwl_get_tx_fail_reason(status), - status, le32_to_cpu(tx_resp->rate_n_flags), - tx_resp->failure_frame); + IWL_DEBUG_TX_REPLY("TXQ %d status %s (0x%08x) " + "rate_n_flags 0x%x retries %d\n", + txq_id, + iwl_get_tx_fail_reason(status), status, + le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); - IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); - - if (index != -1) { - int freed = iwl_tx_queue_reclaim(priv, txq_id, index); - if (tid != MAX_TID_COUNT) + freed = iwl_tx_queue_reclaim(priv, txq_id, index); + if (qc && likely(sta_id != IWL_INVALID_STATION)) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - (txq_id >= 0) && priv->mac80211_registered) + + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark)) ieee80211_wake_queue(priv->hw, txq_id); - if (tid != MAX_TID_COUNT) - iwl_txq_check_empty(priv, sta_id, tid, txq_id); - } } + if (qc && likely(sta_id != IWL_INVALID_STATION)) + iwl_txq_check_empty(priv, sta_id, tid, txq_id); + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } @@ -2328,9 +2283,6 @@ static struct iwl_hcmd_utils_ops iwl4965_hcmd_utils = { static struct iwl_lib_ops iwl4965_lib = { .set_hw_params = iwl4965_hw_set_hw_params, - .alloc_shared_mem = iwl4965_alloc_shared_mem, - .free_shared_mem = iwl4965_free_shared_mem, - .shared_mem_rx_idx = iwl4965_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl4965_txq_update_byte_cnt_tbl, .txq_set_sched = iwl4965_txq_set_sched, .txq_agg_enable = iwl4965_txq_agg_enable, @@ -2347,7 +2299,7 @@ static struct iwl_lib_ops iwl4965_lib = { .reset = iwl4965_apm_reset, .stop = iwl4965_apm_stop, .config = iwl4965_nic_config, - .set_pwr_src = iwl4965_set_pwr_src, + .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { @@ -2362,11 +2314,11 @@ static struct iwl_lib_ops iwl4965_lib = { .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, - .check_version = iwl4965_eeprom_check_version, + .calib_version = iwl4965_eeprom_calib_version, .query_addr = iwlcore_eeprom_query_addr, }, .send_tx_power = iwl4965_send_tx_power, - .update_chain_flags = iwl4965_update_chain_flags, + .update_chain_flags = iwl_update_chain_flags, .temperature = iwl4965_temperature_calib, }; @@ -2378,15 +2330,19 @@ static struct iwl_ops iwl4965_ops = { struct iwl_cfg iwl4965_agn_cfg = { .name = "4965AGN", - .fw_name = "iwlwifi-4965" IWL4965_UCODE_API ".ucode", + .fw_name_pre = IWL4965_FW_PRE, + .ucode_api_max = IWL4965_UCODE_API_MAX, + .ucode_api_min = IWL4965_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .eeprom_size = IWL4965_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_4965_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_4965_TX_POWER_VERSION, .ops = &iwl4965_ops, .mod_params = &iwl4965_mod_params, }; /* Module firmware */ -MODULE_FIRMWARE("iwlwifi-4965" IWL4965_UCODE_API ".ucode"); +MODULE_FIRMWARE(IWL4965_MODULE_FIRMWARE(IWL4965_UCODE_API_MAX)); module_param_named(antenna, iwl4965_mod_params.antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); @@ -2394,7 +2350,7 @@ module_param_named(disable, iwl4965_mod_params.disable, int, 0444); MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param_named(swcrypto, iwl4965_mod_params.sw_crypto, int, 0444); MODULE_PARM_DESC(swcrypto, "using crypto in software (default 0 [hardware])"); -module_param_named(debug, iwl4965_mod_params.debug, int, 0444); +module_param_named(debug, iwl4965_mod_params.debug, uint, 0444); MODULE_PARM_DESC(debug, "debug output mask"); module_param_named( disable_hw_scan, iwl4965_mod_params.disable_hw_scan, int, 0444); @@ -2402,9 +2358,6 @@ MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); module_param_named(queues_num, iwl4965_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num, "number of hw queues."); -/* QoS */ -module_param_named(qos_enable, iwl4965_mod_params.enable_qos, int, 0444); -MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); /* 11n */ module_param_named(11n_disable, iwl4965_mod_params.disable_11n, int, 0444); MODULE_PARM_DESC(11n_disable, "disable 11n functionality"); diff --git a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h index c479ee211c5cf14d322db770c0c9e91a17a9e27a..82c3859ce0f8bf8fb95ac751ef53810984986458 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000-hw.h +++ b/drivers/net/wireless/iwlwifi/iwl-5000-hw.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -73,69 +73,27 @@ #define IWL50_RTC_INST_SIZE (IWL50_RTC_INST_UPPER_BOUND - RTC_INST_LOWER_BOUND) #define IWL50_RTC_DATA_SIZE (IWL50_RTC_DATA_UPPER_BOUND - RTC_DATA_LOWER_BOUND) -/* EERPROM */ +/* EEPROM */ #define IWL_5000_EEPROM_IMG_SIZE 2048 - -#define IWL50_MAX_WIN_SIZE 64 -#define IWL50_QUEUE_SIZE 256 #define IWL50_CMD_FIFO_NUM 7 #define IWL50_NUM_QUEUES 20 #define IWL50_NUM_AMPDU_QUEUES 10 #define IWL50_FIRST_AMPDU_QUEUE 10 -#define IWL_sta_id_POS 12 -#define IWL_sta_id_LEN 4 -#define IWL_sta_id_SYM val - /* Fixed (non-configurable) rx data from phy */ -/* Base physical address of iwl5000_shared is provided to SCD_DRAM_BASE_ADDR - * and &iwl5000_shared.val0 is provided to FH_RSCSR_CHNL0_STTS_WPTR_REG */ -struct iwl5000_sched_queue_byte_cnt_tbl { - struct iwl4965_queue_byte_cnt_entry tfd_offset[IWL50_QUEUE_SIZE + - IWL50_MAX_WIN_SIZE]; -} __attribute__ ((packed)); - -struct iwl5000_shared { - struct iwl5000_sched_queue_byte_cnt_tbl - queues_byte_cnt_tbls[IWL50_NUM_QUEUES]; - __le32 rb_closed; - - /* __le32 rb_closed_stts_rb_num:12; */ -#define IWL_rb_closed_stts_rb_num_POS 0 -#define IWL_rb_closed_stts_rb_num_LEN 12 -#define IWL_rb_closed_stts_rb_num_SYM rb_closed - /* __le32 rsrv1:4; */ - /* __le32 rb_closed_stts_rx_frame_num:12; */ -#define IWL_rb_closed_stts_rx_frame_num_POS 16 -#define IWL_rb_closed_stts_rx_frame_num_LEN 12 -#define IWL_rb_closed_stts_rx_frame_num_SYM rb_closed - /* __le32 rsrv2:4; */ - - __le32 frm_finished; - /* __le32 frame_finished_stts_rb_num:12; */ -#define IWL_frame_finished_stts_rb_num_POS 0 -#define IWL_frame_finished_stts_rb_num_LEN 12 -#define IWL_frame_finished_stts_rb_num_SYM frm_finished - /* __le32 rsrv3:4; */ - /* __le32 frame_finished_stts_rx_frame_num:12; */ -#define IWL_frame_finished_stts_rx_frame_num_POS 16 -#define IWL_frame_finished_stts_rx_frame_num_LEN 12 -#define IWL_frame_finished_stts_rx_frame_num_SYM frm_finished - /* __le32 rsrv4:4; */ - - __le32 padding1; /* so that allocation will be aligned to 16B */ - __le32 padding2; +/** + * struct iwl5000_schedq_bc_tbl scheduler byte count table + * base physical address of iwl5000_shared + * is provided to SCD_DRAM_BASE_ADDR + * @tfd_offset 0-12 - tx command byte count + * 12-16 - station index + */ +struct iwl5000_scd_bc_tbl { + __le16 tfd_offset[TFD_QUEUE_BC_SIZE]; } __attribute__ ((packed)); -/* calibrations defined for 5000 */ -/* defines the order in which results should be sent to the runtime uCode */ -enum iwl5000_calib { - IWL5000_CALIB_LO, - IWL5000_CALIB_TX_IQ, - IWL5000_CALIB_TX_IQ_PERD, -}; #endif /* __iwl_5000_hw_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index 5155b8a760a7299cd5b01ae139821ec3c5dd0fe1..66d053d28a7470dbb395dd57202edb224cd36b15 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c @@ -44,7 +44,21 @@ #include "iwl-helpers.h" #include "iwl-5000-hw.h" -#define IWL5000_UCODE_API "-1" +/* Highest firmware API version supported */ +#define IWL5000_UCODE_API_MAX 1 +#define IWL5150_UCODE_API_MAX 1 + +/* Lowest firmware API version supported */ +#define IWL5000_UCODE_API_MIN 1 +#define IWL5150_UCODE_API_MIN 1 + +#define IWL5000_FW_PRE "iwlwifi-5000-" +#define _IWL5000_MODULE_FIRMWARE(api) IWL5000_FW_PRE #api ".ucode" +#define IWL5000_MODULE_FIRMWARE(api) _IWL5000_MODULE_FIRMWARE(api) + +#define IWL5150_FW_PRE "iwlwifi-5150-" +#define _IWL5150_MODULE_FIRMWARE(api) IWL5150_FW_PRE #api ".ucode" +#define IWL5150_MODULE_FIRMWARE(api) _IWL5150_MODULE_FIRMWARE(api) static const u16 iwl5000_default_queue_to_tx_fifo[] = { IWL_TX_FIFO_AC3, @@ -59,7 +73,6 @@ static const u16 iwl5000_default_queue_to_tx_fifo[] = { /* FIXME: same implementation as 4965 */ static int iwl5000_apm_stop_master(struct iwl_priv *priv) { - int ret = 0; unsigned long flags; spin_lock_irqsave(&priv->lock, flags); @@ -67,17 +80,13 @@ static int iwl5000_apm_stop_master(struct iwl_priv *priv) /* set stop master bit */ iwl_set_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_STOP_MASTER); - ret = iwl_poll_bit(priv, CSR_RESET, - CSR_RESET_REG_FLAG_MASTER_DISABLED, + iwl_poll_direct_bit(priv, CSR_RESET, CSR_RESET_REG_FLAG_MASTER_DISABLED, 100); - if (ret < 0) - goto out; -out: spin_unlock_irqrestore(&priv->lock, flags); IWL_DEBUG_INFO("stop master\n"); - return ret; + return 0; } @@ -92,7 +101,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GIO_CHICKEN_BITS, CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX); - /* Set FH wait treshold to maximum (HW error during stress W/A) */ + /* Set FH wait threshold to maximum (HW error during stress W/A) */ iwl_set_bit(priv, CSR_DBG_HPET_MEM_REG, CSR_DBG_HPET_MEM_REG_VAL); /* enable HAP INTA to move device L1a -> L0s */ @@ -106,9 +115,8 @@ static int iwl5000_apm_init(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO("Failed to init the card\n"); return ret; @@ -132,7 +140,7 @@ static int iwl5000_apm_init(struct iwl_priv *priv) return ret; } -/* FIXME: this is indentical to 4965 */ +/* FIXME: this is identical to 4965 */ static void iwl5000_apm_stop(struct iwl_priv *priv) { unsigned long flags; @@ -175,9 +183,8 @@ static int iwl5000_apm_reset(struct iwl_priv *priv) iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); /* wait for clock stabilization */ - ret = iwl_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); if (ret < 0) { IWL_DEBUG_INFO("Failed to init the card\n"); goto out; @@ -217,7 +224,7 @@ static void iwl5000_nic_config(struct iwl_priv *priv) /* L1 is enabled by BIOS */ if ((link & PCI_CFG_LINK_CTRL_VAL_L1_EN) == PCI_CFG_LINK_CTRL_VAL_L1_EN) - /* diable L0S disabled L1A enabled */ + /* disable L0S disabled L1A enabled */ iwl_set_bit(priv, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED); else /* L0S enabled L1A disabled */ @@ -291,30 +298,17 @@ static u32 eeprom_indirect_address(const struct iwl_priv *priv, u32 address) return (address & ADDRESS_MSK) + (offset << 1); } -static int iwl5000_eeprom_check_version(struct iwl_priv *priv) +static u16 iwl5000_eeprom_calib_version(struct iwl_priv *priv) { - u16 eeprom_ver; struct iwl_eeprom_calib_hdr { u8 version; u8 pa_type; u16 voltage; } *hdr; - eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); - hdr = (struct iwl_eeprom_calib_hdr *)iwl_eeprom_query_addr(priv, EEPROM_5000_CALIB_ALL); - - if (eeprom_ver < EEPROM_5000_EEPROM_VERSION || - hdr->version < EEPROM_5000_TX_POWER_VERSION) - goto err; - - return 0; -err: - IWL_ERROR("Unsuported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", - eeprom_ver, EEPROM_5000_EEPROM_VERSION, - hdr->version, EEPROM_5000_TX_POWER_VERSION); - return -EINVAL; + return hdr->version; } @@ -348,10 +342,14 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, data->delta_gain_code[1], data->delta_gain_code[2]); if (!data->radio_write) { - struct iwl5000_calibration_chain_noise_gain_cmd cmd; + struct iwl_calib_chain_noise_gain_cmd cmd; + memset(&cmd, 0, sizeof(cmd)); - cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD; + cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD; + cmd.hdr.first_group = 0; + cmd.hdr.groups_num = 1; + cmd.hdr.data_valid = 1; cmd.delta_gain_1 = data->delta_gain_code[1]; cmd.delta_gain_2 = data->delta_gain_code[2]; iwl_send_cmd_pdu_async(priv, REPLY_PHY_CALIBRATION_CMD, @@ -373,14 +371,19 @@ static void iwl5000_gain_computation(struct iwl_priv *priv, static void iwl5000_chain_noise_reset(struct iwl_priv *priv) { struct iwl_chain_noise_data *data = &priv->chain_noise_data; + int ret; if ((data->state == IWL_CHAIN_NOISE_ALIVE) && iwl_is_associated(priv)) { - struct iwl5000_calibration_chain_noise_reset_cmd cmd; - + struct iwl_calib_chain_noise_reset_cmd cmd; memset(&cmd, 0, sizeof(cmd)); - cmd.op_code = IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; - if (iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cmd), &cmd)) + + cmd.hdr.op_code = IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD; + cmd.hdr.first_group = 0; + cmd.hdr.groups_num = 1; + cmd.hdr.data_valid = 1; + ret = iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, + sizeof(cmd), &cmd); + if (ret) IWL_ERROR("Could not send REPLY_PHY_CALIBRATION_CMD\n"); data->state = IWL_CHAIN_NOISE_ACCUMULATE; IWL_DEBUG_CALIB("Run chain_noise_calibrate\n"); @@ -390,8 +393,8 @@ static void iwl5000_chain_noise_reset(struct iwl_priv *priv) static void iwl5000_rts_tx_cmd_flag(struct ieee80211_tx_info *info, __le32 *tx_flags) { - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) + if ((info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) *tx_flags |= TX_CMD_FLG_RTS_CTS_MSK; else *tx_flags &= ~TX_CMD_FLG_RTS_CTS_MSK; @@ -426,31 +429,41 @@ static const u8 *iwl5000_eeprom_query_addr(const struct iwl_priv *priv, return &priv->eeprom[address]; } +static s32 iwl5150_get_ct_threshold(struct iwl_priv *priv) +{ + const s32 volt2temp_coef = -5; + u16 *temp_calib = (u16 *)iwl_eeprom_query_addr(priv, + EEPROM_5000_TEMPERATURE); + /* offset = temperate - voltage / coef */ + s32 offset = temp_calib[0] - temp_calib[1] / volt2temp_coef; + s32 threshold = (s32)CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD) - offset; + return threshold * volt2temp_coef; +} + /* * Calibration */ -static int iwl5000_send_Xtal_calib(struct iwl_priv *priv) +static int iwl5000_set_Xtal_calib(struct iwl_priv *priv) { + struct iwl_calib_xtal_freq_cmd cmd; u16 *xtal_calib = (u16 *)iwl_eeprom_query_addr(priv, EEPROM_5000_XTAL); - struct iwl5000_calibration cal_cmd = { - .op_code = IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD, - .data = { - (u8)xtal_calib[0], - (u8)xtal_calib[1], - } - }; - - return iwl_send_cmd_pdu(priv, REPLY_PHY_CALIBRATION_CMD, - sizeof(cal_cmd), &cal_cmd); + cmd.hdr.op_code = IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD; + cmd.hdr.first_group = 0; + cmd.hdr.groups_num = 1; + cmd.hdr.data_valid = 1; + cmd.cap_pin1 = (u8)xtal_calib[0]; + cmd.cap_pin2 = (u8)xtal_calib[1]; + return iwl_calib_set(&priv->calib_results[IWL_CALIB_XTAL], + (u8 *)&cmd, sizeof(cmd)); } static int iwl5000_send_calib_cfg(struct iwl_priv *priv) { - struct iwl5000_calib_cfg_cmd calib_cfg_cmd; + struct iwl_calib_cfg_cmd calib_cfg_cmd; struct iwl_host_cmd cmd = { .id = CALIBRATION_CFG_CMD, - .len = sizeof(struct iwl5000_calib_cfg_cmd), + .len = sizeof(struct iwl_calib_cfg_cmd), .data = &calib_cfg_cmd, }; @@ -467,7 +480,7 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (void *)rxb->skb->data; - struct iwl5000_calib_hdr *hdr = (struct iwl5000_calib_hdr *)pkt->u.raw; + struct iwl_calib_hdr *hdr = (struct iwl_calib_hdr *)pkt->u.raw; int len = le32_to_cpu(pkt->len) & FH_RSCSR_FRAME_SIZE_MSK; int index; @@ -478,14 +491,20 @@ static void iwl5000_rx_calib_result(struct iwl_priv *priv, * uCode. iwl_send_calib_results sends them in a row according to their * index. We sort them here */ switch (hdr->op_code) { - case IWL5000_PHY_CALIBRATE_LO_CMD: - index = IWL5000_CALIB_LO; + case IWL_PHY_CALIBRATE_DC_CMD: + index = IWL_CALIB_DC; + break; + case IWL_PHY_CALIBRATE_LO_CMD: + index = IWL_CALIB_LO; break; - case IWL5000_PHY_CALIBRATE_TX_IQ_CMD: - index = IWL5000_CALIB_TX_IQ; + case IWL_PHY_CALIBRATE_TX_IQ_CMD: + index = IWL_CALIB_TX_IQ; break; - case IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD: - index = IWL5000_CALIB_TX_IQ_PERD; + case IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD: + index = IWL_CALIB_TX_IQ_PERD; + break; + case IWL_PHY_CALIBRATE_BASE_BAND_CMD: + index = IWL_CALIB_BASE_BAND; break; default: IWL_ERROR("Unknown calibration notification %d\n", @@ -535,7 +554,7 @@ static int iwl5000_load_section(struct iwl_priv *priv, iwl_write_direct32(priv, FH_TFDIB_CTRL1_REG(FH_SRVC_CHNL), - (iwl_get_dma_hi_address(phy_addr) + (iwl_get_dma_hi_addr(phy_addr) << FH_MEM_TFDIB_REG1_ADDR_BITSHIFT) | byte_cnt); iwl_write_direct32(priv, @@ -547,7 +566,7 @@ static int iwl5000_load_section(struct iwl_priv *priv, iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(FH_SRVC_CHNL), FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE | FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD); iwl_release_nic_access(priv); @@ -561,14 +580,13 @@ static int iwl5000_load_given_ucode(struct iwl_priv *priv, { int ret = 0; - ret = iwl5000_load_section( - priv, inst_image, RTC_INST_LOWER_BOUND); + ret = iwl5000_load_section(priv, inst_image, RTC_INST_LOWER_BOUND); if (ret) return ret; IWL_DEBUG_INFO("INST uCode section being loaded...\n"); ret = wait_event_interruptible_timeout(priv->wait_command_queue, - priv->ucode_write_complete, 5 * HZ); + priv->ucode_write_complete, 5 * HZ); if (ret == -ERESTARTSYS) { IWL_ERROR("Could not load the INST uCode section due " "to interrupt\n"); @@ -682,7 +700,7 @@ static void iwl5000_tx_queue_set_status(struct iwl_priv *priv, int tx_fifo_id, int scd_retry) { int txq_id = txq->q.id; - int active = test_bit(txq_id, &priv->txq_ctx_active_msk)?1:0; + int active = test_bit(txq_id, &priv->txq_ctx_active_msk) ? 1 : 0; iwl_write_prph(priv, IWL50_SCD_QUEUE_STATUS_BITS(txq_id), (active << IWL50_SCD_QUEUE_STTS_REG_POS_ACTIVE) | @@ -710,9 +728,10 @@ static int iwl5000_send_wimax_coex(struct iwl_priv *priv) static int iwl5000_alive_notify(struct iwl_priv *priv) { u32 a; - int i = 0; unsigned long flags; int ret; + int i, chan; + u32 reg_val; spin_lock_irqsave(&priv->lock, flags); @@ -734,11 +753,21 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl_write_targ_mem(priv, a, 0); iwl_write_prph(priv, IWL50_SCD_DRAM_BASE_ADDR, - (priv->shared_phys + - offsetof(struct iwl5000_shared, queues_byte_cnt_tbls)) >> 10); + priv->scd_bc_tbls.dma >> 10); + + /* Enable DMA channel */ + for (chan = 0; chan < FH50_TCSR_CHNL_NUM ; chan++) + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(chan), + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | + FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE); + + /* Update FH chicken bits */ + reg_val = iwl_read_direct32(priv, FH_TX_CHICKEN_BITS_REG); + iwl_write_direct32(priv, FH_TX_CHICKEN_BITS_REG, + reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN); + iwl_write_prph(priv, IWL50_SCD_QUEUECHAIN_SEL, - IWL50_SCD_QUEUECHAIN_SEL_ALL( - priv->hw_params.max_txq_num)); + IWL50_SCD_QUEUECHAIN_SEL_ALL(priv->hw_params.max_txq_num)); iwl_write_prph(priv, IWL50_SCD_AGGR_SEL, 0); /* initiate the queues */ @@ -765,6 +794,7 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) priv->cfg->ops->lib->txq_set_sched(priv, IWL_MASK(0, 7)); iwl5000_set_wr_ptrs(priv, IWL_CMD_QUEUE_NUM, 0); + /* map qos queues to fifos one-to-one */ for (i = 0; i < ARRAY_SIZE(iwl5000_default_queue_to_tx_fifo); i++) { int ac = iwl5000_default_queue_to_tx_fifo[i]; @@ -784,10 +814,8 @@ static int iwl5000_alive_notify(struct iwl_priv *priv) iwl5000_send_wimax_coex(priv); - iwl5000_send_Xtal_calib(priv); - - if (priv->ucode_type == UCODE_RT) - iwl_send_calib_results(priv); + iwl5000_set_Xtal_calib(priv); + iwl_send_calib_results(priv); return 0; } @@ -802,7 +830,9 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) } priv->hw_params.max_txq_num = priv->cfg->mod_params->num_of_queues; - priv->hw_params.first_ampdu_q = IWL50_FIRST_AMPDU_QUEUE; + priv->hw_params.dma_chnl_num = FH50_TCSR_CHNL_NUM; + priv->hw_params.scd_bc_tbls_size = + IWL50_NUM_QUEUES * sizeof(struct iwl5000_scd_bc_tbl); priv->hw_params.max_stations = IWL5000_STATION_COUNT; priv->hw_params.bcast_sta_id = IWL5000_BROADCAST_ID; priv->hw_params.max_data_size = IWL50_RTC_DATA_SIZE; @@ -814,10 +844,14 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { case CSR_HW_REV_TYPE_5100: + priv->hw_params.tx_chains_num = 1; + priv->hw_params.rx_chains_num = 2; + priv->hw_params.valid_tx_ant = ANT_B; + priv->hw_params.valid_rx_ant = ANT_AB; + break; case CSR_HW_REV_TYPE_5150: priv->hw_params.tx_chains_num = 1; priv->hw_params.rx_chains_num = 2; - /* FIXME: move to ANT_A, ANT_B, ANT_C enum */ priv->hw_params.valid_tx_ant = ANT_A; priv->hw_params.valid_rx_ant = ANT_AB; break; @@ -840,43 +874,36 @@ static int iwl5000_hw_set_hw_params(struct iwl_priv *priv) case CSR_HW_REV_TYPE_5150: /* 5150 wants in Kelvin */ priv->hw_params.ct_kill_threshold = - CELSIUS_TO_KELVIN(CT_KILL_THRESHOLD); + iwl5150_get_ct_threshold(priv); break; } - return 0; -} - -static int iwl5000_alloc_shared_mem(struct iwl_priv *priv) -{ - priv->shared_virt = pci_alloc_consistent(priv->pci_dev, - sizeof(struct iwl5000_shared), - &priv->shared_phys); - if (!priv->shared_virt) - return -ENOMEM; + /* Set initial calibration set */ + switch (priv->hw_rev & CSR_HW_REV_TYPE_MSK) { + case CSR_HW_REV_TYPE_5100: + case CSR_HW_REV_TYPE_5300: + case CSR_HW_REV_TYPE_5350: + priv->hw_params.calib_init_cfg = + BIT(IWL_CALIB_XTAL) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_TX_IQ_PERD) | + BIT(IWL_CALIB_BASE_BAND); + break; + case CSR_HW_REV_TYPE_5150: + priv->hw_params.calib_init_cfg = + BIT(IWL_CALIB_DC) | + BIT(IWL_CALIB_LO) | + BIT(IWL_CALIB_TX_IQ) | + BIT(IWL_CALIB_BASE_BAND); - memset(priv->shared_virt, 0, sizeof(struct iwl5000_shared)); + break; + } - priv->rb_closed_offset = offsetof(struct iwl5000_shared, rb_closed); return 0; } -static void iwl5000_free_shared_mem(struct iwl_priv *priv) -{ - if (priv->shared_virt) - pci_free_consistent(priv->pci_dev, - sizeof(struct iwl5000_shared), - priv->shared_virt, - priv->shared_phys); -} - -static int iwl5000_shared_mem_rx_idx(struct iwl_priv *priv) -{ - struct iwl5000_shared *s = priv->shared_virt; - return le32_to_cpu(s->rb_closed) & 0xFFF; -} - /** * iwl5000_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array */ @@ -884,16 +911,18 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq, u16 byte_cnt) { - struct iwl5000_shared *shared_data = priv->shared_virt; + struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; + int write_ptr = txq->q.write_ptr; int txq_id = txq->q.id; u8 sec_ctl = 0; - u8 sta = 0; - int len; + u8 sta_id = 0; + u16 len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + __le16 bc_ent; - len = byte_cnt + IWL_TX_CRC_SIZE + IWL_TX_DELIMITER_SIZE; + WARN_ON(len > 0xFFF || write_ptr >= TFD_QUEUE_SIZE_MAX); if (txq_id != IWL_CMD_QUEUE_NUM) { - sta = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; + sta_id = txq->cmd[txq->q.write_ptr]->cmd.tx.sta_id; sec_ctl = txq->cmd[txq->q.write_ptr]->cmd.tx.sec_ctl; switch (sec_ctl & TX_CMD_SEC_MSK) { @@ -909,40 +938,35 @@ static void iwl5000_txq_update_byte_cnt_tbl(struct iwl_priv *priv, } } - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[txq->q.write_ptr], byte_cnt, len); + bc_ent = cpu_to_le16((len & 0xFFF) | (sta_id << 12)); - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[txq->q.write_ptr], sta_id, sta); + scd_bc_tbl[txq_id].tfd_offset[write_ptr] = bc_ent; - if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], - byte_cnt, len); - IWL_SET_BITS16(shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL50_QUEUE_SIZE + txq->q.write_ptr], - sta_id, sta); - } + if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) + scd_bc_tbl[txq_id]. + tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent; } static void iwl5000_txq_inval_byte_cnt_tbl(struct iwl_priv *priv, struct iwl_tx_queue *txq) { + struct iwl5000_scd_bc_tbl *scd_bc_tbl = priv->scd_bc_tbls.addr; int txq_id = txq->q.id; - struct iwl5000_shared *shared_data = priv->shared_virt; - u8 sta = 0; + int read_ptr = txq->q.read_ptr; + u8 sta_id = 0; + __le16 bc_ent; + + WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX); if (txq_id != IWL_CMD_QUEUE_NUM) - sta = txq->cmd[txq->q.read_ptr]->cmd.tx.sta_id; + sta_id = txq->cmd[read_ptr]->cmd.tx.sta_id; - shared_data->queues_byte_cnt_tbls[txq_id].tfd_offset[txq->q.read_ptr]. - val = cpu_to_le16(1 | (sta << 12)); + bc_ent = cpu_to_le16(1 | (sta_id << 12)); + scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent; - if (txq->q.write_ptr < IWL50_MAX_WIN_SIZE) { - shared_data->queues_byte_cnt_tbls[txq_id]. - tfd_offset[IWL50_QUEUE_SIZE + txq->q.read_ptr]. - val = cpu_to_le16(1 | (sta << 12)); - } + if (txq->q.write_ptr < TFD_QUEUE_SIZE_BC_DUP) + scd_bc_tbl[txq_id]. + tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent; } static int iwl5000_tx_queue_set_q2ratid(struct iwl_priv *priv, u16 ra_tid, @@ -996,7 +1020,7 @@ static int iwl5000_txq_agg_enable(struct iwl_priv *priv, int txq_id, ra_tid = BUILD_RAxTID(sta_id, tid); /* Modify device's station table to Tx this TID */ - iwl_sta_modify_enable_tid_tx(priv, sta_id, tid); + iwl_sta_tx_modify_enable_tid(priv, sta_id, tid); spin_lock_irqsave(&priv->lock, flags); ret = iwl_grab_nic_access(priv); @@ -1089,7 +1113,7 @@ static u16 iwl5000_build_addsta_hcmd(const struct iwl_addsta_cmd *cmd, u8 *data) /* - * Activate/Deactivat Tx DMA/FIFO channels according tx fifos mask + * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask * must be called under priv->lock and mac access */ static void iwl5000_txq_set_sched(struct iwl_priv *priv, u32 mask) @@ -1136,10 +1160,10 @@ static int iwl5000_tx_status_reply_tx(struct iwl_priv *priv, agg->frame_count, agg->start_idx, idx); info = IEEE80211_SKB_CB(priv->txq[txq_id].txb[idx].skb[0]); - info->status.retry_count = tx_resp->failure_frame; + info->status.rates[0].count = tx_resp->failure_frame + 1; info->flags &= ~IEEE80211_TX_CTL_AMPDU; - info->flags |= iwl_is_tx_success(status)? - IEEE80211_TX_STAT_ACK : 0; + info->flags |= iwl_is_tx_success(status) ? + IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, rate_n_flags, info); /* FIXME: code repetition end */ @@ -1225,9 +1249,9 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, struct ieee80211_tx_info *info; struct iwl5000_tx_resp *tx_resp = (void *)&pkt->u.raw[0]; u32 status = le16_to_cpu(tx_resp->status.status); - int tid = MAX_TID_COUNT, sta_id = IWL_INVALID_STATION; - struct ieee80211_hdr *hdr; - u8 *qc = NULL; + int tid; + int sta_id; + int freed; if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) { IWL_ERROR("Read index for DMA queue txq_id (%d) index %d " @@ -1240,25 +1264,13 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, info = IEEE80211_SKB_CB(txq->txb[txq->q.read_ptr].skb[0]); memset(&info->status, 0, sizeof(info->status)); - hdr = iwl_tx_queue_get_hdr(priv, txq_id, index); - if (ieee80211_is_data_qos(hdr->frame_control)) { - qc = ieee80211_get_qos_ctl(hdr); - tid = qc[0] & 0xf; - } - - sta_id = iwl_get_ra_sta_id(priv, hdr); - if (txq->sched_retry && unlikely(sta_id == IWL_INVALID_STATION)) { - IWL_ERROR("Station not known\n"); - return; - } + tid = (tx_resp->ra_tid & IWL50_TX_RES_TID_MSK) >> IWL50_TX_RES_TID_POS; + sta_id = (tx_resp->ra_tid & IWL50_TX_RES_RA_MSK) >> IWL50_TX_RES_RA_POS; if (txq->sched_retry) { const u32 scd_ssn = iwl5000_get_scd_ssn(tx_resp); struct iwl_ht_agg *agg = NULL; - if (!qc) - return; - agg = &priv->stations[sta_id].tid[tid].agg; iwl5000_tx_status_reply_tx(priv, agg, tx_resp, txq_id, index); @@ -1268,58 +1280,58 @@ static void iwl5000_rx_reply_tx(struct iwl_priv *priv, info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK; if (txq->q.read_ptr != (scd_ssn & 0xff)) { - int freed, ampdu_q; 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); + IWL_DEBUG_TX_REPLY("Retry scheduler reclaim " + "scd_ssn=%d idx=%d txq=%d swq=%d\n", + scd_ssn , index, txq_id, txq->swq_id); + freed = iwl_tx_queue_reclaim(priv, txq_id, index); priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - txq_id >= 0 && priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) { - /* calculate mac80211 ampdu sw queue to wake */ - ampdu_q = txq_id - IWL50_FIRST_AMPDU_QUEUE + - priv->hw->queues; + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark) && + (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) { if (agg->state == IWL_AGG_OFF) ieee80211_wake_queue(priv->hw, txq_id); else - ieee80211_wake_queue(priv->hw, ampdu_q); + ieee80211_wake_queue(priv->hw, + txq->swq_id); } - iwl_txq_check_empty(priv, sta_id, tid, txq_id); } } else { - info->status.retry_count = tx_resp->failure_frame; - info->flags = - iwl_is_tx_success(status) ? IEEE80211_TX_STAT_ACK : 0; + BUG_ON(txq_id != txq->swq_id); + + info->status.rates[0].count = tx_resp->failure_frame + 1; + info->flags |= iwl_is_tx_success(status) ? + IEEE80211_TX_STAT_ACK : 0; iwl_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags), info); - IWL_DEBUG_TX("Tx queue %d Status %s (0x%08x) rate_n_flags " - "0x%x retries %d\n", txq_id, - iwl_get_tx_fail_reason(status), - status, le32_to_cpu(tx_resp->rate_n_flags), - tx_resp->failure_frame); + IWL_DEBUG_TX_REPLY("TXQ %d status %s (0x%08x) rate_n_flags " + "0x%x retries %d\n", + txq_id, + iwl_get_tx_fail_reason(status), status, + le32_to_cpu(tx_resp->rate_n_flags), + tx_resp->failure_frame); - IWL_DEBUG_TX_REPLY("Tx queue reclaim %d\n", index); - if (index != -1) { - int freed = iwl_tx_queue_reclaim(priv, txq_id, index); - if (tid != MAX_TID_COUNT) + freed = iwl_tx_queue_reclaim(priv, txq_id, index); + if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - (txq_id >= 0) && priv->mac80211_registered) + + if (priv->mac80211_registered && + (iwl_queue_space(&txq->q) > txq->q.low_mark)) ieee80211_wake_queue(priv->hw, txq_id); - if (tid != MAX_TID_COUNT) - iwl_txq_check_empty(priv, sta_id, tid, txq_id); - } } + if (ieee80211_is_data_qos(tx_resp->frame_ctrl)) + iwl_txq_check_empty(priv, sta_id, tid, txq_id); + if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK)) IWL_ERROR("TODO: Implement Tx ABORT REQUIRED!!!\n"); } -/* Currently 5000 is the supperset of everything */ +/* Currently 5000 is the superset of everything */ static u16 iwl5000_get_hcmd_size(u8 cmd_id, u16 len) { return len; @@ -1466,9 +1478,6 @@ static struct iwl_hcmd_utils_ops iwl5000_hcmd_utils = { static struct iwl_lib_ops iwl5000_lib = { .set_hw_params = iwl5000_hw_set_hw_params, - .alloc_shared_mem = iwl5000_alloc_shared_mem, - .free_shared_mem = iwl5000_free_shared_mem, - .shared_mem_rx_idx = iwl5000_shared_mem_rx_idx, .txq_update_byte_cnt_tbl = iwl5000_txq_update_byte_cnt_tbl, .txq_inval_byte_cnt_tbl = iwl5000_txq_inval_byte_cnt_tbl, .txq_set_sched = iwl5000_txq_set_sched, @@ -1482,13 +1491,13 @@ static struct iwl_lib_ops iwl5000_lib = { .alive_notify = iwl5000_alive_notify, .send_tx_power = iwl5000_send_tx_power, .temperature = iwl5000_temperature, - .update_chain_flags = iwl4965_update_chain_flags, + .update_chain_flags = iwl_update_chain_flags, .apm_ops = { .init = iwl5000_apm_init, .reset = iwl5000_apm_reset, .stop = iwl5000_apm_stop, .config = iwl5000_nic_config, - .set_pwr_src = iwl4965_set_pwr_src, + .set_pwr_src = iwl_set_pwr_src, }, .eeprom_ops = { .regulatory_bands = { @@ -1503,7 +1512,7 @@ static struct iwl_lib_ops iwl5000_lib = { .verify_signature = iwlcore_eeprom_verify_signature, .acquire_semaphore = iwlcore_eeprom_acquire_semaphore, .release_semaphore = iwlcore_eeprom_release_semaphore, - .check_version = iwl5000_eeprom_check_version, + .calib_version = iwl5000_eeprom_calib_version, .query_addr = iwl5000_eeprom_query_addr, }, }; @@ -1517,7 +1526,6 @@ static struct iwl_ops iwl5000_ops = { static struct iwl_mod_params iwl50_mod_params = { .num_of_queues = IWL50_NUM_QUEUES, .num_of_ampdu_queues = IWL50_NUM_AMPDU_QUEUES, - .enable_qos = 1, .amsdu_size_8K = 1, .restart_fw = 1, /* the rest are 0 by default */ @@ -1526,50 +1534,84 @@ static struct iwl_mod_params iwl50_mod_params = { struct iwl_cfg iwl5300_agn_cfg = { .name = "5300AGN", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5100_bg_cfg = { .name = "5100BG", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_G, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5100_abg_cfg = { .name = "5100ABG", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5100_agn_cfg = { .name = "5100AGN", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5000_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; struct iwl_cfg iwl5350_agn_cfg = { .name = "5350AGN", - .fw_name = "iwlwifi-5000" IWL5000_UCODE_API ".ucode", + .fw_name_pre = IWL5000_FW_PRE, + .ucode_api_max = IWL5000_UCODE_API_MAX, + .ucode_api_min = IWL5000_UCODE_API_MIN, + .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, + .ops = &iwl5000_ops, + .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, + .mod_params = &iwl50_mod_params, +}; + +struct iwl_cfg iwl5150_agn_cfg = { + .name = "5150AGN", + .fw_name_pre = IWL5150_FW_PRE, + .ucode_api_max = IWL5150_UCODE_API_MAX, + .ucode_api_min = IWL5150_UCODE_API_MIN, .sku = IWL_SKU_A|IWL_SKU_G|IWL_SKU_N, .ops = &iwl5000_ops, .eeprom_size = IWL_5000_EEPROM_IMG_SIZE, + .eeprom_ver = EEPROM_5050_EEPROM_VERSION, + .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION, .mod_params = &iwl50_mod_params, }; -MODULE_FIRMWARE("iwlwifi-5000" IWL5000_UCODE_API ".ucode"); +MODULE_FIRMWARE(IWL5000_MODULE_FIRMWARE(IWL5000_UCODE_API_MAX)); +MODULE_FIRMWARE(IWL5150_MODULE_FIRMWARE(IWL5150_UCODE_API_MAX)); module_param_named(disable50, iwl50_mod_params.disable, int, 0444); MODULE_PARM_DESC(disable50, @@ -1577,12 +1619,10 @@ MODULE_PARM_DESC(disable50, module_param_named(swcrypto50, iwl50_mod_params.sw_crypto, bool, 0444); MODULE_PARM_DESC(swcrypto50, "using software crypto engine (default 0 [hardware])\n"); -module_param_named(debug50, iwl50_mod_params.debug, int, 0444); +module_param_named(debug50, iwl50_mod_params.debug, uint, 0444); MODULE_PARM_DESC(debug50, "50XX debug output mask"); module_param_named(queues_num50, iwl50_mod_params.num_of_queues, int, 0444); MODULE_PARM_DESC(queues_num50, "number of hw queues in 50xx series"); -module_param_named(qos_enable50, iwl50_mod_params.enable_qos, int, 0444); -MODULE_PARM_DESC(qos_enable50, "enable all 50XX QoS functionality"); module_param_named(11n_disable50, iwl50_mod_params.disable_11n, int, 0444); MODULE_PARM_DESC(11n_disable50, "disable 50XX 11n functionality"); module_param_named(amsdu_size_8K50, iwl50_mod_params.amsdu_size_8K, int, 0444); diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c new file mode 100644 index 0000000000000000000000000000000000000000..b8137eeae1db87eae6a6dd19fda2e65c8e19712f --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-agn-hcmd-check.c @@ -0,0 +1,108 @@ +/****************************************************************************** + * + * 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: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + *****************************************************************************/ + +#include +#include +#include "iwl-dev.h" +#include "iwl-debug.h" +#include "iwl-commands.h" + + +/** + * iwl_check_rxon_cmd - validate RXON structure is valid + * + * NOTE: This is really only useful during development and can eventually + * be #ifdef'd out once the driver is stable and folks aren't actively + * making changes + */ +int iwl_agn_check_rxon_cmd(struct iwl_rxon_cmd *rxon) +{ + int error = 0; + int counter = 1; + + if (rxon->flags & RXON_FLG_BAND_24G_MSK) { + error |= le32_to_cpu(rxon->flags & + (RXON_FLG_TGJ_NARROW_BAND_MSK | + RXON_FLG_RADAR_DETECT_MSK)); + if (error) + IWL_WARNING("check 24G fields %d | %d\n", + counter++, error); + } else { + error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? + 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); + if (error) + IWL_WARNING("check 52 fields %d | %d\n", + counter++, error); + error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); + if (error) + IWL_WARNING("check 52 CCK %d | %d\n", + counter++, error); + } + error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; + if (error) + IWL_WARNING("check mac addr %d | %d\n", counter++, error); + + /* make sure basic rates 6Mbps and 1Mbps are supported */ + error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && + ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); + if (error) + IWL_WARNING("check basic rate %d | %d\n", counter++, error); + + error |= (le16_to_cpu(rxon->assoc_id) > 2007); + if (error) + IWL_WARNING("check assoc id %d | %d\n", counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); + if (error) + IWL_WARNING("check CCK and short slot %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) + == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); + if (error) + IWL_WARNING("check CCK & auto detect %d | %d\n", + counter++, error); + + error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | + RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); + if (error) + IWL_WARNING("check TGG and auto detect %d | %d\n", + counter++, error); + + if (error) + IWL_WARNING("Tuning to channel %d\n", + le16_to_cpu(rxon->channel)); + + if (error) { + IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n"); + return -1; + } + return 0; +} + diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c index e2a58e477036e611da5ffc78abeda5748f7392ce..f3f17929ca0bb1546721f0a1a22e8b7fe2a6dc8d 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -38,7 +38,6 @@ #include "iwl-dev.h" #include "iwl-sta.h" #include "iwl-core.h" -#include "iwl-helpers.h" #define RS_NAME "iwl-agn-rs" @@ -188,7 +187,7 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta, * 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54, 60 MBits * "G" is the only table that supports CCK (the first 4 rates). */ -/*FIXME:RS:need to spearate tables for MIMO2/MIMO3*/ +/*FIXME:RS:need to separate tables for MIMO2/MIMO3*/ static s32 expected_tpt_A[IWL_RATE_COUNT] = { 0, 0, 0, 0, 40, 57, 72, 98, 121, 154, 177, 186, 186 }; @@ -281,10 +280,9 @@ static u8 rs_tl_add_packet(struct iwl_lq_sta *lq_data, u32 time_diff; s32 index; struct iwl_traffic_load *tl = NULL; - __le16 fc = hdr->frame_control; u8 tid; - if (ieee80211_is_data_qos(fc)) { + if (ieee80211_is_data_qos(hdr->frame_control)) { u8 *qc = ieee80211_get_qos_ctl(hdr); tid = qc[0] & 0xf; } else @@ -357,11 +355,9 @@ static void rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv, struct iwl_lq_sta *lq_data, u8 tid, struct ieee80211_sta *sta) { - DECLARE_MAC_BUF(mac); - if (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); + IWL_DEBUG_HT("Starting Tx agg: STA: %pM tid: %d\n", + sta->addr, tid); ieee80211_start_tx_ba_session(priv->hw, sta->addr, tid); } } @@ -775,7 +771,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, int status; u8 retries; int rs_index, index = 0; - struct iwl_lq_sta *lq_sta; + struct iwl_lq_sta *lq_sta = priv_sta; struct iwl_link_quality_cmd *table; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct iwl_priv *priv = (struct iwl_priv *)priv_r; @@ -787,12 +783,12 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, struct iwl_scale_tbl_info tbl_type; struct iwl_scale_tbl_info *curr_tbl, *search_tbl; u8 active_index = 0; - __le16 fc = hdr->frame_control; s32 tpt = 0; IWL_DEBUG_RATE_LIMIT("get frame ack response, update rate scale window\n"); - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) + if (!ieee80211_is_data(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1)) return; /* This packet was aggregated but doesn't carry rate scale info */ @@ -800,13 +796,11 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, !(info->flags & IEEE80211_TX_STAT_AMPDU)) return; - retries = info->status.retry_count; + retries = info->status.rates[0].count - 1; if (retries > 15) retries = 15; - lq_sta = (struct iwl_lq_sta *)priv_sta; - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) goto out; @@ -832,21 +826,20 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband, if (priv->band == IEEE80211_BAND_5GHZ) rs_index -= IWL_FIRST_OFDM_RATE; - if ((info->tx_rate_idx < 0) || - (tbl_type.is_SGI ^ - !!(info->flags & IEEE80211_TX_CTL_SHORT_GI)) || - (tbl_type.is_fat ^ - !!(info->flags & IEEE80211_TX_CTL_40_MHZ_WIDTH)) || - (tbl_type.is_dup ^ - !!(info->flags & IEEE80211_TX_CTL_DUP_DATA)) || - (tbl_type.ant_type ^ info->antenna_sel_tx) || - (!!(tx_rate & RATE_MCS_HT_MSK) ^ - !!(info->flags & IEEE80211_TX_CTL_OFDM_HT)) || - (!!(tx_rate & RATE_MCS_GF_MSK) ^ - !!(info->flags & IEEE80211_TX_CTL_GREEN_FIELD)) || + if ((info->status.rates[0].idx < 0) || + (tbl_type.is_SGI != !!(info->status.rates[0].flags & IEEE80211_TX_RC_SHORT_GI)) || + (tbl_type.is_fat != !!(info->status.rates[0].flags & IEEE80211_TX_RC_40_MHZ_WIDTH)) || + (tbl_type.is_dup != !!(info->status.rates[0].flags & IEEE80211_TX_RC_DUP_DATA)) || + (tbl_type.ant_type != info->antenna_sel_tx) || + (!!(tx_rate & RATE_MCS_HT_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) || + (!!(tx_rate & RATE_MCS_GF_MSK) != !!(info->status.rates[0].flags & IEEE80211_TX_RC_GREEN_FIELD)) || (hw->wiphy->bands[priv->band]->bitrates[rs_index].bitrate != - hw->wiphy->bands[info->band]->bitrates[info->tx_rate_idx].bitrate)) { + hw->wiphy->bands[info->band]->bitrates[info->status.rates[0].idx].bitrate)) { IWL_DEBUG_RATE("initial rate does not match 0x%x\n", tx_rate); + /* the last LQ command could failed so the LQ in ucode not + * the same in driver sync up + */ + iwl_send_lq_cmd(priv, &lq_sta->lq, CMD_ASYNC); goto out; } @@ -1135,11 +1128,10 @@ static int rs_switch_to_mimo2(struct iwl_priv *priv, s32 rate; s8 is_green = lq_sta->is_green; - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_info.ht_supported) + if (!conf->ht.enabled || !sta->ht_cap.ht_supported) return -1; - if (((sta->ht_info.cap & IEEE80211_HT_CAP_SM_PS) >> 2) + if (((sta->ht_cap.cap & IEEE80211_HT_CAP_SM_PS) >> 2) == WLAN_HT_CAP_SM_PS_STATIC) return -1; @@ -1203,8 +1195,7 @@ static int rs_switch_to_siso(struct iwl_priv *priv, u8 is_green = lq_sta->is_green; s32 rate; - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) || - !sta->ht_info.ht_supported) + if (!conf->ht.enabled || !sta->ht_cap.ht_supported) return -1; IWL_DEBUG_RATE("LQ: try to switch to SISO\n"); @@ -1684,7 +1675,6 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, int high_tpt = IWL_INVALID_VALUE; u32 fail_count; s8 scale_action = 0; - __le16 fc; u16 rate_mask; u8 update_lq = 0; struct iwl_scale_tbl_info *tbl, *tbl1; @@ -1699,13 +1689,12 @@ static void rs_rate_scale_perform(struct iwl_priv *priv, IWL_DEBUG_RATE("rate scale calculate new rate for skb\n"); - fc = hdr->frame_control; - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1)) { - /* Send management frames and broadcast/multicast data using - * lowest rate. */ - /* TODO: this could probably be improved.. */ + /* Send management frames and broadcast/multicast data using + * lowest rate. */ + /* TODO: this could probably be improved.. */ + if (!ieee80211_is_data(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1)) return; - } if (!sta || !lq_sta) return; @@ -2003,9 +1992,8 @@ lq_update: * stay with best antenna legacy modulation for a while * before next round of mode comparisons. */ tbl1 = &(lq_sta->lq_info[lq_sta->active_tbl]); - if (is_legacy(tbl1->lq_type) && - (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) && - (lq_sta->action_counter >= 1)) { + if (is_legacy(tbl1->lq_type) && !conf->ht.enabled && + lq_sta->action_counter >= 1) { lq_sta->action_counter = 0; IWL_DEBUG_RATE("LQ: STAY in legacy table\n"); rs_set_stay_in_table(priv, 1, lq_sta); @@ -2081,15 +2069,13 @@ static void rs_initialize_lq(struct iwl_priv *priv, if ((i < 0) || (i >= IWL_RATE_COUNT)) i = 0; - /* FIXME:RS: This is also wrong in 4965 */ rate = iwl_rates[i].plcp; - rate |= RATE_MCS_ANT_B_MSK; - rate &= ~RATE_MCS_ANT_A_MSK; + tbl->ant_type = first_antenna(valid_tx_ant); + rate |= tbl->ant_type << RATE_MCS_ANT_POS; if (i >= IWL_FIRST_CCK_RATE && i <= IWL_LAST_CCK_RATE) rate |= RATE_MCS_CCK_MSK; - tbl->ant_type = ANT_B; rs_get_tbl_info_from_mcs(rate, priv->band, tbl, &rate_idx); if (!rs_is_valid_ant(valid_tx_ant, tbl->ant_type)) rs_toggle_antenna(valid_tx_ant, &rate, tbl); @@ -2103,40 +2089,38 @@ static void rs_initialize_lq(struct iwl_priv *priv, return; } -static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { - int i; + struct sk_buff *skb = txrc->skb; + struct ieee80211_supported_band *sband = txrc->sband; struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; - __le16 fc; - struct iwl_lq_sta *lq_sta; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + struct iwl_lq_sta *lq_sta = priv_sta; + int rate_idx; IWL_DEBUG_RATE_LIMIT("rate scale calculate new rate for skb\n"); /* Send management frames and broadcast/multicast data using lowest * rate. */ - fc = hdr->frame_control; - if (!ieee80211_is_data(fc) || is_multicast_ether_addr(hdr->addr1) || - !sta || !priv_sta) { - sel->rate_idx = rate_lowest_index(sband, sta); + if (!ieee80211_is_data(hdr->frame_control) || + is_multicast_ether_addr(hdr->addr1) || !sta || !lq_sta) { + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } - lq_sta = (struct iwl_lq_sta *)priv_sta; - i = lq_sta->last_txrate_idx; + rate_idx = lq_sta->last_txrate_idx; if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && !lq_sta->ibss_sta_added) { u8 sta_id = iwl_find_station(priv, hdr->addr1); - DECLARE_MAC_BUF(mac); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_RATE("LQ: ADD station %pM\n", + hdr->addr1); sta_id = iwl_add_station_flags(priv, hdr->addr1, 0, CMD_ASYNC, NULL); } @@ -2148,14 +2132,12 @@ static void rs_get_rate(void *priv_r, struct ieee80211_supported_band *sband, } } - if ((i < 0) || (i > IWL_RATE_COUNT)) { - sel->rate_idx = rate_lowest_index(sband, sta); - return; - } + if (rate_idx < 0 || rate_idx > IWL_RATE_COUNT) + rate_idx = rate_lowest_index(sband, sta); + else if (sband->band == IEEE80211_BAND_5GHZ) + rate_idx -= IWL_FIRST_OFDM_RATE; - if (sband->band == IEEE80211_BAND_5GHZ) - i -= IWL_FIRST_OFDM_RATE; - sel->rate_idx = i; + info->control.rates[0].idx = rate_idx; } static void *rs_alloc_sta(void *priv_rate, struct ieee80211_sta *sta, @@ -2189,6 +2171,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, struct iwl_priv *priv = (struct iwl_priv *)priv_r; struct ieee80211_conf *conf = &priv->hw->conf; struct iwl_lq_sta *lq_sta = priv_sta; + u16 mask_bit = 0; lq_sta->flush_timer = 0; lq_sta->supp_rates = sta->supp_rates[sband->band]; @@ -2205,15 +2188,12 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->ibss_sta_added = 0; if (priv->iw_mode == NL80211_IFTYPE_AP) { u8 sta_id = iwl_find_station(priv, sta->addr); - DECLARE_MAC_BUF(mac); /* for IBSS the call are from tasklet */ - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, sta->addr)); + IWL_DEBUG_RATE("LQ: ADD station %pM\n", sta->addr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_RATE("LQ: ADD station %s\n", - print_mac(mac, sta->addr)); + IWL_DEBUG_RATE("LQ: ADD station %pM\n", sta->addr); sta_id = iwl_add_station_flags(priv, sta->addr, 0, CMD_ASYNC, NULL); } @@ -2225,16 +2205,6 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, priv->assoc_station_added = 1; } - /* Find highest tx rate supported by hardware and destination station */ - lq_sta->last_txrate_idx = 3; - for (i = 0; i < sband->n_bitrates; i++) - if (sta->supp_rates[sband->band] & BIT(i)) - lq_sta->last_txrate_idx = i; - - /* For MODE_IEEE80211A, skip over cck rates in global rate table */ - if (sband->band == IEEE80211_BAND_5GHZ) - lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; - lq_sta->is_dup = 0; lq_sta->is_green = rs_use_green(priv, conf); lq_sta->active_legacy_rate = priv->active_rate & ~(0x1000); @@ -2244,19 +2214,19 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, * active_siso_rate mask includes 9 MBits (bit 5), and CCK (bits 0-3), * supp_rates[] does not; shift to convert format, force 9 MBits off. */ - lq_sta->active_siso_rate = conf->ht_conf.supp_mcs_set[0] << 1; - lq_sta->active_siso_rate |= conf->ht_conf.supp_mcs_set[0] & 0x1; + lq_sta->active_siso_rate = sta->ht_cap.mcs.rx_mask[0] << 1; + lq_sta->active_siso_rate |= sta->ht_cap.mcs.rx_mask[0] & 0x1; lq_sta->active_siso_rate &= ~((u16)0x2); lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE; /* Same here */ - lq_sta->active_mimo2_rate = conf->ht_conf.supp_mcs_set[1] << 1; - lq_sta->active_mimo2_rate |= conf->ht_conf.supp_mcs_set[1] & 0x1; + lq_sta->active_mimo2_rate = sta->ht_cap.mcs.rx_mask[1] << 1; + lq_sta->active_mimo2_rate |= sta->ht_cap.mcs.rx_mask[1] & 0x1; lq_sta->active_mimo2_rate &= ~((u16)0x2); lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE; - lq_sta->active_mimo3_rate = conf->ht_conf.supp_mcs_set[2] << 1; - lq_sta->active_mimo3_rate |= conf->ht_conf.supp_mcs_set[2] & 0x1; + lq_sta->active_mimo3_rate = sta->ht_cap.mcs.rx_mask[2] << 1; + lq_sta->active_mimo3_rate |= sta->ht_cap.mcs.rx_mask[2] & 0x1; lq_sta->active_mimo3_rate &= ~((u16)0x2); lq_sta->active_mimo3_rate <<= IWL_FIRST_OFDM_RATE; @@ -2265,7 +2235,7 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->active_mimo2_rate, lq_sta->active_mimo3_rate); - /* These values will be overriden later */ + /* These values will be overridden later */ lq_sta->lq.general_params.single_stream_ant_msk = ANT_A; lq_sta->lq.general_params.dual_stream_ant_msk = ANT_AB; @@ -2273,6 +2243,17 @@ static void rs_rate_init(void *priv_r, struct ieee80211_supported_band *sband, lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID; lq_sta->drv = priv; + /* Find highest tx rate supported by hardware and destination station */ + mask_bit = sta->supp_rates[sband->band] & lq_sta->active_legacy_rate; + lq_sta->last_txrate_idx = 3; + for (i = 0; i < sband->n_bitrates; i++) + if (mask_bit & BIT(i)) + lq_sta->last_txrate_idx = i; + + /* For MODE_IEEE80211A, skip over cck rates in global rate table */ + if (sband->band == IEEE80211_BAND_5GHZ) + lq_sta->last_txrate_idx += IWL_FIRST_OFDM_RATE; + rs_initialize_lq(priv, conf, sta, lq_sta); } @@ -2405,19 +2386,6 @@ static void rs_free(void *priv_rate) return; } -static void rs_clear(void *priv_rate) -{ -#ifdef CONFIG_IWLWIFI_DEBUG - struct iwl_priv *priv = (struct iwl_priv *) priv_rate; - - IWL_DEBUG_RATE("enter\n"); - - /* TODO - add rate scale state reset */ - - IWL_DEBUG_RATE("leave\n"); -#endif /* CONFIG_IWLWIFI_DEBUG */ -} - static void rs_free_sta(void *priv_r, struct ieee80211_sta *sta, void *priv_sta) { @@ -2552,7 +2520,7 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file, for (i = 0; i < LQ_SIZE; i++) { desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n" "rate=0x%X\n", - lq_sta->active_tbl == i?"*":"x", + lq_sta->active_tbl == i ? "*" : "x", lq_sta->lq_info[i].lq_type, lq_sta->lq_info[i].is_SGI, lq_sta->lq_info[i].is_fat, @@ -2605,7 +2573,6 @@ static struct rate_control_ops rs_ops = { .tx_status = rs_tx_status, .get_rate = rs_get_rate, .rate_init = rs_rate_init, - .clear = rs_clear, .alloc = rs_alloc, .free = rs_free, .alloc_sta = rs_alloc_sta, diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h index d148d73635eb5ddec4669fc1fe0bf185959a5d04..78ee83adf742d632c440710d4bdd7ec056ffb6f6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn-rs.h +++ b/drivers/net/wireless/iwlwifi/iwl-agn-rs.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -229,7 +229,7 @@ enum { #define IWL_MIMO2_SWITCH_SISO_C 4 #define IWL_MIMO2_SWITCH_GI 5 -/*FIXME:RS:add posible acctions for MIMO3*/ +/*FIXME:RS:add possible actions for MIMO3*/ #define IWL_ACTION_LIMIT 3 /* # possible actions */ @@ -284,7 +284,17 @@ static inline u8 num_of_ant(u8 mask) !!((mask) & ANT_C); } -static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) +static inline u8 first_antenna(u8 mask) +{ + if (mask & ANT_A) + return ANT_A; + if (mask & ANT_B) + return ANT_B; + return ANT_C; +} + + +static inline u8 iwl_get_prev_ieee_rate(u8 rate_index) { u8 rate = iwl_rates[rate_index].prev_ieee; @@ -294,11 +304,11 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) } /** - * iwl4965_rate_control_register - Register the rate control algorithm callbacks + * iwl_rate_control_register - Register the rate control algorithm callbacks * * Since the rate control algorithm is hardware specific, there is no need * or reason to place it as a stand alone module. The driver can call - * iwl4965_rate_control_register in order to register the rate control callbacks + * iwl_rate_control_register in order to register the rate control callbacks * with the mac80211 subsystem. This should be performed prior to calling * ieee80211_register_hw * @@ -306,7 +316,7 @@ static inline u8 iwl4965_get_prev_ieee_rate(u8 rate_index) extern int iwlagn_rate_control_register(void); /** - * iwl4965_rate_control_unregister - Unregister the rate control callbacks + * iwl_rate_control_unregister - Unregister the rate control callbacks * * This should be called after calling ieee80211_unregister_hw, but before * the driver is unloaded. diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index c4c0371c763b5d3b0e1ee13bfd1fcc1a386a6a6f..5da6b35cd26dbfa52da035a6ed78b871957b5c42 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -83,7 +83,7 @@ MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); MODULE_ALIAS("iwl4965"); @@ -96,7 +96,7 @@ MODULE_ALIAS("iwl4965"); -static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) +static void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; @@ -107,79 +107,6 @@ static void iwl4965_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt) } -/** - * iwl4965_check_rxon_cmd - validate RXON structure is valid - * - * NOTE: This is really only useful during development and can eventually - * be #ifdef'd out once the driver is stable and folks aren't actively - * making changes - */ -static int iwl4965_check_rxon_cmd(struct iwl_rxon_cmd *rxon) -{ - int error = 0; - int counter = 1; - - if (rxon->flags & RXON_FLG_BAND_24G_MSK) { - error |= le32_to_cpu(rxon->flags & - (RXON_FLG_TGJ_NARROW_BAND_MSK | - RXON_FLG_RADAR_DETECT_MSK)); - if (error) - IWL_WARNING("check 24G fields %d | %d\n", - counter++, error); - } else { - error |= (rxon->flags & RXON_FLG_SHORT_SLOT_MSK) ? - 0 : le32_to_cpu(RXON_FLG_SHORT_SLOT_MSK); - if (error) - IWL_WARNING("check 52 fields %d | %d\n", - counter++, error); - error |= le32_to_cpu(rxon->flags & RXON_FLG_CCK_MSK); - if (error) - IWL_WARNING("check 52 CCK %d | %d\n", - counter++, error); - } - error |= (rxon->node_addr[0] | rxon->bssid_addr[0]) & 0x1; - if (error) - IWL_WARNING("check mac addr %d | %d\n", counter++, error); - - /* make sure basic rates 6Mbps and 1Mbps are supported */ - error |= (((rxon->ofdm_basic_rates & IWL_RATE_6M_MASK) == 0) && - ((rxon->cck_basic_rates & IWL_RATE_1M_MASK) == 0)); - if (error) - IWL_WARNING("check basic rate %d | %d\n", counter++, error); - - error |= (le16_to_cpu(rxon->assoc_id) > 2007); - if (error) - IWL_WARNING("check assoc id %d | %d\n", counter++, error); - - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_SHORT_SLOT_MSK)); - if (error) - IWL_WARNING("check CCK and short slot %d | %d\n", - counter++, error); - - error |= ((rxon->flags & (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)) - == (RXON_FLG_CCK_MSK | RXON_FLG_AUTO_DETECT_MSK)); - if (error) - IWL_WARNING("check CCK & auto detect %d | %d\n", - counter++, error); - - error |= ((rxon->flags & (RXON_FLG_AUTO_DETECT_MSK | - RXON_FLG_TGG_PROTECT_MSK)) == RXON_FLG_TGG_PROTECT_MSK); - if (error) - IWL_WARNING("check TGG and auto detect %d | %d\n", - counter++, error); - - if (error) - IWL_WARNING("Tuning to channel %d\n", - le16_to_cpu(rxon->channel)); - - if (error) { - IWL_ERROR("Not a valid iwl4965_rxon_assoc_cmd field values\n"); - return -1; - } - return 0; -} - /** * iwl_full_rxon_required - check if full RXON (vs RXON_ASSOC) cmd is needed * @priv: staging_rxon is compared to active_rxon @@ -228,18 +155,17 @@ static int iwl_full_rxon_required(struct iwl_priv *priv) } /** - * iwl4965_commit_rxon - commit staging_rxon to hardware + * iwl_commit_rxon - commit staging_rxon to hardware * * The RXON command in staging_rxon is committed to the hardware and * the active_rxon structure is updated with the new data. This * function correctly transitions out of the RXON_ASSOC_MSK state if * a HW tune is required based on the RXON structure changes. */ -static int iwl4965_commit_rxon(struct iwl_priv *priv) +static int iwl_commit_rxon(struct iwl_priv *priv) { /* cast away the const for active_rxon in this function */ struct iwl_rxon_cmd *active_rxon = (void *)&priv->active_rxon; - DECLARE_MAC_BUF(mac); int ret; bool new_assoc = !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK); @@ -253,14 +179,14 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) * 5000, but will not damage 4965 */ priv->staging_rxon.flags |= RXON_FLG_SELF_CTS_EN; - ret = iwl4965_check_rxon_cmd(&priv->staging_rxon); + ret = iwl_agn_check_rxon_cmd(&priv->staging_rxon); if (ret) { IWL_ERROR("Invalid RXON configuration. Not committing.\n"); return -EINVAL; } /* If we don't need to send a full RXON, we can use - * iwl4965_rxon_assoc_cmd which is used to reconfigure filter + * iwl_rxon_assoc_cmd which is used to reconfigure filter * and other flags for the current radio configuration. */ if (!iwl_full_rxon_required(priv)) { ret = iwl_send_rxon_assoc(priv); @@ -300,12 +226,12 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) IWL_DEBUG_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" - "* bssid = %s\n", + "* bssid = %pM\n", (new_assoc ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), - print_mac(mac, priv->staging_rxon.bssid_addr)); + priv->staging_rxon.bssid_addr); - iwl4965_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); + iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto); /* Apply the new configuration * RXON unassoc clears the station table in uCode, send it before @@ -375,16 +301,16 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv) return 0; } -void iwl4965_update_chain_flags(struct iwl_priv *priv) +void iwl_update_chain_flags(struct iwl_priv *priv) { iwl_set_rxon_chain(priv); - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } -static int iwl4965_send_bt_config(struct iwl_priv *priv) +static int iwl_send_bt_config(struct iwl_priv *priv) { - struct iwl4965_bt_cmd bt_cmd = { + struct iwl_bt_cmd bt_cmd = { .flags = 3, .lead_time = 0xAA, .max_kill = 1, @@ -393,7 +319,7 @@ static int iwl4965_send_bt_config(struct iwl_priv *priv) }; return iwl_send_cmd_pdu(priv, REPLY_BT_CONFIG, - sizeof(struct iwl4965_bt_cmd), &bt_cmd); + sizeof(struct iwl_bt_cmd), &bt_cmd); } static void iwl_clear_free_frames(struct iwl_priv *priv) @@ -445,7 +371,7 @@ static void iwl_free_frame(struct iwl_priv *priv, struct iwl_frame *frame) static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, struct ieee80211_hdr *hdr, - const u8 *dest, int left) + int left) { if (!iwl_is_associated(priv) || !priv->ibss_beacon || ((priv->iw_mode != NL80211_IFTYPE_ADHOC) && @@ -460,16 +386,16 @@ static unsigned int iwl_fill_beacon_frame(struct iwl_priv *priv, return priv->ibss_beacon->len; } -static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) +static u8 iwl_rate_get_lowest_plcp(struct iwl_priv *priv) { int i; int rate_mask; /* Set rate mask*/ if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) - rate_mask = priv->active_rate_basic & 0xF; + rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK; else - rate_mask = priv->active_rate_basic & 0xFF0; + rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK; /* Find lowest valid rate */ for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; @@ -485,7 +411,7 @@ static u8 iwl4965_rate_get_lowest_plcp(struct iwl_priv *priv) return IWL_RATE_6M_PLCP; } -static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, +static unsigned int iwl_hw_get_beacon_cmd(struct iwl_priv *priv, struct iwl_frame *frame, u8 rate) { struct iwl_tx_beacon_cmd *tx_beacon_cmd; @@ -498,7 +424,6 @@ static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, tx_beacon_cmd->tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; frame_size = iwl_fill_beacon_frame(priv, tx_beacon_cmd->frame, - iwl_bcast_addr, sizeof(frame->u) - sizeof(*tx_beacon_cmd)); BUG_ON(frame_size > MAX_MPDU_SIZE); @@ -517,7 +442,7 @@ static unsigned int iwl4965_hw_get_beacon_cmd(struct iwl_priv *priv, return sizeof(*tx_beacon_cmd) + frame_size; } -static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) +static int iwl_send_beacon_cmd(struct iwl_priv *priv) { struct iwl_frame *frame; unsigned int frame_size; @@ -532,9 +457,9 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) return -ENOMEM; } - rate = iwl4965_rate_get_lowest_plcp(priv); + rate = iwl_rate_get_lowest_plcp(priv); - frame_size = iwl4965_hw_get_beacon_cmd(priv, frame, rate); + frame_size = iwl_hw_get_beacon_cmd(priv, frame, rate); rc = iwl_send_cmd_pdu(priv, REPLY_TX_BEACON, frame_size, &frame->u.cmd[0]); @@ -550,20 +475,33 @@ static int iwl4965_send_beacon_cmd(struct iwl_priv *priv) * ******************************************************************************/ -static void iwl4965_ht_conf(struct iwl_priv *priv, +static void iwl_ht_conf(struct iwl_priv *priv, struct ieee80211_bss_conf *bss_conf) { - struct ieee80211_ht_info *ht_conf = bss_conf->ht_conf; - struct ieee80211_ht_bss_info *ht_bss_conf = bss_conf->ht_bss_conf; + struct ieee80211_sta_ht_cap *ht_conf; struct iwl_ht_info *iwl_conf = &priv->current_ht_config; + struct ieee80211_sta *sta; IWL_DEBUG_MAC80211("enter: \n"); - iwl_conf->is_ht = bss_conf->assoc_ht; - if (!iwl_conf->is_ht) return; + + /* + * It is totally wrong to base global information on something + * that is valid only when associated, alas, this driver works + * that way and I don't know how to fix it. + */ + + rcu_read_lock(); + sta = ieee80211_find_sta(priv->hw, priv->bssid); + if (!sta) { + rcu_read_unlock(); + return; + } + ht_conf = &sta->ht_cap; + if (ht_conf->cap & IEEE80211_HT_CAP_SGI_20) iwl_conf->sgf |= HT_SHORT_GI_20MHZ; if (ht_conf->cap & IEEE80211_HT_CAP_SGI_40) @@ -574,29 +512,36 @@ static void iwl4965_ht_conf(struct iwl_priv *priv, !!(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; + !!(ht_conf->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40); + + /* + * XXX: The HT configuration needs to be moved into iwl_mac_config() + * to be done there correctly. + */ + + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_NONE; + if (priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40MINUS) + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_BELOW; + else if(priv->hw->conf.ht.channel_type == NL80211_CHAN_HT40PLUS) + iwl_conf->extension_chan_offset = IEEE80211_HT_PARAM_CHA_SEC_ABOVE; + /* If no above or below channel supplied disable FAT channel */ - if (iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_ABOVE && - iwl_conf->extension_chan_offset != IEEE80211_HT_IE_CHA_SEC_BELOW) { - iwl_conf->extension_chan_offset = IEEE80211_HT_IE_CHA_SEC_NONE; + if (iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_ABOVE && + iwl_conf->extension_chan_offset != IEEE80211_HT_PARAM_CHA_SEC_BELOW) iwl_conf->supported_chan_width = 0; - } iwl_conf->sm_ps = (u8)((ht_conf->cap & IEEE80211_HT_CAP_SM_PS) >> 2); - memcpy(iwl_conf->supp_mcs_set, ht_conf->supp_mcs_set, 16); + memcpy(&iwl_conf->mcs, &ht_conf->mcs, 16); - iwl_conf->control_channel = ht_bss_conf->primary_channel; - iwl_conf->tx_chan_width = - !!(ht_bss_conf->bss_cap & IEEE80211_HT_IE_CHA_WIDTH); + iwl_conf->tx_chan_width = iwl_conf->supported_chan_width != 0; iwl_conf->ht_protection = - ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_HT_PROTECTION; + bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_PROTECTION; iwl_conf->non_GF_STA_present = - !!(ht_bss_conf->bss_op_mode & IEEE80211_HT_IE_NON_GF_STA_PRSNT); + !!(bss_conf->ht.operation_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT); + + rcu_read_unlock(); - IWL_DEBUG_MAC80211("control channel %d\n", iwl_conf->control_channel); IWL_DEBUG_MAC80211("leave\n"); } @@ -608,9 +553,6 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (!priv->qos_data.qos_enable) - return; - priv->qos_data.def_qos_parm.qos_flags = 0; if (priv->qos_data.qos_cap.q_AP.queue_request && @@ -637,23 +579,22 @@ static void iwl_activate_qos(struct iwl_priv *priv, u8 force) #define MAX_UCODE_BEACON_INTERVAL 4096 -static __le16 iwl4965_adjust_beacon_interval(u16 beacon_val) +static u16 iwl_adjust_beacon_interval(u16 beacon_val) { u16 new_val = 0; u16 beacon_factor = 0; - beacon_factor = - (beacon_val + MAX_UCODE_BEACON_INTERVAL) - / MAX_UCODE_BEACON_INTERVAL; + beacon_factor = (beacon_val + MAX_UCODE_BEACON_INTERVAL) + / MAX_UCODE_BEACON_INTERVAL; new_val = beacon_val / beacon_factor; - return cpu_to_le16(new_val); + return new_val; } -static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) +static void iwl_setup_rxon_timing(struct iwl_priv *priv) { - u64 interval_tm_unit; - u64 tsf, result; + u64 tsf; + s32 interval_tm, rem; unsigned long flags; struct ieee80211_conf *conf = NULL; u16 beacon_int = 0; @@ -661,49 +602,32 @@ static void iwl4965_setup_rxon_timing(struct iwl_priv *priv) conf = ieee80211_get_hw_conf(priv->hw); spin_lock_irqsave(&priv->lock, flags); - priv->rxon_timing.timestamp.dw[1] = cpu_to_le32(priv->timestamp >> 32); - priv->rxon_timing.timestamp.dw[0] = - cpu_to_le32(priv->timestamp & 0xFFFFFFFF); - + priv->rxon_timing.timestamp = cpu_to_le64(priv->timestamp); priv->rxon_timing.listen_interval = cpu_to_le16(conf->listen_interval); - tsf = priv->timestamp; - - beacon_int = priv->beacon_int; - spin_unlock_irqrestore(&priv->lock, flags); - if (priv->iw_mode == NL80211_IFTYPE_STATION) { - if (beacon_int == 0) { - priv->rxon_timing.beacon_interval = cpu_to_le16(100); - priv->rxon_timing.beacon_init_val = cpu_to_le32(102400); - } else { - priv->rxon_timing.beacon_interval = - cpu_to_le16(beacon_int); - priv->rxon_timing.beacon_interval = - iwl4965_adjust_beacon_interval( - le16_to_cpu(priv->rxon_timing.beacon_interval)); - } - + beacon_int = iwl_adjust_beacon_interval(priv->beacon_int); priv->rxon_timing.atim_window = 0; } else { - priv->rxon_timing.beacon_interval = - iwl4965_adjust_beacon_interval(conf->beacon_int); + beacon_int = iwl_adjust_beacon_interval(conf->beacon_int); + /* TODO: we need to get atim_window from upper stack * for now we set to 0 */ priv->rxon_timing.atim_window = 0; } - interval_tm_unit = - (le16_to_cpu(priv->rxon_timing.beacon_interval) * 1024); - result = do_div(tsf, interval_tm_unit); - priv->rxon_timing.beacon_init_val = - cpu_to_le32((u32) ((u64) interval_tm_unit - result)); + priv->rxon_timing.beacon_interval = cpu_to_le16(beacon_int); - IWL_DEBUG_ASSOC - ("beacon interval %d beacon timer %d beacon tim %d\n", - le16_to_cpu(priv->rxon_timing.beacon_interval), - le32_to_cpu(priv->rxon_timing.beacon_init_val), - le16_to_cpu(priv->rxon_timing.atim_window)); + tsf = priv->timestamp; /* tsf is modifed by do_div: copy it */ + interval_tm = beacon_int * 1024; + rem = do_div(tsf, interval_tm); + priv->rxon_timing.beacon_init_val = cpu_to_le32(interval_tm - rem); + + spin_unlock_irqrestore(&priv->lock, flags); + IWL_DEBUG_ASSOC("beacon interval %d beacon timer %d beacon tim %d\n", + le16_to_cpu(priv->rxon_timing.beacon_interval), + le32_to_cpu(priv->rxon_timing.beacon_init_val), + le16_to_cpu(priv->rxon_timing.atim_window)); } static void iwl_set_flags_for_band(struct iwl_priv *priv, @@ -715,7 +639,7 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv, | RXON_FLG_CCK_MSK); priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; } else { - /* Copied from iwl4965_post_associate() */ + /* Copied from iwl_post_associate() */ if (priv->assoc_capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) priv->staging_rxon.flags |= RXON_FLG_SHORT_SLOT_MSK; else @@ -733,13 +657,13 @@ static void iwl_set_flags_for_band(struct iwl_priv *priv, /* * initialize rxon structure with default values from eeprom */ -static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) +static void iwl_connection_init_rx_config(struct iwl_priv *priv, int mode) { const struct iwl_channel_info *ch_info; memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); - switch (priv->iw_mode) { + switch (mode) { case NL80211_IFTYPE_AP: priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; break; @@ -762,7 +686,7 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; default: - IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode); + IWL_ERROR("Unsupported interface type %d\n", mode); break; } @@ -808,11 +732,9 @@ static void iwl4965_connection_init_rx_config(struct iwl_priv *priv) iwl_set_rxon_chain(priv); } -static int iwl4965_set_mode(struct iwl_priv *priv, int mode) +static int iwl_set_mode(struct iwl_priv *priv, int mode) { - priv->iw_mode = mode; - - iwl4965_connection_init_rx_config(priv); + iwl_connection_init_rx_config(priv, mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); iwl_clear_stations_table(priv); @@ -828,12 +750,12 @@ static int iwl4965_set_mode(struct iwl_priv *priv, int mode) return -EAGAIN; } - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); return 0; } -static void iwl4965_set_rate(struct iwl_priv *priv) +static void iwl_set_rate(struct iwl_priv *priv) { const struct ieee80211_supported_band *hw = NULL; struct ieee80211_rate *rate; @@ -880,138 +802,6 @@ static void iwl4965_set_rate(struct iwl_priv *priv) (IWL_OFDM_BASIC_RATES_MASK >> IWL_FIRST_OFDM_RATE) & 0xFF; } -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - -#include "iwl-spectrum.h" - -#define BEACON_TIME_MASK_LOW 0x00FFFFFF -#define BEACON_TIME_MASK_HIGH 0xFF000000 -#define TIME_UNIT 1024 - -/* - * extended beacon time format - * time in usec will be changed into a 32-bit value in 8:24 format - * the high 1 byte is the beacon counts - * the lower 3 bytes is the time in usec within one beacon interval - */ - -static u32 iwl4965_usecs_to_beacons(u32 usec, u32 beacon_interval) -{ - u32 quot; - u32 rem; - u32 interval = beacon_interval * 1024; - - if (!interval || !usec) - return 0; - - quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); - rem = (usec % interval) & BEACON_TIME_MASK_LOW; - - return (quot << 24) + rem; -} - -/* base is usually what we get from ucode with each received frame, - * the same as HW timer counter counting down - */ - -static __le32 iwl4965_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) -{ - u32 base_low = base & BEACON_TIME_MASK_LOW; - u32 addon_low = addon & BEACON_TIME_MASK_LOW; - u32 interval = beacon_interval * TIME_UNIT; - u32 res = (base & BEACON_TIME_MASK_HIGH) + - (addon & BEACON_TIME_MASK_HIGH); - - if (base_low > addon_low) - res += base_low - addon_low; - else if (base_low < addon_low) { - res += interval + base_low - addon_low; - res += (1 << 24); - } else - res += (1 << 24); - - return cpu_to_le32(res); -} - -static int iwl4965_get_measurement(struct iwl_priv *priv, - struct ieee80211_measurement_params *params, - u8 type) -{ - struct iwl4965_spectrum_cmd spectrum; - struct iwl_rx_packet *res; - struct iwl_host_cmd cmd = { - .id = REPLY_SPECTRUM_MEASUREMENT_CMD, - .data = (void *)&spectrum, - .meta.flags = CMD_WANT_SKB, - }; - u32 add_time = le64_to_cpu(params->start_time); - int rc; - int spectrum_resp_status; - int duration = le16_to_cpu(params->duration); - - if (iwl_is_associated(priv)) - add_time = - iwl4965_usecs_to_beacons( - le64_to_cpu(params->start_time) - priv->last_tsf, - le16_to_cpu(priv->rxon_timing.beacon_interval)); - - memset(&spectrum, 0, sizeof(spectrum)); - - spectrum.channel_count = cpu_to_le16(1); - spectrum.flags = - RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; - spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; - cmd.len = sizeof(spectrum); - spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); - - if (iwl_is_associated(priv)) - spectrum.start_time = - iwl4965_add_beacon_time(priv->last_beacon_time, - add_time, - le16_to_cpu(priv->rxon_timing.beacon_interval)); - else - spectrum.start_time = 0; - - spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); - spectrum.channels[0].channel = params->channel; - spectrum.channels[0].type = type; - if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) - spectrum.flags |= RXON_FLG_BAND_24G_MSK | - RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; - - rc = iwl_send_cmd_sync(priv, &cmd); - if (rc) - return rc; - - res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; - if (res->hdr.flags & IWL_CMD_FAILED_MSK) { - IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); - rc = -EIO; - } - - spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); - switch (spectrum_resp_status) { - case 0: /* Command will be handled */ - if (res->u.spectrum.id != 0xff) { - IWL_DEBUG_INFO - ("Replaced existing measurement: %d\n", - res->u.spectrum.id); - priv->measurement_status &= ~MEASUREMENT_READY; - } - priv->measurement_status |= MEASUREMENT_ACTIVE; - rc = 0; - break; - - case 1: /* Command will not be handled */ - rc = -EAGAIN; - break; - } - - dev_kfree_skb_any(cmd.meta.u.skb); - - return rc; -} -#endif /****************************************************************************** * @@ -1054,7 +844,7 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv, IWL_WARNING("uCode did not respond OK.\n"); } -static void iwl4965_rx_reply_error(struct iwl_priv *priv, +static void iwl_rx_reply_error(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; @@ -1070,47 +860,29 @@ static void iwl4965_rx_reply_error(struct iwl_priv *priv, #define TX_STATUS_ENTRY(x) case TX_STATUS_FAIL_ ## x: return #x -static void iwl4965_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) +static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_rxon_cmd *rxon = (void *)&priv->active_rxon; - struct iwl4965_csa_notification *csa = &(pkt->u.csa_notif); + struct iwl_csa_notification *csa = &(pkt->u.csa_notif); IWL_DEBUG_11H("CSA notif: channel %d, status %d\n", le16_to_cpu(csa->channel), le32_to_cpu(csa->status)); rxon->channel = csa->channel; priv->staging_rxon.channel = csa->channel; } -static void iwl4965_rx_spectrum_measure_notif(struct iwl_priv *priv, - struct iwl_rx_mem_buffer *rxb) -{ -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_spectrum_notification *report = &(pkt->u.spectrum_notif); - - if (!report->state) { - IWL_DEBUG(IWL_DL_11H, - "Spectrum Measure Notification: Start\n"); - return; - } - - memcpy(&priv->measure_report, report, sizeof(*report)); - priv->measurement_status |= MEASUREMENT_READY; -#endif -} - -static void iwl4965_rx_pm_sleep_notif(struct iwl_priv *priv, +static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_sleep_notification *sleep = &(pkt->u.sleep_notif); + struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif); IWL_DEBUG_RX("sleep mode: %d, src: %d\n", sleep->pm_sleep_mode, sleep->pm_wakeup_src); #endif } -static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, +static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; @@ -1120,7 +892,7 @@ static void iwl4965_rx_pm_debug_statistics_notif(struct iwl_priv *priv, iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len)); } -static void iwl4965_bg_beacon_update(struct work_struct *work) +static void iwl_bg_beacon_update(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, beacon_update); @@ -1142,11 +914,11 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) priv->ibss_beacon = beacon; mutex_unlock(&priv->mutex); - iwl4965_send_beacon_cmd(priv); + iwl_send_beacon_cmd(priv); } /** - * iwl4965_bg_statistics_periodic - Timer callback to queue statistics + * iwl_bg_statistics_periodic - Timer callback to queue statistics * * This callback is provided in order to send a statistics request. * @@ -1155,22 +927,27 @@ static void iwl4965_bg_beacon_update(struct work_struct *work) * was received. We need to ensure we receive the statistics in order * to update the temperature used for calibrating the TXPOWER. */ -static void iwl4965_bg_statistics_periodic(unsigned long data) +static void iwl_bg_statistics_periodic(unsigned long data) { struct iwl_priv *priv = (struct iwl_priv *)data; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + /* dont send host command if rf-kill is on */ + if (!iwl_is_ready_rf(priv)) + return; + iwl_send_statistics_request(priv, CMD_ASYNC); } -static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, +static void iwl_rx_beacon_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { #ifdef CONFIG_IWLWIFI_DEBUG struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_beacon_notif *beacon = &(pkt->u.beacon_status); + struct iwl4965_beacon_notif *beacon = + (struct iwl4965_beacon_notif *)pkt->u.raw; u8 rate = iwl_hw_get_rate(beacon->beacon_notify_hdr.rate_n_flags); IWL_DEBUG_RX("beacon status %x retries %d iss %d " @@ -1189,7 +966,7 @@ static void iwl4965_rx_beacon_notif(struct iwl_priv *priv, /* Handle notification from uCode that card's power state is changing * due to software, hardware, or critical temperature RFKILL */ -static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, +static void iwl_rx_card_state_notif(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; @@ -1258,7 +1035,7 @@ static void iwl4965_rx_card_state_notif(struct iwl_priv *priv, wake_up_interruptible(&priv->wait_command_queue); } -int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) +int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src) { int ret; unsigned long flags; @@ -1290,7 +1067,7 @@ err: } /** - * iwl4965_setup_rx_handlers - Initialize Rx handler callbacks + * iwl_setup_rx_handlers - Initialize Rx handler callbacks * * Setup the RX handlers for each of the reply types sent from the uCode * to the host. @@ -1301,14 +1078,12 @@ err: static void iwl_setup_rx_handlers(struct iwl_priv *priv) { priv->rx_handlers[REPLY_ALIVE] = iwl_rx_reply_alive; - priv->rx_handlers[REPLY_ERROR] = iwl4965_rx_reply_error; - priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl4965_rx_csa; - priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = - iwl4965_rx_spectrum_measure_notif; - priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl4965_rx_pm_sleep_notif; + priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error; + priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa; + priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif; priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] = - iwl4965_rx_pm_debug_statistics_notif; - priv->rx_handlers[BEACON_NOTIFICATION] = iwl4965_rx_beacon_notif; + iwl_rx_pm_debug_statistics_notif; + priv->rx_handlers[BEACON_NOTIFICATION] = iwl_rx_beacon_notif; /* * The same handler is used for both the REPLY to a discrete @@ -1318,10 +1093,11 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl_rx_statistics; priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl_rx_statistics; + iwl_setup_spectrum_handlers(priv); iwl_setup_rx_scan_handlers(priv); /* status change handler */ - priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl4965_rx_card_state_notif; + priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl_rx_card_state_notif; priv->rx_handlers[MISSED_BEACONS_NOTIFICATION] = iwl_rx_missed_beacon_notif; @@ -1334,16 +1110,6 @@ static void iwl_setup_rx_handlers(struct iwl_priv *priv) priv->cfg->ops->lib->rx_handler_setup(priv); } -/* - * this should be called while priv->lock is locked -*/ -static void __iwl_rx_replenish(struct iwl_priv *priv) -{ - iwl_rx_allocate(priv); - iwl_rx_queue_restock(priv); -} - - /** * iwl_rx_handle - Main entry function for receiving responses from uCode * @@ -1364,7 +1130,7 @@ void iwl_rx_handle(struct iwl_priv *priv) /* uCode's read index (stored in shared DRAM) indicates the last Rx * buffer that the driver may process (last buffer filled by ucode). */ - r = priv->cfg->ops->lib->shared_mem_rx_idx(priv); + r = le16_to_cpu(rxq->rb_stts->closed_rb_num) & 0x0FFF; i = rxq->read; /* Rx interrupt, but nothing sent from uCode */ @@ -1400,13 +1166,14 @@ void iwl_rx_handle(struct iwl_priv *priv) reclaim = !(pkt->hdr.sequence & SEQ_RX_FRAME) && (pkt->hdr.cmd != REPLY_RX_PHY_CMD) && (pkt->hdr.cmd != REPLY_RX) && + (pkt->hdr.cmd != REPLY_RX_MPDU_CMD) && (pkt->hdr.cmd != REPLY_COMPRESSED_BA) && (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && (pkt->hdr.cmd != REPLY_TX); /* Based on type of command response or notification, * handle those that need handling via function in - * rx_handlers table. See iwl4965_setup_rx_handlers() */ + * rx_handlers table. See iwl_setup_rx_handlers() */ if (priv->rx_handlers[pkt->hdr.cmd]) { IWL_DEBUG(IWL_DL_RX, "r = %d, i = %d, %s, 0x%02x\n", r, i, get_cmd_string(pkt->hdr.cmd), pkt->hdr.cmd); @@ -1451,7 +1218,7 @@ void iwl_rx_handle(struct iwl_priv *priv) count++; if (count >= 8) { priv->rxq.read = i; - __iwl_rx_replenish(priv); + iwl_rx_queue_restock(priv); count = 0; } } @@ -1463,10 +1230,9 @@ void iwl_rx_handle(struct iwl_priv *priv) } #ifdef CONFIG_IWLWIFI_DEBUG -static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) +static void iwl_print_rx_config_cmd(struct iwl_priv *priv) { struct iwl_rxon_cmd *rxon = &priv->staging_rxon; - DECLARE_MAC_BUF(mac); IWL_DEBUG_RADIO("RX CONFIG:\n"); iwl_print_hex_dump(priv, IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); @@ -1478,50 +1244,26 @@ static void iwl4965_print_rx_config_cmd(struct iwl_priv *priv) IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", rxon->ofdm_basic_rates); IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", - print_mac(mac, rxon->node_addr)); - IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", - print_mac(mac, rxon->bssid_addr)); + IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr); + IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif -static void iwl4965_enable_interrupts(struct iwl_priv *priv) -{ - IWL_DEBUG_ISR("Enabling interrupts\n"); - set_bit(STATUS_INT_ENABLED, &priv->status); - iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); -} - /* call this function to flush any scheduled tasklet */ static inline void iwl_synchronize_irq(struct iwl_priv *priv) { - /* wait to make sure we flush pedding tasklet*/ + /* wait to make sure we flush pending tasklet*/ synchronize_irq(priv->pci_dev->irq); tasklet_kill(&priv->irq_tasklet); } -static inline void iwl4965_disable_interrupts(struct iwl_priv *priv) -{ - clear_bit(STATUS_INT_ENABLED, &priv->status); - - /* disable interrupts from uCode/NIC to host */ - iwl_write32(priv, CSR_INT_MASK, 0x00000000); - - /* acknowledge/clear/reset any interrupts still pending - * from uCode or flow handler (Rx/Tx DMA) */ - iwl_write32(priv, CSR_INT, 0xffffffff); - iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); - IWL_DEBUG_ISR("Disabled interrupts\n"); -} - - /** - * iwl4965_irq_handle_error - called for HW or SW error interrupt from card + * iwl_irq_handle_error - called for HW or SW error interrupt from card */ -static void iwl4965_irq_handle_error(struct iwl_priv *priv) +static void iwl_irq_handle_error(struct iwl_priv *priv) { - /* Set the FW error flag -- cleared on iwl4965_down */ + /* Set the FW error flag -- cleared on iwl_down */ set_bit(STATUS_FW_ERROR, &priv->status); /* Cancel currently queued command. */ @@ -1531,7 +1273,7 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) if (priv->debug_level & IWL_DL_FW_ERRORS) { iwl_dump_nic_error_log(priv); iwl_dump_nic_event_log(priv); - iwl4965_print_rx_config_cmd(priv); + iwl_print_rx_config_cmd(priv); } #endif @@ -1555,14 +1297,14 @@ static void iwl4965_irq_handle_error(struct iwl_priv *priv) } } -static void iwl4965_error_recovery(struct iwl_priv *priv) +static void iwl_error_recovery(struct iwl_priv *priv) { unsigned long flags; memcpy(&priv->staging_rxon, &priv->recovery_rxon, sizeof(priv->staging_rxon)); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); iwl_rxon_add_station(priv, priv->bssid, 1); @@ -1572,7 +1314,7 @@ static void iwl4965_error_recovery(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static void iwl4965_irq_tasklet(struct iwl_priv *priv) +static void iwl_irq_tasklet(struct iwl_priv *priv) { u32 inta, handled = 0; u32 inta_fh; @@ -1618,9 +1360,9 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) IWL_ERROR("Microcode HW error detected. Restarting.\n"); /* Tell the device to stop sending interrupts */ - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); - iwl4965_irq_handle_error(priv); + iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_HW_ERR; @@ -1652,14 +1394,17 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) hw_rf_kill = 1; IWL_DEBUG(IWL_DL_RF_KILL, "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio":"enable radio"); + hw_rf_kill ? "disable radio" : "enable radio"); /* driver only loads ucode once setting the interface up. * the driver as well won't allow loading if RFKILL is set * therefore no need to restart the driver from this handler */ - if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) + if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) { clear_bit(STATUS_RF_KILL_HW, &priv->status); + if (priv->is_open && !iwl_is_rfkill(priv)) + queue_work(priv->workqueue, &priv->up); + } handled |= CSR_INT_BIT_RF_KILL; } @@ -1674,7 +1419,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", inta); - iwl4965_irq_handle_error(priv); + iwl_irq_handle_error(priv); handled |= CSR_INT_BIT_SW_ERR; } @@ -1720,7 +1465,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) /* Re-enable all interrupts */ /* only Re-enable if diabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); #ifdef CONFIG_IWLWIFI_DEBUG if (priv->debug_level & (IWL_DL_ISR)) { @@ -1734,7 +1479,7 @@ static void iwl4965_irq_tasklet(struct iwl_priv *priv) spin_unlock_irqrestore(&priv->lock, flags); } -static irqreturn_t iwl4965_isr(int irq, void *data) +static irqreturn_t iwl_isr(int irq, void *data) { struct iwl_priv *priv = data; u32 inta, inta_mask; @@ -1766,7 +1511,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data) if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { /* Hardware disappeared. It might have already raised * an interrupt */ - IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); + IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta); goto unplugged; } @@ -1775,7 +1520,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data) inta &= ~CSR_INT_BIT_SCD; - /* iwl4965_irq_tasklet() will service interrupts and re-enable them */ + /* iwl_irq_tasklet() will service interrupts and re-enable them */ if (likely(inta || inta_fh)) tasklet_schedule(&priv->irq_tasklet); @@ -1787,7 +1532,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data) /* re-enable interrupts here since we don't have anything to service. */ /* only Re-enable if diabled by irq */ if (test_bit(STATUS_INT_ENABLED, &priv->status)) - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); spin_unlock(&priv->lock); return IRQ_NONE; } @@ -1798,7 +1543,7 @@ static irqreturn_t iwl4965_isr(int irq, void *data) * ******************************************************************************/ -static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) +static void iwl_dealloc_ucode_pci(struct iwl_priv *priv) { iwl_free_fw_desc(priv->pci_dev, &priv->ucode_code); iwl_free_fw_desc(priv->pci_dev, &priv->ucode_data); @@ -1808,7 +1553,7 @@ static void iwl4965_dealloc_ucode_pci(struct iwl_priv *priv) iwl_free_fw_desc(priv->pci_dev, &priv->ucode_boot); } -static void iwl4965_nic_start(struct iwl_priv *priv) +static void iwl_nic_start(struct iwl_priv *priv) { /* Remove all resets to allow NIC to operate */ iwl_write32(priv, CSR_RESET, 0); @@ -1816,31 +1561,47 @@ static void iwl4965_nic_start(struct iwl_priv *priv) /** - * iwl4965_read_ucode - Read uCode images from disk file. + * iwl_read_ucode - Read uCode images from disk file. * * Copy into buffers for card to fetch via bus-mastering */ -static int iwl4965_read_ucode(struct iwl_priv *priv) +static int iwl_read_ucode(struct iwl_priv *priv) { struct iwl_ucode *ucode; - int ret; + int ret = -EINVAL, index; const struct firmware *ucode_raw; - const char *name = priv->cfg->fw_name; + const char *name_pre = priv->cfg->fw_name_pre; + const unsigned int api_max = priv->cfg->ucode_api_max; + const unsigned int api_min = priv->cfg->ucode_api_min; + char buf[25]; u8 *src; size_t len; - u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; + u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ - ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); - if (ret < 0) { - IWL_ERROR("%s firmware file req failed: Reason %d\n", - name, ret); - goto error; + for (index = api_max; index >= api_min; index--) { + sprintf(buf, "%s%d%s", name_pre, index, ".ucode"); + ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); + if (ret < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", + buf, ret); + if (ret == -ENOENT) + continue; + else + goto error; + } else { + if (index < api_max) + IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n", + buf, api_max); + IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", + buf, ucode_raw->size); + break; + } } - IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", - name, ucode_raw->size); + if (ret < 0) + goto error; /* Make sure that we got at least our header! */ if (ucode_raw->size < sizeof(*ucode)) { @@ -1852,14 +1613,40 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) /* Data from ucode file: header followed by uCode images */ ucode = (void *)ucode_raw->data; - ver = le32_to_cpu(ucode->ver); + priv->ucode_ver = le32_to_cpu(ucode->ver); + api_ver = IWL_UCODE_API(priv->ucode_ver); inst_size = le32_to_cpu(ucode->inst_size); data_size = le32_to_cpu(ucode->data_size); init_size = le32_to_cpu(ucode->init_size); init_data_size = le32_to_cpu(ucode->init_data_size); boot_size = le32_to_cpu(ucode->boot_size); - IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); + /* api_ver should match the api version forming part of the + * firmware filename ... but we don't check for that and only rely + * on the API version read from firware header from here on forward */ + + if (api_ver < api_min || api_ver > api_max) { + IWL_ERROR("Driver unable to support your firmware API. " + "Driver supports v%u, firmware is v%u.\n", + api_max, api_ver); + priv->ucode_ver = 0; + ret = -EINVAL; + goto err_release; + } + if (api_ver != api_max) + IWL_ERROR("Firmware has old API version. Expected v%u, " + "got v%u. New firmware can be obtained " + "from http://www.intellinuxwireless.org.\n", + api_max, api_ver); + + printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n", + IWL_UCODE_MAJOR(priv->ucode_ver), + IWL_UCODE_MINOR(priv->ucode_ver), + IWL_UCODE_API(priv->ucode_ver), + IWL_UCODE_SERIAL(priv->ucode_ver)); + + IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", + priv->ucode_ver); IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size); IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", @@ -1964,7 +1751,7 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) priv->ucode_code.v_addr, (u32)priv->ucode_code.p_addr); /* Runtime data (2nd block) - * NOTE: Copy into backup buffer will be done in iwl4965_up() */ + * NOTE: Copy into backup buffer will be done in iwl_up() */ src = &ucode->data[inst_size]; len = priv->ucode_data.len; IWL_DEBUG_INFO("Copying (but not loading) uCode data len %Zd\n", len); @@ -2002,7 +1789,7 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) err_pci_alloc: IWL_ERROR("failed to allocate pci memory\n"); ret = -ENOMEM; - iwl4965_dealloc_ucode_pci(priv); + iwl_dealloc_ucode_pci(priv); err_release: release_firmware(ucode_raw); @@ -2011,6 +1798,10 @@ static int iwl4965_read_ucode(struct iwl_priv *priv) return ret; } +/* temporary */ +static int iwl_mac_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *skb); + /** * iwl_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -2047,7 +1838,7 @@ static void iwl_alive_start(struct iwl_priv *priv) goto restart; } - /* After the ALIVE response, we can send host commands to 4965 uCode */ + /* After the ALIVE response, we can send host commands to the uCode */ set_bit(STATUS_ALIVE, &priv->status); if (iwl_is_rfkill(priv)) @@ -2067,17 +1858,17 @@ static void iwl_alive_start(struct iwl_priv *priv) active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; } else { /* Initialize our rx_config data */ - iwl4965_connection_init_rx_config(priv); + iwl_connection_init_rx_config(priv, priv->iw_mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } /* Configure Bluetooth device coexistence support */ - iwl4965_send_bt_config(priv); + iwl_send_bt_config(priv); iwl_reset_run_time_calib(priv); /* Configure the adapter for unassociated operation */ - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); /* At this point, the NIC is initialized and operational */ iwl_rf_kill_ct_config(priv); @@ -2089,12 +1880,21 @@ static void iwl_alive_start(struct iwl_priv *priv) wake_up_interruptible(&priv->wait_command_queue); if (priv->error_recovering) - iwl4965_error_recovery(priv); + iwl_error_recovery(priv); iwl_power_update_mode(priv, 1); + /* reassociate for ADHOC mode */ + if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { + struct sk_buff *beacon = ieee80211_beacon_get(priv->hw, + priv->vif); + if (beacon) + iwl_mac_beacon_update(priv->hw, beacon); + } + + if (test_and_clear_bit(STATUS_MODE_PENDING, &priv->status)) - iwl4965_set_mode(priv, priv->iw_mode); + iwl_set_mode(priv, priv->iw_mode); return; @@ -2104,7 +1904,7 @@ static void iwl_alive_start(struct iwl_priv *priv) static void iwl_cancel_deferred_work(struct iwl_priv *priv); -static void __iwl4965_down(struct iwl_priv *priv) +static void __iwl_down(struct iwl_priv *priv) { unsigned long flags; int exit_pending = test_bit(STATUS_EXIT_PENDING, &priv->status); @@ -2131,14 +1931,14 @@ static void __iwl4965_down(struct iwl_priv *priv) /* tell the device to stop sending interrupts */ spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); iwl_synchronize_irq(priv); if (priv->mac80211_registered) ieee80211_stop_queues(priv->hw); - /* If we have not previously called iwl4965_init() then + /* If we have not previously called iwl_init() then * clear all bits but the RF Kill and SUSPEND bits and return */ if (!iwl_is_init(priv)) { priv->status = test_bit(STATUS_RF_KILL_HW, &priv->status) << @@ -2192,8 +1992,6 @@ static void __iwl4965_down(struct iwl_priv *priv) priv->cfg->ops->lib->apm_ops.stop(priv); else priv->cfg->ops->lib->apm_ops.reset(priv); - priv->cfg->ops->lib->free_shared_mem(priv); - exit: memset(&priv->card_alive, 0, sizeof(struct iwl_alive_resp)); @@ -2205,10 +2003,10 @@ static void __iwl4965_down(struct iwl_priv *priv) iwl_clear_free_frames(priv); } -static void iwl4965_down(struct iwl_priv *priv) +static void iwl_down(struct iwl_priv *priv) { mutex_lock(&priv->mutex); - __iwl4965_down(priv); + __iwl_down(priv); mutex_unlock(&priv->mutex); iwl_cancel_deferred_work(priv); @@ -2216,7 +2014,7 @@ static void iwl4965_down(struct iwl_priv *priv) #define MAX_HW_RESTARTS 5 -static int __iwl4965_up(struct iwl_priv *priv) +static int __iwl_up(struct iwl_priv *priv) { int i; int ret; @@ -2238,7 +2036,7 @@ static int __iwl4965_up(struct iwl_priv *priv) set_bit(STATUS_RF_KILL_HW, &priv->status); if (iwl_is_rfkill(priv)) { - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); IWL_WARNING("Radio disabled by %s RF Kill switch\n", test_bit(STATUS_RF_KILL_HW, &priv->status) ? "HW" : "SW"); return 0; @@ -2246,12 +2044,6 @@ static int __iwl4965_up(struct iwl_priv *priv) iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - ret = priv->cfg->ops->lib->alloc_shared_mem(priv); - if (ret) { - IWL_ERROR("Unable to allocate shared memory\n"); - return ret; - } - ret = iwl_hw_nic_init(priv); if (ret) { IWL_ERROR("Unable to init nic\n"); @@ -2265,7 +2057,7 @@ static int __iwl4965_up(struct iwl_priv *priv) /* clear (again), then enable host interrupts */ iwl_write32(priv, CSR_INT, 0xFFFFFFFF); - iwl4965_enable_interrupts(priv); + iwl_enable_interrupts(priv); /* really make sure rfkill handshake bits are cleared */ iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL); @@ -2295,7 +2087,7 @@ static int __iwl4965_up(struct iwl_priv *priv) clear_bit(STATUS_FW_ERROR, &priv->status); /* start card; "initialize" will load runtime ucode */ - iwl4965_nic_start(priv); + iwl_nic_start(priv); IWL_DEBUG_INFO(DRV_NAME " is coming up\n"); @@ -2303,7 +2095,7 @@ static int __iwl4965_up(struct iwl_priv *priv) } set_bit(STATUS_EXIT_PENDING, &priv->status); - __iwl4965_down(priv); + __iwl_down(priv); clear_bit(STATUS_EXIT_PENDING, &priv->status); /* tried to restart and config the device for as long as our @@ -2345,7 +2137,7 @@ static void iwl_bg_alive_start(struct work_struct *data) mutex_unlock(&priv->mutex); } -static void iwl4965_bg_rf_kill(struct work_struct *work) +static void iwl_bg_rf_kill(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, rf_kill); @@ -2379,28 +2171,6 @@ static void iwl4965_bg_rf_kill(struct work_struct *work) iwl_rfkill_set_hw_state(priv); } -static void iwl4965_bg_set_monitor(struct work_struct *work) -{ - struct iwl_priv *priv = container_of(work, - struct iwl_priv, set_monitor); - int ret; - - IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); - - mutex_lock(&priv->mutex); - - ret = iwl4965_set_mode(priv, NL80211_IFTYPE_MONITOR); - - if (ret) { - if (ret == -EAGAIN) - IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); - else - IWL_ERROR("iwl4965_set_mode() failed ret = %d\n", ret); - } - - mutex_unlock(&priv->mutex); -} - static void iwl_bg_run_time_calib_work(struct work_struct *work) { struct iwl_priv *priv = container_of(work, struct iwl_priv, @@ -2424,7 +2194,7 @@ static void iwl_bg_run_time_calib_work(struct work_struct *work) return; } -static void iwl4965_bg_up(struct work_struct *data) +static void iwl_bg_up(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, up); @@ -2432,23 +2202,23 @@ static void iwl4965_bg_up(struct work_struct *data) return; mutex_lock(&priv->mutex); - __iwl4965_up(priv); + __iwl_up(priv); mutex_unlock(&priv->mutex); iwl_rfkill_set_hw_state(priv); } -static void iwl4965_bg_restart(struct work_struct *data) +static void iwl_bg_restart(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, restart); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - iwl4965_down(priv); + iwl_down(priv); queue_work(priv->workqueue, &priv->up); } -static void iwl4965_bg_rx_replenish(struct work_struct *data) +static void iwl_bg_rx_replenish(struct work_struct *data) { struct iwl_priv *priv = container_of(data, struct iwl_priv, rx_replenish); @@ -2463,11 +2233,10 @@ static void iwl4965_bg_rx_replenish(struct work_struct *data) #define IWL_DELAY_NEXT_SCAN (HZ*2) -static void iwl4965_post_associate(struct iwl_priv *priv) +static void iwl_post_associate(struct iwl_priv *priv) { struct ieee80211_conf *conf = NULL; int ret = 0; - DECLARE_MAC_BUF(mac); unsigned long flags; if (priv->iw_mode == NL80211_IFTYPE_AP) { @@ -2475,9 +2244,8 @@ static void iwl4965_post_associate(struct iwl_priv *priv) return; } - IWL_DEBUG_ASSOC("Associated as %d to: %s\n", - priv->assoc_id, - print_mac(mac, priv->active_rxon.bssid_addr)); + IWL_DEBUG_ASSOC("Associated as %d to: %pM\n", + priv->assoc_id, priv->active_rxon.bssid_addr); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) @@ -2493,10 +2261,9 @@ static void iwl4965_post_associate(struct iwl_priv *priv) conf = ieee80211_get_hw_conf(priv->hw); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); - memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); - iwl4965_setup_rxon_timing(priv); + iwl_setup_rxon_timing(priv); ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (ret) @@ -2529,7 +2296,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) } - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); switch (priv->iw_mode) { case NL80211_IFTYPE_STATION: @@ -2541,7 +2308,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) priv->assoc_id = 1; iwl_rxon_add_station(priv, priv->bssid, 0); - iwl4965_send_beacon_cmd(priv); + iwl_send_beacon_cmd(priv); break; @@ -2578,7 +2345,7 @@ static void iwl4965_post_associate(struct iwl_priv *priv) #define UCODE_READY_TIMEOUT (4 * HZ) -static int iwl4965_mac_start(struct ieee80211_hw *hw) +static int iwl_mac_start(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; int ret; @@ -2600,7 +2367,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); } - ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED, + ret = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED, DRV_NAME, priv); if (ret) { IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); @@ -2615,7 +2382,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) * ucode filename and max sizes are card-specific. */ if (!priv->ucode_code.len) { - ret = iwl4965_read_ucode(priv); + ret = iwl_read_ucode(priv); if (ret) { IWL_ERROR("Could not read microcode: %d\n", ret); mutex_unlock(&priv->mutex); @@ -2623,7 +2390,7 @@ static int iwl4965_mac_start(struct ieee80211_hw *hw) } } - ret = __iwl4965_up(priv); + ret = __iwl_up(priv); mutex_unlock(&priv->mutex); @@ -2669,7 +2436,7 @@ out_disable_msi: return ret; } -static void iwl4965_mac_stop(struct ieee80211_hw *hw) +static void iwl_mac_stop(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; @@ -2691,7 +2458,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) mutex_unlock(&priv->mutex); } - iwl4965_down(priv); + iwl_down(priv); flush_workqueue(priv->workqueue); free_irq(priv->pci_dev->irq, priv); @@ -2702,7 +2469,7 @@ static void iwl4965_mac_stop(struct ieee80211_hw *hw) IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) +static int iwl_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; @@ -2718,12 +2485,11 @@ static int iwl4965_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) return 0; } -static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, +static int iwl_mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct iwl_priv *priv = hw->priv; unsigned long flags; - DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); @@ -2734,17 +2500,18 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, spin_lock_irqsave(&priv->lock, flags); priv->vif = conf->vif; + priv->iw_mode = conf->type; spin_unlock_irqrestore(&priv->lock, flags); mutex_lock(&priv->mutex); if (conf->mac_addr) { - IWL_DEBUG_MAC80211("Set %s\n", print_mac(mac, conf->mac_addr)); + IWL_DEBUG_MAC80211("Set %pM\n", conf->mac_addr); memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } - if (iwl4965_set_mode(priv, conf->type) == -EAGAIN) + if (iwl_set_mode(priv, conf->type) == -EAGAIN) /* we are not ready, will run again when ready */ set_bit(STATUS_MODE_PENDING, &priv->status); @@ -2755,16 +2522,17 @@ static int iwl4965_mac_add_interface(struct ieee80211_hw *hw, } /** - * iwl4965_mac_config - mac80211 config callback + * iwl_mac_config - mac80211 config callback * * We ignore conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME since it seems to * be set inappropriately and the driver currently sets the hardware up to * use it whenever needed. */ -static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int iwl_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl_priv *priv = hw->priv; const struct iwl_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int ret = 0; u16 channel; @@ -2772,6 +2540,8 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter to channel %d\n", conf->channel->hw_value); + priv->current_ht_config.is_ht = conf->ht.enabled; + if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) { IWL_DEBUG_MAC80211("leave - RF-KILL - waiting for uCode\n"); goto out; @@ -2829,13 +2599,13 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co /* The list of supported rates and rate mask can be different * for each band; since the band may have changed, reset * the rate mask to what mac80211 lists */ - iwl4965_set_rate(priv); + iwl_set_rate(priv); spin_unlock_irqrestore(&priv->lock, flags); #ifdef IEEE80211_CONF_CHANNEL_SWITCH if (conf->flags & IEEE80211_CONF_CHANNEL_SWITCH) { - iwl4965_hw_channel_switch(priv, conf->channel); + iwl_hw_channel_switch(priv, conf->channel); goto out; } #endif @@ -2863,11 +2633,11 @@ static int iwl4965_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *co iwl_set_tx_power(priv, conf->power_level, false); - iwl4965_set_rate(priv); + iwl_set_rate(priv); if (memcmp(&priv->active_rxon, &priv->staging_rxon, sizeof(priv->staging_rxon))) - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); else IWL_DEBUG_INFO("No re-sending same RXON configuration.\n"); @@ -2878,7 +2648,7 @@ out: return ret; } -static void iwl4965_config_ap(struct iwl_priv *priv) +static void iwl_config_ap(struct iwl_priv *priv) { int ret = 0; unsigned long flags; @@ -2887,15 +2657,14 @@ static void iwl4965_config_ap(struct iwl_priv *priv) return; /* The following should be done only at AP bring up */ - if (!(iwl_is_associated(priv))) { + if (!iwl_is_associated(priv)) { /* RXON - unassoc (to set timing command) */ priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); /* RXON Timing */ - memset(&priv->rxon_timing, 0, sizeof(struct iwl4965_rxon_time_cmd)); - iwl4965_setup_rxon_timing(priv); + iwl_setup_rxon_timing(priv); ret = iwl_send_cmd_pdu(priv, REPLY_RXON_TIMING, sizeof(priv->rxon_timing), &priv->rxon_timing); if (ret) @@ -2928,29 +2697,25 @@ static void iwl4965_config_ap(struct iwl_priv *priv) } /* restore RXON assoc */ priv->staging_rxon.filter_flags |= RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); spin_lock_irqsave(&priv->lock, flags); iwl_activate_qos(priv, 1); spin_unlock_irqrestore(&priv->lock, flags); iwl_rxon_add_station(priv, iwl_bcast_addr, 0); } - iwl4965_send_beacon_cmd(priv); + iwl_send_beacon_cmd(priv); /* FIXME - we need to add code here to detect a totally new * configuration, reset the AP, unassoc, rxon timing, assoc, * clear sta table, add BCAST sta... */ } -/* temporary */ -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); -static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, +static int iwl_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - unsigned long flags; int rc; if (conf == NULL) @@ -2966,26 +2731,20 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) return -ENOMEM; - rc = iwl4965_mac_beacon_update(hw, beacon); + mutex_lock(&priv->mutex); + rc = iwl_mac_beacon_update(hw, beacon); + mutex_unlock(&priv->mutex); if (rc) return rc; } - if ((priv->iw_mode == NL80211_IFTYPE_AP) && - (!conf->ssid_len)) { - IWL_DEBUG_MAC80211 - ("Leaving in AP mode because HostAPD is not ready.\n"); - return 0; - } - if (!iwl_is_alive(priv)) return -EAGAIN; mutex_lock(&priv->mutex); if (conf->bssid) - IWL_DEBUG_MAC80211("bssid: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid); /* * very dubious code was here; the probe filtering flag is never set: @@ -2998,8 +2757,8 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211("bssid was set to: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid was set to: %pM\n", + conf->bssid); } if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -3030,9 +2789,9 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, memcpy(priv->bssid, conf->bssid, ETH_ALEN); if (priv->iw_mode == NL80211_IFTYPE_AP) - iwl4965_config_ap(priv); + iwl_config_ap(priv); else { - rc = iwl4965_commit_rxon(priv); + rc = iwl_commit_rxon(priv); if ((priv->iw_mode == NL80211_IFTYPE_STATION) && rc) iwl_rxon_add_station( priv, priv->active_rxon.bssid_addr, 1); @@ -3041,45 +2800,63 @@ static int iwl4965_mac_config_interface(struct ieee80211_hw *hw, } else { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } done: - spin_lock_irqsave(&priv->lock, flags); - if (!conf->ssid_len) - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - else - memcpy(priv->essid, conf->ssid, conf->ssid_len); - - priv->essid_len = conf->ssid_len; - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_MAC80211("leave\n"); mutex_unlock(&priv->mutex); return 0; } -static void iwl4965_configure_filter(struct ieee80211_hw *hw, +static void iwl_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags, unsigned int *total_flags, int mc_count, struct dev_addr_list *mc_list) { struct iwl_priv *priv = hw->priv; + __le32 *filter_flags = &priv->staging_rxon.filter_flags; - if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { - IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - NL80211_IFTYPE_MONITOR, - changed_flags, *total_flags); - /* queue work 'cuz mac80211 is holding a lock which - * prevents us from issuing (synchronous) f/w cmds */ - queue_work(priv->workqueue, &priv->set_monitor); + IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", + changed_flags, *total_flags); + + if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) { + if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) + *filter_flags |= RXON_FILTER_PROMISC_MSK; + else + *filter_flags &= ~RXON_FILTER_PROMISC_MSK; + } + if (changed_flags & FIF_ALLMULTI) { + if (*total_flags & FIF_ALLMULTI) + *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK; + else + *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK; + } + if (changed_flags & FIF_CONTROL) { + if (*total_flags & FIF_CONTROL) + *filter_flags |= RXON_FILTER_CTL2HOST_MSK; + else + *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK; } - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + *filter_flags |= RXON_FILTER_BCON_AWARE_MSK; + else + *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK; + } + + /* We avoid iwl_commit_rxon here to commit the new filter flags + * since mac80211 will call ieee80211_hw_config immediately. + * (mc_list is not supported at this time). Otherwise, we need to + * queue a background iwl_commit_rxon work. + */ + + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } -static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, +static void iwl_mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { struct iwl_priv *priv = hw->priv; @@ -3091,13 +2868,11 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, if (iwl_is_ready_rf(priv)) { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } if (priv->vif == conf->vif) { priv->vif = NULL; memset(priv->bssid, 0, ETH_ALEN); - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - priv->essid_len = 0; } mutex_unlock(&priv->mutex); @@ -3106,7 +2881,7 @@ static void iwl4965_mac_remove_interface(struct ieee80211_hw *hw, } #define IWL_DELAY_NEXT_SCAN_AFTER_ASSOC (HZ*6) -static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, +static void iwl_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_bss_conf *bss_conf, u32 changes) @@ -3133,8 +2908,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, } if (changes & BSS_CHANGED_HT) { - IWL_DEBUG_MAC80211("HT %d\n", bss_conf->assoc_ht); - iwl4965_ht_conf(priv, bss_conf); + iwl_ht_conf(priv, bss_conf); iwl_set_rxon_chain(priv); } @@ -3157,7 +2931,7 @@ static void iwl4965_bss_info_changed(struct ieee80211_hw *hw, priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN_AFTER_ASSOC; mutex_lock(&priv->mutex); - iwl4965_post_associate(priv); + iwl_post_associate(priv); mutex_unlock(&priv->mutex); } else { priv->assoc_id = 0; @@ -3187,12 +2961,6 @@ static int iwl_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t ssid_len) goto out_unlock; } - if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */ - ret = -EIO; - IWL_ERROR("ERROR: APs don't scan\n"); - goto out_unlock; - } - /* We don't schedule scan within next_scan_jiffies period. * Avoid scanning during possible EAPOL exchange, return * success immediately. @@ -3233,64 +3001,24 @@ out_unlock: return ret; } -static void iwl4965_mac_update_tkip_key(struct ieee80211_hw *hw, +static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw, struct ieee80211_key_conf *keyconf, const u8 *addr, u32 iv32, u16 *phase1key) { - struct iwl_priv *priv = hw->priv; - u8 sta_id = IWL_INVALID_STATION; - unsigned long flags; - __le16 key_flags = 0; - int i; - DECLARE_MAC_BUF(mac); + struct iwl_priv *priv = hw->priv; IWL_DEBUG_MAC80211("enter\n"); - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); - return; - } - - if (iwl_scan_cancel(priv)) { - /* cancel scan failed, just live w/ bad key and rely - briefly on SW decryption */ - return; - } - - key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); - key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); - key_flags &= ~STA_KEY_FLG_INVALID; - - if (sta_id == priv->hw_params.bcast_sta_id) - key_flags |= STA_KEY_MULTICAST_MSK; - - spin_lock_irqsave(&priv->sta_lock, flags); - - priv->stations[sta_id].sta.key.key_flags = key_flags; - priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; - - for (i = 0; i < 5; i++) - priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = - cpu_to_le16(phase1key[i]); - - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); - - spin_unlock_irqrestore(&priv->sta_lock, flags); + iwl_update_tkip_key(priv, keyconf, addr, iv32, phase1key); IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, +static int iwl_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, const u8 *local_addr, const u8 *addr, struct ieee80211_key_conf *key) { struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); int ret = 0; u8 sta_id = IWL_INVALID_STATION; u8 is_default_wep_key = 0; @@ -3308,8 +3036,8 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, sta_id = iwl_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); + IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", + addr); return -EINVAL; } @@ -3357,7 +3085,7 @@ static int iwl4965_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, return ret; } -static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, +static int iwl_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { struct iwl_priv *priv = hw->priv; @@ -3376,11 +3104,6 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } - if (!priv->qos_data.qos_enable) { - priv->qos_data.qos_active = 0; - IWL_DEBUG_MAC80211("leave - qos not enabled\n"); - return 0; - } q = AC_NUM - 1 - queue; spin_lock_irqsave(&priv->lock, flags); @@ -3405,15 +3128,14 @@ static int iwl4965_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } -static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, +static int iwl_mac_ampdu_action(struct ieee80211_hw *hw, enum ieee80211_ampdu_mlme_action action, struct ieee80211_sta *sta, u16 tid, u16 *ssn) { struct iwl_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - IWL_DEBUG_HT("A-MPDU action on addr %s tid %d\n", - print_mac(mac, sta->addr), tid); + IWL_DEBUG_HT("A-MPDU action on addr %pM tid %d\n", + sta->addr, tid); if (!(priv->cfg->sku & IWL_SKU_N)) return -EACCES; @@ -3421,10 +3143,10 @@ static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, switch (action) { case IEEE80211_AMPDU_RX_START: IWL_DEBUG_HT("start Rx\n"); - return iwl_rx_agg_start(priv, sta->addr, tid, *ssn); + return iwl_sta_rx_agg_start(priv, sta->addr, tid, *ssn); case IEEE80211_AMPDU_RX_STOP: IWL_DEBUG_HT("stop Rx\n"); - return iwl_rx_agg_stop(priv, sta->addr, tid); + return iwl_sta_rx_agg_stop(priv, sta->addr, tid); case IEEE80211_AMPDU_TX_START: IWL_DEBUG_HT("start Tx\n"); return iwl_tx_agg_start(priv, sta->addr, tid, ssn); @@ -3438,7 +3160,8 @@ static int iwl4965_mac_ampdu_action(struct ieee80211_hw *hw, } return 0; } -static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, + +static int iwl_mac_get_tx_stats(struct ieee80211_hw *hw, struct ieee80211_tx_queue_stats *stats) { struct iwl_priv *priv = hw->priv; @@ -3473,7 +3196,7 @@ static int iwl4965_mac_get_tx_stats(struct ieee80211_hw *hw, return 0; } -static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, +static int iwl_mac_get_stats(struct ieee80211_hw *hw, struct ieee80211_low_level_stats *stats) { struct iwl_priv *priv = hw->priv; @@ -3485,7 +3208,7 @@ static int iwl4965_mac_get_stats(struct ieee80211_hw *hw, return 0; } -static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) +static void iwl_mac_reset_tsf(struct ieee80211_hw *hw) { struct iwl_priv *priv = hw->priv; unsigned long flags; @@ -3529,7 +3252,7 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) if (priv->iw_mode != NL80211_IFTYPE_AP) { iwl_scan_cancel_timeout(priv, 100); priv->staging_rxon.filter_flags &= ~RXON_FILTER_ASSOC_MSK; - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } iwl_power_update_mode(priv, 0); @@ -3552,31 +3275,28 @@ static void iwl4965_mac_reset_tsf(struct ieee80211_hw *hw) return; } - iwl4965_set_rate(priv); + iwl_set_rate(priv); mutex_unlock(&priv->mutex); IWL_DEBUG_MAC80211("leave\n"); } -static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) +static int iwl_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb) { struct iwl_priv *priv = hw->priv; unsigned long flags; __le64 timestamp; - mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); if (!iwl_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); - mutex_unlock(&priv->mutex); return -EIO; } if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not IBSS\n"); - mutex_unlock(&priv->mutex); return -EIO; } @@ -3596,9 +3316,8 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk iwl_reset_qos(priv); - iwl4965_post_associate(priv); + iwl_post_associate(priv); - mutex_unlock(&priv->mutex); return 0; } @@ -3613,7 +3332,7 @@ static int iwl4965_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk /* * The following adds a new attribute to the sysfs representation - * of this device driver (i.e. a new file in /sys/bus/pci/drivers/iwl/) + * of this device driver (i.e. a new file in /sys/class/net/wlan0/device/) * used for controlling the debug level. * * See the level definitions in iwl for details. @@ -3699,7 +3418,11 @@ static ssize_t show_tx_power(struct device *d, struct device_attribute *attr, char *buf) { struct iwl_priv *priv = (struct iwl_priv *)d->driver_data; - return sprintf(buf, "%d\n", priv->tx_power_user_lmt); + + if (!iwl_is_ready_rf(priv)) + return sprintf(buf, "off\n"); + else + return sprintf(buf, "%d\n", priv->tx_power_user_lmt); } static ssize_t store_tx_power(struct device *d, @@ -3750,7 +3473,7 @@ static ssize_t store_flags(struct device *d, else { IWL_DEBUG_INFO("Commit rxon.flags = 0x%04X\n", flags); priv->staging_rxon.flags = cpu_to_le32(flags); - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -3791,7 +3514,7 @@ static ssize_t store_filter_flags(struct device *d, "0x%04X\n", filter_flags); priv->staging_rxon.filter_flags = cpu_to_le32(filter_flags); - iwl4965_commit_rxon(priv); + iwl_commit_rxon(priv); } } mutex_unlock(&priv->mutex); @@ -3802,79 +3525,6 @@ static ssize_t store_filter_flags(struct device *d, static DEVICE_ATTR(filter_flags, S_IWUSR | S_IRUGO, show_filter_flags, store_filter_flags); -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - -static ssize_t show_measurement(struct device *d, - struct device_attribute *attr, char *buf) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct iwl4965_spectrum_notification measure_report; - u32 size = sizeof(measure_report), len = 0, ofs = 0; - u8 *data = (u8 *)&measure_report; - unsigned long flags; - - spin_lock_irqsave(&priv->lock, flags); - if (!(priv->measurement_status & MEASUREMENT_READY)) { - spin_unlock_irqrestore(&priv->lock, flags); - return 0; - } - memcpy(&measure_report, &priv->measure_report, size); - priv->measurement_status = 0; - spin_unlock_irqrestore(&priv->lock, flags); - - while (size && (PAGE_SIZE - len)) { - hex_dump_to_buffer(data + ofs, size, 16, 1, buf + len, - PAGE_SIZE - len, 1); - len = strlen(buf); - if (PAGE_SIZE - len) - buf[len++] = '\n'; - - ofs += 16; - size -= min(size, 16U); - } - - return len; -} - -static ssize_t store_measurement(struct device *d, - struct device_attribute *attr, - const char *buf, size_t count) -{ - struct iwl_priv *priv = dev_get_drvdata(d); - struct ieee80211_measurement_params params = { - .channel = le16_to_cpu(priv->active_rxon.channel), - .start_time = cpu_to_le64(priv->last_tsf), - .duration = cpu_to_le16(1), - }; - u8 type = IWL_MEASURE_BASIC; - u8 buffer[32]; - u8 channel; - - if (count) { - char *p = buffer; - strncpy(buffer, buf, min(sizeof(buffer), count)); - channel = simple_strtoul(p, NULL, 0); - if (channel) - params.channel = channel; - - p = buffer; - while (*p && *p != ' ') - p++; - if (*p) - type = simple_strtoul(p + 1, NULL, 0); - } - - IWL_DEBUG_INFO("Invoking measurement of type %d on " - "channel %d (for '%s')\n", type, params.channel, buf); - iwl4965_get_measurement(priv, ¶ms, type); - - return count; -} - -static DEVICE_ATTR(measurement, S_IRUSR | S_IWUSR, - show_measurement, store_measurement); -#endif /* CONFIG_IWLAGN_SPECTRUM_MEASUREMENT */ - static ssize_t store_retry_rate(struct device *d, struct device_attribute *attr, const char *buf, size_t count) @@ -3953,7 +3603,8 @@ static ssize_t show_power_level(struct device *d, break; } - p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO)?"fixed":"auto"); + p += sprintf(p, "\tMODE:%s", (mode < IWL_POWER_AUTO) ? + "fixed" : "auto"); p += sprintf(p, "\tINDEX:%d", level); p += sprintf(p, "\n"); return p - buf + 1; @@ -3962,68 +3613,6 @@ static ssize_t show_power_level(struct device *d, static DEVICE_ATTR(power_level, S_IWUSR | S_IRUSR, show_power_level, store_power_level); -static ssize_t show_channels(struct device *d, - struct device_attribute *attr, char *buf) -{ - - struct iwl_priv *priv = dev_get_drvdata(d); - struct ieee80211_channel *channels = NULL; - const struct ieee80211_supported_band *supp_band = NULL; - int len = 0, i; - int count = 0; - - if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) - return -EAGAIN; - - supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); - channels = supp_band->channels; - count = supp_band->n_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", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); - - supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); - channels = supp_band->channels; - count = supp_band->n_channels; - - 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", - ieee80211_frequency_to_channel( - channels[i].center_freq), - channels[i].max_power, - channels[i].flags & IEEE80211_CHAN_RADAR ? - " (IEEE 802.11h required)" : "", - ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) - || (channels[i].flags & - IEEE80211_CHAN_RADAR)) ? "" : - ", IBSS", - channels[i].flags & - IEEE80211_CHAN_PASSIVE_SCAN ? - "passive only" : "active/passive"); - - return len; -} - -static DEVICE_ATTR(channels, S_IRUSR, show_channels, NULL); static ssize_t show_statistics(struct device *d, struct device_attribute *attr, char *buf) @@ -4086,12 +3675,11 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) init_waitqueue_head(&priv->wait_command_queue); - INIT_WORK(&priv->up, iwl4965_bg_up); - INIT_WORK(&priv->restart, iwl4965_bg_restart); - INIT_WORK(&priv->rx_replenish, iwl4965_bg_rx_replenish); - INIT_WORK(&priv->rf_kill, iwl4965_bg_rf_kill); - INIT_WORK(&priv->beacon_update, iwl4965_bg_beacon_update); - INIT_WORK(&priv->set_monitor, iwl4965_bg_set_monitor); + INIT_WORK(&priv->up, iwl_bg_up); + INIT_WORK(&priv->restart, iwl_bg_restart); + INIT_WORK(&priv->rx_replenish, iwl_bg_rx_replenish); + INIT_WORK(&priv->rf_kill, iwl_bg_rf_kill); + INIT_WORK(&priv->beacon_update, iwl_bg_beacon_update); INIT_WORK(&priv->run_time_calib_work, iwl_bg_run_time_calib_work); INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); @@ -4104,10 +3692,10 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv) init_timer(&priv->statistics_periodic); priv->statistics_periodic.data = (unsigned long)priv; - priv->statistics_periodic.function = iwl4965_bg_statistics_periodic; + priv->statistics_periodic.function = iwl_bg_statistics_periodic; tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) - iwl4965_irq_tasklet, (unsigned long)priv); + iwl_irq_tasklet, (unsigned long)priv); } static void iwl_cancel_deferred_work(struct iwl_priv *priv) @@ -4123,13 +3711,9 @@ static void iwl_cancel_deferred_work(struct iwl_priv *priv) del_timer_sync(&priv->statistics_periodic); } -static struct attribute *iwl4965_sysfs_entries[] = { - &dev_attr_channels.attr, +static struct attribute *iwl_sysfs_entries[] = { &dev_attr_flags.attr, &dev_attr_filter_flags.attr, -#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT - &dev_attr_measurement.attr, -#endif &dev_attr_power_level.attr, &dev_attr_retry_rate.attr, &dev_attr_statistics.attr, @@ -4144,39 +3728,38 @@ static struct attribute *iwl4965_sysfs_entries[] = { NULL }; -static struct attribute_group iwl4965_attribute_group = { +static struct attribute_group iwl_attribute_group = { .name = NULL, /* put in device directory */ - .attrs = iwl4965_sysfs_entries, + .attrs = iwl_sysfs_entries, }; -static struct ieee80211_ops iwl4965_hw_ops = { - .tx = iwl4965_mac_tx, - .start = iwl4965_mac_start, - .stop = iwl4965_mac_stop, - .add_interface = iwl4965_mac_add_interface, - .remove_interface = iwl4965_mac_remove_interface, - .config = iwl4965_mac_config, - .config_interface = iwl4965_mac_config_interface, - .configure_filter = iwl4965_configure_filter, - .set_key = iwl4965_mac_set_key, - .update_tkip_key = iwl4965_mac_update_tkip_key, - .get_stats = iwl4965_mac_get_stats, - .get_tx_stats = iwl4965_mac_get_tx_stats, - .conf_tx = iwl4965_mac_conf_tx, - .reset_tsf = iwl4965_mac_reset_tsf, - .bss_info_changed = iwl4965_bss_info_changed, - .ampdu_action = iwl4965_mac_ampdu_action, +static struct ieee80211_ops iwl_hw_ops = { + .tx = iwl_mac_tx, + .start = iwl_mac_start, + .stop = iwl_mac_stop, + .add_interface = iwl_mac_add_interface, + .remove_interface = iwl_mac_remove_interface, + .config = iwl_mac_config, + .config_interface = iwl_mac_config_interface, + .configure_filter = iwl_configure_filter, + .set_key = iwl_mac_set_key, + .update_tkip_key = iwl_mac_update_tkip_key, + .get_stats = iwl_mac_get_stats, + .get_tx_stats = iwl_mac_get_tx_stats, + .conf_tx = iwl_mac_conf_tx, + .reset_tsf = iwl_mac_reset_tsf, + .bss_info_changed = iwl_bss_info_changed, + .ampdu_action = iwl_mac_ampdu_action, .hw_scan = iwl_mac_hw_scan }; -static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) +static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { int err = 0; struct iwl_priv *priv; struct ieee80211_hw *hw; struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); unsigned long flags; - DECLARE_MAC_BUF(mac); /************************ * 1. Allocating HW data @@ -4188,10 +3771,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (cfg->mod_params->debug & IWL_DL_INFO) dev_printk(KERN_DEBUG, &(pdev->dev), "Disabling hw_scan\n"); - iwl4965_hw_ops.hw_scan = NULL; + iwl_hw_ops.hw_scan = NULL; } - hw = iwl_alloc_all(cfg, &iwl4965_hw_ops); + hw = iwl_alloc_all(cfg, &iwl_hw_ops); if (!hw) { err = -ENOMEM; goto out; @@ -4285,7 +3868,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e /* extract MAC Address */ iwl_eeprom_get_mac(priv, priv->mac_addr); - IWL_DEBUG_INFO("MAC address: %s\n", print_mac(mac, priv->mac_addr)); + IWL_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr); SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); /************************ @@ -4319,10 +3902,10 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e * 8. Setup services ********************/ spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); - err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); + err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group); if (err) { IWL_ERROR("failed to create sysfs device attributes\n"); goto out_uninit_drv; @@ -4358,7 +3941,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return 0; out_remove_sysfs: - sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); out_uninit_drv: iwl_uninit_drv(priv); out_free_eeprom: @@ -4376,7 +3959,7 @@ static int iwl4965_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return err; } -static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) +static void __devexit iwl_pci_remove(struct pci_dev *pdev) { struct iwl_priv *priv = pci_get_drvdata(pdev); unsigned long flags; @@ -4387,10 +3970,10 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) IWL_DEBUG_INFO("*** UNLOAD DRIVER ***\n"); iwl_dbgfs_unregister(priv); - sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); + sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group); - /* ieee80211_unregister_hw call wil cause iwl4965_mac_stop to - * to be called and iwl4965_down since we are removing the device + /* ieee80211_unregister_hw call wil cause iwl_mac_stop to + * to be called and iwl_down since we are removing the device * we need to set STATUS_EXIT_PENDING bit. */ set_bit(STATUS_EXIT_PENDING, &priv->status); @@ -4398,20 +3981,20 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) ieee80211_unregister_hw(priv->hw); priv->mac80211_registered = 0; } else { - iwl4965_down(priv); + iwl_down(priv); } /* make sure we flush any pending irq or * tasklet for the driver */ spin_lock_irqsave(&priv->lock, flags); - iwl4965_disable_interrupts(priv); + iwl_disable_interrupts(priv); spin_unlock_irqrestore(&priv->lock, flags); iwl_synchronize_irq(priv); iwl_rfkill_unregister(priv); - iwl4965_dealloc_ucode_pci(priv); + iwl_dealloc_ucode_pci(priv); if (priv->rxq.bd) iwl_rx_queue_free(priv, &priv->rxq); @@ -4424,7 +4007,7 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) /*netif_stop_queue(dev); */ flush_workqueue(priv->workqueue); - /* ieee80211_unregister_hw calls iwl4965_mac_stop, which flushes + /* ieee80211_unregister_hw calls iwl_mac_stop, which flushes * priv->workqueue... so we can't take down the workqueue * until now... */ destroy_workqueue(priv->workqueue); @@ -4445,13 +4028,13 @@ static void __devexit iwl4965_pci_remove(struct pci_dev *pdev) #ifdef CONFIG_PM -static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) +static int iwl_pci_suspend(struct pci_dev *pdev, pm_message_t state) { struct iwl_priv *priv = pci_get_drvdata(pdev); if (priv->is_open) { set_bit(STATUS_IN_SUSPEND, &priv->status); - iwl4965_mac_stop(priv->hw); + iwl_mac_stop(priv->hw); priv->is_open = 1; } @@ -4460,14 +4043,14 @@ static int iwl4965_pci_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -static int iwl4965_pci_resume(struct pci_dev *pdev) +static int iwl_pci_resume(struct pci_dev *pdev) { struct iwl_priv *priv = pci_get_drvdata(pdev); pci_set_power_state(pdev, PCI_D0); if (priv->is_open) - iwl4965_mac_start(priv->hw); + iwl_mac_start(priv->hw); clear_bit(STATUS_IN_SUSPEND, &priv->status); return 0; @@ -4502,7 +4085,11 @@ static struct pci_device_id iwl_hw_card_ids[] = { {IWL_PCI_DEVICE(0x423A, 0x1001, iwl5350_agn_cfg)}, {IWL_PCI_DEVICE(0x423A, 0x1021, iwl5350_agn_cfg)}, {IWL_PCI_DEVICE(0x423B, 0x1011, iwl5350_agn_cfg)}, +/* 5150 Wifi/WiMax */ + {IWL_PCI_DEVICE(0x423C, PCI_ANY_ID, iwl5150_agn_cfg)}, + {IWL_PCI_DEVICE(0x423D, PCI_ANY_ID, iwl5150_agn_cfg)}, #endif /* CONFIG_IWL5000 */ + {0} }; MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); @@ -4510,15 +4097,15 @@ MODULE_DEVICE_TABLE(pci, iwl_hw_card_ids); static struct pci_driver iwl_driver = { .name = DRV_NAME, .id_table = iwl_hw_card_ids, - .probe = iwl4965_pci_probe, - .remove = __devexit_p(iwl4965_pci_remove), + .probe = iwl_pci_probe, + .remove = __devexit_p(iwl_pci_remove), #ifdef CONFIG_PM - .suspend = iwl4965_pci_suspend, - .resume = iwl4965_pci_resume, + .suspend = iwl_pci_suspend, + .resume = iwl_pci_resume, #endif }; -static int __init iwl4965_init(void) +static int __init iwl_init(void) { int ret; @@ -4544,11 +4131,11 @@ error_register: return ret; } -static void __exit iwl4965_exit(void) +static void __exit iwl_exit(void) { pci_unregister_driver(&iwl_driver); iwlagn_rate_control_unregister(); } -module_exit(iwl4965_exit); -module_init(iwl4965_init); +module_exit(iwl_exit); +module_init(iwl_init); diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.c b/drivers/net/wireless/iwlwifi/iwl-calib.c index 72fbf47229db7da9832c3eb05a6c2722df651b7e..f836ecc55758a4d4ab12bf0a796fbd17b9ef2556 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.c +++ b/drivers/net/wireless/iwlwifi/iwl-calib.c @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -70,7 +70,16 @@ * INIT calibrations framework *****************************************************************************/ - int iwl_send_calib_results(struct iwl_priv *priv) +struct statistics_general_data { + u32 beacon_silence_rssi_a; + u32 beacon_silence_rssi_b; + u32 beacon_silence_rssi_c; + u32 beacon_energy_a; + u32 beacon_energy_b; + u32 beacon_energy_c; +}; + +int iwl_send_calib_results(struct iwl_priv *priv) { int ret = 0; int i = 0; @@ -80,14 +89,16 @@ .meta.flags = CMD_SIZE_HUGE, }; - for (i = 0; i < IWL_CALIB_MAX; i++) - if (priv->calib_results[i].buf) { + for (i = 0; i < IWL_CALIB_MAX; i++) { + if ((BIT(i) & priv->hw_params.calib_init_cfg) && + priv->calib_results[i].buf) { hcmd.len = priv->calib_results[i].buf_len; hcmd.data = priv->calib_results[i].buf; ret = iwl_send_cmd_sync(priv, &hcmd); if (ret) goto err; } + } return 0; err: diff --git a/drivers/net/wireless/iwlwifi/iwl-calib.h b/drivers/net/wireless/iwlwifi/iwl-calib.h index 94c8e316382a4a9140dae3ede569dc34b770d29d..1abe84bb74ad0bd022e3a7318160f3c2e31c8c21 100644 --- a/drivers/net/wireless/iwlwifi/iwl-calib.h +++ b/drivers/net/wireless/iwlwifi/iwl-calib.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE diff --git a/drivers/net/wireless/iwlwifi/iwl-commands.h b/drivers/net/wireless/iwlwifi/iwl-commands.h index 8d04e966ad48fe31bc3cad9fbc0d5e010895e54b..52966ffbef6ec6231bfbb18fc2228572faec23a6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-commands.h +++ b/drivers/net/wireless/iwlwifi/iwl-commands.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -66,8 +66,14 @@ * Please use iwl-dev.h for driver implementation definitions. */ -#ifndef __iwl4965_commands_h__ -#define __iwl4965_commands_h__ +#ifndef __iwl_commands_h__ +#define __iwl_commands_h__ + +/* uCode version contains 4 values: Major/Minor/API/Serial */ +#define IWL_UCODE_MAJOR(ver) (((ver) & 0xFF000000) >> 24) +#define IWL_UCODE_MINOR(ver) (((ver) & 0x00FF0000) >> 16) +#define IWL_UCODE_API(ver) (((ver) & 0x0000FF00) >> 8) +#define IWL_UCODE_SERIAL(ver) ((ver) & 0x000000FF) enum { REPLY_ALIVE = 0x1, @@ -88,6 +94,7 @@ enum { REPLY_WEPKEY = 0x20, /* RX, TX, LEDs */ + REPLY_3945_RX = 0x1b, /* 3945 only */ REPLY_TX = 0x1c, REPLY_RATE_SCALE = 0x47, /* 3945 only */ REPLY_LEDS_CMD = 0x48, @@ -98,6 +105,11 @@ enum { COEX_MEDIUM_NOTIFICATION = 0x5b, COEX_EVENT_CMD = 0x5c, + /* Calibration */ + CALIBRATION_CFG_CMD = 0x65, + CALIBRATION_RES_NOTIFICATION = 0x66, + CALIBRATION_COMPLETE_NOTIFICATION = 0x67, + /* 802.11h related */ RADAR_NOTIFICATION = 0x70, /* not used */ REPLY_QUIET_CMD = 0x71, /* not used */ @@ -129,7 +141,7 @@ enum { REPLY_TX_POWER_DBM_CMD = 0x98, MEASURE_ABORT_NOTIFICATION = 0x99, /* not used */ - /* Bluetooth device coexistance config command */ + /* Bluetooth device coexistence config command */ REPLY_BT_CONFIG = 0x9b, /* Statistics */ @@ -167,8 +179,8 @@ enum { #define QUEUE_TO_SEQ(q) (((q) & 0x1f) << 8) #define SEQ_TO_INDEX(s) ((s) & 0xff) #define INDEX_TO_SEQ(i) ((i) & 0xff) -#define SEQ_HUGE_FRAME __constant_cpu_to_le16(0x4000) -#define SEQ_RX_FRAME __constant_cpu_to_le16(0x8000) +#define SEQ_HUGE_FRAME cpu_to_le16(0x4000) +#define SEQ_RX_FRAME cpu_to_le16(0x8000) /** * struct iwl_cmd_header @@ -180,7 +192,7 @@ struct iwl_cmd_header { u8 cmd; /* Command ID: REPLY_RXON, etc. */ u8 flags; /* 0:5 reserved, 6 abort, 7 internal */ /* - * The driver sets up the sequence number to values of its chosing. + * The driver sets up the sequence number to values of its choosing. * uCode does not use this value, but passes it back to the driver * when sending the response to each driver-originated command, so * the driver can match the response to the command. Since the values @@ -208,10 +220,11 @@ struct iwl_cmd_header { } __attribute__ ((packed)); /** - * 4965 rate_n_flags bit fields + * iwlagn rate_n_flags bit fields * - * rate_n_flags format is used in following 4965 commands: + * rate_n_flags format is used in following iwlagn commands: * REPLY_RX (response only) + * REPLY_RX_MPDU (response only) * REPLY_TX (both command and response) * REPLY_TX_LINK_QUALITY_CMD * @@ -225,8 +238,9 @@ struct iwl_cmd_header { * 6) 54 Mbps * 7) 60 Mbps * - * 3: 0) Single stream (SISO) + * 4-3: 0) Single stream (SISO) * 1) Dual stream (MIMO) + * 2) Triple stream (MIMO) * * 5: Value of 0x20 in bits 7:0 indicates 6 Mbps FAT duplicate data * @@ -247,8 +261,8 @@ struct iwl_cmd_header { * 110) 11 Mbps */ #define RATE_MCS_CODE_MSK 0x7 -#define RATE_MCS_MIMO_POS 3 -#define RATE_MCS_MIMO_MSK 0x8 +#define RATE_MCS_SPATIAL_POS 3 +#define RATE_MCS_SPATIAL_MSK 0x18 #define RATE_MCS_HT_DUP_POS 5 #define RATE_MCS_HT_DUP_MSK 0x20 @@ -278,18 +292,20 @@ struct iwl_cmd_header { #define RATE_MCS_SGI_MSK 0x2000 /** - * rate_n_flags Tx antenna masks (4965 has 2 transmitters): - * bit14:15 01 B inactive, A active - * 10 B active, A inactive - * 11 Both active + * rate_n_flags Tx antenna masks + * 4965 has 2 transmitters + * 5100 has 1 transmitter B + * 5150 has 1 transmitter A + * 5300 has 3 transmitters + * 5350 has 3 transmitters + * bit14:16 */ #define RATE_MCS_ANT_POS 14 #define RATE_MCS_ANT_A_MSK 0x04000 #define RATE_MCS_ANT_B_MSK 0x08000 #define RATE_MCS_ANT_C_MSK 0x10000 #define RATE_MCS_ANT_ABC_MSK 0x1C000 - -#define RATE_MCS_ANT_INIT_IND 1 +#define RATE_ANT_NUM 3 #define POWER_TABLE_NUM_ENTRIES 33 #define POWER_TABLE_NUM_HT_OFDM_ENTRIES 32 @@ -340,7 +356,7 @@ struct iwl4965_tx_power_db { } __attribute__ ((packed)); /** - * Commad REPLY_TX_POWER_DBM_CMD = 0x98 + * Command REPLY_TX_POWER_DBM_CMD = 0x98 * struct iwl5000_tx_power_dbm_cmd */ #define IWL50_TX_POWER_AUTO 0x7f @@ -359,7 +375,7 @@ struct iwl5000_tx_power_dbm_cmd { * *****************************************************************************/ -#define UCODE_VALID_OK __constant_cpu_to_le32(0x1) +#define UCODE_VALID_OK cpu_to_le32(0x1) #define INITIALIZE_SUBTYPE (9) /* @@ -376,7 +392,7 @@ struct iwl5000_tx_power_dbm_cmd { * calculating txpower settings: * * 1) Power supply voltage indication. The voltage sensor outputs higher - * values for lower voltage, and vice versa. + * values for lower voltage, and vice verse. * * 2) Temperature measurement parameters, for each of two channel widths * (20 MHz and 40 MHz) supported by the radios. Temperature sensing @@ -477,11 +493,6 @@ struct iwl_alive_resp { } __attribute__ ((packed)); -union tsf { - u8 byte[8]; - __le16 word[4]; - __le32 dw[2]; -}; /* * REPLY_ERROR = 0x2 (response only, not a command) @@ -492,7 +503,7 @@ struct iwl_error_resp { u8 reserved1; __le16 bad_cmd_seq_num; __le32 error_info; - union tsf timestamp; + __le64 timestamp; } __attribute__ ((packed)); /****************************************************************************** @@ -513,75 +524,75 @@ enum { }; -#define RXON_RX_CHAIN_DRIVER_FORCE_MSK __constant_cpu_to_le16(0x1 << 0) -#define RXON_RX_CHAIN_VALID_MSK __constant_cpu_to_le16(0x7 << 1) +#define RXON_RX_CHAIN_DRIVER_FORCE_MSK cpu_to_le16(0x1 << 0) +#define RXON_RX_CHAIN_VALID_MSK cpu_to_le16(0x7 << 1) #define RXON_RX_CHAIN_VALID_POS (1) -#define RXON_RX_CHAIN_FORCE_SEL_MSK __constant_cpu_to_le16(0x7 << 4) +#define RXON_RX_CHAIN_FORCE_SEL_MSK cpu_to_le16(0x7 << 4) #define RXON_RX_CHAIN_FORCE_SEL_POS (4) -#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK __constant_cpu_to_le16(0x7 << 7) +#define RXON_RX_CHAIN_FORCE_MIMO_SEL_MSK cpu_to_le16(0x7 << 7) #define RXON_RX_CHAIN_FORCE_MIMO_SEL_POS (7) -#define RXON_RX_CHAIN_CNT_MSK __constant_cpu_to_le16(0x3 << 10) +#define RXON_RX_CHAIN_CNT_MSK cpu_to_le16(0x3 << 10) #define RXON_RX_CHAIN_CNT_POS (10) -#define RXON_RX_CHAIN_MIMO_CNT_MSK __constant_cpu_to_le16(0x3 << 12) +#define RXON_RX_CHAIN_MIMO_CNT_MSK cpu_to_le16(0x3 << 12) #define RXON_RX_CHAIN_MIMO_CNT_POS (12) -#define RXON_RX_CHAIN_MIMO_FORCE_MSK __constant_cpu_to_le16(0x1 << 14) +#define RXON_RX_CHAIN_MIMO_FORCE_MSK cpu_to_le16(0x1 << 14) #define RXON_RX_CHAIN_MIMO_FORCE_POS (14) /* rx_config flags */ /* band & modulation selection */ -#define RXON_FLG_BAND_24G_MSK __constant_cpu_to_le32(1 << 0) -#define RXON_FLG_CCK_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FLG_BAND_24G_MSK cpu_to_le32(1 << 0) +#define RXON_FLG_CCK_MSK cpu_to_le32(1 << 1) /* auto detection enable */ -#define RXON_FLG_AUTO_DETECT_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FLG_AUTO_DETECT_MSK cpu_to_le32(1 << 2) /* TGg protection when tx */ -#define RXON_FLG_TGG_PROTECT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FLG_TGG_PROTECT_MSK cpu_to_le32(1 << 3) /* cck short slot & preamble */ -#define RXON_FLG_SHORT_SLOT_MSK __constant_cpu_to_le32(1 << 4) -#define RXON_FLG_SHORT_PREAMBLE_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FLG_SHORT_SLOT_MSK cpu_to_le32(1 << 4) +#define RXON_FLG_SHORT_PREAMBLE_MSK cpu_to_le32(1 << 5) /* antenna selection */ -#define RXON_FLG_DIS_DIV_MSK __constant_cpu_to_le32(1 << 7) -#define RXON_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0x0f00) -#define RXON_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define RXON_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define RXON_FLG_DIS_DIV_MSK cpu_to_le32(1 << 7) +#define RXON_FLG_ANT_SEL_MSK cpu_to_le32(0x0f00) +#define RXON_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define RXON_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* radar detection enable */ -#define RXON_FLG_RADAR_DETECT_MSK __constant_cpu_to_le32(1 << 12) -#define RXON_FLG_TGJ_NARROW_BAND_MSK __constant_cpu_to_le32(1 << 13) +#define RXON_FLG_RADAR_DETECT_MSK cpu_to_le32(1 << 12) +#define RXON_FLG_TGJ_NARROW_BAND_MSK cpu_to_le32(1 << 13) /* rx response to host with 8-byte TSF * (according to ON_AIR deassertion) */ -#define RXON_FLG_TSF2HOST_MSK __constant_cpu_to_le32(1 << 15) +#define RXON_FLG_TSF2HOST_MSK cpu_to_le32(1 << 15) /* HT flags */ #define RXON_FLG_CTRL_CHANNEL_LOC_POS (22) -#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK __constant_cpu_to_le32(0x1 << 22) +#define RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK cpu_to_le32(0x1 << 22) #define RXON_FLG_HT_OPERATING_MODE_POS (23) -#define RXON_FLG_HT_PROT_MSK __constant_cpu_to_le32(0x1 << 23) -#define RXON_FLG_FAT_PROT_MSK __constant_cpu_to_le32(0x2 << 23) +#define RXON_FLG_HT_PROT_MSK cpu_to_le32(0x1 << 23) +#define RXON_FLG_FAT_PROT_MSK cpu_to_le32(0x2 << 23) #define RXON_FLG_CHANNEL_MODE_POS (25) -#define RXON_FLG_CHANNEL_MODE_MSK __constant_cpu_to_le32(0x3 << 25) -#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK __constant_cpu_to_le32(0x1 << 25) -#define RXON_FLG_CHANNEL_MODE_MIXED_MSK __constant_cpu_to_le32(0x2 << 25) +#define RXON_FLG_CHANNEL_MODE_MSK cpu_to_le32(0x3 << 25) +#define RXON_FLG_CHANNEL_MODE_PURE_40_MSK cpu_to_le32(0x1 << 25) +#define RXON_FLG_CHANNEL_MODE_MIXED_MSK cpu_to_le32(0x2 << 25) /* CTS to self (if spec allows) flag */ -#define RXON_FLG_SELF_CTS_EN __constant_cpu_to_le32(0x1<<30) +#define RXON_FLG_SELF_CTS_EN cpu_to_le32(0x1<<30) /* rx_config filter flags */ /* accept all data frames */ -#define RXON_FILTER_PROMISC_MSK __constant_cpu_to_le32(1 << 0) +#define RXON_FILTER_PROMISC_MSK cpu_to_le32(1 << 0) /* pass control & management to host */ -#define RXON_FILTER_CTL2HOST_MSK __constant_cpu_to_le32(1 << 1) +#define RXON_FILTER_CTL2HOST_MSK cpu_to_le32(1 << 1) /* accept multi-cast */ -#define RXON_FILTER_ACCEPT_GRP_MSK __constant_cpu_to_le32(1 << 2) +#define RXON_FILTER_ACCEPT_GRP_MSK cpu_to_le32(1 << 2) /* don't decrypt uni-cast frames */ -#define RXON_FILTER_DIS_DECRYPT_MSK __constant_cpu_to_le32(1 << 3) +#define RXON_FILTER_DIS_DECRYPT_MSK cpu_to_le32(1 << 3) /* don't decrypt multi-cast frames */ -#define RXON_FILTER_DIS_GRP_DECRYPT_MSK __constant_cpu_to_le32(1 << 4) +#define RXON_FILTER_DIS_GRP_DECRYPT_MSK cpu_to_le32(1 << 4) /* STA is associated */ -#define RXON_FILTER_ASSOC_MSK __constant_cpu_to_le32(1 << 5) +#define RXON_FILTER_ASSOC_MSK cpu_to_le32(1 << 5) /* transfer to host non bssid beacons in associated state */ -#define RXON_FILTER_BCON_AWARE_MSK __constant_cpu_to_le32(1 << 6) +#define RXON_FILTER_BCON_AWARE_MSK cpu_to_le32(1 << 6) /** * REPLY_RXON = 0x10 (command, has simple generic response) @@ -620,7 +631,7 @@ struct iwl4965_rxon_cmd { u8 ofdm_ht_dual_stream_basic_rates; } __attribute__ ((packed)); -/* 5000 HW just extend this cmmand */ +/* 5000 HW just extend this command */ struct iwl_rxon_cmd { u8 node_addr[6]; __le16 reserved1; @@ -679,8 +690,8 @@ struct iwl4965_rxon_assoc_cmd { /* * REPLY_RXON_TIMING = 0x14 (command, has simple generic response) */ -struct iwl4965_rxon_time_cmd { - union tsf timestamp; +struct iwl_rxon_time_cmd { + __le64 timestamp; __le16 beacon_interval; __le16 atim_window; __le32 beacon_init_val; @@ -691,7 +702,7 @@ struct iwl4965_rxon_time_cmd { /* * REPLY_CHANNEL_SWITCH = 0x72 (command, has simple generic response) */ -struct iwl4965_channel_switch_cmd { +struct iwl_channel_switch_cmd { u8 band; u8 expect_beacon; __le16 channel; @@ -704,7 +715,7 @@ struct iwl4965_channel_switch_cmd { /* * CHANNEL_SWITCH_NOTIFICATION = 0x73 (notification only, not a command) */ -struct iwl4965_csa_notification { +struct iwl_csa_notification { __le16 band; __le16 channel; __le32 status; /* 0 - OK, 1 - fail */ @@ -741,9 +752,9 @@ struct iwl_ac_qos { } __attribute__ ((packed)); /* QoS flags defines */ -#define QOS_PARAM_FLG_UPDATE_EDCA_MSK __constant_cpu_to_le32(0x01) -#define QOS_PARAM_FLG_TGN_MSK __constant_cpu_to_le32(0x02) -#define QOS_PARAM_FLG_TXOP_TYPE_MSK __constant_cpu_to_le32(0x10) +#define QOS_PARAM_FLG_UPDATE_EDCA_MSK cpu_to_le32(0x01) +#define QOS_PARAM_FLG_TGN_MSK cpu_to_le32(0x02) +#define QOS_PARAM_FLG_TXOP_TYPE_MSK cpu_to_le32(0x10) /* Number of Access Categories (AC) (EDCA), queues 0..3 */ #define AC_NUM 4 @@ -780,34 +791,34 @@ struct iwl_qosparam_cmd { #define IWL_STATION_COUNT 32 /* MAX(3945,4965)*/ #define IWL_INVALID_STATION 255 -#define STA_FLG_PWR_SAVE_MSK __constant_cpu_to_le32(1 << 8); -#define STA_FLG_RTS_MIMO_PROT_MSK __constant_cpu_to_le32(1 << 17) -#define STA_FLG_AGG_MPDU_8US_MSK __constant_cpu_to_le32(1 << 18) +#define STA_FLG_PWR_SAVE_MSK cpu_to_le32(1 << 8); +#define STA_FLG_RTS_MIMO_PROT_MSK cpu_to_le32(1 << 17) +#define STA_FLG_AGG_MPDU_8US_MSK cpu_to_le32(1 << 18) #define STA_FLG_MAX_AGG_SIZE_POS (19) -#define STA_FLG_MAX_AGG_SIZE_MSK __constant_cpu_to_le32(3 << 19) -#define STA_FLG_FAT_EN_MSK __constant_cpu_to_le32(1 << 21) -#define STA_FLG_MIMO_DIS_MSK __constant_cpu_to_le32(1 << 22) +#define STA_FLG_MAX_AGG_SIZE_MSK cpu_to_le32(3 << 19) +#define STA_FLG_FAT_EN_MSK cpu_to_le32(1 << 21) +#define STA_FLG_MIMO_DIS_MSK cpu_to_le32(1 << 22) #define STA_FLG_AGG_MPDU_DENSITY_POS (23) -#define STA_FLG_AGG_MPDU_DENSITY_MSK __constant_cpu_to_le32(7 << 23) +#define STA_FLG_AGG_MPDU_DENSITY_MSK cpu_to_le32(7 << 23) /* Use in mode field. 1: modify existing entry, 0: add new station entry */ #define STA_CONTROL_MODIFY_MSK 0x01 /* key flags __le16*/ -#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_ENCRYPT_MSK cpu_to_le16(0x0007) +#define STA_KEY_FLG_NO_ENC cpu_to_le16(0x0000) +#define STA_KEY_FLG_WEP cpu_to_le16(0x0001) +#define STA_KEY_FLG_CCMP cpu_to_le16(0x0002) +#define STA_KEY_FLG_TKIP cpu_to_le16(0x0003) #define STA_KEY_FLG_KEYID_POS 8 -#define STA_KEY_FLG_INVALID __constant_cpu_to_le16(0x0800) +#define STA_KEY_FLG_INVALID 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) +#define STA_KEY_FLG_MAP_KEY_MSK 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) +#define STA_KEY_FLG_KEY_SIZE_MSK cpu_to_le16(0x1000) +#define STA_KEY_MULTICAST_MSK cpu_to_le16(0x4000) #define STA_KEY_MAX_NUM 8 /* Flags indicate whether to modify vs. don't change various station params */ @@ -1013,33 +1024,14 @@ struct iwl_wep_cmd { * *****************************************************************************/ -struct iwl4965_rx_frame_stats { - u8 phy_count; - u8 id; - u8 rssi; - u8 agc; - __le16 sig_avg; - __le16 noise_diff; - u8 payload[0]; -} __attribute__ ((packed)); - -struct iwl4965_rx_frame_hdr { - __le16 channel; - __le16 phy_flags; - u8 reserved1; - u8 rate; - __le16 len; - 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 cpu_to_le32(1 << 0) +#define RX_RES_STATUS_NO_RXE_OVERFLOW 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 cpu_to_le16(1 << 0) +#define RX_RES_PHY_FLAGS_MOD_CCK_MSK cpu_to_le16(1 << 1) +#define RX_RES_PHY_FLAGS_SHORT_PREAMBLE_MSK cpu_to_le16(1 << 2) +#define RX_RES_PHY_FLAGS_NARROW_BAND_MSK cpu_to_le16(1 << 3) +#define RX_RES_PHY_FLAGS_ANTENNA_MSK cpu_to_le16(0xf0) #define RX_RES_STATUS_SEC_TYPE_MSK (0x7 << 8) #define RX_RES_STATUS_SEC_TYPE_NONE (0x0 << 8) @@ -1062,26 +1054,6 @@ struct iwl4965_rx_frame_hdr { #define RX_MPDU_RES_STATUS_TTAK_OK (1 << 7) #define RX_MPDU_RES_STATUS_DEC_DONE_MSK (0x800) -struct iwl4965_rx_frame_end { - __le32 status; - __le64 timestamp; - __le32 beacon_timestamp; -} __attribute__ ((packed)); - -/* - * REPLY_3945_RX = 0x1b (response only, not a command) - * - * NOTE: DO NOT dereference from casts to this structure - * It is provided only for calculating minimum data set size. - * The actual offsets of the hdr and end are dynamic based on - * stats.phy_count - */ -struct iwl4965_rx_frame { - struct iwl4965_rx_frame_stats stats; - struct iwl4965_rx_frame_hdr hdr; - struct iwl4965_rx_frame_end end; -} __attribute__ ((packed)); - /* Fixed (non-configurable) rx data from phy */ #define IWL49_RX_RES_PHY_CNT 14 @@ -1111,7 +1083,7 @@ struct iwl4965_rx_non_cfg_phy { #define IWL50_OFDM_RSSI_C_BIT_POS 0 struct iwl5000_non_cfg_phy { - __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* upto 8 phy entries */ + __le32 non_cfg_phy[IWL50_RX_RES_PHY_CNT]; /* up to 8 phy entries */ } __attribute__ ((packed)); @@ -1167,24 +1139,24 @@ struct iwl4965_rx_mpdu_res_start { /* REPLY_TX Tx flags field */ -/* 1: Use RTS/CTS protocol or CTS-to-self if spec alows it +/* 1: Use RTS/CTS protocol or CTS-to-self if spec allows it * before this frame. if CTS-to-self required check * RXON_FLG_SELF_CTS_EN status. */ -#define TX_CMD_FLG_RTS_CTS_MSK __constant_cpu_to_le32(1 << 0) +#define TX_CMD_FLG_RTS_CTS_MSK cpu_to_le32(1 << 0) /* 1: Use Request-To-Send protocol before this frame. * Mutually exclusive vs. TX_CMD_FLG_CTS_MSK. */ -#define TX_CMD_FLG_RTS_MSK __constant_cpu_to_le32(1 << 1) +#define TX_CMD_FLG_RTS_MSK cpu_to_le32(1 << 1) /* 1: Transmit Clear-To-Send to self before this frame. * Driver should set this for AUTH/DEAUTH/ASSOC-REQ/REASSOC mgmnt frames. * Mutually exclusive vs. TX_CMD_FLG_RTS_MSK. */ -#define TX_CMD_FLG_CTS_MSK __constant_cpu_to_le32(1 << 2) +#define TX_CMD_FLG_CTS_MSK cpu_to_le32(1 << 2) /* 1: Expect ACK from receiving station * 0: Don't expect ACK (MAC header's duration field s/b 0) * Set this for unicast frames, but not broadcast/multicast. */ -#define TX_CMD_FLG_ACK_MSK __constant_cpu_to_le32(1 << 3) +#define TX_CMD_FLG_ACK_MSK cpu_to_le32(1 << 3) /* For 4965: * 1: Use rate scale table (see REPLY_TX_LINK_QUALITY_CMD). @@ -1192,40 +1164,40 @@ struct iwl4965_rx_mpdu_res_start { * uCode walks through table for additional Tx attempts. * 0: Use Tx rate/MCS from Tx command's rate_n_flags field. * This rate will be used for all Tx attempts; it will not be scaled. */ -#define TX_CMD_FLG_STA_RATE_MSK __constant_cpu_to_le32(1 << 4) +#define TX_CMD_FLG_STA_RATE_MSK cpu_to_le32(1 << 4) /* 1: Expect immediate block-ack. * Set when Txing a block-ack request frame. Also set TX_CMD_FLG_ACK_MSK. */ -#define TX_CMD_FLG_IMM_BA_RSP_MASK __constant_cpu_to_le32(1 << 6) +#define TX_CMD_FLG_IMM_BA_RSP_MASK cpu_to_le32(1 << 6) /* 1: Frame requires full Tx-Op protection. * Set this if either RTS or CTS Tx Flag gets set. */ -#define TX_CMD_FLG_FULL_TXOP_PROT_MSK __constant_cpu_to_le32(1 << 7) +#define TX_CMD_FLG_FULL_TXOP_PROT_MSK cpu_to_le32(1 << 7) /* Tx antenna selection field; used only for 3945, reserved (0) for 4965. * Set field to "0" to allow 3945 uCode to select antenna (normal usage). */ -#define TX_CMD_FLG_ANT_SEL_MSK __constant_cpu_to_le32(0xf00) -#define TX_CMD_FLG_ANT_A_MSK __constant_cpu_to_le32(1 << 8) -#define TX_CMD_FLG_ANT_B_MSK __constant_cpu_to_le32(1 << 9) +#define TX_CMD_FLG_ANT_SEL_MSK cpu_to_le32(0xf00) +#define TX_CMD_FLG_ANT_A_MSK cpu_to_le32(1 << 8) +#define TX_CMD_FLG_ANT_B_MSK cpu_to_le32(1 << 9) /* 1: Ignore Bluetooth priority for this frame. * 0: Delay Tx until Bluetooth device is done (normal usage). */ -#define TX_CMD_FLG_BT_DIS_MSK __constant_cpu_to_le32(1 << 12) +#define TX_CMD_FLG_BT_DIS_MSK cpu_to_le32(1 << 12) /* 1: uCode overrides sequence control field in MAC header. * 0: Driver provides sequence control field in MAC header. * Set this for management frames, non-QOS data frames, non-unicast frames, * and also in Tx command embedded in REPLY_SCAN_CMD for active scans. */ -#define TX_CMD_FLG_SEQ_CTL_MSK __constant_cpu_to_le32(1 << 13) +#define TX_CMD_FLG_SEQ_CTL_MSK cpu_to_le32(1 << 13) /* 1: This frame is non-last MPDU; more fragments are coming. * 0: Last fragment, or not using fragmentation. */ -#define TX_CMD_FLG_MORE_FRAG_MSK __constant_cpu_to_le32(1 << 14) +#define TX_CMD_FLG_MORE_FRAG_MSK cpu_to_le32(1 << 14) /* 1: uCode calculates and inserts Timestamp Function (TSF) in outgoing frame. * 0: No TSF required in outgoing frame. * Set this for transmitting beacons and probe responses. */ -#define TX_CMD_FLG_TSF_MSK __constant_cpu_to_le32(1 << 16) +#define TX_CMD_FLG_TSF_MSK cpu_to_le32(1 << 16) /* 1: Driver inserted 2 bytes pad after the MAC header, for (required) dword * alignment of frame's payload data field. @@ -1233,14 +1205,14 @@ struct iwl4965_rx_mpdu_res_start { * Set this for MAC headers with 26 or 30 bytes, i.e. those with QOS or ADDR4 * field (but not both). Driver must align frame data (i.e. data following * MAC header) to DWORD boundary. */ -#define TX_CMD_FLG_MH_PAD_MSK __constant_cpu_to_le32(1 << 20) +#define TX_CMD_FLG_MH_PAD_MSK cpu_to_le32(1 << 20) /* accelerate aggregation support * 0 - no CCMP encryption; 1 - CCMP encryption */ -#define TX_CMD_FLG_AGG_CCMP_MSK __constant_cpu_to_le32(1 << 22) +#define TX_CMD_FLG_AGG_CCMP_MSK cpu_to_le32(1 << 22) /* HCCA-AP - disable duration overwriting. */ -#define TX_CMD_FLG_DUR_MSK __constant_cpu_to_le32(1 << 25) +#define TX_CMD_FLG_DUR_MSK cpu_to_le32(1 << 25) /* @@ -1266,7 +1238,7 @@ struct iwl4965_rx_mpdu_res_start { * Used for managing Tx retries when expecting block-acks. * Driver should set these fields to 0. */ -struct iwl4965_dram_scratch { +struct iwl_dram_scratch { u8 try_cnt; /* Tx attempts */ u8 bt_kill_cnt; /* Tx attempts blocked by Bluetooth device */ __le16 reserved; @@ -1297,9 +1269,9 @@ struct iwl_tx_cmd { __le32 tx_flags; /* TX_CMD_FLG_* */ - /* 4965's uCode may modify this field of the Tx command (in host DRAM!). + /* uCode may modify this field of the Tx command (in host DRAM!). * Driver must also set dram_lsb_ptr and dram_msb_ptr in this cmd. */ - struct iwl4965_dram_scratch scratch; + struct iwl_dram_scratch scratch; /* Rate for *all* Tx attempts, if TX_CMD_FLG_STA_RATE_MSK is cleared. */ __le32 rate_n_flags; /* RATE_MCS_* */ @@ -1411,21 +1383,21 @@ enum { }; enum { - TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */ + TX_STATUS_MSK = 0x000000ff, /* bits 0:7 */ TX_STATUS_DELAY_MSK = 0x00000040, TX_STATUS_ABORT_MSK = 0x00000080, TX_PACKET_MODE_MSK = 0x0000ff00, /* bits 8:15 */ TX_FIFO_NUMBER_MSK = 0x00070000, /* bits 16:18 */ - TX_RESERVED = 0x00780000, /* bits 19:22 */ + TX_RESERVED = 0x00780000, /* bits 19:22 */ TX_POWER_PA_DETECT_MSK = 0x7f800000, /* bits 23:30 */ TX_ABORT_REQUIRED_MSK = 0x80000000, /* bits 31:31 */ }; -static inline int iwl_is_tx_success(u32 status) +static inline bool iwl_is_tx_success(u32 status) { status &= TX_STATUS_MSK; - return (status == TX_STATUS_SUCCESS) - || (status == TX_STATUS_DIRECT_DONE); + return (status == TX_STATUS_SUCCESS) || + (status == TX_STATUS_DIRECT_DONE); } @@ -1450,10 +1422,9 @@ enum { AGG_TX_STATE_DELAY_TX_MSK = 0x400 }; -#define AGG_TX_STATE_LAST_SENT_MSK \ -(AGG_TX_STATE_LAST_SENT_TTL_MSK | \ - AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ - AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) +#define AGG_TX_STATE_LAST_SENT_MSK (AGG_TX_STATE_LAST_SENT_TTL_MSK | \ + AGG_TX_STATE_LAST_SENT_TRY_CNT_MSK | \ + AGG_TX_STATE_LAST_SENT_BT_KILL_MSK) /* # tx attempts for first frame in aggregation */ #define AGG_TX_STATE_TRY_CNT_POS 12 @@ -1526,6 +1497,28 @@ struct iwl4965_tx_resp { } u; } __attribute__ ((packed)); +/* + * definitions for initial rate index field + * bits [3:0] initial rate index + * bits [6:4] rate table color, used for the initial rate + * bit-7 invalid rate indication + * i.e. rate was not chosen from rate table + * or rate table color was changed during frame retries + * refer tlc rate info + */ + +#define IWL50_TX_RES_INIT_RATE_INDEX_POS 0 +#define IWL50_TX_RES_INIT_RATE_INDEX_MSK 0x0f +#define IWL50_TX_RES_RATE_TABLE_COLOR_POS 4 +#define IWL50_TX_RES_RATE_TABLE_COLOR_MSK 0x70 +#define IWL50_TX_RES_INV_RATE_INDEX_MSK 0x80 + +/* refer to ra_tid */ +#define IWL50_TX_RES_TID_POS 0 +#define IWL50_TX_RES_TID_MSK 0x0f +#define IWL50_TX_RES_RA_POS 4 +#define IWL50_TX_RES_RA_MSK 0xf0 + struct iwl5000_tx_resp { u8 frame_count; /* 1 no aggregation, >1 aggregation */ u8 bt_kill_count; /* # blocked by bluetooth (unused for agg) */ @@ -1540,14 +1533,17 @@ struct iwl5000_tx_resp { * For agg: RTS + CTS + aggregation tx time + block-ack time. */ __le16 wireless_media_time; /* uSecs */ - __le16 reserved; - __le32 pa_power1; /* RF power amplifier measurement (not used) */ - __le32 pa_power2; + u8 pa_status; /* RF power amplifier measurement (not used) */ + u8 pa_integ_res_a[3]; + u8 pa_integ_res_b[3]; + u8 pa_integ_res_C[3]; __le32 tfd_info; __le16 seq_ctl; __le16 byte_cnt; - __le32 tlc_info; + u8 tlc_info; + u8 ra_tid; /* tid (0:3), sta_id (4:7) */ + __le16 frame_ctrl; /* * For non-agg: frame status TX_STATUS_* * For agg: status of 1st frame, AGG_TX_STATE_*; other frame status @@ -1742,7 +1738,7 @@ struct iwl_link_qual_agg_params { * match the modulation characteristics of the history set. * * When using block-ack (aggregation), all frames are transmitted at the same - * rate, since there is no per-attempt acknowledgement from the destination + * rate, since there is no per-attempt acknowledgment from the destination * station. The Tx response struct iwl_tx_resp indicates the Tx rate in * rate_n_flags field. After receiving a block-ack, the driver can update * history for the entire block all at once. @@ -1881,9 +1877,9 @@ struct iwl_link_quality_cmd { * * 3945 and 4965 support hardware handshake with Bluetooth device on * same platform. Bluetooth device alerts wireless device when it will Tx; - * wireless device can delay or kill its own Tx to accomodate. + * wireless device can delay or kill its own Tx to accommodate. */ -struct iwl4965_bt_cmd { +struct iwl_bt_cmd { u8 flags; u8 lead_time; u8 max_kill; @@ -1909,18 +1905,18 @@ struct iwl4965_bt_cmd { RXON_FILTER_ASSOC_MSK | \ RXON_FILTER_BCON_AWARE_MSK) -struct iwl4965_measure_channel { +struct iwl_measure_channel { __le32 duration; /* measurement duration in extended beacon * format */ u8 channel; /* channel to measure */ - u8 type; /* see enum iwl4965_measure_type */ + u8 type; /* see enum iwl_measure_type */ __le16 reserved; } __attribute__ ((packed)); /* * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (command) */ -struct iwl4965_spectrum_cmd { +struct iwl_spectrum_cmd { __le16 len; /* number of bytes starting from token */ u8 token; /* token id */ u8 id; /* measurement id -- 0 or 1 */ @@ -1933,13 +1929,13 @@ struct iwl4965_spectrum_cmd { __le32 filter_flags; /* rxon filter flags */ __le16 channel_count; /* minimum 1, maximum 10 */ __le16 reserved3; - struct iwl4965_measure_channel channels[10]; + struct iwl_measure_channel channels[10]; } __attribute__ ((packed)); /* * REPLY_SPECTRUM_MEASUREMENT_CMD = 0x74 (response) */ -struct iwl4965_spectrum_resp { +struct iwl_spectrum_resp { u8 token; u8 id; /* id of the prior command replaced, or 0xff */ __le16 status; /* 0 - command will be handled @@ -1947,12 +1943,12 @@ struct iwl4965_spectrum_resp { * measurement) */ } __attribute__ ((packed)); -enum iwl4965_measurement_state { +enum iwl_measurement_state { IWL_MEASUREMENT_START = 0, IWL_MEASUREMENT_STOP = 1, }; -enum iwl4965_measurement_status { +enum iwl_measurement_status { IWL_MEASUREMENT_OK = 0, IWL_MEASUREMENT_CONCURRENT = 1, IWL_MEASUREMENT_CSA_CONFLICT = 2, @@ -1965,18 +1961,18 @@ enum iwl4965_measurement_status { #define NUM_ELEMENTS_IN_HISTOGRAM 8 -struct iwl4965_measurement_histogram { +struct iwl_measurement_histogram { __le32 ofdm[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 0.8usec counts */ __le32 cck[NUM_ELEMENTS_IN_HISTOGRAM]; /* in 1usec counts */ } __attribute__ ((packed)); /* clear channel availability counters */ -struct iwl4965_measurement_cca_counters { +struct iwl_measurement_cca_counters { __le32 ofdm; __le32 cck; } __attribute__ ((packed)); -enum iwl4965_measure_type { +enum iwl_measure_type { IWL_MEASURE_BASIC = (1 << 0), IWL_MEASURE_CHANNEL_LOAD = (1 << 1), IWL_MEASURE_HISTOGRAM_RPI = (1 << 2), @@ -1989,7 +1985,7 @@ enum iwl4965_measure_type { /* * SPECTRUM_MEASURE_NOTIFICATION = 0x75 (notification only, not a command) */ -struct iwl4965_spectrum_notification { +struct iwl_spectrum_notification { u8 id; /* measurement id -- 0 or 1 */ u8 token; u8 channel_index; /* index in measurement channel list */ @@ -1997,7 +1993,7 @@ struct iwl4965_spectrum_notification { __le32 start_time; /* lower 32-bits of TSF */ u8 band; /* 0 - 5.2GHz, 1 - 2.4GHz */ u8 channel; - u8 type; /* see enum iwl4965_measurement_type */ + u8 type; /* see enum iwl_measurement_type */ u8 reserved1; /* NOTE: cca_ofdm, cca_cck, basic_type, and histogram are only only * valid if applicable for measurement type requested. */ @@ -2007,9 +2003,9 @@ struct iwl4965_spectrum_notification { u8 basic_type; /* 0 - bss, 1 - ofdm preamble, 2 - * unidentified */ u8 reserved2[3]; - struct iwl4965_measurement_histogram histogram; + struct iwl_measurement_histogram histogram; __le32 stop_time; /* lower 32-bits of TSF */ - __le32 status; /* see iwl4965_measurement_status */ + __le32 status; /* see iwl_measurement_status */ } __attribute__ ((packed)); /****************************************************************************** @@ -2043,15 +2039,15 @@ struct iwl4965_spectrum_notification { * '11' Illegal set * * NOTE: if sleep_interval[SLEEP_INTRVL_TABLE_SIZE-1] > DTIM period then - * ucode assume sleep over DTIM is allowed and we don't need to wakeup + * ucode assume sleep over DTIM is allowed and we don't need to wake up * for every DTIM. */ #define IWL_POWER_VEC_SIZE 5 -#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK __constant_cpu_to_le16(1 << 0) -#define IWL_POWER_SLEEP_OVER_DTIM_MSK __constant_cpu_to_le16(1 << 2) -#define IWL_POWER_PCI_PM_MSK __constant_cpu_to_le16(1 << 3) -#define IWL_POWER_FAST_PD __constant_cpu_to_le16(1 << 4) +#define IWL_POWER_DRIVER_ALLOW_SLEEP_MSK cpu_to_le16(1 << 0) +#define IWL_POWER_SLEEP_OVER_DTIM_MSK cpu_to_le16(1 << 2) +#define IWL_POWER_PCI_PM_MSK cpu_to_le16(1 << 3) +#define IWL_POWER_FAST_PD cpu_to_le16(1 << 4) struct iwl_powertable_cmd { __le16 flags; @@ -2067,7 +2063,7 @@ struct iwl_powertable_cmd { * PM_SLEEP_NOTIFICATION = 0x7A (notification only, not a command) * 3945 and 4965 identical. */ -struct iwl4965_sleep_notification { +struct iwl_sleep_notification { u8 pm_sleep_mode; u8 pm_wakeup_src; __le16 reserved; @@ -2097,14 +2093,14 @@ enum { #define CARD_STATE_CMD_DISABLE 0x00 /* Put card to sleep */ #define CARD_STATE_CMD_ENABLE 0x01 /* Wake up card */ #define CARD_STATE_CMD_HALT 0x02 /* Power down permanently */ -struct iwl4965_card_state_cmd { +struct iwl_card_state_cmd { __le32 status; /* CARD_STATE_CMD_* request new power state */ } __attribute__ ((packed)); /* * CARD_STATE_NOTIFICATION = 0xa1 (notification only, not a command) */ -struct iwl4965_card_state_notif { +struct iwl_card_state_notif { __le32 flags; } __attribute__ ((packed)); @@ -2125,8 +2121,8 @@ struct iwl_ct_kill_config { * *****************************************************************************/ -#define SCAN_CHANNEL_TYPE_PASSIVE __constant_cpu_to_le32(0) -#define SCAN_CHANNEL_TYPE_ACTIVE __constant_cpu_to_le32(1) +#define SCAN_CHANNEL_TYPE_PASSIVE cpu_to_le32(0) +#define SCAN_CHANNEL_TYPE_ACTIVE cpu_to_le32(1) /** * struct iwl_scan_channel - entry in REPLY_SCAN_CMD channel table @@ -2167,7 +2163,7 @@ struct iwl_scan_channel { * struct iwl_ssid_ie - directed scan network information element * * Up to 4 of these may appear in REPLY_SCAN_CMD, selected by "type" field - * in struct iwl4965_scan_channel; each channel may select different ssids from + * in struct iwl_scan_channel; each channel may select different ssids from * among the 4 entries. SSID IEs get transmitted in reverse order of entry. */ struct iwl_ssid_ie { @@ -2177,8 +2173,8 @@ struct iwl_ssid_ie { } __attribute__ ((packed)); #define PROBE_OPTION_MAX 0x14 -#define TX_CMD_LIFE_TIME_INFINITE __constant_cpu_to_le32(0xFFFFFFFF) -#define IWL_GOOD_CRC_TH __constant_cpu_to_le16(1) +#define TX_CMD_LIFE_TIME_INFINITE cpu_to_le32(0xFFFFFFFF) +#define IWL_GOOD_CRC_TH cpu_to_le16(1) #define IWL_MAX_SCAN_SIZE 1024 /* @@ -2267,7 +2263,7 @@ struct iwl_scan_cmd { * Number of channels in list is specified by channel_count. * Each channel in list is of type: * - * struct iwl4965_scan_channel channels[0]; + * struct iwl_scan_channel channels[0]; * * NOTE: Only one band of channels can be scanned per pass. You * must not mix 2.4GHz channels and 5.2GHz channels, and you must wait @@ -2278,7 +2274,7 @@ struct iwl_scan_cmd { } __attribute__ ((packed)); /* Can abort will notify by complete notification with abort status. */ -#define CAN_ABORT_STATUS __constant_cpu_to_le32(0x1) +#define CAN_ABORT_STATUS cpu_to_le32(0x1) /* complete notification statuses */ #define ABORT_STATUS 0x2 @@ -2422,6 +2418,8 @@ struct statistics_rx_ht_phy { __le32 reserved2; } __attribute__ ((packed)); +#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) + struct statistics_rx_non_phy { __le32 bogus_cts; /* CTS received when not expecting CTS */ __le32 bogus_ack; /* ACK received when not expecting ACK */ @@ -2540,8 +2538,8 @@ struct statistics_general { * STATISTICS_NOTIFICATIONs after received beacons (see below). This flag * does not affect the response to the REPLY_STATISTICS_CMD 0x9c itself. */ -#define IWL_STATS_CONF_CLEAR_STATS __constant_cpu_to_le32(0x1) /* see above */ -#define IWL_STATS_CONF_DISABLE_NOTIF __constant_cpu_to_le32(0x2)/* see above */ +#define IWL_STATS_CONF_CLEAR_STATS cpu_to_le32(0x1) /* see above */ +#define IWL_STATS_CONF_DISABLE_NOTIF cpu_to_le32(0x2)/* see above */ struct iwl_statistics_cmd { __le32 configuration_flags; /* IWL_STATS_CONF_* */ } __attribute__ ((packed)); @@ -2561,8 +2559,8 @@ struct iwl_statistics_cmd { * appropriately so that each notification contains statistics for only the * one channel that has just been scanned. */ -#define STATISTICS_REPLY_FLG_BAND_24G_MSK __constant_cpu_to_le32(0x2) -#define STATISTICS_REPLY_FLG_FAT_MODE_MSK __constant_cpu_to_le32(0x8) +#define STATISTICS_REPLY_FLG_BAND_24G_MSK cpu_to_le32(0x2) +#define STATISTICS_REPLY_FLG_FAT_MODE_MSK cpu_to_le32(0x8) struct iwl_notif_statistics { __le32 flag; struct statistics_rx rx; @@ -2578,7 +2576,7 @@ struct iwl_notif_statistics { * then this notification will be sent. */ #define CONSECUTIVE_MISSED_BCONS_TH 20 -struct iwl4965_missed_beacon_notif { +struct iwl_missed_beacon_notif { __le32 consequtive_missed_beacons; __le32 total_missed_becons; __le32 num_expected_beacons; @@ -2778,8 +2776,8 @@ struct iwl4965_missed_beacon_notif { #define HD_OFDM_ENERGY_TH_IN_INDEX (10) /* Control field in struct iwl_sensitivity_cmd */ -#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE __constant_cpu_to_le16(0) -#define SENSITIVITY_CMD_CONTROL_WORK_TABLE __constant_cpu_to_le16(1) +#define SENSITIVITY_CMD_CONTROL_DEFAULT_TABLE cpu_to_le16(0) +#define SENSITIVITY_CMD_CONTROL_WORK_TABLE cpu_to_le16(1) /** * struct iwl_sensitivity_cmd @@ -2849,56 +2847,26 @@ struct iwl_sensitivity_cmd { * 1-0: amount of gain, units of 1.5 dB */ -/* "Differential Gain" opcode used in REPLY_PHY_CALIBRATION_CMD. */ -#define PHY_CALIBRATE_DIFF_GAIN_CMD (7) - -struct iwl4965_calibration_cmd { - u8 opCode; /* PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ - u8 flags; /* not used */ - __le16 reserved; - s8 diff_gain_a; /* see above */ - s8 diff_gain_b; - s8 diff_gain_c; - u8 reserved1; -} __attribute__ ((packed)); - -/* Phy calibration command for 5000 series */ - -enum { - IWL5000_PHY_CALIBRATE_DC_CMD = 8, - IWL5000_PHY_CALIBRATE_LO_CMD = 9, - IWL5000_PHY_CALIBRATE_RX_BB_CMD = 10, - IWL5000_PHY_CALIBRATE_TX_IQ_CMD = 11, - IWL5000_PHY_CALIBRATE_RX_IQ_CMD = 12, - IWL5000_PHY_CALIBRATION_NOISE_CMD = 13, - IWL5000_PHY_CALIBRATE_AGC_TABLE_CMD = 14, - IWL5000_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, - IWL5000_PHY_CALIBRATE_BASE_BAND_CMD = 16, - IWL5000_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17, - IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, - IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, -}; +/* Phy calibration command for series */ enum { - CALIBRATION_CFG_CMD = 0x65, - CALIBRATION_RES_NOTIFICATION = 0x66, - CALIBRATION_COMPLETE_NOTIFICATION = 0x67 + IWL_PHY_CALIBRATE_DIFF_GAIN_CMD = 7, + IWL_PHY_CALIBRATE_DC_CMD = 8, + IWL_PHY_CALIBRATE_LO_CMD = 9, + IWL_PHY_CALIBRATE_RX_BB_CMD = 10, + IWL_PHY_CALIBRATE_TX_IQ_CMD = 11, + IWL_PHY_CALIBRATE_RX_IQ_CMD = 12, + IWL_PHY_CALIBRATION_NOISE_CMD = 13, + IWL_PHY_CALIBRATE_AGC_TABLE_CMD = 14, + IWL_PHY_CALIBRATE_CRYSTAL_FRQ_CMD = 15, + IWL_PHY_CALIBRATE_BASE_BAND_CMD = 16, + IWL_PHY_CALIBRATE_TX_IQ_PERD_CMD = 17, + IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD = 18, + IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD = 19, }; -struct iwl_cal_crystal_freq_cmd { - u8 cap_pin1; - u8 cap_pin2; -} __attribute__ ((packed)); - -struct iwl5000_calibration { - u8 op_code; - u8 first_group; - u8 num_groups; - u8 all_data_valid; - struct iwl_cal_crystal_freq_cmd data; -} __attribute__ ((packed)); -#define IWL_CALIB_INIT_CFG_ALL __constant_cpu_to_le32(0xffffffff) +#define IWL_CALIB_INIT_CFG_ALL cpu_to_le32(0xffffffff) struct iwl_calib_cfg_elmnt_s { __le32 is_enable; @@ -2914,32 +2882,52 @@ struct iwl_calib_cfg_status_s { __le32 flags; } __attribute__ ((packed)); -struct iwl5000_calib_cfg_cmd { +struct iwl_calib_cfg_cmd { struct iwl_calib_cfg_status_s ucd_calib_cfg; struct iwl_calib_cfg_status_s drv_calib_cfg; __le32 reserved1; } __attribute__ ((packed)); -struct iwl5000_calib_hdr { +struct iwl_calib_hdr { u8 op_code; u8 first_group; u8 groups_num; u8 data_valid; } __attribute__ ((packed)); -struct iwl5000_calibration_chain_noise_reset_cmd { - u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ - u8 flags; /* not used */ - __le16 reserved; +struct iwl_calib_cmd { + struct iwl_calib_hdr hdr; + u8 data[0]; } __attribute__ ((packed)); -struct iwl5000_calibration_chain_noise_gain_cmd { - u8 op_code; /* IWL5000_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ - u8 flags; /* not used */ - __le16 reserved; +/* IWL_PHY_CALIBRATE_DIFF_GAIN_CMD (7) */ +struct iwl_calib_diff_gain_cmd { + struct iwl_calib_hdr hdr; + s8 diff_gain_a; /* see above */ + s8 diff_gain_b; + s8 diff_gain_c; + u8 reserved1; +} __attribute__ ((packed)); + +struct iwl_calib_xtal_freq_cmd { + struct iwl_calib_hdr hdr; + u8 cap_pin1; + u8 cap_pin2; + u8 pad[2]; +} __attribute__ ((packed)); + +/* IWL_PHY_CALIBRATE_CHAIN_NOISE_RESET_CMD */ +struct iwl_calib_chain_noise_reset_cmd { + struct iwl_calib_hdr hdr; + u8 data[0]; +}; + +/* IWL_PHY_CALIBRATE_CHAIN_NOISE_GAIN_CMD */ +struct iwl_calib_chain_noise_gain_cmd { + struct iwl_calib_hdr hdr; u8 delta_gain_1; u8 delta_gain_2; - __le16 reserved1; + u8 pad[2]; } __attribute__ ((packed)); /****************************************************************************** @@ -2999,11 +2987,11 @@ struct iwl_wimax_coex_event_entry { /* COEX flag masks */ -/* Staion table is valid */ +/* Station table is valid */ #define COEX_FLAGS_STA_TABLE_VALID_MSK (0x1) -/* UnMask wakeup src at unassociated sleep */ +/* UnMask wake up src at unassociated sleep */ #define COEX_FLAGS_UNASSOC_WA_UNMASK_MSK (0x4) -/* UnMask wakeup src at associated sleep */ +/* UnMask wake up src at associated sleep */ #define COEX_FLAGS_ASSOC_WA_UNMASK_MSK (0x8) /* Enable CoEx feature. */ #define COEX_FLAGS_COEX_ENABLE_MSK (0x80) @@ -3025,26 +3013,22 @@ struct iwl_rx_packet { struct iwl_cmd_header hdr; union { struct iwl_alive_resp alive_frame; - struct iwl4965_rx_frame rx_frame; - struct iwl4965_tx_resp tx_resp; - struct iwl4965_spectrum_notification spectrum_notif; - struct iwl4965_csa_notification csa_notif; + struct iwl_spectrum_notification spectrum_notif; + struct iwl_csa_notification csa_notif; struct iwl_error_resp err_resp; - struct iwl4965_card_state_notif card_state_notif; - struct iwl4965_beacon_notif beacon_status; + struct iwl_card_state_notif card_state_notif; struct iwl_add_sta_resp add_sta; struct iwl_rem_sta_resp rem_sta; - struct iwl4965_sleep_notification sleep_notif; - struct iwl4965_spectrum_resp spectrum; + struct iwl_sleep_notification sleep_notif; + struct iwl_spectrum_resp spectrum; struct iwl_notif_statistics stats; struct iwl_compressed_ba_resp compressed_ba; - struct iwl4965_missed_beacon_notif missed_beacon; - struct iwl5000_calibration calib; + struct iwl_missed_beacon_notif missed_beacon; __le32 status; u8 raw[0]; } u; } __attribute__ ((packed)); -#define IWL_RX_FRAME_SIZE (4 + sizeof(struct iwl4965_rx_frame)) +int iwl_agn_check_rxon_cmd(struct iwl_rxon_cmd *rxon); -#endif /* __iwl4965_commands_h__ */ +#endif /* __iwl_commands_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c index 01a84585133834a45c603a0c55763b7864441181..73d7973707eb023243dccc545a9bc0f29570e291 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.c +++ b/drivers/net/wireless/iwlwifi/iwl-core.c @@ -22,7 +22,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -30,19 +30,19 @@ #include #include -struct iwl_priv; /* FIXME: remove */ -#include "iwl-debug.h" #include "iwl-eeprom.h" #include "iwl-dev.h" /* FIXME: remove */ +#include "iwl-debug.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-rfkill.h" #include "iwl-power.h" +#include "iwl-sta.h" MODULE_DESCRIPTION("iwl core"); MODULE_VERSION(IWLWIFI_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); #define IWL_DECLARE_RATE_INFO(r, s, ip, in, rp, rn, pp, np) \ @@ -88,26 +88,27 @@ EXPORT_SYMBOL(iwl_rates); * translate ucode response to mac80211 tx status control values */ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, - struct ieee80211_tx_info *control) + struct ieee80211_tx_info *info) { int rate_index; + struct ieee80211_tx_rate *r = &info->control.rates[0]; - control->antenna_sel_tx = + info->antenna_sel_tx = ((rate_n_flags & RATE_MCS_ANT_ABC_MSK) >> RATE_MCS_ANT_POS); if (rate_n_flags & RATE_MCS_HT_MSK) - control->flags |= IEEE80211_TX_CTL_OFDM_HT; + r->flags |= IEEE80211_TX_RC_MCS; if (rate_n_flags & RATE_MCS_GF_MSK) - control->flags |= IEEE80211_TX_CTL_GREEN_FIELD; + r->flags |= IEEE80211_TX_RC_GREEN_FIELD; if (rate_n_flags & RATE_MCS_FAT_MSK) - control->flags |= IEEE80211_TX_CTL_40_MHZ_WIDTH; + r->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; if (rate_n_flags & RATE_MCS_DUP_MSK) - control->flags |= IEEE80211_TX_CTL_DUP_DATA; + r->flags |= IEEE80211_TX_RC_DUP_DATA; if (rate_n_flags & RATE_MCS_SGI_MSK) - control->flags |= IEEE80211_TX_CTL_SHORT_GI; + r->flags |= IEEE80211_TX_RC_SHORT_GI; rate_index = iwl_hwrate_to_plcp_idx(rate_n_flags); - if (control->band == IEEE80211_BAND_5GHZ) + if (info->band == IEEE80211_BAND_5GHZ) rate_index -= IWL_FIRST_OFDM_RATE; - control->tx_rate_idx = rate_index; + r->idx = rate_index; } EXPORT_SYMBOL(iwl_hwrate_to_tx_control); @@ -119,7 +120,9 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) if (rate_n_flags & RATE_MCS_HT_MSK) { idx = (rate_n_flags & 0xff); - if (idx >= IWL_RATE_MIMO2_6M_PLCP) + if (idx >= IWL_RATE_MIMO3_6M_PLCP) + idx = idx - IWL_RATE_MIMO3_6M_PLCP; + else if (idx >= IWL_RATE_MIMO2_6M_PLCP) idx = idx - IWL_RATE_MIMO2_6M_PLCP; idx += IWL_FIRST_OFDM_RATE; @@ -140,7 +143,17 @@ int iwl_hwrate_to_plcp_idx(u32 rate_n_flags) } EXPORT_SYMBOL(iwl_hwrate_to_plcp_idx); - +u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant) +{ + int i; + u8 ind = ant; + for (i = 0; i < RATE_ANT_NUM - 1; i++) { + ind = (ind + 1) < RATE_ANT_NUM ? ind + 1 : 0; + if (priv->hw_params.valid_tx_ant & BIT(ind)) + return ind; + } + return ant; +} const u8 iwl_bcast_addr[ETH_ALEN] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; EXPORT_SYMBOL(iwl_bcast_addr); @@ -177,52 +190,6 @@ void iwl_hw_detect(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_hw_detect); -/* Tell nic where to find the "keep warm" buffer */ -int iwl_kw_init(struct iwl_priv *priv) -{ - unsigned long flags; - int ret; - - spin_lock_irqsave(&priv->lock, flags); - ret = iwl_grab_nic_access(priv); - if (ret) - goto out; - - iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, - priv->kw.dma_addr >> 4); - iwl_release_nic_access(priv); -out: - spin_unlock_irqrestore(&priv->lock, flags); - return ret; -} - -int iwl_kw_alloc(struct iwl_priv *priv) -{ - struct pci_dev *dev = priv->pci_dev; - struct iwl_kw *kw = &priv->kw; - - kw->size = IWL_KW_SIZE; - kw->v_addr = pci_alloc_consistent(dev, kw->size, &kw->dma_addr); - if (!kw->v_addr) - return -ENOMEM; - - return 0; -} - -/** - * iwl_kw_free - Free the "keep warm" buffer - */ -void iwl_kw_free(struct iwl_priv *priv) -{ - struct pci_dev *dev = priv->pci_dev; - struct iwl_kw *kw = &priv->kw; - - if (kw->v_addr) { - pci_free_consistent(dev, kw->size, kw->v_addr, kw->dma_addr); - memset(kw, 0, sizeof(*kw)); - } -} - int iwl_hw_nic_init(struct iwl_priv *priv) { unsigned long flags; @@ -271,55 +238,30 @@ int iwl_hw_nic_init(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_hw_nic_init); -/** - * iwl_clear_stations_table - Clear the driver's station table - * - * NOTE: This does not clear or otherwise alter the device's station table. - */ -void iwl_clear_stations_table(struct iwl_priv *priv) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - - if (iwl_is_alive(priv) && - !test_bit(STATUS_EXIT_PENDING, &priv->status) && - iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) - IWL_ERROR("Couldn't clear the station table\n"); - - priv->num_stations = 0; - memset(priv->stations, 0, sizeof(priv->stations)); - - /* clean ucode key table bit map */ - priv->ucode_key_table = 0; - - spin_unlock_irqrestore(&priv->sta_lock, flags); -} -EXPORT_SYMBOL(iwl_clear_stations_table); - void iwl_reset_qos(struct iwl_priv *priv) { u16 cw_min = 15; u16 cw_max = 1023; u8 aifs = 2; - u8 is_legacy = 0; + bool is_legacy = false; unsigned long flags; int i; spin_lock_irqsave(&priv->lock, flags); - priv->qos_data.qos_active = 0; + /* QoS always active in AP and ADHOC mode + * In STA mode wait for association + */ + if (priv->iw_mode == NL80211_IFTYPE_ADHOC || + priv->iw_mode == NL80211_IFTYPE_AP) + priv->qos_data.qos_active = 1; + else + priv->qos_data.qos_active = 0; - if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - if (!(priv->active_rate & 0xfff0)) { - cw_min = 31; - is_legacy = 1; - } - } else if (priv->iw_mode == NL80211_IFTYPE_AP) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { + /* check for legacy mode */ + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC && + (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) || + (priv->iw_mode == NL80211_IFTYPE_STATION && + (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) { cw_min = 31; is_legacy = 1; } @@ -385,10 +327,10 @@ void iwl_reset_qos(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_reset_qos); -#define MAX_BIT_RATE_40_MHZ 0x96 /* 150 Mbps */ -#define MAX_BIT_RATE_20_MHZ 0x48 /* 72 Mbps */ +#define MAX_BIT_RATE_40_MHZ 150 /* Mbps */ +#define MAX_BIT_RATE_20_MHZ 72 /* Mbps */ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, - struct ieee80211_ht_info *ht_info, + struct ieee80211_sta_ht_cap *ht_info, enum ieee80211_band band) { u16 max_bit_rate = 0; @@ -396,45 +338,46 @@ static void iwlcore_init_ht_hw_capab(const struct iwl_priv *priv, u8 tx_chains_num = priv->hw_params.tx_chains_num; ht_info->cap = 0; - memset(ht_info->supp_mcs_set, 0, 16); + memset(&ht_info->mcs, 0, sizeof(ht_info->mcs)); - ht_info->ht_supported = 1; + ht_info->ht_supported = true; - ht_info->cap |= (u16)IEEE80211_HT_CAP_GRN_FLD; - ht_info->cap |= (u16)IEEE80211_HT_CAP_SGI_20; - ht_info->cap |= (u16)(IEEE80211_HT_CAP_SM_PS & + ht_info->cap |= IEEE80211_HT_CAP_GRN_FLD; + ht_info->cap |= IEEE80211_HT_CAP_SGI_20; + ht_info->cap |= (IEEE80211_HT_CAP_SM_PS & (WLAN_HT_CAP_SM_PS_DISABLED << 2)); max_bit_rate = MAX_BIT_RATE_20_MHZ; if (priv->hw_params.fat_channel & BIT(band)) { - 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; + ht_info->cap |= IEEE80211_HT_CAP_SUP_WIDTH_20_40; + ht_info->cap |= IEEE80211_HT_CAP_SGI_40; + ht_info->mcs.rx_mask[4] = 0x01; max_bit_rate = MAX_BIT_RATE_40_MHZ; } if (priv->cfg->mod_params->amsdu_size_8K) - ht_info->cap |= (u16)IEEE80211_HT_CAP_MAX_AMSDU; + ht_info->cap |= IEEE80211_HT_CAP_MAX_AMSDU; ht_info->ampdu_factor = CFG_HT_RX_AMPDU_FACTOR_DEF; ht_info->ampdu_density = CFG_HT_MPDU_DENSITY_DEF; - ht_info->supp_mcs_set[0] = 0xFF; + ht_info->mcs.rx_mask[0] = 0xFF; if (rx_chains_num >= 2) - ht_info->supp_mcs_set[1] = 0xFF; + ht_info->mcs.rx_mask[1] = 0xFF; if (rx_chains_num >= 3) - ht_info->supp_mcs_set[2] = 0xFF; + ht_info->mcs.rx_mask[2] = 0xFF; /* Highest supported Rx data rate */ max_bit_rate *= rx_chains_num; - ht_info->supp_mcs_set[10] = (u8)(max_bit_rate & 0x00FF); - ht_info->supp_mcs_set[11] = (u8)((max_bit_rate & 0xFF00) >> 8); + WARN_ON(max_bit_rate & ~IEEE80211_HT_MCS_RX_HIGHEST_MASK); + ht_info->mcs.rx_highest = cpu_to_le16(max_bit_rate); /* Tx MCS capabilities */ - ht_info->supp_mcs_set[12] = IEEE80211_HT_CAP_MCS_TX_DEFINED; + ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; if (tx_chains_num != rx_chains_num) { - ht_info->supp_mcs_set[12] |= IEEE80211_HT_CAP_MCS_TX_RX_DIFF; - ht_info->supp_mcs_set[12] |= ((tx_chains_num - 1) << 2); + ht_info->mcs.tx_params |= IEEE80211_HT_MCS_TX_RX_DIFF; + ht_info->mcs.tx_params |= ((tx_chains_num - 1) << + IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT); } } @@ -498,7 +441,7 @@ static int iwlcore_init_geos(struct iwl_priv *priv) sband->n_bitrates = IWL_RATE_COUNT - IWL_FIRST_OFDM_RATE; if (priv->cfg->sku & IWL_SKU_N) - iwlcore_init_ht_hw_capab(priv, &sband->ht_info, + iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_5GHZ); sband = &priv->bands[IEEE80211_BAND_2GHZ]; @@ -508,7 +451,7 @@ static int iwlcore_init_geos(struct iwl_priv *priv) sband->n_bitrates = IWL_RATE_COUNT; if (priv->cfg->sku & IWL_SKU_N) - iwlcore_init_ht_hw_capab(priv, &sband->ht_info, + iwlcore_init_ht_hw_capab(priv, &sband->ht_cap, IEEE80211_BAND_2GHZ); priv->ieee_channels = channels; @@ -598,8 +541,8 @@ static void iwlcore_free_geos(struct iwl_priv *priv) static bool is_single_rx_stream(struct iwl_priv *priv) { return !priv->current_ht_config.is_ht || - ((priv->current_ht_config.supp_mcs_set[1] == 0) && - (priv->current_ht_config.supp_mcs_set[2] == 0)); + ((priv->current_ht_config.mcs.rx_mask[1] == 0) && + (priv->current_ht_config.mcs.rx_mask[2] == 0)); } static u8 iwl_is_channel_extension(struct iwl_priv *priv, @@ -612,10 +555,10 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, if (!is_channel_valid(ch_info)) return 0; - if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_ABOVE) + if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_ABOVE) return !(ch_info->fat_extension_channel & IEEE80211_CHAN_NO_FAT_ABOVE); - else if (extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_BELOW) + else if (extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_BELOW) return !(ch_info->fat_extension_channel & IEEE80211_CHAN_NO_FAT_BELOW); @@ -623,24 +566,24 @@ static u8 iwl_is_channel_extension(struct iwl_priv *priv, } u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, - struct ieee80211_ht_info *sta_ht_inf) + struct ieee80211_sta_ht_cap *sta_ht_inf) { struct iwl_ht_info *iwl_ht_conf = &priv->current_ht_config; if ((!iwl_ht_conf->is_ht) || (iwl_ht_conf->supported_chan_width != IWL_CHANNEL_WIDTH_40MHZ) || - (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_IE_CHA_SEC_NONE)) + (iwl_ht_conf->extension_chan_offset == IEEE80211_HT_PARAM_CHA_SEC_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_20_40))) return 0; } return iwl_is_channel_extension(priv, priv->band, - iwl_ht_conf->control_channel, - iwl_ht_conf->extension_chan_offset); + le16_to_cpu(priv->staging_rxon.channel), + iwl_ht_conf->extension_chan_offset); } EXPORT_SYMBOL(iwl_is_fat_tx_allowed); @@ -665,22 +608,15 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) rxon->flags &= ~(RXON_FLG_CHANNEL_MODE_MIXED_MSK | RXON_FLG_CHANNEL_MODE_PURE_40_MSK); - if (le16_to_cpu(rxon->channel) != ht_info->control_channel) { - IWL_DEBUG_ASSOC("control diff than current %d %d\n", - le16_to_cpu(rxon->channel), - ht_info->control_channel); - return; - } - /* Note: control channel is opposite of extension channel */ switch (ht_info->extension_chan_offset) { - case IEEE80211_HT_IE_CHA_SEC_ABOVE: + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: rxon->flags &= ~(RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK); break; - case IEEE80211_HT_IE_CHA_SEC_BELOW: + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: rxon->flags |= RXON_FLG_CTRL_CHANNEL_LOC_HI_MSK; break; - case IEEE80211_HT_IE_CHA_SEC_NONE: + case IEEE80211_HT_PARAM_CHA_SEC_NONE: default: rxon->flags &= ~RXON_FLG_CHANNEL_MODE_MIXED_MSK; break; @@ -694,14 +630,12 @@ void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info) IWL_DEBUG_ASSOC("supported HT rate 0x%X 0x%X 0x%X " "rxon flags 0x%X operation mode :0x%X " - "extension channel offset 0x%x " - "control chan %d\n", - ht_info->supp_mcs_set[0], - ht_info->supp_mcs_set[1], - ht_info->supp_mcs_set[2], + "extension channel offset 0x%x\n", + ht_info->mcs.rx_mask[0], + ht_info->mcs.rx_mask[1], + ht_info->mcs.rx_mask[2], le32_to_cpu(rxon->flags), ht_info->ht_protection, - ht_info->extension_chan_offset, - ht_info->control_channel); + ht_info->extension_chan_offset); return; } EXPORT_SYMBOL(iwl_set_rxon_ht); @@ -745,7 +679,7 @@ static int iwl_get_idle_rx_chain_count(struct iwl_priv *priv, int active_cnt) break; case WLAN_HT_CAP_SM_PS_INVALID: default: - IWL_ERROR("invalide mimo ps mode %d\n", + IWL_ERROR("invalid mimo ps mode %d\n", priv->current_ht_config.sm_ps); WARN_ON(1); idle_cnt = -1; @@ -871,11 +805,14 @@ int iwl_setup_mac(struct iwl_priv *priv) /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | - IEEE80211_HW_NOISE_DBM; + IEEE80211_HW_NOISE_DBM | + IEEE80211_HW_AMPDU_AGGREGATION; hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + + hw->wiphy->fw_handles_regulatory = true; + /* Default value; 4 EDCA QOS priorities */ hw->queues = 4; /* queues to support 11n aggregation */ @@ -948,16 +885,12 @@ int iwl_init_drv(struct iwl_priv *priv) priv->iw_mode = NL80211_IFTYPE_STATION; - priv->use_ant_b_for_management_frame = 1; /* start with ant B */ priv->current_ht_config.sm_ps = WLAN_HT_CAP_SM_PS_DISABLED; /* Choose which receivers/antennas to use */ iwl_set_rxon_chain(priv); iwl_init_scan_params(priv); - if (priv->cfg->mod_params->enable_qos) - priv->qos_data.qos_enable = 1; - iwl_reset_qos(priv); priv->qos_data.qos_active = 0; @@ -1025,6 +958,30 @@ void iwl_uninit_drv(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_uninit_drv); + +void iwl_disable_interrupts(struct iwl_priv *priv) +{ + clear_bit(STATUS_INT_ENABLED, &priv->status); + + /* disable interrupts from uCode/NIC to host */ + iwl_write32(priv, CSR_INT_MASK, 0x00000000); + + /* acknowledge/clear/reset any interrupts still pending + * from uCode or flow handler (Rx/Tx DMA) */ + iwl_write32(priv, CSR_INT, 0xffffffff); + iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff); + IWL_DEBUG_ISR("Disabled interrupts\n"); +} +EXPORT_SYMBOL(iwl_disable_interrupts); + +void iwl_enable_interrupts(struct iwl_priv *priv) +{ + IWL_DEBUG_ISR("Enabling interrupts\n"); + set_bit(STATUS_INT_ENABLED, &priv->status); + iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK); +} +EXPORT_SYMBOL(iwl_enable_interrupts); + int iwl_send_statistics_request(struct iwl_priv *priv, u8 flags) { u32 stat_flags = 0; @@ -1172,24 +1129,47 @@ int iwl_verify_ucode(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_verify_ucode); + +static const char *desc_lookup_text[] = { + "OK", + "FAIL", + "BAD_PARAM", + "BAD_CHECKSUM", + "NMI_INTERRUPT_WDG", + "SYSASSERT", + "FATAL_ERROR", + "BAD_COMMAND", + "HW_ERROR_TUNE_LOCK", + "HW_ERROR_TEMPERATURE", + "ILLEGAL_CHAN_FREQ", + "VCC_NOT_STABLE", + "FH_ERROR", + "NMI_INTERRUPT_HOST", + "NMI_INTERRUPT_ACTION_PT", + "NMI_INTERRUPT_UNKNOWN", + "UCODE_VERSION_MISMATCH", + "HW_ERROR_ABS_LOCK", + "HW_ERROR_CAL_LOCK_FAIL", + "NMI_INTERRUPT_INST_ACTION_PT", + "NMI_INTERRUPT_DATA_ACTION_PT", + "NMI_TRM_HW_ER", + "NMI_INTERRUPT_TRM", + "NMI_INTERRUPT_BREAK_POINT" + "DEBUG_0", + "DEBUG_1", + "DEBUG_2", + "DEBUG_3", + "UNKNOWN" +}; + static const char *desc_lookup(int i) { - switch (i) { - case 1: - return "FAIL"; - case 2: - return "BAD_PARAM"; - case 3: - return "BAD_CHECKSUM"; - case 4: - return "NMI_INTERRUPT"; - case 5: - return "SYSASSERT"; - case 6: - return "FATAL_ERROR"; - } + int max = ARRAY_SIZE(desc_lookup_text) - 1; - return "UNKNOWN"; + if (i < 0 || i > max) + i = max; + + return desc_lookup_text[i]; } #define ERROR_START_OFFSET (1 * sizeof(u32)) @@ -1235,9 +1215,9 @@ void iwl_dump_nic_error_log(struct iwl_priv *priv) line = iwl_read_targ_mem(priv, base + 9 * sizeof(u32)); time = iwl_read_targ_mem(priv, base + 11 * sizeof(u32)); - IWL_ERROR("Desc Time " + IWL_ERROR("Desc Time " "data1 data2 line\n"); - IWL_ERROR("%-13s (#%d) %010u 0x%08X 0x%08X %u\n", + IWL_ERROR("%-28s (#%02d) %010u 0x%08X 0x%08X %u\n", desc_lookup(desc), desc, time, data1, data2, line); IWL_ERROR("blink1 blink2 ilink1 ilink2\n"); IWL_ERROR("0x%05X 0x%05X 0x%05X 0x%05X\n", blink1, blink2, @@ -1377,6 +1357,7 @@ void iwl_rf_kill_ct_config(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rf_kill_ct_config); + /* * CARD_STATE_CMD * @@ -1465,6 +1446,16 @@ int iwl_radio_kill_sw_enable_radio(struct iwl_priv *priv) return 0; } + /* when driver is up while rfkill is on, it wont receive + * any CARD_STATE_NOTIFICATION notifications so we have to + * restart it in here + */ + if (priv->is_open && !test_bit(STATUS_ALIVE, &priv->status)) { + clear_bit(STATUS_RF_KILL_SW, &priv->status); + if (!iwl_is_rfkill(priv)) + queue_work(priv->workqueue, &priv->up); + } + /* If the driver is already loaded, it will receive * CARD_STATE_NOTIFICATION notifications and the handler will * call restart to reload the driver. diff --git a/drivers/net/wireless/iwlwifi/iwl-core.h b/drivers/net/wireless/iwlwifi/iwl-core.h index 288b6a800e03306cc2cc34885e364450b9389cb2..7c3a20a986bbd3567a6ed7c9102206e0d81e9aa1 100644 --- a/drivers/net/wireless/iwlwifi/iwl-core.h +++ b/drivers/net/wireless/iwlwifi/iwl-core.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -72,6 +72,7 @@ struct iwl_cmd; #define IWLWIFI_VERSION "1.3.27k" #define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" +#define DRV_AUTHOR "" #define IWL_PCI_DEVICE(dev, subdev, cfg) \ .vendor = PCI_VENDOR_ID_INTEL, .device = (dev), \ @@ -100,12 +101,8 @@ struct iwl_hcmd_utils_ops { }; struct iwl_lib_ops { - /* set hw dependant perameters */ + /* set hw dependent parameters */ int (*set_hw_params)(struct iwl_priv *priv); - /* ucode shared memory */ - int (*alloc_shared_mem)(struct iwl_priv *priv); - void (*free_shared_mem)(struct iwl_priv *priv); - int (*shared_mem_rx_idx)(struct iwl_priv *priv); /* Handling TX */ void (*txq_update_byte_cnt_tbl)(struct iwl_priv *priv, struct iwl_tx_queue *txq, @@ -157,22 +154,53 @@ struct iwl_ops { struct iwl_mod_params { int disable; /* def: 0 = enable radio */ int sw_crypto; /* def: 0 = using hardware encryption */ - int debug; /* def: 0 = minimal debug log messages */ + u32 debug; /* def: 0 = minimal debug log messages */ int disable_hw_scan; /* def: 0 = use h/w scan */ int num_of_queues; /* def: HW dependent */ int num_of_ampdu_queues;/* def: HW dependent */ - int enable_qos; /* def: 1 = use quality of service */ int disable_11n; /* def: 0 = disable 11n capabilities */ int amsdu_size_8K; /* def: 1 = enable 8K amsdu size */ int antenna; /* def: 0 = both antennas (use diversity) */ int restart_fw; /* def: 1 = restart firmware */ }; +/** + * struct iwl_cfg + * @fw_name_pre: Firmware filename prefix. The api version and extension + * (.ucode) will be added to filename before loading from disk. The + * filename is constructed as fw_name_pre.ucode. + * @ucode_api_max: Highest version of uCode API supported by driver. + * @ucode_api_min: Lowest version of uCode API supported by driver. + * + * We enable the driver to be backward compatible wrt API version. The + * driver specifies which APIs it supports (with @ucode_api_max being the + * highest and @ucode_api_min the lowest). Firmware will only be loaded if + * it has a supported API version. The firmware's API version will be + * stored in @iwl_priv, enabling the driver to make runtime changes based + * on firmware version used. + * + * For example, + * if (IWL_UCODE_API(priv->ucode_ver) >= 2) { + * Driver interacts with Firmware API version >= 2. + * } else { + * Driver interacts with Firmware API version 1. + * } + * + * The ideal usage of this infrastructure is to treat a new ucode API + * release as a new hardware revision. That is, through utilizing the + * iwl_hcmd_utils_ops etc. we accommodate different command structures + * and flows between hardware versions (4965/5000) as well as their API + * versions. + */ struct iwl_cfg { const char *name; - const char *fw_name; + const char *fw_name_pre; + const unsigned int ucode_api_max; + const unsigned int ucode_api_min; unsigned int sku; int eeprom_size; + u16 eeprom_ver; + u16 eeprom_calib_ver; const struct iwl_ops *ops; const struct iwl_mod_params *mod_params; }; @@ -184,22 +212,17 @@ struct iwl_cfg { struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg, struct ieee80211_ops *hw_ops); void iwl_hw_detect(struct iwl_priv *priv); -void iwl_clear_stations_table(struct iwl_priv *priv); void iwl_reset_qos(struct iwl_priv *priv); void iwl_set_rxon_chain(struct iwl_priv *priv); int iwl_set_rxon_channel(struct iwl_priv *priv, struct ieee80211_channel *ch); void iwl_set_rxon_ht(struct iwl_priv *priv, struct iwl_ht_info *ht_info); u8 iwl_is_fat_tx_allowed(struct iwl_priv *priv, - struct ieee80211_ht_info *sta_ht_inf); + struct ieee80211_sta_ht_cap *sta_ht_inf); int iwl_hw_nic_init(struct iwl_priv *priv); int iwl_setup_mac(struct iwl_priv *priv); int iwl_set_hw_params(struct iwl_priv *priv); int iwl_init_drv(struct iwl_priv *priv); void iwl_uninit_drv(struct iwl_priv *priv); -/* "keep warm" functions */ -int iwl_kw_init(struct iwl_priv *priv); -int iwl_kw_alloc(struct iwl_priv *priv); -void iwl_kw_free(struct iwl_priv *priv); /***************************************************** * RX @@ -212,8 +235,6 @@ int iwl_rx_queue_update_write_ptr(struct iwl_priv *priv, void iwl_rx_queue_reset(struct iwl_priv *priv, struct iwl_rx_queue *rxq); void iwl_rx_replenish(struct iwl_priv *priv); int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq); -int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn); -int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); int iwl_rx_queue_restock(struct iwl_priv *priv); int iwl_rx_queue_space(const struct iwl_rx_queue *q); void iwl_rx_allocate(struct iwl_priv *priv); @@ -237,7 +258,6 @@ int iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq); int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn); int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid); int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id); - /***************************************************** * TX power ****************************************************/ @@ -259,6 +279,13 @@ void iwl_hwrate_to_tx_control(struct iwl_priv *priv, u32 rate_n_flags, struct ieee80211_tx_info *info); int iwl_hwrate_to_plcp_idx(u32 rate_n_flags); +u8 iwl_toggle_tx_ant(struct iwl_priv *priv, u8 ant_idx); + +static inline u32 iwl_ant_idx_to_flags(u8 ant_idx) +{ + return BIT(ant_idx) << RATE_MCS_ANT_POS; +} + static inline u8 iwl_hw_get_rate(__le32 rate_n_flags) { return le32_to_cpu(rate_n_flags) & 0xFF; @@ -289,6 +316,14 @@ int iwl_send_calib_results(struct iwl_priv *priv); int iwl_calib_set(struct iwl_calib_result *res, const u8 *buf, int len); void iwl_calib_free_results(struct iwl_priv *priv); +/******************************************************************************* + * Spectrum Measureemtns in iwl-spectrum.c + ******************************************************************************/ +#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT +void iwl_setup_spectrum_handlers(struct iwl_priv *priv); +#else +static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {} +#endif /***************************************************** * S e n d i n g H o s t C o m m a n d s * *****************************************************/ @@ -307,12 +342,19 @@ int iwl_send_cmd_pdu_async(struct iwl_priv *priv, u8 id, u16 len, int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd); +/***************************************************** + * PCI * + *****************************************************/ +void iwl_disable_interrupts(struct iwl_priv *priv); +void iwl_enable_interrupts(struct iwl_priv *priv); + /***************************************************** * Error Handling Debugging ******************************************************/ void iwl_dump_nic_error_log(struct iwl_priv *priv); void iwl_dump_nic_event_log(struct iwl_priv *priv); + /*************** DRIVER STATUS FUNCTIONS *****/ #define STATUS_HCMD_ACTIVE 0 /* host command in progress */ diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h index 662edf4f8d226a13e8ce915e9c2aa085d581adc5..f34ede44ed109604d0463fac8a39d0a2ae9b483b 100644 --- a/drivers/net/wireless/iwlwifi/iwl-csr.h +++ b/drivers/net/wireless/iwlwifi/iwl-csr.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -60,6 +60,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +#ifndef __iwl_csr_h__ +#define __iwl_csr_h__ /*=== CSR (control and status registers) ===*/ #define CSR_BASE (0x000) @@ -214,6 +216,8 @@ /* EEPROM REG */ #define CSR_EEPROM_REG_READ_VALID_MSK (0x00000001) #define CSR_EEPROM_REG_BIT_CMD (0x00000002) +#define CSR_EEPROM_REG_MSK_ADDR (0x0000FFFC) +#define CSR_EEPROM_REG_MSK_DATA (0xFFFF0000) /* EEPROM GP */ #define CSR_EEPROM_GP_VALID_MSK (0x00000006) @@ -286,4 +290,4 @@ #define HBUS_TARG_MBX_C_REG_BIT_CMD_BLOCKED (0x00000004) - +#endif /* !__iwl_csr_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-debug.h b/drivers/net/wireless/iwlwifi/iwl-debug.h index e548d67f87fd400583d1ff61ab06d24f78a2885b..56c13b458de7fc7571298591ec3d2eb2b20bfc27 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debug.h +++ b/drivers/net/wireless/iwlwifi/iwl-debug.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -40,6 +40,13 @@ do { if ((priv->debug_level & (level)) && net_ratelimit()) \ dev_printk(KERN_ERR, &(priv->hw->wiphy->dev), "%c %s " fmt, \ in_interrupt() ? 'I' : 'U', __func__ , ## args); } while (0) +#define iwl_print_hex_dump(priv, level, p, len) \ +do { \ + if (priv->debug_level & level) \ + print_hex_dump(KERN_DEBUG, "iwl data: ", \ + DUMP_PREFIX_OFFSET, 16, 1, p, len, 1); \ +} while (0) + #ifdef CONFIG_IWLWIFI_DEBUGFS struct iwl_debugfs { const char *name; @@ -53,6 +60,7 @@ struct iwl_debugfs { struct dentry *file_rx_statistics; struct dentry *file_tx_statistics; struct dentry *file_log_event; + struct dentry *file_channels; } dbgfs_data_files; struct dir_rf_files { struct dentry *file_disable_sensitivity; @@ -70,6 +78,9 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv); #else #define IWL_DEBUG(level, fmt, args...) #define IWL_DEBUG_LIMIT(level, fmt, args...) +static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, + void *p, u32 len) +{} #endif /* CONFIG_IWLWIFI_DEBUG */ @@ -85,29 +96,25 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #endif /* CONFIG_IWLWIFI_DEBUGFS */ /* - * To use the debug system; + * To use the debug system: * * If you are defining a new debug classification, simply add it to the #define - * list here in the form of: + * list here in the form of * * #define IWL_DL_xxxx VALUE * - * shifting value to the left one bit from the previous entry. xxxx should be - * the name of the classification (for example, WEP) + * where xxxx should be the name of the classification (for example, WEP). * * You then need to either add a IWL_xxxx_DEBUG() macro definition for your * classification, or use IWL_DEBUG(IWL_DL_xxxx, ...) whenever you want * to send output to that classification. * - * To add your debug level to the list of levels seen when you perform - * - * % cat /proc/net/iwl/debug_level - * - * you simply need to add your entry to the iwl_debug_levels array. + * The active debug levels can be accessed via files * - * If you do not see debug_level in /proc/net/iwl then you do not have - * CONFIG_IWLWIFI_DEBUG defined in your kernel configuration + * /sys/module/iwlagn/parameters/debug{50} + * /sys/class/net/wlan0/device/debug_level * + * when CONFIG_IWLWIFI_DEBUG=y. */ #define IWL_DL_INFO (1 << 0) @@ -183,6 +190,8 @@ static inline void iwl_dbgfs_unregister(struct iwl_priv *priv) #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_TX_REPLY_LIMIT(f, a...) \ + IWL_DEBUG_LIMIT(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) #define IWL_DEBUG_POWER(f, a...) IWL_DEBUG(IWL_DL_POWER, f, ## a) diff --git a/drivers/net/wireless/iwlwifi/iwl-debugfs.c b/drivers/net/wireless/iwlwifi/iwl-debugfs.c index 20db0eb636a82b64a85f403ef5c096ab37827aaf..d5253a179dec6fd35cd37a4d9687046899ca782a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-debugfs.c +++ b/drivers/net/wireless/iwlwifi/iwl-debugfs.c @@ -22,7 +22,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -58,7 +58,8 @@ #define DEBUGFS_ADD_BOOL(name, parent, ptr) do { \ dbgfs->dbgfs_##parent##_files.file_##name = \ debugfs_create_bool(#name, 0644, dbgfs->dir_##parent, ptr); \ - if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name)) \ + if (IS_ERR(dbgfs->dbgfs_##parent##_files.file_##name) \ + || !dbgfs->dbgfs_##parent##_files.file_##name) \ goto err; \ } while (0) @@ -228,7 +229,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, ssize_t ret; /* Add 30 for initial string */ const size_t bufsz = 30 + sizeof(char) * 500 * (priv->num_stations); - DECLARE_MAC_BUF(mac); buf = kmalloc(bufsz, GFP_KERNEL); if (!buf) @@ -242,7 +242,6 @@ static ssize_t iwl_dbgfs_stations_read(struct file *file, char __user *user_buf, if (station->used) { pos += scnprintf(buf + pos, bufsz - pos, "station %d:\ngeneral data:\n", i+1); - print_mac(mac, station->sta.sta.addr); pos += scnprintf(buf + pos, bufsz - pos, "id: %u\n", station->sta.sta.sta_id); pos += scnprintf(buf + pos, bufsz - pos, "mode: %u\n", @@ -349,12 +348,86 @@ static ssize_t iwl_dbgfs_log_event_write(struct file *file, return count; } + + +static ssize_t iwl_dbgfs_channels_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct iwl_priv *priv = (struct iwl_priv *)file->private_data; + struct ieee80211_channel *channels = NULL; + const struct ieee80211_supported_band *supp_band = NULL; + int pos = 0, i, bufsz = PAGE_SIZE; + char *buf; + ssize_t ret; + + if (!test_bit(STATUS_GEO_CONFIGURED, &priv->status)) + return -EAGAIN; + + buf = kzalloc(bufsz, GFP_KERNEL); + if (!buf) { + IWL_ERROR("Can not allocate Buffer\n"); + return -ENOMEM; + } + + supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_2GHZ); + channels = supp_band->channels; + + pos += scnprintf(buf + pos, bufsz - pos, + "Displaying %d channels in 2.4GHz band 802.11bg):\n", + supp_band->n_channels); + + for (i = 0; i < supp_band->n_channels; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + (!(channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + + supp_band = iwl_get_hw_mode(priv, IEEE80211_BAND_5GHZ); + channels = supp_band->channels; + + pos += scnprintf(buf + pos, bufsz - pos, + "Displaying %d channels in 5.2GHz band (802.11a)\n", + supp_band->n_channels); + + for (i = 0; i < supp_band->n_channels; i++) + pos += scnprintf(buf + pos, bufsz - pos, + "%d: %ddBm: BSS%s%s, %s.\n", + ieee80211_frequency_to_channel( + channels[i].center_freq), + channels[i].max_power, + channels[i].flags & IEEE80211_CHAN_RADAR ? + " (IEEE 802.11h required)" : "", + ((channels[i].flags & IEEE80211_CHAN_NO_IBSS) + || (channels[i].flags & + IEEE80211_CHAN_RADAR)) ? "" : + ", IBSS", + channels[i].flags & + IEEE80211_CHAN_PASSIVE_SCAN ? + "passive only" : "active/passive"); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, pos); + kfree(buf); + return ret; +} + + DEBUGFS_READ_WRITE_FILE_OPS(sram); DEBUGFS_WRITE_FILE_OPS(log_event); DEBUGFS_READ_FILE_OPS(eeprom); DEBUGFS_READ_FILE_OPS(stations); DEBUGFS_READ_FILE_OPS(rx_statistics); DEBUGFS_READ_FILE_OPS(tx_statistics); +DEBUGFS_READ_FILE_OPS(channels); /* * Create the debugfs files and directories @@ -388,6 +461,7 @@ int iwl_dbgfs_register(struct iwl_priv *priv, const char *name) DEBUGFS_ADD_FILE(stations, data); DEBUGFS_ADD_FILE(rx_statistics, data); DEBUGFS_ADD_FILE(tx_statistics, data); + DEBUGFS_ADD_FILE(channels, data); DEBUGFS_ADD_BOOL(disable_sensitivity, rf, &priv->disable_sens_cal); DEBUGFS_ADD_BOOL(disable_chain_noise, rf, &priv->disable_chain_noise_cal); @@ -416,6 +490,7 @@ void iwl_dbgfs_unregister(struct iwl_priv *priv) DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_sram); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_log_event); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_stations); + DEBUGFS_REMOVE(priv->dbgfs->dbgfs_data_files.file_channels); DEBUGFS_REMOVE(priv->dbgfs->dir_data); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_sensitivity); DEBUGFS_REMOVE(priv->dbgfs->dbgfs_rf_files.file_disable_chain_noise); diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h index 9966d4e384ce75d37264345431be2122a5304c68..0468fcc1ea98ed58d42e6988cb248a7a162a3589 100644 --- a/drivers/net/wireless/iwlwifi/iwl-dev.h +++ b/drivers/net/wireless/iwlwifi/iwl-dev.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -54,6 +54,7 @@ extern struct iwl_cfg iwl5100_agn_cfg; extern struct iwl_cfg iwl5350_agn_cfg; extern struct iwl_cfg iwl5100_bg_cfg; extern struct iwl_cfg iwl5100_abg_cfg; +extern struct iwl_cfg iwl5150_agn_cfg; /* CT-KILL constants */ #define CT_KILL_THRESHOLD 110 /* in Celsius */ @@ -113,11 +114,9 @@ struct iwl_queue { * space less than this */ } __attribute__ ((packed)); -#define MAX_NUM_OF_TBS (20) - /* One for each TFD */ struct iwl_tx_info { - struct sk_buff *skb[MAX_NUM_OF_TBS]; + struct sk_buff *skb[IWL_NUM_OF_TBS - 1]; }; /** @@ -135,12 +134,13 @@ struct iwl_tx_info { */ struct iwl_tx_queue { struct iwl_queue q; - struct iwl_tfd_frame *bd; + struct iwl_tfd *tfds; struct iwl_cmd *cmd[TFD_TX_CMD_SLOTS]; struct iwl_tx_info *txb; - int need_update; - int sched_retry; - int active; + u8 need_update; + u8 sched_retry; + u8 active; + u8 swq_id; }; #define IWL_NUM_SCAN_RATES (2) @@ -186,12 +186,6 @@ struct iwl_channel_info { u8 fat_extension_channel; /* HT_IE_EXT_CHANNEL_* */ }; -struct iwl4965_clip_group { - /* maximum power level to prevent clipping for each rate, derived by - * us from this band's saturation power in EEPROM */ - const s8 clip_powers[IWL_MAX_RATES]; -}; - #define IWL_TX_FIFO_AC0 0 #define IWL_TX_FIFO_AC1 1 @@ -253,7 +247,8 @@ struct iwl_cmd_meta { /* The CMD_SIZE_HUGE flag bit indicates that the command * structure is stored at the end of the shared queue memory. */ u32 flags; - + DECLARE_PCI_UNMAP_ADDR(mapping) + DECLARE_PCI_UNMAP_LEN(len) } __attribute__ ((packed)); #define IWL_CMD_MAX_PAYLOAD 320 @@ -269,24 +264,16 @@ struct iwl_cmd { struct iwl_cmd_meta meta; /* driver data */ struct iwl_cmd_header hdr; /* uCode API */ union { - struct iwl_addsta_cmd addsta; - struct iwl_led_cmd led; u32 flags; u8 val8; u16 val16; u32 val32; - struct iwl4965_bt_cmd bt; - struct iwl4965_rxon_time_cmd rxon_time; - struct iwl_powertable_cmd powertable; - struct iwl_qosparam_cmd qosparam; struct iwl_tx_cmd tx; - struct iwl4965_rxon_assoc_cmd rxon_assoc; - struct iwl_rem_sta_cmd rm_sta; - u8 *indirect; u8 payload[IWL_CMD_MAX_PAYLOAD]; } __attribute__ ((packed)) cmd; } __attribute__ ((packed)); + struct iwl_host_cmd { u8 id; u16 len; @@ -309,7 +296,6 @@ struct iwl_host_cmd { /** * struct iwl_rx_queue - Rx queue - * @processed: Internal index to last handled Rx packet * @read: Shared index to newest available Rx buffer * @write: Shared index to oldest written Rx packet * @free_count: Number of pre-allocated buffers in rx_free @@ -324,26 +310,19 @@ struct iwl_rx_queue { dma_addr_t dma_addr; struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS]; struct iwl_rx_mem_buffer *queue[RX_QUEUE_SIZE]; - u32 processed; u32 read; u32 write; u32 free_count; struct list_head rx_free; struct list_head rx_used; int need_update; + struct iwl_rb_status *rb_stts; + dma_addr_t rb_stts_dma; spinlock_t lock; }; #define IWL_SUPPORTED_RATES_IE_LEN 8 -#define SCAN_INTERVAL 100 - -#define MAX_A_CHANNELS 252 -#define MIN_A_CHANNELS 7 - -#define MAX_B_CHANNELS 14 -#define MIN_B_CHANNELS 1 - #define MAX_TID_COUNT 9 #define IWL_INVALID_RATE 0xFF @@ -413,9 +392,8 @@ struct iwl_ht_info { u8 max_amsdu_size; u8 ampdu_factor; u8 mpdu_density; - u8 supp_mcs_set[16]; + struct ieee80211_mcs_info mcs; /* BSS related data */ - u8 control_channel; u8 extension_chan_offset; u8 tx_chan_width; u8 ht_protection; @@ -444,7 +422,6 @@ union iwl_qos_capabity { /* QoS structures */ struct iwl_qos_info { - int qos_enable; int qos_active; union iwl_qos_capabity qos_cap; struct iwl_qosparam_cmd def_qos_parm; @@ -470,7 +447,7 @@ struct fw_desc { /* uCode file layout */ struct iwl_ucode { - __le32 ver; /* major/minor/subminor */ + __le32 ver; /* major/minor/API/serial */ __le32 inst_size; /* bytes of runtime instructions */ __le32 data_size; /* bytes of runtime data */ __le32 init_size; /* bytes of initialization instructions */ @@ -511,11 +488,15 @@ struct iwl_sensitivity_ranges { }; -#define IWL_FAT_CHANNEL_52 BIT(IEEE80211_BAND_5GHZ) +#define KELVIN_TO_CELSIUS(x) ((x)-273) +#define CELSIUS_TO_KELVIN(x) ((x)+273) + /** * struct iwl_hw_params * @max_txq_num: Max # Tx queues supported + * @dma_chnl_num: Number of Tx DMA/FIFO channels + * @scd_bc_tbls_size: size of scheduler byte count tables * @tx/rx_chains_num: Number of TX/RX chains * @valid_tx/rx_ant: usable antennas * @max_rxq_size: Max # Rx frames in Rx queue (must be power-of-2) @@ -528,11 +509,13 @@ struct iwl_sensitivity_ranges { * @sw_crypto: 0 for hw, 1 for sw * @max_xxx_size: for ucode uses * @ct_kill_threshold: temperature threshold + * @calib_init_cfg: setup initial calibrations for the hw * @struct iwl_sensitivity_ranges: range of sensitivity values - * @first_ampdu_q: first HW queue available for ampdu */ struct iwl_hw_params { - u16 max_txq_num; + u8 max_txq_num; + u8 dma_chnl_num; + u16 scd_bc_tbls_size; u8 tx_chains_num; u8 rx_chains_num; u8 valid_tx_ant; @@ -549,22 +532,10 @@ struct iwl_hw_params { u32 max_data_size; u32 max_bsm_size; u32 ct_kill_threshold; /* value in hw-dependent units */ + u32 calib_init_cfg; const struct iwl_sensitivity_ranges *sens; - u8 first_ampdu_q; }; -#define HT_SHORT_GI_20MHZ (1 << 0) -#define HT_SHORT_GI_40MHZ (1 << 1) - - -#define IWL_RX_HDR(x) ((struct iwl4965_rx_frame_hdr *)(\ - x->u.rx_frame.stats.payload + \ - x->u.rx_frame.stats.phy_count)) -#define IWL_RX_END(x) ((struct iwl4965_rx_frame_end *)(\ - IWL_RX_HDR(x)->payload + \ - le16_to_cpu(IWL_RX_HDR(x)->len))) -#define IWL_RX_STATS(x) (&x->u.rx_frame.stats) -#define IWL_RX_DATA(x) (IWL_RX_HDR(x)->payload) /****************************************************************************** * @@ -581,13 +552,8 @@ struct iwl_hw_params { * iwl4965_mac_ <-- mac80211 callback * ****************************************************************************/ -struct iwl_addsta_cmd; -extern int iwl_send_add_sta(struct iwl_priv *priv, - struct iwl_addsta_cmd *sta, u8 flags); -extern u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, - int is_ap, u8 flags, struct ieee80211_ht_info *ht_info); -extern void iwl4965_update_chain_flags(struct iwl_priv *priv); -extern int iwl4965_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); +extern void iwl_update_chain_flags(struct iwl_priv *priv); +extern int iwl_set_pwr_src(struct iwl_priv *priv, enum iwl_pwr_src src); extern const u8 iwl_bcast_addr[ETH_ALEN]; extern int iwl_rxq_stop(struct iwl_priv *priv); extern void iwl_txq_ctx_stop(struct iwl_priv *priv); @@ -611,19 +577,15 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index, int is_huge) } -struct iwl_priv; - - -/* Structures, enum, and defines specific to the 4965 */ - -#define IWL_KW_SIZE 0x1000 /*4k */ - -struct iwl_kw { - dma_addr_t dma_addr; - void *v_addr; +struct iwl_dma_ptr { + dma_addr_t dma; + void *addr; size_t size; }; +#define HT_SHORT_GI_20MHZ (1 << 0) +#define HT_SHORT_GI_40MHZ (1 << 1) + #define IWL_CHANNEL_WIDTH_20MHZ 0 #define IWL_CHANNEL_WIDTH_40MHZ 1 @@ -638,7 +600,6 @@ struct iwl_kw { #define TX_POWER_IWL_ILLEGAL_VOLTAGE -10000 /* Sensitivity and chain noise calibration */ -#define INTERFERENCE_DATA_AVAILABLE __constant_cpu_to_le32(1) #define INITIALIZATION_VALUE 0xFFFF #define CAL_NUM_OF_BEACONS 20 #define MAXIMUM_ALLOWED_PATHLOSS 15 @@ -691,13 +652,20 @@ enum iwl4965_calib_enabled_state { IWL_CALIB_ENABLED = 1, }; -struct statistics_general_data { - u32 beacon_silence_rssi_a; - u32 beacon_silence_rssi_b; - u32 beacon_silence_rssi_c; - u32 beacon_energy_a; - u32 beacon_energy_b; - u32 beacon_energy_c; + +/* + * enum iwl_calib + * defines the order in which results of initial calibrations + * should be sent to the runtime uCode + */ +enum iwl_calib { + IWL_CALIB_XTAL, + IWL_CALIB_DC, + IWL_CALIB_LO, + IWL_CALIB_TX_IQ, + IWL_CALIB_TX_IQ_PERD, + IWL_CALIB_BASE_BAND, + IWL_CALIB_MAX }; /* Opaque calibration results */ @@ -766,7 +734,6 @@ enum { #define IWL_MAX_NUM_QUEUES 20 /* FIXME: do dynamic allocation */ -#define IWL_CALIB_MAX 3 struct iwl_priv { @@ -790,7 +757,7 @@ struct iwl_priv { #ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT /* spectrum measurement report caching */ - struct iwl4965_spectrum_notification measure_report; + struct iwl_spectrum_notification measure_report; u8 measurement_status; #endif /* ucode beacon time */ @@ -801,10 +768,6 @@ struct iwl_priv { struct iwl_channel_info *channel_info; /* channel info array */ u8 channel_count; /* # of channels */ - /* each calibration channel group in the EEPROM has a derived - * clip setting for each rate. */ - const struct iwl4965_clip_group clip_groups[5]; - /* thermal calibration */ s32 temperature; /* degrees Kelvin */ s32 last_temperature; @@ -818,12 +781,13 @@ struct iwl_priv { unsigned long scan_start; unsigned long scan_pass_start; unsigned long scan_start_tsf; + struct iwl_scan_cmd *scan; int scan_bands; int one_direct_scan; u8 direct_ssid_len; u8 direct_ssid[IW_ESSID_MAX_SIZE]; - struct iwl_scan_cmd *scan; - u32 scan_tx_ant[IEEE80211_NUM_BANDS]; + u8 scan_tx_ant[IEEE80211_NUM_BANDS]; + u8 mgmt_tx_ant; /* spinlock */ spinlock_t lock; /* protect general shared data */ @@ -840,6 +804,8 @@ struct iwl_priv { u8 rev_id; /* uCode images, save to reload in case of failure */ + u32 ucode_ver; /* version of ucode, copy of + iwl_ucode.ver */ struct fw_desc ucode_code; /* runtime inst */ struct fw_desc ucode_data; /* runtime data original */ struct fw_desc ucode_data_backup; /* runtime data save/restore */ @@ -850,7 +816,7 @@ struct iwl_priv { u8 ucode_write_complete; /* the image write is complete */ - struct iwl4965_rxon_time_cmd rxon_timing; + struct iwl_rxon_time_cmd rxon_timing; /* We declare this const so it can only be * changed via explicit cast within the @@ -882,7 +848,6 @@ struct iwl_priv { u16 active_rate_basic; u8 assoc_station_added; - u8 use_ant_b_for_management_frame; /* Tx antenna selection */ u8 start_calib; struct iwl_sensitivity_data sensitivity_data; struct iwl_chain_noise_data chain_noise_data; @@ -903,12 +868,14 @@ struct iwl_priv { struct iwl_rx_queue rxq; struct iwl_tx_queue txq[IWL_MAX_NUM_QUEUES]; unsigned long txq_ctx_active_msk; - struct iwl_kw kw; /* keep warm address */ + struct iwl_dma_ptr kw; /* keep warm address */ + struct iwl_dma_ptr scd_bc_tbls; + u32 scd_base_addr; /* scheduler sram base address */ unsigned long status; - int last_rx_rssi; /* From Rx packet statisitics */ + int last_rx_rssi; /* From Rx packet statistics */ int last_rx_noise; /* From beacon statistics */ /* counts mgmt, ctl, and data packets */ @@ -923,8 +890,6 @@ struct iwl_priv { unsigned long last_statistics_time; /* context information */ - u8 essid[IW_ESSID_MAX_SIZE]; - u8 essid_len; u16 rates_mask; u32 power_mode; @@ -965,11 +930,7 @@ struct iwl_priv { struct ieee80211_vif *vif; struct iwl_hw_params hw_params; - /* driver/uCode shared Tx Byte Counts and Rx status */ - void *shared_virt; - int rb_closed_offset; - /* Physical Pointer to Tx Byte Counts and Rx status */ - dma_addr_t shared_phys; + /* Current association information needed to configure the * hardware */ @@ -992,7 +953,6 @@ struct iwl_priv { struct work_struct report_work; struct work_struct request_scan; struct work_struct beacon_update; - struct work_struct set_monitor; struct tasklet_struct irq_tasklet; @@ -1004,9 +964,6 @@ struct iwl_priv { s8 tx_power_user_lmt; s8 tx_power_channel_lmt; -#ifdef CONFIG_PM - u32 pm_state[16]; -#endif #ifdef CONFIG_IWLWIFI_DEBUG /* debugging info */ @@ -1091,26 +1048,4 @@ static inline int is_channel_ibss(const struct iwl_channel_info *ch) return ((ch->flags & EEPROM_CHANNEL_IBSS)) ? 1 : 0; } -#ifdef CONFIG_IWLWIFI_DEBUG -static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, - void *p, u32 len) -{ - if (!(priv->debug_level & level)) - return; - - print_hex_dump(KERN_DEBUG, "iwl data: ", DUMP_PREFIX_OFFSET, 16, 1, - p, len, 1); -} -#else -static inline void iwl_print_hex_dump(struct iwl_priv *priv, int level, - void *p, u32 len) -{ -} -#endif - -extern const struct iwl_channel_info *iwl_get_channel_info( - const struct iwl_priv *priv, enum ieee80211_band band, u16 channel); - -/* Requires full declaration of iwl_priv before including */ - #endif /* __iwl_dev_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.c b/drivers/net/wireless/iwlwifi/iwl-eeprom.c index 37155755efc596bb51d3dc395374bf40a533b086..ce2f47306cea3bce863d7a87de4728d629c5c664 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.c +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.c @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -169,10 +169,9 @@ int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv) CSR_HW_IF_CONFIG_REG_BIT_EEPROM_OWN_SEM); /* See if we got it */ - ret = iwl_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); + ret = iwl_poll_direct_bit(priv, CSR_HW_IF_CONFIG_REG, + 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); @@ -210,10 +209,8 @@ int iwl_eeprom_init(struct iwl_priv *priv) { u16 *e; u32 gp = iwl_read32(priv, CSR_EEPROM_GP); - u32 r; int sz = priv->cfg->eeprom_size; int ret; - int i; u16 addr; /* allocate eeprom */ @@ -241,22 +238,19 @@ int iwl_eeprom_init(struct iwl_priv *priv) /* eeprom is an array of 16bit values */ for (addr = 0; addr < sz; addr += sizeof(u16)) { - _iwl_write32(priv, CSR_EEPROM_REG, addr << 1); - _iwl_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 = _iwl_read_direct32(priv, CSR_EEPROM_REG); - if (r & CSR_EEPROM_REG_READ_VALID_MSK) - break; - udelay(IWL_EEPROM_ACCESS_DELAY); - } + u32 r; + + _iwl_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); - if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { + ret = iwl_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { IWL_ERROR("Time out reading EEPROM[%d]\n", addr); - ret = -ETIMEDOUT; goto done; } + r = _iwl_read_direct32(priv, CSR_EEPROM_REG); e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } ret = 0; @@ -279,7 +273,23 @@ EXPORT_SYMBOL(iwl_eeprom_free); int iwl_eeprom_check_version(struct iwl_priv *priv) { - return priv->cfg->ops->lib->eeprom_ops.check_version(priv); + u16 eeprom_ver; + u16 calib_ver; + + eeprom_ver = iwl_eeprom_query16(priv, EEPROM_VERSION); + calib_ver = priv->cfg->ops->lib->eeprom_ops.calib_version(priv); + + if (eeprom_ver < priv->cfg->eeprom_ver || + calib_ver < priv->cfg->eeprom_calib_ver) + goto err; + + return 0; +err: + IWL_ERROR("Unsupported EEPROM VER=0x%x < 0x%x CALIB=0x%x < 0x%x\n", + eeprom_ver, priv->cfg->eeprom_ver, + calib_ver, priv->cfg->eeprom_calib_ver); + return -EINVAL; + } EXPORT_SYMBOL(iwl_eeprom_check_version); diff --git a/drivers/net/wireless/iwlwifi/iwl-eeprom.h b/drivers/net/wireless/iwlwifi/iwl-eeprom.h index d3a2a5b4ac56214f4127c4a6456650e0f6fc82b6..603c84bed6300b2e195082377c242f48b4a90930 100644 --- a/drivers/net/wireless/iwlwifi/iwl-eeprom.h +++ b/drivers/net/wireless/iwlwifi/iwl-eeprom.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -68,17 +68,14 @@ struct iwl_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 initiates EEPROM read by writing byte address << 1 to CSR_EEPROM_REG. * 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_TIMEOUT 10 /* microseconds */ #define IWL_EEPROM_SEM_RETRY_LIMIT 1000 /* number of attempts (not time) */ @@ -147,6 +144,7 @@ struct iwl_eeprom_channel { /*5000 calibrations */ #define EEPROM_5000_CALIB_ALL (INDIRECT_ADDRESS | INDIRECT_CALIBRATION) #define EEPROM_5000_XTAL ((2*0x128) | EEPROM_5000_CALIB_ALL) +#define EEPROM_5000_TEMPERATURE ((2*0x12A) | EEPROM_5000_CALIB_ALL) /* 5000 links */ #define EEPROM_5000_LINK_HOST (2*0x64) @@ -174,6 +172,9 @@ struct iwl_eeprom_channel { #define EEPROM_5000_REG_BAND_52_FAT_CHANNELS ((0x92)\ | INDIRECT_ADDRESS | INDIRECT_REGULATORY) /* 22 bytes */ +/* 5050 Specific */ +#define EEPROM_5050_TX_POWER_VERSION (4) +#define EEPROM_5050_EEPROM_VERSION (0x21E) /* 2.4 GHz */ extern const u8 iwl_eeprom_band_1[14]; @@ -371,7 +372,7 @@ struct iwl_eeprom_ops { int (*verify_signature) (struct iwl_priv *priv); int (*acquire_semaphore) (struct iwl_priv *priv); void (*release_semaphore) (struct iwl_priv *priv); - int (*check_version) (struct iwl_priv *priv); + u16 (*calib_version) (struct iwl_priv *priv); const u8* (*query_addr) (const struct iwl_priv *priv, size_t offset); }; diff --git a/drivers/net/wireless/iwlwifi/iwl-fh.h b/drivers/net/wireless/iwlwifi/iwl-fh.h index a72efdf6d1dd20160f5bf1526717007615ad875e..d7da1986455092ac6b5cfe47582630f436caeffb 100644 --- a/drivers/net/wireless/iwlwifi/iwl-fh.h +++ b/drivers/net/wireless/iwlwifi/iwl-fh.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -60,6 +60,8 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *****************************************************************************/ +#ifndef __iwl_fh_h__ +#define __iwl_fh_h__ /****************************/ /* Flow Handler Definitions */ @@ -70,7 +72,7 @@ * Addresses are offsets from device's PCI hardware base address. */ #define FH_MEM_LOWER_BOUND (0x1000) -#define FH_MEM_UPPER_BOUND (0x1EF0) +#define FH_MEM_UPPER_BOUND (0x2000) /** * Keep-Warm (KW) buffer base address. @@ -264,6 +266,7 @@ #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_NO_INT_VAL (0x00000000) #define FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL (0x00001000) +#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ /** * Rx Shared Status Registers (RSSR) @@ -290,6 +293,13 @@ #define FH_MEM_TFDIB_REG1_ADDR_BITSHIFT 28 +/* TFDB Area - TFDs buffer table */ +#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) +#define FH_TFDIB_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x900) +#define FH_TFDIB_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x958) +#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) +#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4) + /** * Transmit DMA Channel Control/Status Registers (TCSR) * @@ -316,34 +326,41 @@ #define FH_TCSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xE60) /* Find Control/Status reg for given Tx DMA/FIFO channel */ -#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl) +#define FH49_TCSR_CHNL_NUM (7) +#define FH50_TCSR_CHNL_NUM (8) + +/* TCSR: tx_config register values */ +#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl)) +#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x4) +#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \ + (FH_TCSR_LOWER_BOUND + 0x20 * (_chnl) + 0x8) + +#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_TXF (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_MSG_MODE_DRV (0x00000001) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE_VAL (0x00000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL (0x00000008) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_DISABLE (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE (0x00000008) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) -#define FH_TCSR_CHNL_NUM (7) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_NOINT (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_ENDTFD (0x00400000) +#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_RTC_IFTFD (0x00800000) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE (0x00000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_PAUSE_EOF (0x40000000) +#define FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE (0x80000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_NOINT (0x00000000) -#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_ENDTFD (0x00100000) -#define FH_TCSR_TX_CONFIG_REG_VAL_CIRQ_HOST_IFTFD (0x00200000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_EMPTY (0x00000000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_WAIT (0x00002000) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_VAL_TFDB_VALID (0x00000003) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) -#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) -#define FH_TCSR_CHNL_TX_CONFIG_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl) -#define FH_TCSR_CHNL_TX_CREDIT_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x4) -#define FH_TCSR_CHNL_TX_BUF_STS_REG(_chnl) \ - (FH_TCSR_LOWER_BOUND + 0x20 * _chnl + 0x8) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_NUM (20) +#define FH_TCSR_CHNL_TX_BUF_STS_REG_POS_TB_IDX (12) /** * Tx Shared Status Registers (TSSR) @@ -360,7 +377,7 @@ #define FH_TSSR_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0xEA0) #define FH_TSSR_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0xEC0) -#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010) +#define FH_TSSR_TX_STATUS_REG (FH_TSSR_LOWER_BOUND + 0x010) #define FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) ((1 << (_chnl)) << 24) #define FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl) ((1 << (_chnl)) << 16) @@ -369,25 +386,99 @@ (FH_TSSR_TX_STATUS_REG_BIT_BUFS_EMPTY(_chnl) | \ FH_TSSR_TX_STATUS_REG_BIT_NO_PEND_REQ(_chnl)) - - -#define FH_REGS_LOWER_BOUND (0x1000) -#define FH_REGS_UPPER_BOUND (0x2000) - /* Tx service channels */ -#define FH_SRVC_CHNL (9) -#define FH_SRVC_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x9C8) -#define FH_SRVC_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x9D0) +#define FH_SRVC_CHNL (9) +#define FH_SRVC_LOWER_BOUND (FH_MEM_LOWER_BOUND + 0x9C8) +#define FH_SRVC_UPPER_BOUND (FH_MEM_LOWER_BOUND + 0x9D0) #define FH_SRVC_CHNL_SRAM_ADDR_REG(_chnl) \ (FH_SRVC_LOWER_BOUND + ((_chnl) - 9) * 0x4) -/* TFDB Area - TFDs buffer table */ -#define FH_MEM_TFDIB_DRAM_ADDR_LSB_MSK (0xFFFFFFFF) -#define FH_TFDIB_LOWER_BOUND (FH_REGS_LOWER_BOUND + 0x900) -#define FH_TFDIB_UPPER_BOUND (FH_REGS_LOWER_BOUND + 0x958) -#define FH_TFDIB_CTRL0_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl)) -#define FH_TFDIB_CTRL1_REG(_chnl) (FH_TFDIB_LOWER_BOUND + 0x8 * (_chnl) + 0x4) +#define FH_TX_CHICKEN_BITS_REG (FH_MEM_LOWER_BOUND + 0xE98) +/* Instruct FH to increment the retry count of a packet when + * it is brought from the memory to TX-FIFO + */ +#define FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN (0x00000002) -/* TCSR: tx_config register values */ -#define FH_RSCSR_FRAME_SIZE_MSK (0x00003FFF) /* bits 0-13 */ +/** + * struct iwl_rb_status - reseve buffer status + * host memory mapped FH registers + * @closed_rb_num [0:11] - Indicates the index of the RB which was closed + * @closed_fr_num [0:11] - Indicates the index of the RX Frame which was closed + * @finished_rb_num [0:11] - Indicates the index of the current RB + * in which the last frame was written to + * @finished_fr_num [0:11] - Indicates the index of the RX Frame + * which was transfered + */ +struct iwl_rb_status { + __le16 closed_rb_num; + __le16 closed_fr_num; + __le16 finished_rb_num; + __le16 finished_fr_nam; +} __attribute__ ((packed)); + + +#define TFD_QUEUE_SIZE_MAX (256) +#define TFD_QUEUE_SIZE_BC_DUP (64) +#define TFD_QUEUE_BC_SIZE (TFD_QUEUE_SIZE_MAX + TFD_QUEUE_SIZE_BC_DUP) +#define IWL_TX_DMA_MASK DMA_BIT_MASK(36) +#define IWL_NUM_OF_TBS 20 + +static inline u8 iwl_get_dma_hi_addr(dma_addr_t addr) +{ + return (sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0) & 0xF; +} +/** + * struct iwl_tfd_tb transmit buffer descriptor within transmit frame descriptor + * + * This structure contains dma address and length of transmission address + * + * @lo: low [31:0] portion of the dma address of TX buffer + * every even is unaligned on 16 bit boundary + * @hi_n_len 0-3 [35:32] portion of dma + * 4-15 length of the tx buffer + */ +struct iwl_tfd_tb { + __le32 lo; + __le16 hi_n_len; +} __attribute__((packed)); + +/** + * struct iwl_tfd + * + * Transmit Frame Descriptor (TFD) + * + * @ __reserved1[3] reserved + * @ num_tbs 0-4 number of active tbs + * 5 reserved + * 6-7 padding (not used) + * @ tbs[20] transmit frame buffer descriptors + * @ __pad padding + * + * Each Tx queue uses a circular buffer of 256 TFDs stored in host DRAM. + * Both driver and device share these circular buffers, each of which must be + * contiguous 256 TFDs x 128 bytes-per-TFD = 32 KBytes + * + * Driver must indicate the physical address of the base of each + * circular buffer via the FH_MEM_CBBC_QUEUE registers. + * + * Each TFD contains pointer/size information for up to 20 data buffers + * in host DRAM. These buffers collectively contain the (one) frame described + * by the TFD. Each buffer must be a single contiguous block of memory within + * itself, but buffers may be scattered in host DRAM. Each buffer has max size + * of (4K - 4). The concatenates all of a TFD's buffers into a single + * Tx frame, up to 8 KBytes in size. + * + * A maximum of 255 (not 256!) TFDs may be on a queue waiting for Tx. + */ +struct iwl_tfd { + u8 __reserved1[3]; + u8 num_tbs; + struct iwl_tfd_tb tbs[IWL_NUM_OF_TBS]; + __le32 __pad; +} __attribute__ ((packed)); + + +/* Keep Warm Size */ +#define IWL_KW_SIZE 0x1000 /* 4k */ +#endif /* !__iwl_fh_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-hcmd.c b/drivers/net/wireless/iwlwifi/iwl-hcmd.c index 8300f3d00a0691ff52d5d65c0340779c28b9128a..01a2169cececb1dc7abbed3d2bf8b41ece10d3d3 100644 --- a/drivers/net/wireless/iwlwifi/iwl-hcmd.c +++ b/drivers/net/wireless/iwlwifi/iwl-hcmd.c @@ -22,7 +22,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -36,7 +36,7 @@ #include "iwl-core.h" -#define IWL_CMD(x) case x : return #x +#define IWL_CMD(x) case x: return #x const char *get_cmd_string(u8 cmd) { diff --git a/drivers/net/wireless/iwlwifi/iwl-helpers.h b/drivers/net/wireless/iwlwifi/iwl-helpers.h index 41eed67933289c6f732dfd08892a229cd369d8ef..ca4f638ab9d0e8f4cd7b26712191c5162961d166 100644 --- a/drivers/net/wireless/iwlwifi/iwl-helpers.h +++ b/drivers/net/wireless/iwlwifi/iwl-helpers.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -32,110 +32,6 @@ #include -/* - * The structures defined by the hardware/uCode interface - * have bit-wise operations. For each bit-field there is - * a data symbol in the structure, the start bit position - * and the length of the bit-field. - * - * iwl_get_bits and iwl_set_bits will return or set the - * appropriate bits on a 32-bit value. - * - * IWL_GET_BITS and IWL_SET_BITS use symbol expansion to - * expand out to the appropriate call to iwl_get_bits - * and iwl_set_bits without having to reference all of the - * numerical constants and defines provided in the hardware - * definition - */ - -/** - * iwl_get_bits - Extract a hardware bit-field value - * @src: source hardware value (__le32) - * @pos: bit-position (0-based) of first bit of value - * @len: length of bit-field - * - * iwl_get_bits will return the bit-field in cpu endian ordering. - * - * NOTE: If used from IWL_GET_BITS then pos and len are compile-constants and - * will collapse to minimal code by the compiler. - */ -static inline u32 iwl_get_bits(__le32 src, u8 pos, u8 len) -{ - u32 tmp = le32_to_cpu(src); - - tmp >>= pos; - tmp &= (1UL << len) - 1; - return tmp; -} - -/** - * iwl_set_bits - Set a hardware bit-field value - * @dst: Address of __le32 hardware value - * @pos: bit-position (0-based) of first bit of value - * @len: length of bit-field - * @val: cpu endian value to encode into the bit-field - * - * iwl_set_bits will encode val into dst, masked to be len bits long at bit - * position pos. - * - * NOTE: If used IWL_SET_BITS pos and len will be compile-constants and - * will collapse to minimal code by the compiler. - */ -static inline void iwl_set_bits(__le32 *dst, u8 pos, u8 len, int val) -{ - u32 tmp = le32_to_cpu(*dst); - - tmp &= ~(((1UL << len) - 1) << pos); - tmp |= (val & ((1UL << len) - 1)) << pos; - *dst = cpu_to_le32(tmp); -} - -static inline void iwl_set_bits16(__le16 *dst, u8 pos, u8 len, int val) -{ - u16 tmp = le16_to_cpu(*dst); - - tmp &= ~((1UL << (pos + len)) - (1UL << pos)); - tmp |= (val & ((1UL << len) - 1)) << pos; - *dst = cpu_to_le16(tmp); -} - -/* - * The bit-field definitions in iwl-xxxx-hw.h are in the form of: - * - * struct example { - * __le32 val1; - * #define IWL_name_POS 8 - * #define IWL_name_LEN 4 - * #define IWL_name_SYM val1 - * }; - * - * The IWL_SET_BITS and IWL_GET_BITS macros are provided to allow the driver - * to call: - * - * struct example bar; - * u32 val = IWL_GET_BITS(bar, name); - * val = val * 2; - * IWL_SET_BITS(bar, name, val); - * - * All cpu / host ordering, masking, and shifts are performed by the macros - * and iwl_{get,set}_bits. - * - */ -#define IWL_SET_BITS(s, sym, v) \ - iwl_set_bits(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ - IWL_ ## sym ## _LEN, (v)) - -#define IWL_SET_BITS16(s, sym, v) \ - iwl_set_bits16(&(s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ - IWL_ ## sym ## _LEN, (v)) - -#define IWL_GET_BITS(s, sym) \ - iwl_get_bits((s).IWL_ ## sym ## _SYM, IWL_ ## sym ## _POS, \ - IWL_ ## sym ## _LEN) - - -#define KELVIN_TO_CELSIUS(x) ((x)-273) -#define CELSIUS_TO_KELVIN(x) ((x)+273) #define IWL_MASK(lo, hi) ((1 << (hi)) | ((1 << (hi)) - (1 << (lo)))) @@ -159,11 +55,6 @@ static inline unsigned long elapsed_jiffies(unsigned long start, return end + (MAX_JIFFY_OFFSET - start) + 1; } -static inline u8 iwl_get_dma_hi_address(dma_addr_t addr) -{ - return sizeof(addr) > sizeof(u32) ? (addr >> 16) >> 16 : 0; -} - /** * iwl_queue_inc_wrap - increment queue index, wrap back to beginning * @index -- current index diff --git a/drivers/net/wireless/iwlwifi/iwl-io.h b/drivers/net/wireless/iwlwifi/iwl-io.h index 9740fcc1805e7eb27f99ed6fd3ccd711aadcccf2..0a92e7431adaa023cc6a6916cdf454406c0ca6fc 100644 --- a/drivers/net/wireless/iwlwifi/iwl-io.h +++ b/drivers/net/wireless/iwlwifi/iwl-io.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -55,7 +55,7 @@ * _iwl_read32.) * * These declarations are *extremely* useful in quickly isolating code deltas - * which result in misconfiguring of the hardware I/O. In combination with + * which result in misconfiguration of the hardware I/O. In combination with * git-bisect and the IO debug level you can quickly determine the specific * commit which breaks the IO sequence to the hardware. * @@ -87,17 +87,18 @@ static inline u32 __iwl_read32(char *f, u32 l, struct iwl_priv *priv, u32 ofs) #define iwl_read32(p, o) _iwl_read32(p, o) #endif +#define IWL_POLL_INTERVAL 10 /* microseconds */ static inline int _iwl_poll_bit(struct iwl_priv *priv, u32 addr, u32 bits, u32 mask, int timeout) { - int i = 0; + int t = 0; do { if ((_iwl_read32(priv, addr) & mask) == (bits & mask)) - return i; - mdelay(10); - i += 10; - } while (i < timeout); + return t; + udelay(IWL_POLL_INTERVAL); + t += IWL_POLL_INTERVAL; + } while (t < timeout); return -ETIMEDOUT; } @@ -109,7 +110,7 @@ static inline int __iwl_poll_bit(const char *f, u32 l, int ret = _iwl_poll_bit(priv, addr, bits, mask, timeout); IWL_DEBUG_IO("poll_bit(0x%08X, 0x%08X, 0x%08X) - %s- %s %d\n", addr, bits, mask, - unlikely(ret == -ETIMEDOUT)?"timeout":"", f, l); + unlikely(ret == -ETIMEDOUT) ? "timeout" : "", f, l); return ret; } #define iwl_poll_bit(priv, addr, bits, mask, timeout) \ @@ -269,19 +270,10 @@ static inline void iwl_write_reg_buf(struct iwl_priv *priv, } } -static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, - u32 addr, u32 mask, int timeout) +static inline int _iwl_poll_direct_bit(struct iwl_priv *priv, u32 addr, + u32 mask, int timeout) { - int i = 0; - - do { - if ((_iwl_read_direct32(priv, addr) & mask) == mask) - return i; - mdelay(10); - i += 10; - } while (i < timeout); - - return -ETIMEDOUT; + return _iwl_poll_bit(priv, addr, mask, mask, timeout); } #ifdef CONFIG_IWLWIFI_DEBUG @@ -308,6 +300,7 @@ static inline int __iwl_poll_direct_bit(const char *f, u32 l, static inline u32 _iwl_read_prph(struct iwl_priv *priv, u32 reg) { _iwl_write_direct32(priv, HBUS_TARG_PRPH_RADDR, reg | (3 << 24)); + rmb(); return _iwl_read_direct32(priv, HBUS_TARG_PRPH_RDAT); } #ifdef CONFIG_IWLWIFI_DEBUG @@ -330,6 +323,7 @@ static inline void _iwl_write_prph(struct iwl_priv *priv, { _iwl_write_direct32(priv, HBUS_TARG_PRPH_WADDR, ((addr & 0x0000FFFF) | (3 << 24))); + wmb(); _iwl_write_direct32(priv, HBUS_TARG_PRPH_WDAT, val); } #ifdef CONFIG_IWLWIFI_DEBUG @@ -392,12 +386,14 @@ static inline void iwl_clear_bits_prph(struct iwl_priv static inline u32 iwl_read_targ_mem(struct iwl_priv *priv, u32 addr) { iwl_write_direct32(priv, HBUS_TARG_MEM_RADDR, addr); + rmb(); return iwl_read_direct32(priv, HBUS_TARG_MEM_RDAT); } static inline void iwl_write_targ_mem(struct iwl_priv *priv, u32 addr, u32 val) { iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, val); } @@ -405,6 +401,7 @@ static inline void iwl_write_targ_mem_buf(struct iwl_priv *priv, u32 addr, u32 len, u32 *values) { iwl_write_direct32(priv, HBUS_TARG_MEM_WADDR, addr); + wmb(); for (; 0 < len; len -= sizeof(u32), values++) iwl_write_direct32(priv, HBUS_TARG_MEM_WDAT, *values); } diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 4eee1b163cd2c27115fa46ce95cc9cc0193011dc..11eccd7d268c2946cc13715ee93160314b8fa48a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -41,7 +41,6 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" -#include "iwl-helpers.h" #ifdef CONFIG_IWLWIFI_DEBUG static const char *led_type_str[] = { @@ -278,7 +277,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) /* FIXME: + priv->rx_stats[2].bytes; */ s64 tpt = current_tpt - priv->led_tpt; - if (tpt < 0) /* wrapparound */ + if (tpt < 0) /* wraparound */ tpt = -tpt; IWL_DEBUG_LED("tpt %lld current_tpt %llu\n", @@ -293,7 +292,7 @@ static int iwl_get_blink_rate(struct iwl_priv *priv) if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) break; - IWL_DEBUG_LED("LED BLINK IDX=%d", i); + IWL_DEBUG_LED("LED BLINK IDX=%d\n", i); return i; } diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h index 588c9ad20e83332d11ffbcce7e44aa9daef70e03..021e00bcd1be1af1fa3296875ae5cba2fbe42365 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.h +++ b/drivers/net/wireless/iwlwifi/iwl-led.h @@ -19,7 +19,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ diff --git a/drivers/net/wireless/iwlwifi/iwl-power.c b/drivers/net/wireless/iwlwifi/iwl-power.c index 60a03d2d2d0e451bc4f56a742b50b99d48a2b5dc..75ca6a542174fd9ef847697b96605ea00403088a 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.c +++ b/drivers/net/wireless/iwlwifi/iwl-power.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ @@ -39,7 +39,6 @@ #include "iwl-commands.h" #include "iwl-debug.h" #include "iwl-power.h" -#include "iwl-helpers.h" /* * Setting power level allow the card to go to sleep when not busy @@ -80,7 +79,7 @@ #define IWL_REDUCED_POWER_TEMPERATURE 95 /* default power management (not Tx power) table values */ -/* for tim 0-10 */ +/* for TIM 0-10 */ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 2, 2, 0xFF)}, 0}, @@ -91,7 +90,7 @@ static struct iwl_power_vec_entry range_0[IWL_POWER_MAX] = { }; -/* for tim = 3-10 */ +/* for TIM = 3-10 */ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, @@ -101,7 +100,7 @@ static struct iwl_power_vec_entry range_1[IWL_POWER_MAX] = { {{SLP, SLP_TOUT(25), SLP_TOUT(25), SLP_VEC(2, 4, 7, 10, 10)}, 2} }; -/* for tim > 11 */ +/* for TIM > 11 */ static struct iwl_power_vec_entry range_2[IWL_POWER_MAX] = { {{NOSLP, SLP_TOUT(0), SLP_TOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TOUT(200), SLP_TOUT(500), SLP_VEC(1, 2, 3, 4, 0xFF)}, 0}, @@ -183,7 +182,7 @@ static int iwl_power_init_handle(struct iwl_priv *priv) return 0; } -/* adjust power command according to dtim period and power level*/ +/* adjust power command according to DTIM period and power level*/ static int iwl_update_power_command(struct iwl_priv *priv, struct iwl_powertable_cmd *cmd, u16 mode) @@ -257,15 +256,11 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) struct iwl_power_mgr *setting = &(priv->power_data); int ret = 0; u16 uninitialized_var(final_mode); + bool update_chains; /* Don't update the RX chain when chain noise calibration is running */ - if (priv->chain_noise_data.state != IWL_CHAIN_NOISE_DONE && - priv->chain_noise_data.state != IWL_CHAIN_NOISE_ALIVE) { - IWL_DEBUG_POWER("Cannot update the power, chain noise " - "calibration running: %d\n", - priv->chain_noise_data.state); - return -EAGAIN; - } + update_chains = priv->chain_noise_data.state == IWL_CHAIN_NOISE_DONE || + priv->chain_noise_data.state == IWL_CHAIN_NOISE_ALIVE; /* If on battery, set to 3, * if plugged into AC power, set to CAM ("continuously aware mode"), @@ -313,9 +308,12 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) else set_bit(STATUS_POWER_PMI, &priv->status); - if (priv->cfg->ops->lib->update_chain_flags) + if (priv->cfg->ops->lib->update_chain_flags && update_chains) priv->cfg->ops->lib->update_chain_flags(priv); - + else + IWL_DEBUG_POWER("Cannot update the power, chain noise " + "calibration running: %d\n", + priv->chain_noise_data.state); if (!ret) setting->power_mode = final_mode; } @@ -325,7 +323,7 @@ int iwl_power_update_mode(struct iwl_priv *priv, bool force) EXPORT_SYMBOL(iwl_power_update_mode); /* Allow other iwl code to disable/enable power management active - * this will be usefull for rate scale to disable PM during heavy + * this will be useful for rate scale to disable PM during heavy * Tx/Rx activities */ int iwl_power_disable_management(struct iwl_priv *priv, u32 ms) @@ -352,8 +350,8 @@ int iwl_power_disable_management(struct iwl_priv *priv, u32 ms) EXPORT_SYMBOL(iwl_power_disable_management); /* Allow other iwl code to disable/enable power management active - * this will be usefull for rate scale to disable PM during hight - * valume activities + * this will be useful for rate scale to disable PM during high + * volume activities */ int iwl_power_enable_management(struct iwl_priv *priv) { @@ -391,7 +389,7 @@ int iwl_power_set_system_mode(struct iwl_priv *priv, u16 mode) } EXPORT_SYMBOL(iwl_power_set_system_mode); -/* initilize to default */ +/* initialize to default */ void iwl_power_initialize(struct iwl_priv *priv) { @@ -443,7 +441,7 @@ static void iwl_bg_set_power_save(struct work_struct *work) mutex_lock(&priv->mutex); - /* on starting association we disable power managment + /* on starting association we disable power management * until association, if association failed then this * timer will expire and enable PM again. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-power.h b/drivers/net/wireless/iwlwifi/iwl-power.h index df484a90ae64f521e798243ebb751eef2ffd0bf1..fa098d8975cec38d84161e51a1f5db3a9ea006ad 100644 --- a/drivers/net/wireless/iwlwifi/iwl-power.h +++ b/drivers/net/wireless/iwlwifi/iwl-power.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #ifndef __iwl_power_setting_h__ diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h index ee5afd48d3af035ed22527c29c1b98264216077d..b7a5f23351c303c994a835124d5add570bb99ec6 100644 --- a/drivers/net/wireless/iwlwifi/iwl-prph.h +++ b/drivers/net/wireless/iwlwifi/iwl-prph.h @@ -25,7 +25,7 @@ * in the file called LICENSE.GPL. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * * BSD LICENSE @@ -158,9 +158,9 @@ * * 4) Point (via BSM_DRAM_*) to the "runtime" uCode data and instruction * images in host DRAM. The last register loaded must be the instruction - * bytecount register ("1" in MSbit tells initialization uCode to load + * byte count register ("1" in MSbit tells initialization uCode to load * the runtime uCode): - * BSM_DRAM_INST_BYTECOUNT_REG = bytecount | BSM_DRAM_INST_LOAD + * BSM_DRAM_INST_BYTECOUNT_REG = byte count | BSM_DRAM_INST_LOAD * * 5) Wait for "alive" notification, then issue normal runtime commands. * @@ -244,7 +244,7 @@ /** * Tx Scheduler * - * The Tx Scheduler selects the next frame to be transmitted, chosing TFDs + * The Tx Scheduler selects the next frame to be transmitted, choosing TFDs * (Transmit Frame Descriptors) from up to 16 circular Tx queues resident in * host DRAM. It steers each frame's Tx command (which contains the frame * data) into one of up to 7 prioritized Tx DMA FIFO channels within the diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.c b/drivers/net/wireless/iwlwifi/iwl-rfkill.c index 5d642298f04c33014c896e5cec97d143a38f1b66..4b69da30665c3b1bd74c93f0dd516aaf4e89809e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.c +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #include @@ -34,8 +34,6 @@ #include "iwl-eeprom.h" #include "iwl-dev.h" #include "iwl-core.h" -#include "iwl-helpers.h" - /* software rf-kill from user */ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) @@ -64,7 +62,7 @@ static int iwl_rfkill_soft_rf_kill(void *data, enum rfkill_state state) iwl_radio_kill_sw_disable_radio(priv); break; default: - IWL_WARNING("we recieved unexpected RFKILL state %d\n", state); + IWL_WARNING("we received unexpected RFKILL state %d\n", state); break; } out_unlock: @@ -83,7 +81,7 @@ int iwl_rfkill_init(struct iwl_priv *priv) IWL_DEBUG_RF_KILL("Initializing RFKILL.\n"); priv->rfkill = rfkill_allocate(device, RFKILL_TYPE_WLAN); if (!priv->rfkill) { - IWL_ERROR("Unable to allocate rfkill device.\n"); + IWL_ERROR("Unable to allocate RFKILL device.\n"); ret = -ENOMEM; goto error; } @@ -99,7 +97,7 @@ int iwl_rfkill_init(struct iwl_priv *priv) ret = rfkill_register(priv->rfkill); if (ret) { - IWL_ERROR("Unable to register rfkill: %d\n", ret); + IWL_ERROR("Unable to register RFKILL: %d\n", ret); goto free_rfkill; } @@ -127,7 +125,7 @@ void iwl_rfkill_unregister(struct iwl_priv *priv) } EXPORT_SYMBOL(iwl_rfkill_unregister); -/* set rf-kill to the right state. */ +/* set RFKILL to the right state. */ void iwl_rfkill_set_hw_state(struct iwl_priv *priv) { if (!priv->rfkill) diff --git a/drivers/net/wireless/iwlwifi/iwl-rfkill.h b/drivers/net/wireless/iwlwifi/iwl-rfkill.h index 402fd4c781dab6de6987fc0d8c184f07839a8f67..86dc055a2e9400cf684ea212935789309c6ffa60 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rfkill.h +++ b/drivers/net/wireless/iwlwifi/iwl-rfkill.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ #ifndef __iwl_rf_kill_h__ diff --git a/drivers/net/wireless/iwlwifi/iwl-rx.c b/drivers/net/wireless/iwlwifi/iwl-rx.c index 0509c16dbe758b32e1a23db7da1a09100493b0c8..c5f1aa0feac8c49ecb635e44b7b89e1c98681158 100644 --- a/drivers/net/wireless/iwlwifi/iwl-rx.c +++ b/drivers/net/wireless/iwlwifi/iwl-rx.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -218,8 +218,7 @@ int iwl_rx_queue_restock(struct iwl_priv *priv) /* If we've added more space for the firmware to place data, tell it. * Increment device's write pointer in multiples of 8. */ - if ((write != (rxq->write & ~0x7)) - || (abs(rxq->write - rxq->read) > 7)) { + if (write != (rxq->write & ~0x7)) { spin_lock_irqsave(&rxq->lock, flags); rxq->need_update = 1; spin_unlock_irqrestore(&rxq->lock, flags); @@ -245,25 +244,31 @@ void iwl_rx_allocate(struct iwl_priv *priv) struct list_head *element; struct iwl_rx_mem_buffer *rxb; unsigned long flags; - spin_lock_irqsave(&rxq->lock, flags); - while (!list_empty(&rxq->rx_used)) { + + while (1) { + spin_lock_irqsave(&rxq->lock, flags); + + if (list_empty(&rxq->rx_used)) { + spin_unlock_irqrestore(&rxq->lock, flags); + return; + } element = rxq->rx_used.next; rxb = list_entry(element, struct iwl_rx_mem_buffer, list); + list_del(element); + + spin_unlock_irqrestore(&rxq->lock, flags); /* Alloc a new receive buffer */ rxb->skb = alloc_skb(priv->hw_params.rx_buf_size + 256, - __GFP_NOWARN | GFP_ATOMIC); + GFP_KERNEL); if (!rxb->skb) { - if (net_ratelimit()) - printk(KERN_CRIT DRV_NAME - ": Can not allocate SKB buffers\n"); + printk(KERN_CRIT DRV_NAME + "Can not allocate SKB buffers\n"); /* We don't reschedule replenish work here -- we will * call the restock method and if it still needs * more buffers it will schedule replenish */ break; } - priv->alloc_rxb_skb++; - list_del(element); /* Get physical address of RB/SKB */ rxb->real_dma_addr = pci_map_single( @@ -277,12 +282,15 @@ void iwl_rx_allocate(struct iwl_priv *priv) rxb->aligned_dma_addr = ALIGN(rxb->real_dma_addr, 256); skb_reserve(rxb->skb, rxb->aligned_dma_addr - rxb->real_dma_addr); + spin_lock_irqsave(&rxq->lock, flags); + list_add_tail(&rxb->list, &rxq->rx_free); rxq->free_count++; + priv->alloc_rxb_skb++; + + spin_unlock_irqrestore(&rxq->lock, flags); } - spin_unlock_irqrestore(&rxq->lock, flags); } -EXPORT_SYMBOL(iwl_rx_allocate); void iwl_rx_replenish(struct iwl_priv *priv) { @@ -317,7 +325,10 @@ void iwl_rx_queue_free(struct iwl_priv *priv, struct iwl_rx_queue *rxq) pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, rxq->dma_addr); + pci_free_consistent(priv->pci_dev, sizeof(struct iwl_rb_status), + rxq->rb_stts, rxq->rb_stts_dma); rxq->bd = NULL; + rxq->rb_stts = NULL; } EXPORT_SYMBOL(iwl_rx_queue_free); @@ -334,7 +345,12 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) /* Alloc the circular buffer of Read Buffer Descriptors (RBDs) */ rxq->bd = pci_alloc_consistent(dev, 4 * RX_QUEUE_SIZE, &rxq->dma_addr); if (!rxq->bd) - return -ENOMEM; + goto err_bd; + + rxq->rb_stts = pci_alloc_consistent(dev, sizeof(struct iwl_rb_status), + &rxq->rb_stts_dma); + if (!rxq->rb_stts) + goto err_rb; /* Fill the rx_used queue with _all_ of the Rx buffers */ for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) @@ -346,6 +362,12 @@ int iwl_rx_queue_alloc(struct iwl_priv *priv) rxq->free_count = 0; rxq->need_update = 0; return 0; + +err_rb: + pci_free_consistent(priv->pci_dev, 4 * RX_QUEUE_SIZE, rxq->bd, + rxq->dma_addr); +err_bd: + return -ENOMEM; } EXPORT_SYMBOL(iwl_rx_queue_alloc); @@ -412,10 +434,10 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) /* Tell device where in DRAM to update its Rx status */ iwl_write_direct32(priv, FH_RSCSR_CHNL0_STTS_WPTR_REG, - (priv->shared_phys + priv->rb_closed_offset) >> 4); + rxq->rb_stts_dma >> 4); /* Enable Rx DMA - * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set becuase of HW bug in + * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in * the credit mechanism in 5000 HW RX FIFO * Direct rx interrupts to hosts * Rx buffer size 4 or 8k @@ -426,6 +448,7 @@ int iwl_rx_init(struct iwl_priv *priv, struct iwl_rx_queue *rxq) FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL | FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY | FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL | + FH_RCSR_CHNL0_RX_CONFIG_SINGLE_FRAME_MSK | rb_size| (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)| (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS)); @@ -453,10 +476,8 @@ int iwl_rxq_stop(struct iwl_priv *priv) /* stop Rx DMA */ iwl_write_direct32(priv, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0); - ret = iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, - (1 << 24), 1000); - if (ret < 0) - IWL_ERROR("Can't stop Rx DMA.\n"); + iwl_poll_direct_bit(priv, FH_MEM_RSSR_RX_STATUS_REG, + FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000); iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -470,7 +491,7 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; - struct iwl4965_missed_beacon_notif *missed_beacon; + struct iwl_missed_beacon_notif *missed_beacon; missed_beacon = &pkt->u.missed_beacon; if (le32_to_cpu(missed_beacon->consequtive_missed_beacons) > 5) { @@ -485,49 +506,6 @@ void iwl_rx_missed_beacon_notif(struct iwl_priv *priv, } EXPORT_SYMBOL(iwl_rx_missed_beacon_notif); -int iwl_rx_agg_start(struct iwl_priv *priv, const u8 *addr, int tid, u16 ssn) -{ - unsigned long flags; - int sta_id; - - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; - priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, - CMD_ASYNC); -} -EXPORT_SYMBOL(iwl_rx_agg_start); - -int iwl_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) -{ - unsigned long flags; - int sta_id; - - sta_id = iwl_find_station(priv, addr); - if (sta_id == IWL_INVALID_STATION) - return -ENXIO; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags_msk = 0; - priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; - priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, - CMD_ASYNC); -} -EXPORT_SYMBOL(iwl_rx_agg_stop); - /* Calculate noise level, based on measurements during network silence just * before arriving beacon. This measurement can be done only if we know @@ -651,20 +629,24 @@ static int iwl_calc_sig_qual(int rssi_dbm, int noise_dbm) return sig_qual; } -#ifdef CONFIG_IWLWIFI_DEBUG +/* Calc max signal level (dBm) among 3 possible receivers */ +static inline int iwl_calc_rssi(struct iwl_priv *priv, + struct iwl_rx_phy_res *rx_resp) +{ + return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); +} +#ifdef CONFIG_IWLWIFI_DEBUG /** * iwl_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. + * group100 parameter selects whether to show 1 out of 100 good data frames. + * All beacon and probe response frames are printed. */ static void iwl_dbg_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, + struct iwl_rx_phy_res *phy_res, u16 length, struct ieee80211_hdr *header, int group100) { u32 to_us; @@ -676,20 +658,9 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, u16 seq_ctl; u16 channel; u16 phy_flags; - int rate_sym; - u16 length; - u16 status; - u16 bcn_tmr; + u32 rate_n_flags; 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); + int rssi; if (likely(!(priv->debug_level & IWL_DL_RX))) return; @@ -699,22 +670,13 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, 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); + channel = le16_to_cpu(phy_res->channel); + phy_flags = le16_to_cpu(phy_res->phy_flags); + rate_n_flags = le32_to_cpu(phy_res->rate_n_flags); /* 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); + rssi = iwl_calc_rssi(priv, phy_res); + tsf_low = le64_to_cpu(phy_res->timestamp) & 0x0ffffffff; to_us = !compare_ether_addr(header->addr1, priv->mac_addr); @@ -768,11 +730,13 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, else title = "Frame"; - rate_idx = iwl_hwrate_to_plcp_idx(rate_sym); - if (unlikely(rate_idx == -1)) + rate_idx = iwl_hwrate_to_plcp_idx(rate_n_flags); + if (unlikely((rate_idx < 0) || (rate_idx >= IWL_RATE_COUNT))) { bitrate = 0; - else + WARN_ON_ONCE(1); + } else { bitrate = iwl_rates[rate_idx].ieee / 2; + } /* print frame summary. * MAC addresses show just the last byte (for brevity), @@ -784,24 +748,17 @@ static void iwl_dbg_report_frame(struct iwl_priv *priv, 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, " + IWL_DEBUG_RX("%s: 0x%04x, dst=0x%02x, src=0x%02x, " + "len=%u, rssi=%d, tim=%lu usec, " "phy=0x%02x, chnl=%d\n", title, le16_to_cpu(fc), header->addr1[5], - header->addr3[5], rssi, + header->addr3[5], length, rssi, tsf_low - priv->scan_start_tsf, phy_flags, channel); } } if (print_dump) - iwl_print_hex_dump(priv, IWL_DL_RX, data, length); -} -#else -static inline void iwl_dbg_report_frame(struct iwl_priv *priv, - struct iwl_rx_packet *pkt, - struct ieee80211_hdr *header, - int group100) -{ + iwl_print_hex_dump(priv, IWL_DL_RX, header, length); } #endif @@ -995,46 +952,6 @@ static void iwl_pass_packet_to_mac80211(struct iwl_priv *priv, rxb->skb = NULL; } -/* Calc max signal level (dBm) among 3 possible receivers */ -static inline int iwl_calc_rssi(struct iwl_priv *priv, - struct iwl_rx_phy_res *rx_resp) -{ - return priv->cfg->ops->utils->calc_rssi(priv, rx_resp); -} - - -static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) -{ - unsigned long flags; - - spin_lock_irqsave(&priv->sta_lock, flags); - priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; - priv->stations[sta_id].sta.sta.modify_mask = 0; - priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; - spin_unlock_irqrestore(&priv->sta_lock, flags); - - iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); -} - -static void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) -{ - /* FIXME: need locking over ps_status ??? */ - u8 sta_id = iwl_find_station(priv, addr); - - if (sta_id != IWL_INVALID_STATION) { - u8 sta_awake = priv->stations[sta_id]. - ps_status == STA_PS_STATUS_WAKE; - - if (sta_awake && ps_bit) - priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; - else if (!sta_awake && !ps_bit) { - iwl_sta_modify_ps_wake(priv, sta_id); - priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; - } - } -} - /* This is necessary only for a number of statistics, see the caller. */ static int iwl_is_network_packet(struct iwl_priv *priv, struct ieee80211_hdr *header) @@ -1157,9 +1074,10 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, priv->last_rx_noise = IWL_NOISE_MEAS_NOT_AVAILABLE; /* Set "1" to report good data frames in groups of 100 */ - /* FIXME: need to optimze the call: */ - iwl_dbg_report_frame(priv, pkt, header, 1); - +#ifdef CONFIG_IWLWIFI_DEBUG + if (unlikely(priv->debug_level & IWL_DL_RX)) + iwl_dbg_report_frame(priv, rx_start, len, header, 1); +#endif IWL_DEBUG_STATS_LIMIT("Rssi %d, noise %d, qual %d, TSF %llu\n", rx_status.signal, rx_status.noise, rx_status.signal, (unsigned long long)rx_status.mactime); @@ -1168,12 +1086,12 @@ void iwl_rx_reply_rx(struct iwl_priv *priv, * "antenna number" * * It seems that the antenna field in the phy flags value - * is actually a bitfield. This is undefined by radiotap, + * is actually a bit field. This is undefined by radiotap, * it wants an actual antenna number but I always get "7" * for most legacy frames I receive indicating that the * same frame was received on all three RX chains. * - * I think this field should be removed in favour of a + * I think this field should be removed in favor of a * new 802.11n radiotap field "RX chains" that is defined * as a bitmask. */ diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index c89365e2ca58e3f4c5d142e9f9d11ed75d7642cc..3c803f6922efe0a03c498fe2efc53c78c4db5c50 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c @@ -22,11 +22,13 @@ * in the file called LICENSE.GPL. * * Contact Information: - * Tomas Winkler + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 *****************************************************************************/ -#include +#include #include +#include +#include #include "iwl-eeprom.h" #include "iwl-dev.h" @@ -64,54 +66,6 @@ #define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1)))) -static int scan_tx_ant[3] = { - RATE_MCS_ANT_A_MSK, RATE_MCS_ANT_B_MSK, RATE_MCS_ANT_C_MSK -}; - - - -static int iwl_is_empty_essid(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - - - -static const char *iwl_escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (iwl_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else - *d++ = *s++; - } - *d = '\0'; - return escaped; -} - /** * iwl_scan_cancel - Cancel any currently executing HW scan * @@ -455,10 +409,11 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv, void iwl_init_scan_params(struct iwl_priv *priv) { + u8 ant_idx = fls(priv->hw_params.valid_tx_ant) - 1; if (!priv->scan_tx_ant[IEEE80211_BAND_5GHZ]) - priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = RATE_MCS_ANT_INIT_IND; + priv->scan_tx_ant[IEEE80211_BAND_5GHZ] = ant_idx; if (!priv->scan_tx_ant[IEEE80211_BAND_2GHZ]) - priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = RATE_MCS_ANT_INIT_IND; + priv->scan_tx_ant[IEEE80211_BAND_2GHZ] = ant_idx; } int iwl_scan_initiate(struct iwl_priv *priv) @@ -550,7 +505,7 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, { struct ieee80211_ht_cap *ht_cap; - if (!sband || !sband->ht_info.ht_supported) + if (!sband || !sband->ht_cap.ht_supported) return; if (*left < sizeof(struct ieee80211_ht_cap)) @@ -559,12 +514,12 @@ static void iwl_ht_cap_to_ie(const struct ieee80211_supported_band *sband, *pos++ = sizeof(struct ieee80211_ht_cap); 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->cap_info = cpu_to_le16(sband->ht_cap.cap); + memcpy(&ht_cap->mcs, &sband->ht_cap.mcs, 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); + (sband->ht_cap.ampdu_factor & IEEE80211_HT_AMPDU_PARM_FACTOR) | + ((sband->ht_cap.ampdu_density << 2) & + IEEE80211_HT_AMPDU_PARM_DENSITY); *left -= sizeof(struct ieee80211_ht_cap); } @@ -670,23 +625,6 @@ static u16 iwl_fill_probe_req(struct iwl_priv *priv, return (u16)len; } -static u32 iwl_scan_tx_ant(struct iwl_priv *priv, enum ieee80211_band band) -{ - int i, ind; - - ind = priv->scan_tx_ant[band]; - for (i = 0; i < priv->hw_params.tx_chains_num; i++) { - ind = (ind+1) >= priv->hw_params.tx_chains_num ? 0 : ind+1; - if (priv->hw_params.valid_tx_ant & (1 << ind)) { - priv->scan_tx_ant[band] = ind; - break; - } - } - IWL_DEBUG_SCAN("select TX ANT = %c\n", 'A' + ind); - return scan_tx_ant[ind]; -} - - static void iwl_bg_request_scan(struct work_struct *data) { struct iwl_priv *priv = @@ -699,11 +637,13 @@ static void iwl_bg_request_scan(struct work_struct *data) struct iwl_scan_cmd *scan; struct ieee80211_conf *conf = NULL; int ret = 0; - u32 tx_ant; + u32 rate_flags = 0; u16 cmd_len; enum ieee80211_band band; u8 n_probes = 2; u8 rx_chain = priv->hw_params.valid_rx_ant; + u8 rate; + DECLARE_SSID_BUF(ssid); conf = ieee80211_get_hw_conf(priv->hw); @@ -714,7 +654,7 @@ static void iwl_bg_request_scan(struct work_struct *data) goto done; } - /* Make sure the scan wasn't cancelled before this queued work + /* Make sure the scan wasn't canceled before this queued work * was given the chance to run... */ if (!test_bit(STATUS_SCANNING, &priv->status)) goto done; @@ -796,20 +736,13 @@ static void iwl_bg_request_scan(struct work_struct *data) /* We should add the ability for user to lock to PASSIVE ONLY */ if (priv->one_direct_scan) { IWL_DEBUG_SCAN("Start direct scan for '%s'\n", - iwl_escape_essid(priv->direct_ssid, - priv->direct_ssid_len)); + print_ssid(ssid, priv->direct_ssid, + priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); n_probes++; - } else if (!iwl_is_associated(priv) && priv->essid_len) { - IWL_DEBUG_SCAN("Start direct scan for '%s' (not associated)\n", - iwl_escape_essid(priv->essid, priv->essid_len)); - scan->direct_scan[0].id = WLAN_EID_SSID; - scan->direct_scan[0].len = priv->essid_len; - memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); - n_probes++; } else { IWL_DEBUG_SCAN("Start indirect scan.\n"); } @@ -822,23 +755,16 @@ static void iwl_bg_request_scan(struct work_struct *data) if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) { band = IEEE80211_BAND_2GHZ; scan->flags = RXON_FLG_BAND_24G_MSK | RXON_FLG_AUTO_DETECT_MSK; - tx_ant = iwl_scan_tx_ant(priv, band); - if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) - scan->tx_cmd.rate_n_flags = - iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, - tx_ant); - else - scan->tx_cmd.rate_n_flags = - iwl_hw_set_rate_n_flags(IWL_RATE_1M_PLCP, - tx_ant | - RATE_MCS_CCK_MSK); + if (priv->active_rxon.flags & RXON_FLG_CHANNEL_MODE_PURE_40_MSK) { + rate = IWL_RATE_6M_PLCP; + } else { + rate = IWL_RATE_1M_PLCP; + rate_flags = RATE_MCS_CCK_MSK; + } scan->good_CRC_th = 0; } else if (priv->scan_bands & BIT(IEEE80211_BAND_5GHZ)) { band = IEEE80211_BAND_5GHZ; - tx_ant = iwl_scan_tx_ant(priv, band); - scan->tx_cmd.rate_n_flags = - iwl_hw_set_rate_n_flags(IWL_RATE_6M_PLCP, - tx_ant); + rate = IWL_RATE_6M_PLCP; scan->good_CRC_th = IWL_GOOD_CRC_TH; /* Force use of chains B and C (0x6) for scan Rx for 4965 @@ -851,6 +777,11 @@ static void iwl_bg_request_scan(struct work_struct *data) goto done; } + priv->scan_tx_ant[band] = + iwl_toggle_tx_ant(priv, priv->scan_tx_ant[band]); + rate_flags |= iwl_ant_idx_to_flags(priv->scan_tx_ant[band]); + scan->tx_cmd.rate_n_flags = iwl_hw_set_rate_n_flags(rate, rate_flags); + /* MIMO is not used here, but value is required */ scan->rx_chain = RXON_RX_CHAIN_DRIVER_FORCE_MSK | cpu_to_le16((0x7 << RXON_RX_CHAIN_VALID_POS) | diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.c b/drivers/net/wireless/iwlwifi/iwl-spectrum.c new file mode 100644 index 0000000000000000000000000000000000000000..836c3c80b69ebbe712a9bd09c6cb3596eb2c1d95 --- /dev/null +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.c @@ -0,0 +1,198 @@ +/****************************************************************************** + * + * 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. + * + * 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. + * + * Contact Information: + * Intel Linux Wireless + * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 + * + *****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "iwl-eeprom.h" +#include "iwl-dev.h" +#include "iwl-core.h" +#include "iwl-io.h" +#include "iwl-spectrum.h" + +#define BEACON_TIME_MASK_LOW 0x00FFFFFF +#define BEACON_TIME_MASK_HIGH 0xFF000000 +#define TIME_UNIT 1024 + +/* + * extended beacon time format + * time in usec will be changed into a 32-bit value in 8:24 format + * the high 1 byte is the beacon counts + * the lower 3 bytes is the time in usec within one beacon interval + */ + +/* TOOD: was used in sysfs debug interface need to add to mac */ +#if 0 +static u32 iwl_usecs_to_beacons(u32 usec, u32 beacon_interval) +{ + u32 quot; + u32 rem; + u32 interval = beacon_interval * 1024; + + if (!interval || !usec) + return 0; + + quot = (usec / interval) & (BEACON_TIME_MASK_HIGH >> 24); + rem = (usec % interval) & BEACON_TIME_MASK_LOW; + + return (quot << 24) + rem; +} + +/* base is usually what we get from ucode with each received frame, + * the same as HW timer counter counting down + */ + +static __le32 iwl_add_beacon_time(u32 base, u32 addon, u32 beacon_interval) +{ + u32 base_low = base & BEACON_TIME_MASK_LOW; + u32 addon_low = addon & BEACON_TIME_MASK_LOW; + u32 interval = beacon_interval * TIME_UNIT; + u32 res = (base & BEACON_TIME_MASK_HIGH) + + (addon & BEACON_TIME_MASK_HIGH); + + if (base_low > addon_low) + res += base_low - addon_low; + else if (base_low < addon_low) { + res += interval + base_low - addon_low; + res += (1 << 24); + } else + res += (1 << 24); + + return cpu_to_le32(res); +} +static int iwl_get_measurement(struct iwl_priv *priv, + struct ieee80211_measurement_params *params, + u8 type) +{ + struct iwl4965_spectrum_cmd spectrum; + struct iwl_rx_packet *res; + struct iwl_host_cmd cmd = { + .id = REPLY_SPECTRUM_MEASUREMENT_CMD, + .data = (void *)&spectrum, + .meta.flags = CMD_WANT_SKB, + }; + u32 add_time = le64_to_cpu(params->start_time); + int rc; + int spectrum_resp_status; + int duration = le16_to_cpu(params->duration); + + if (iwl_is_associated(priv)) + add_time = + iwl_usecs_to_beacons( + le64_to_cpu(params->start_time) - priv->last_tsf, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + + memset(&spectrum, 0, sizeof(spectrum)); + + spectrum.channel_count = cpu_to_le16(1); + spectrum.flags = + RXON_FLG_TSF2HOST_MSK | RXON_FLG_ANT_A_MSK | RXON_FLG_DIS_DIV_MSK; + spectrum.filter_flags = MEASUREMENT_FILTER_FLAG; + cmd.len = sizeof(spectrum); + spectrum.len = cpu_to_le16(cmd.len - sizeof(spectrum.len)); + + if (iwl_is_associated(priv)) + spectrum.start_time = + iwl_add_beacon_time(priv->last_beacon_time, + add_time, + le16_to_cpu(priv->rxon_timing.beacon_interval)); + else + spectrum.start_time = 0; + + spectrum.channels[0].duration = cpu_to_le32(duration * TIME_UNIT); + spectrum.channels[0].channel = params->channel; + spectrum.channels[0].type = type; + if (priv->active_rxon.flags & RXON_FLG_BAND_24G_MSK) + spectrum.flags |= RXON_FLG_BAND_24G_MSK | + RXON_FLG_AUTO_DETECT_MSK | RXON_FLG_TGG_PROTECT_MSK; + + rc = iwl_send_cmd_sync(priv, &cmd); + if (rc) + return rc; + + res = (struct iwl_rx_packet *)cmd.meta.u.skb->data; + if (res->hdr.flags & IWL_CMD_FAILED_MSK) { + IWL_ERROR("Bad return from REPLY_RX_ON_ASSOC command\n"); + rc = -EIO; + } + + spectrum_resp_status = le16_to_cpu(res->u.spectrum.status); + switch (spectrum_resp_status) { + case 0: /* Command will be handled */ + if (res->u.spectrum.id != 0xff) { + IWL_DEBUG_INFO + ("Replaced existing measurement: %d\n", + res->u.spectrum.id); + priv->measurement_status &= ~MEASUREMENT_READY; + } + priv->measurement_status |= MEASUREMENT_ACTIVE; + rc = 0; + break; + + case 1: /* Command will not be handled */ + rc = -EAGAIN; + break; + } + + dev_kfree_skb_any(cmd.meta.u.skb); + + return rc; +} +#endif + +static void iwl_rx_spectrum_measure_notif(struct iwl_priv *priv, + struct iwl_rx_mem_buffer *rxb) +{ + struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; + struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif); + + if (!report->state) { + IWL_DEBUG(IWL_DL_11H, + "Spectrum Measure Notification: Start\n"); + return; + } + + memcpy(&priv->measure_report, report, sizeof(*report)); + priv->measurement_status |= MEASUREMENT_READY; +} + +void iwl_setup_spectrum_handlers(struct iwl_priv *priv) +{ + priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] = + iwl_rx_spectrum_measure_notif; +} +EXPORT_SYMBOL(iwl_setup_spectrum_handlers); diff --git a/drivers/net/wireless/iwlwifi/iwl-spectrum.h b/drivers/net/wireless/iwlwifi/iwl-spectrum.h index a40a2174df985df31a19409d72a1f100c63c8bb5..b7d7943e476b055ad7d6204b0fbd8f3ad7e342e5 100644 --- a/drivers/net/wireless/iwlwifi/iwl-spectrum.h +++ b/drivers/net/wireless/iwlwifi/iwl-spectrum.h @@ -21,7 +21,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -88,4 +88,5 @@ struct ieee80211_measurement_report { struct ieee80211_basic_report basic[0]; } u; } __attribute__ ((packed)); + #endif diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.c b/drivers/net/wireless/iwlwifi/iwl-sta.c index 26f7084d3011b7f8f514a4e23090ddfce33ca62c..412f66bac1afc0f4024169b719f179405345a86e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.c +++ b/drivers/net/wireless/iwlwifi/iwl-sta.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -33,8 +33,6 @@ #include "iwl-dev.h" #include "iwl-core.h" #include "iwl-sta.h" -#include "iwl-helpers.h" - #define IWL_STA_DRIVER_ACTIVE BIT(0) /* driver entry is active */ #define IWL_STA_UCODE_ACTIVE BIT(1) /* ucode entry is active */ @@ -45,7 +43,6 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) int start = 0; int ret = IWL_INVALID_STATION; unsigned long flags; - DECLARE_MAC_BUF(mac); if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) || (priv->iw_mode == NL80211_IFTYPE_AP)) @@ -63,8 +60,8 @@ u8 iwl_find_station(struct iwl_priv *priv, const u8 *addr) goto out; } - IWL_DEBUG_ASSOC_LIMIT("can not find STA %s total %d\n", - print_mac(mac, addr), priv->num_stations); + IWL_DEBUG_ASSOC_LIMIT("can not find STA %pM total %d\n", + addr, priv->num_stations); out: spin_unlock_irqrestore(&priv->sta_lock, flags); @@ -86,7 +83,6 @@ EXPORT_SYMBOL(iwl_get_ra_sta_id); static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) { unsigned long flags; - DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags); @@ -94,8 +90,8 @@ static void iwl_sta_ucode_activate(struct iwl_priv *priv, u8 sta_id) IWL_ERROR("ACTIVATE a non DRIVER active station %d\n", sta_id); priv->stations[sta_id].used |= IWL_STA_UCODE_ACTIVE; - IWL_DEBUG_ASSOC("Added STA to Ucode: %s\n", - print_mac(mac, priv->stations[sta_id].sta.sta.addr)); + IWL_DEBUG_ASSOC("Added STA to Ucode: %pM\n", + priv->stations[sta_id].sta.sta.addr); spin_unlock_irqrestore(&priv->sta_lock, flags); } @@ -104,7 +100,9 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; - u8 sta_id = cmd->cmd.addsta.sta.sta_id; + struct iwl_addsta_cmd *addsta = + (struct iwl_addsta_cmd *)cmd->cmd.payload; + u8 sta_id = addsta->sta.sta_id; if (!skb) { IWL_ERROR("Error: Response NULL in REPLY_ADD_STA.\n"); @@ -132,7 +130,7 @@ static int iwl_add_sta_callback(struct iwl_priv *priv, return 1; } -int iwl_send_add_sta(struct iwl_priv *priv, +static int iwl_send_add_sta(struct iwl_priv *priv, struct iwl_addsta_cmd *sta, u8 flags) { struct iwl_rx_packet *res = NULL; @@ -180,10 +178,9 @@ int iwl_send_add_sta(struct iwl_priv *priv, return ret; } -EXPORT_SYMBOL(iwl_send_add_sta); static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, - struct ieee80211_ht_info *sta_ht_inf) + struct ieee80211_sta_ht_cap *sta_ht_inf) { __le32 sta_flags; u8 mimo_ps_mode; @@ -231,13 +228,12 @@ static void iwl_set_ht_add_station(struct iwl_priv *priv, u8 index, * iwl_add_station_flags - Add station to tables in driver and device */ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, - u8 flags, struct ieee80211_ht_info *ht_info) + u8 flags, struct ieee80211_sta_ht_cap *ht_info) { int i; int sta_id = IWL_INVALID_STATION; struct iwl_station_entry *station; unsigned long flags_spin; - DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags_spin); if (is_ap) @@ -273,8 +269,8 @@ u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, int is_ap, station = &priv->stations[sta_id]; station->used = IWL_STA_DRIVER_ACTIVE; - IWL_DEBUG_ASSOC("Add STA to driver ID %d: %s\n", - sta_id, print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Add STA to driver ID %d: %pM\n", + sta_id, addr); priv->num_stations++; /* Set up the REPLY_ADD_STA command to send to device */ @@ -301,14 +297,11 @@ EXPORT_SYMBOL(iwl_add_station_flags); static void iwl_sta_ucode_deactivate(struct iwl_priv *priv, const char *addr) { unsigned long flags; - DECLARE_MAC_BUF(mac); - u8 sta_id = iwl_find_station(priv, addr); BUG_ON(sta_id == IWL_INVALID_STATION); - IWL_DEBUG_ASSOC("Removed STA from Ucode: %s\n", - print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Removed STA from Ucode: %pM\n", addr); spin_lock_irqsave(&priv->sta_lock, flags); @@ -326,7 +319,9 @@ static int iwl_remove_sta_callback(struct iwl_priv *priv, struct iwl_cmd *cmd, struct sk_buff *skb) { struct iwl_rx_packet *res = NULL; - const char *addr = cmd->cmd.rm_sta.addr; + struct iwl_rem_sta_cmd *rm_sta = + (struct iwl_rem_sta_cmd *)cmd->cmd.payload; + const char *addr = rm_sta->addr; if (!skb) { IWL_ERROR("Error: Response NULL in REPLY_REMOVE_STA.\n"); @@ -415,7 +410,6 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) int sta_id = IWL_INVALID_STATION; int i, ret = -EINVAL; unsigned long flags; - DECLARE_MAC_BUF(mac); spin_lock_irqsave(&priv->sta_lock, flags); @@ -435,18 +429,18 @@ int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap) if (unlikely(sta_id == IWL_INVALID_STATION)) goto out; - IWL_DEBUG_ASSOC("Removing STA from driver:%d %s\n", - sta_id, print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Removing STA from driver:%d %pM\n", + sta_id, addr); if (!(priv->stations[sta_id].used & IWL_STA_DRIVER_ACTIVE)) { - IWL_ERROR("Removing %s but non DRIVER active\n", - print_mac(mac, addr)); + IWL_ERROR("Removing %pM but non DRIVER active\n", + addr); goto out; } if (!(priv->stations[sta_id].used & IWL_STA_UCODE_ACTIVE)) { - IWL_ERROR("Removing %s but non UCODE active\n", - print_mac(mac, addr)); + IWL_ERROR("Removing %pM but non UCODE active\n", + addr); goto out; } @@ -467,6 +461,29 @@ out: } EXPORT_SYMBOL(iwl_remove_station); +/** + * iwl_clear_stations_table - Clear the driver's station table + * + * NOTE: This does not clear or otherwise alter the device's station table. + */ +void iwl_clear_stations_table(struct iwl_priv *priv) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + + if (iwl_is_alive(priv) && + !test_bit(STATUS_EXIT_PENDING, &priv->status) && + iwl_send_cmd_pdu_async(priv, REPLY_REMOVE_ALL_STA, 0, NULL, NULL)) + IWL_ERROR("Couldn't clear the station table\n"); + + priv->num_stations = 0; + memset(priv->stations, 0, sizeof(priv->stations)); + + spin_unlock_irqrestore(&priv->sta_lock, flags); +} +EXPORT_SYMBOL(iwl_clear_stations_table); + static int iwl_get_free_ucode_key_index(struct iwl_priv *priv) { int i; @@ -717,6 +734,55 @@ static int iwl_set_tkip_dynamic_key_info(struct iwl_priv *priv, return ret; } +void iwl_update_tkip_key(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + const u8 *addr, u32 iv32, u16 *phase1key) +{ + u8 sta_id = IWL_INVALID_STATION; + unsigned long flags; + __le16 key_flags = 0; + int i; + DECLARE_MAC_BUF(mac); + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) { + IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", + addr); + return; + } + + if (iwl_scan_cancel(priv)) { + /* cancel scan failed, just live w/ bad key and rely + briefly on SW decryption */ + return; + } + + key_flags |= (STA_KEY_FLG_TKIP | STA_KEY_FLG_MAP_KEY_MSK); + key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS); + key_flags &= ~STA_KEY_FLG_INVALID; + + if (sta_id == priv->hw_params.bcast_sta_id) + key_flags |= STA_KEY_MULTICAST_MSK; + + spin_lock_irqsave(&priv->sta_lock, flags); + + priv->stations[sta_id].sta.key.key_flags = key_flags; + priv->stations[sta_id].sta.key.tkip_rx_tsc_byte2 = (u8) iv32; + + for (i = 0; i < 5; i++) + priv->stations[sta_id].sta.key.tkip_rx_ttak[i] = + cpu_to_le16(phase1key[i]); + + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); + + spin_unlock_irqrestore(&priv->sta_lock, flags); + +} +EXPORT_SYMBOL(iwl_update_tkip_key); + int iwl_remove_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *keyconf, u8 sta_id) @@ -809,7 +875,7 @@ static void iwl_dump_lq_cmd(struct iwl_priv *priv, { int i; IWL_DEBUG_RATE("lq station id 0x%x\n", lq->sta_id); - IWL_DEBUG_RATE("lq dta 0x%X 0x%X\n", + IWL_DEBUG_RATE("lq ant 0x%X 0x%X\n", lq->general_params.single_stream_ant_msk, lq->general_params.dual_stream_ant_msk); @@ -870,7 +936,7 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) struct iwl_link_quality_cmd link_cmd = { .reserved1 = 0, }; - u16 rate_flags; + u32 rate_flags; /* Set up the rate scaling to start at selected rate, fall back * all the way down to 1M in IEEE order, and then spin on 1M */ @@ -886,15 +952,16 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) if (r >= IWL_FIRST_CCK_RATE && r <= IWL_LAST_CCK_RATE) rate_flags |= RATE_MCS_CCK_MSK; - /* Use Tx antenna B only */ - rate_flags |= RATE_MCS_ANT_B_MSK; /*FIXME:RS*/ + rate_flags |= first_antenna(priv->hw_params.valid_tx_ant) << + RATE_MCS_ANT_POS; link_cmd.rs_table[i].rate_n_flags = iwl_hw_set_rate_n_flags(iwl_rates[r].plcp, rate_flags); - r = iwl4965_get_prev_ieee_rate(r); + r = iwl_get_prev_ieee_rate(r); } - link_cmd.general_params.single_stream_ant_msk = 2; + link_cmd.general_params.single_stream_ant_msk = + first_antenna(priv->hw_params.valid_tx_ant); link_cmd.general_params.dual_stream_ant_msk = 3; link_cmd.agg_params.agg_dis_start_th = 3; link_cmd.agg_params.agg_time_limit = cpu_to_le16(4000); @@ -910,24 +977,35 @@ static void iwl_sta_init_lq(struct iwl_priv *priv, const u8 *addr, int is_ap) * iwl_rxon_add_station - add station into station table. * * there is only one AP station with id= IWL_AP_ID - * NOTE: mutex must be held before calling this fnction + * NOTE: mutex must be held before calling this function */ int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap) { + struct ieee80211_sta *sta; + struct ieee80211_sta_ht_cap ht_config; + struct ieee80211_sta_ht_cap *cur_ht_config = NULL; u8 sta_id; /* Add station to device's station table */ - struct ieee80211_conf *conf = &priv->hw->conf; - struct ieee80211_ht_info *cur_ht_config = &conf->ht_conf; - - if ((is_ap) && - (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) && - (priv->iw_mode == NL80211_IFTYPE_STATION)) - sta_id = iwl_add_station_flags(priv, addr, is_ap, - 0, cur_ht_config); - else - sta_id = iwl_add_station_flags(priv, addr, is_ap, - 0, NULL); + + /* + * XXX: This check is definitely not correct, if we're an AP + * it'll always be false which is not what we want, but + * it doesn't look like iwlagn is prepared to be an HT + * AP anyway. + */ + if (priv->current_ht_config.is_ht) { + rcu_read_lock(); + sta = ieee80211_find_sta(priv->hw, addr); + if (sta) { + memcpy(&ht_config, &sta->ht_cap, sizeof(ht_config)); + cur_ht_config = &ht_config; + } + rcu_read_unlock(); + } + + sta_id = iwl_add_station_flags(priv, addr, is_ap, + 0, cur_ht_config); /* Set up default rate scaling table in device's station table */ iwl_sta_init_lq(priv, addr, is_ap); @@ -945,7 +1023,6 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) { int sta_id; u16 fc = le16_to_cpu(hdr->frame_control); - DECLARE_MAC_BUF(mac); /* If this frame is broadcast or management, use broadcast station id */ if (((fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA) || @@ -980,9 +1057,9 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) if (sta_id != IWL_INVALID_STATION) return sta_id; - IWL_DEBUG_DROP("Station %s not in station map. " + IWL_DEBUG_DROP("Station %pM not in station map. " "Defaulting to broadcast...\n", - print_mac(mac, hdr->addr1)); + hdr->addr1); iwl_print_hex_dump(priv, IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_params.bcast_sta_id; @@ -999,9 +1076,9 @@ int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr) EXPORT_SYMBOL(iwl_get_sta_id); /** - * iwl_sta_modify_enable_tid_tx - Enable Tx for this TID in station table + * iwl_sta_tx_modify_enable_tid - Enable Tx for this TID in station table */ -void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid) +void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid) { unsigned long flags; @@ -1014,5 +1091,81 @@ void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid) iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); } -EXPORT_SYMBOL(iwl_sta_modify_enable_tid_tx); +EXPORT_SYMBOL(iwl_sta_tx_modify_enable_tid); + +int iwl_sta_rx_agg_start(struct iwl_priv *priv, + const u8 *addr, int tid, u16 ssn) +{ + unsigned long flags; + int sta_id; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_ADDBA_TID_MSK; + priv->stations[sta_id].sta.add_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.add_immediate_ba_ssn = cpu_to_le16(ssn); + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_sta_rx_agg_start); + +int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid) +{ + unsigned long flags; + int sta_id; + + sta_id = iwl_find_station(priv, addr); + if (sta_id == IWL_INVALID_STATION) + return -ENXIO; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags_msk = 0; + priv->stations[sta_id].sta.sta.modify_mask = STA_MODIFY_DELBA_TID_MSK; + priv->stations[sta_id].sta.remove_immediate_ba_tid = (u8)tid; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + return iwl_send_add_sta(priv, &priv->stations[sta_id].sta, + CMD_ASYNC); +} +EXPORT_SYMBOL(iwl_sta_rx_agg_stop); + +static void iwl_sta_modify_ps_wake(struct iwl_priv *priv, int sta_id) +{ + unsigned long flags; + + spin_lock_irqsave(&priv->sta_lock, flags); + priv->stations[sta_id].sta.station_flags &= ~STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.station_flags_msk = STA_FLG_PWR_SAVE_MSK; + priv->stations[sta_id].sta.sta.modify_mask = 0; + priv->stations[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK; + spin_unlock_irqrestore(&priv->sta_lock, flags); + + iwl_send_add_sta(priv, &priv->stations[sta_id].sta, CMD_ASYNC); +} + +void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr) +{ + /* FIXME: need locking over ps_status ??? */ + u8 sta_id = iwl_find_station(priv, addr); + + if (sta_id != IWL_INVALID_STATION) { + u8 sta_awake = priv->stations[sta_id]. + ps_status == STA_PS_STATUS_WAKE; + + if (sta_awake && ps_bit) + priv->stations[sta_id].ps_status = STA_PS_STATUS_SLEEP; + else if (!sta_awake && !ps_bit) { + iwl_sta_modify_ps_wake(priv, sta_id); + priv->stations[sta_id].ps_status = STA_PS_STATUS_WAKE; + } + } +} diff --git a/drivers/net/wireless/iwlwifi/iwl-sta.h b/drivers/net/wireless/iwlwifi/iwl-sta.h index 221b93e670a6c4e4d0d29d1431af2e388020f7a8..9bb7cefc1f3cd2fc2157831c7958024ef5c7214e 100644 --- a/drivers/net/wireless/iwlwifi/iwl-sta.h +++ b/drivers/net/wireless/iwlwifi/iwl-sta.h @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -47,9 +47,21 @@ int iwl_set_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); int iwl_remove_dynamic_key(struct iwl_priv *priv, struct ieee80211_key_conf *key, u8 sta_id); +void iwl_update_tkip_key(struct iwl_priv *priv, + struct ieee80211_key_conf *keyconf, + const u8 *addr, u32 iv32, u16 *phase1key); + int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap); int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap); +void iwl_clear_stations_table(struct iwl_priv *priv); int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); -void iwl_sta_modify_enable_tid_tx(struct iwl_priv *priv, int sta_id, int tid); int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr); +u8 iwl_add_station_flags(struct iwl_priv *priv, const u8 *addr, + int is_ap, u8 flags, + struct ieee80211_sta_ht_cap *ht_info); +void iwl_sta_tx_modify_enable_tid(struct iwl_priv *priv, int sta_id, int tid); +int iwl_sta_rx_agg_start(struct iwl_priv *priv, + const u8 *addr, int tid, u16 ssn); +int iwl_sta_rx_agg_stop(struct iwl_priv *priv, const u8 *addr, int tid); +void iwl_update_ps_mode(struct iwl_priv *priv, u16 ps_bit, u8 *addr); #endif /* __iwl_sta_h__ */ diff --git a/drivers/net/wireless/iwlwifi/iwl-tx.c b/drivers/net/wireless/iwlwifi/iwl-tx.c index 907a53ebc6e4dc62fc7a5226b6706af72d1e0d85..b0ee86c6268501754651206d88b87fdcfceb2401 100644 --- a/drivers/net/wireless/iwlwifi/iwl-tx.c +++ b/drivers/net/wireless/iwlwifi/iwl-tx.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -56,96 +56,132 @@ static const u16 default_tid_to_tx_fifo[] = { IWL_TX_FIFO_AC3 }; +static inline int iwl_alloc_dma_ptr(struct iwl_priv *priv, + struct iwl_dma_ptr *ptr, size_t size) +{ + ptr->addr = pci_alloc_consistent(priv->pci_dev, size, &ptr->dma); + if (!ptr->addr) + return -ENOMEM; + ptr->size = size; + return 0; +} + +static inline void iwl_free_dma_ptr(struct iwl_priv *priv, + struct iwl_dma_ptr *ptr) +{ + if (unlikely(!ptr->addr)) + return; + + pci_free_consistent(priv->pci_dev, ptr->size, ptr->addr, ptr->dma); + memset(ptr, 0, sizeof(*ptr)); +} + +static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx) +{ + struct iwl_tfd_tb *tb = &tfd->tbs[idx]; + + dma_addr_t addr = get_unaligned_le32(&tb->lo); + if (sizeof(dma_addr_t) > sizeof(u32)) + addr |= + ((dma_addr_t)(le16_to_cpu(tb->hi_n_len) & 0xF) << 16) << 16; + + return addr; +} + +static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx) +{ + struct iwl_tfd_tb *tb = &tfd->tbs[idx]; + + return le16_to_cpu(tb->hi_n_len) >> 4; +} + +static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx, + dma_addr_t addr, u16 len) +{ + struct iwl_tfd_tb *tb = &tfd->tbs[idx]; + u16 hi_n_len = len << 4; + + put_unaligned_le32(addr, &tb->lo); + if (sizeof(dma_addr_t) > sizeof(u32)) + hi_n_len |= ((addr >> 16) >> 16) & 0xF; + + tb->hi_n_len = cpu_to_le16(hi_n_len); + + tfd->num_tbs = idx + 1; +} + +static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd) +{ + return tfd->num_tbs & 0x1f; +} /** * iwl_hw_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr] + * @priv - driver private data + * @txq - tx queue * * Does NOT advance any TFD circular buffer read/write indexes * Does NOT free the TFD itself (which is within circular buffer) */ -static int iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) +static void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - struct iwl_tfd_frame *bd_tmp = (struct iwl_tfd_frame *)&txq->bd[0]; - struct iwl_tfd_frame *bd = &bd_tmp[txq->q.read_ptr]; + struct iwl_tfd *tfd_tmp = (struct iwl_tfd *)&txq->tfds[0]; + struct iwl_tfd *tfd; struct pci_dev *dev = priv->pci_dev; + int index = txq->q.read_ptr; int i; - int counter = 0; - int index, is_odd; + int num_tbs; - /* Host command buffers stay mapped in memory, nothing to clean */ - if (txq->q.id == IWL_CMD_QUEUE_NUM) - return 0; + tfd = &tfd_tmp[index]; /* Sanity check on number of chunks */ - counter = IWL_GET_BITS(*bd, num_tbs); - if (counter > MAX_NUM_OF_TBS) { - IWL_ERROR("Too many chunks: %i\n", counter); + num_tbs = iwl_tfd_get_num_tbs(tfd); + + if (num_tbs >= IWL_NUM_OF_TBS) { + IWL_ERROR("Too many chunks: %i\n", num_tbs); /* @todo issue fatal error, it is quite serious situation */ - return 0; + return; } - /* Unmap chunks, if any. - * TFD info for odd chunks is different format than for even chunks. */ - for (i = 0; i < counter; i++) { - index = i / 2; - is_odd = i & 0x1; - - if (is_odd) - pci_unmap_single( - dev, - IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | - (IWL_GET_BITS(bd->pa[index], - tb2_addr_hi20) << 16), - IWL_GET_BITS(bd->pa[index], tb2_len), + /* Unmap tx_cmd */ + if (num_tbs) + pci_unmap_single(dev, + pci_unmap_addr(&txq->cmd[index]->meta, mapping), + pci_unmap_len(&txq->cmd[index]->meta, len), PCI_DMA_TODEVICE); - else if (i > 0) - pci_unmap_single(dev, - le32_to_cpu(bd->pa[index].tb1_addr), - IWL_GET_BITS(bd->pa[index], tb1_len), - PCI_DMA_TODEVICE); + /* Unmap chunks, if any. */ + for (i = 1; i < num_tbs; i++) { + pci_unmap_single(dev, iwl_tfd_tb_get_addr(tfd, i), + iwl_tfd_tb_get_len(tfd, i), PCI_DMA_TODEVICE); - /* Free SKB, if any, for this chunk */ - if (txq->txb[txq->q.read_ptr].skb[i]) { - struct sk_buff *skb = txq->txb[txq->q.read_ptr].skb[i]; - - dev_kfree_skb(skb); - txq->txb[txq->q.read_ptr].skb[i] = NULL; + if (txq->txb) { + dev_kfree_skb(txq->txb[txq->q.read_ptr].skb[i - 1]); + txq->txb[txq->q.read_ptr].skb[i - 1] = NULL; } } - return 0; } -static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, void *ptr, - dma_addr_t addr, u16 len) +static int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv, + struct iwl_tfd *tfd, + dma_addr_t addr, u16 len) { - int index, is_odd; - struct iwl_tfd_frame *tfd = ptr; - u32 num_tbs = IWL_GET_BITS(*tfd, num_tbs); + + u32 num_tbs = iwl_tfd_get_num_tbs(tfd); /* Each TFD can point to a maximum 20 Tx buffers */ - if (num_tbs >= MAX_NUM_OF_TBS) { + if (num_tbs >= IWL_NUM_OF_TBS) { IWL_ERROR("Error can not send more than %d chunks\n", - MAX_NUM_OF_TBS); + IWL_NUM_OF_TBS); return -EINVAL; } - index = num_tbs / 2; - is_odd = num_tbs & 0x1; - - if (!is_odd) { - tfd->pa[index].tb1_addr = cpu_to_le32(addr); - IWL_SET_BITS(tfd->pa[index], tb1_addr_hi, - iwl_get_dma_hi_address(addr)); - IWL_SET_BITS(tfd->pa[index], tb1_len, len); - } else { - IWL_SET_BITS(tfd->pa[index], tb2_addr_lo16, - (u32) (addr & 0xffff)); - IWL_SET_BITS(tfd->pa[index], tb2_addr_hi20, addr >> 16); - IWL_SET_BITS(tfd->pa[index], tb2_len, len); - } + BUG_ON(addr & ~DMA_BIT_MASK(36)); + if (unlikely(addr & ~IWL_TX_DMA_MASK)) + IWL_ERROR("Unaligned address = %llx\n", + (unsigned long long)addr); - IWL_SET_BITS(*tfd, num_tbs, num_tbs + 1); + iwl_tfd_set_tb(tfd, num_tbs, addr, len); return 0; } @@ -210,7 +246,7 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; struct pci_dev *dev = priv->pci_dev; - int i, slots_num, len; + int i, len; if (q->n_bd == 0) return; @@ -221,21 +257,15 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) iwl_hw_txq_free_tfd(priv, txq); len = sizeof(struct iwl_cmd) * q->n_window; - if (q->id == IWL_CMD_QUEUE_NUM) - len += IWL_MAX_SCAN_SIZE; /* De-alloc array of command/tx buffers */ - slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? - TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS; - for (i = 0; i < slots_num; i++) + for (i = 0; i < TFD_TX_CMD_SLOTS; i++) kfree(txq->cmd[i]); - if (txq_id == IWL_CMD_QUEUE_NUM) - kfree(txq->cmd[slots_num]); /* De-alloc circular buffer of TFDs */ if (txq->q.n_bd) - pci_free_consistent(dev, sizeof(struct iwl_tfd_frame) * - txq->q.n_bd, txq->bd, txq->q.dma_addr); + pci_free_consistent(dev, sizeof(struct iwl_tfd) * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); /* De-alloc array of per-TFD driver data */ kfree(txq->txb); @@ -245,6 +275,40 @@ static void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id) memset(txq, 0, sizeof(*txq)); } + +/** + * iwl_cmd_queue_free - Deallocate DMA queue. + * @txq: Transmit queue to deallocate. + * + * Empty queue by removing and destroying all BD's. + * Free all buffers. + * 0-fill, but do not free "txq" descriptor structure. + */ +static void iwl_cmd_queue_free(struct iwl_priv *priv) +{ + struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; + struct iwl_queue *q = &txq->q; + struct pci_dev *dev = priv->pci_dev; + int i, len; + + if (q->n_bd == 0) + return; + + len = sizeof(struct iwl_cmd) * q->n_window; + len += IWL_MAX_SCAN_SIZE; + + /* De-alloc array of command/tx buffers */ + for (i = 0; i <= TFD_CMD_SLOTS; i++) + kfree(txq->cmd[i]); + + /* De-alloc circular buffer of TFDs */ + if (txq->q.n_bd) + pci_free_consistent(dev, sizeof(struct iwl_tfd) * + txq->q.n_bd, txq->tfds, txq->q.dma_addr); + + /* 0-fill queue descriptor structure */ + memset(txq, 0, sizeof(*txq)); +} /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services * @@ -340,13 +404,13 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv, /* Circular buffer of transmit frame descriptors (TFDs), * shared with device */ - txq->bd = pci_alloc_consistent(dev, - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX, + txq->tfds = pci_alloc_consistent(dev, + sizeof(txq->tfds[0]) * TFD_QUEUE_SIZE_MAX, &txq->q.dma_addr); - if (!txq->bd) { + if (!txq->tfds) { IWL_ERROR("pci_alloc_consistent(%zd) failed\n", - sizeof(txq->bd[0]) * TFD_QUEUE_SIZE_MAX); + sizeof(txq->tfds[0]) * TFD_QUEUE_SIZE_MAX); goto error; } txq->q.id = id; @@ -370,26 +434,21 @@ static int iwl_tx_queue_alloc(struct iwl_priv *priv, static int iwl_hw_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq) { - int rc; + int ret; unsigned long flags; int txq_id = txq->q.id; spin_lock_irqsave(&priv->lock, flags); - rc = iwl_grab_nic_access(priv); - if (rc) { + ret = iwl_grab_nic_access(priv); + if (ret) { spin_unlock_irqrestore(&priv->lock, flags); - return rc; + return ret; } /* Circular buffer (TFD queue in DRAM) physical base address */ iwl_write_direct32(priv, FH_MEM_CBBC_QUEUE(txq_id), txq->q.dma_addr >> 8); - /* Enable DMA channel, using same id as for TFD queue */ - iwl_write_direct32( - priv, FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE | - FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE_VAL); iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -468,16 +527,20 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv) /* Tx queues */ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) - iwl_tx_queue_free(priv, txq_id); + if (txq_id == IWL_CMD_QUEUE_NUM) + iwl_cmd_queue_free(priv); + else + iwl_tx_queue_free(priv, txq_id); - /* Keep-warm buffer */ - iwl_kw_free(priv); + iwl_free_dma_ptr(priv, &priv->kw); + + iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); } EXPORT_SYMBOL(iwl_hw_txq_ctx_free); /** * iwl_txq_ctx_reset - Reset TX queue context - * Destroys all DMA structures and initialise them again + * Destroys all DMA structures and initialize them again * * @param priv * @return error code @@ -488,13 +551,17 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) int txq_id, slots_num; unsigned long flags; - iwl_kw_free(priv); - /* Free all tx/cmd queues and keep-warm buffer */ iwl_hw_txq_ctx_free(priv); + ret = iwl_alloc_dma_ptr(priv, &priv->scd_bc_tbls, + priv->hw_params.scd_bc_tbls_size); + if (ret) { + IWL_ERROR("Scheduler BC Table allocation failed\n"); + goto error_bc_tbls; + } /* Alloc keep-warm buffer */ - ret = iwl_kw_alloc(priv); + ret = iwl_alloc_dma_ptr(priv, &priv->kw, IWL_KW_SIZE); if (ret) { IWL_ERROR("Keep Warm allocation failed\n"); goto error_kw; @@ -509,17 +576,12 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) /* Turn off all Tx DMA fifos */ priv->cfg->ops->lib->txq_set_sched(priv, 0); + /* Tell NIC where to find the "keep warm" buffer */ + iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4); + iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); - - /* Tell nic where to find the keep-warm buffer */ - ret = iwl_kw_init(priv); - if (ret) { - IWL_ERROR("kw_init failed\n"); - goto error_reset; - } - /* Alloc and init all Tx queues, including the command queue (#4) */ for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { slots_num = (txq_id == IWL_CMD_QUEUE_NUM) ? @@ -537,8 +599,10 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) error: iwl_hw_txq_ctx_free(priv); error_reset: - iwl_kw_free(priv); + iwl_free_dma_ptr(priv, &priv->kw); error_kw: + iwl_free_dma_ptr(priv, &priv->scd_bc_tbls); + error_bc_tbls: return ret; } @@ -547,11 +611,9 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv) */ void iwl_txq_ctx_stop(struct iwl_priv *priv) { - - int txq_id; + int ch; unsigned long flags; - /* Turn off all Tx DMA fifos */ spin_lock_irqsave(&priv->lock, flags); if (iwl_grab_nic_access(priv)) { @@ -562,12 +624,11 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv) priv->cfg->ops->lib->txq_set_sched(priv, 0); /* Stop each Tx DMA channel, and wait for it to be idle */ - for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) { - iwl_write_direct32(priv, - FH_TCSR_CHNL_TX_CONFIG_REG(txq_id), 0x0); + for (ch = 0; ch < priv->hw_params.dma_chnl_num; ch++) { + iwl_write_direct32(priv, FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0); iwl_poll_direct_bit(priv, FH_TSSR_TX_STATUS_REG, - FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE - (txq_id), 200); + FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), + 1000); } iwl_release_nic_access(priv); spin_unlock_irqrestore(&priv->lock, flags); @@ -584,7 +645,7 @@ static void iwl_tx_cmd_build_basic(struct iwl_priv *priv, struct iwl_tx_cmd *tx_cmd, struct ieee80211_tx_info *info, struct ieee80211_hdr *hdr, - int is_unicast, u8 std_id) + u8 std_id) { __le16 fc = hdr->frame_control; __le32 tx_flags = tx_cmd->tx_flags; @@ -647,11 +708,11 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, __le16 fc, int sta_id, int is_hcca) { + u32 rate_flags = 0; + int rate_idx; u8 rts_retry_limit = 0; u8 data_retry_limit = 0; u8 rate_plcp; - u16 rate_flags = 0; - int rate_idx; rate_idx = min(ieee80211_get_tx_rate(priv->hw, info)->hw_value & 0xffff, IWL_RATE_COUNT - 1); @@ -694,14 +755,8 @@ static void iwl_tx_cmd_build_rate(struct iwl_priv *priv, break; } - /* Alternate between antenna A and B for successive frames */ - if (priv->use_ant_b_for_management_frame) { - priv->use_ant_b_for_management_frame = 0; - rate_flags |= RATE_MCS_ANT_B_MSK; - } else { - priv->use_ant_b_for_management_frame = 1; - rate_flags |= RATE_MCS_ANT_A_MSK; - } + priv->mgmt_tx_ant = iwl_toggle_tx_ant(priv, priv->mgmt_tx_ant); + rate_flags |= iwl_ant_idx_to_flags(priv->mgmt_tx_ant); } tx_cmd->rts_retry_limit = rts_retry_limit; @@ -723,7 +778,7 @@ static void iwl_tx_cmd_build_hwcrypto(struct iwl_priv *priv, memcpy(tx_cmd->key, keyconf->key, keyconf->keylen); if (info->flags & IEEE80211_TX_CTL_AMPDU) tx_cmd->tx_flags |= TX_CMD_FLG_AGG_CCMP_MSK; - IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + IWL_DEBUG_TX("tx_cmd with AES hwcrypto\n"); break; case ALG_TKIP: @@ -767,7 +822,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct iwl_tfd_frame *tfd; + struct iwl_tfd *tfd; struct iwl_tx_queue *txq; struct iwl_queue *q; struct iwl_cmd *out_cmd; @@ -776,10 +831,10 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) dma_addr_t phys_addr; dma_addr_t txcmd_phys; dma_addr_t scratch_phys; - u16 len, idx, len_org; + u16 len, len_org; u16 seq_number = 0; __le16 fc; - u8 hdr_len, unicast; + u8 hdr_len; u8 sta_id; u8 wait_write_ptr = 0; u8 tid = 0; @@ -799,8 +854,6 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) goto drop_unlock; } - unicast = !is_multicast_ether_addr(hdr->addr1); - fc = hdr->frame_control; #ifdef CONFIG_IWLWIFI_DEBUG @@ -830,10 +883,8 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Find (or create) index into station table for destination station */ sta_id = iwl_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_DROP("Dropping - INVALID STATION: %pM\n", + hdr->addr1); goto drop; } @@ -856,23 +907,22 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) priv->stations[sta_id].tid[tid].tfds_in_queue++; } - /* Descriptor for chosen Tx queue */ txq = &priv->txq[txq_id]; q = &txq->q; + txq->swq_id = swq_id; spin_lock_irqsave(&priv->lock, flags); /* Set up first empty TFD within this queue's circular TFD buffer */ - tfd = &txq->bd[q->write_ptr]; + tfd = &txq->tfds[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); - idx = get_cmd_index(q, q->write_ptr, 0); /* Set up driver data for this TFD */ memset(&(txq->txb[q->write_ptr]), 0, sizeof(struct iwl_tx_info)); txq->txb[q->write_ptr].skb[0] = skb; /* Set up first empty entry in queue's array of Tx/cmd buffers */ - out_cmd = txq->cmd[idx]; + out_cmd = txq->cmd[q->write_ptr]; tx_cmd = &out_cmd->cmd.tx; memset(&out_cmd->hdr, 0, sizeof(out_cmd->hdr)); memset(tx_cmd, 0, sizeof(struct iwl_tx_cmd)); @@ -912,12 +962,14 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) /* Physical address of this Tx command's header (not MAC header!), * within command buffer array. */ - txcmd_phys = pci_map_single(priv->pci_dev, out_cmd, - sizeof(struct iwl_cmd), PCI_DMA_TODEVICE); - txcmd_phys += offsetof(struct iwl_cmd, hdr); - + txcmd_phys = pci_map_single(priv->pci_dev, + out_cmd, sizeof(struct iwl_cmd), + PCI_DMA_TODEVICE); + pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys); + pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd)); /* Add buffer containing Tx command and MAC(!) header to TFD's * first entry */ + txcmd_phys += offsetof(struct iwl_cmd, hdr); iwl_hw_txq_attach_buf_to_tfd(priv, tfd, txcmd_phys, len); if (info->control.hw_key) @@ -940,7 +992,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) len = (u16)skb->len; tx_cmd->len = cpu_to_le16(len); /* TODO need this for burst mode later on */ - iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, unicast, sta_id); + iwl_tx_cmd_build_basic(priv, tx_cmd, info, hdr, sta_id); /* set is_hcca to 0; it probably will never be implemented */ iwl_tx_cmd_build_rate(priv, tx_cmd, info, fc, sta_id, 0); @@ -950,7 +1002,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) + offsetof(struct iwl_tx_cmd, scratch); tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys); - tx_cmd->dram_msb_ptr = iwl_get_dma_hi_address(scratch_phys); + tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys); if (!ieee80211_has_morefrags(hdr->frame_control)) { txq->need_update = 1; @@ -983,7 +1035,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb) iwl_txq_update_write_ptr(priv, txq); spin_unlock_irqrestore(&priv->lock, flags); } else { - ieee80211_stop_queue(priv->hw, swq_id); + ieee80211_stop_queue(priv->hw, txq->swq_id); } } @@ -1011,7 +1063,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) { struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM]; struct iwl_queue *q = &txq->q; - struct iwl_tfd_frame *tfd; + struct iwl_tfd *tfd; struct iwl_cmd *out_cmd; dma_addr_t phys_addr; unsigned long flags; @@ -1040,7 +1092,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) spin_lock_irqsave(&priv->hcmd_lock, flags); - tfd = &txq->bd[q->write_ptr]; + tfd = &txq->tfds[q->write_ptr]; memset(tfd, 0, sizeof(*tfd)); @@ -1061,9 +1113,13 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd) out_cmd->hdr.sequence |= SEQ_HUGE_FRAME; len = (idx == TFD_CMD_SLOTS) ? IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd); - phys_addr = pci_map_single(priv->pci_dev, out_cmd, len, - PCI_DMA_TODEVICE); + + phys_addr = pci_map_single(priv->pci_dev, out_cmd, + len, PCI_DMA_TODEVICE); + pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr); + pci_unmap_len_set(&out_cmd->meta, len, len); phys_addr += offsetof(struct iwl_cmd, hdr); + iwl_hw_txq_attach_buf_to_tfd(priv, tfd, phys_addr, fix_size); #ifdef CONFIG_IWLWIFI_DEBUG @@ -1113,8 +1169,9 @@ int iwl_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) return 0; } - 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)) { + 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]); @@ -1138,44 +1195,34 @@ EXPORT_SYMBOL(iwl_tx_queue_reclaim); * 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 iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int index) +static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, + int idx, int cmd_idx) { struct iwl_tx_queue *txq = &priv->txq[txq_id]; struct iwl_queue *q = &txq->q; - struct iwl_tfd_frame *bd = &txq->bd[index]; - dma_addr_t dma_addr; - int is_odd, buf_len; int nfreed = 0; - if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) { + if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 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); + idx, 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)) { + pci_unmap_single(priv->pci_dev, + pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping), + pci_unmap_len(&txq->cmd[cmd_idx]->meta, len), + PCI_DMA_TODEVICE); + + for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx; + 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, + if (nfreed++ > 0) { + IWL_ERROR("HCMD skipped: index (%d) %d %d\n", idx, q->write_ptr, q->read_ptr); queue_work(priv->workqueue, &priv->restart); } - is_odd = (index/2) & 0x1; - if (is_odd) { - dma_addr = IWL_GET_BITS(bd->pa[index], tb2_addr_lo16) | - (IWL_GET_BITS(bd->pa[index], - tb2_addr_hi20) << 16); - buf_len = IWL_GET_BITS(bd->pa[index], tb2_len); - } else { - dma_addr = le32_to_cpu(bd->pa[index].tb1_addr); - buf_len = IWL_GET_BITS(bd->pa[index], tb1_len); - } - pci_unmap_single(priv->pci_dev, dma_addr, buf_len, - PCI_DMA_TODEVICE); - nfreed++; } } @@ -1201,8 +1248,13 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) * command queue then there a command routing bug has been introduced * in the queue management code. */ if (WARN(txq_id != IWL_CMD_QUEUE_NUM, - "wrong command queue %d, command id 0x%X\n", txq_id, pkt->hdr.cmd)) + "wrong command queue %d, sequence 0x%X readp=%d writep=%d\n", + txq_id, sequence, + priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr, + priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) { + iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32); return; + } cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge); cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index]; @@ -1215,7 +1267,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb) !cmd->meta.u.callback(priv, cmd, rxb->skb)) rxb->skb = NULL; - iwl_hcmd_queue_reclaim(priv, txq_id, index); + iwl_hcmd_queue_reclaim(priv, txq_id, index, cmd_index); if (!(cmd->meta.flags & CMD_ASYNC)) { clear_bit(STATUS_HCMD_ACTIVE, &priv->status); @@ -1248,15 +1300,14 @@ int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn) int ret; unsigned long flags; struct iwl_tid_data *tid_data; - DECLARE_MAC_BUF(mac); if (likely(tid < ARRAY_SIZE(default_tid_to_tx_fifo))) tx_fifo = default_tid_to_tx_fifo[tid]; else return -EINVAL; - IWL_WARNING("%s on ra = %s tid = %d\n", - __func__, print_mac(mac, ra), tid); + IWL_WARNING("%s on ra = %pM tid = %d\n", + __func__, ra, tid); sta_id = iwl_find_station(priv, ra); if (sta_id == IWL_INVALID_STATION) @@ -1301,7 +1352,6 @@ int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid) struct iwl_tid_data *tid_data; int ret, write_ptr, read_ptr; unsigned long flags; - DECLARE_MAC_BUF(mac); if (!ra) { IWL_ERROR("ra = NULL\n"); @@ -1362,8 +1412,8 @@ int iwl_txq_check_empty(struct iwl_priv *priv, int sta_id, u8 tid, int txq_id) 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) { + 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"); @@ -1414,7 +1464,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, 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(seq_ctl>>4); + sh = agg->start_idx - SEQ_TO_INDEX(seq_ctl >> 4); if (sh < 0) /* tbw something is wrong with indices */ sh += 0x100; @@ -1436,7 +1486,7 @@ static int iwl_tx_status_reply_compressed_ba(struct iwl_priv *priv, ack = bitmap & (1ULL << i); successes += !!ack; IWL_DEBUG_TX_REPLY("%s ON i=%d idx=%d raw=%d\n", - ack? "ACK":"NACK", i, (agg->start_idx + i) & 0xff, + ack ? "ACK" : "NACK", i, (agg->start_idx + i) & 0xff, agg->start_idx + i); } @@ -1464,10 +1514,11 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, { struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data; struct iwl_compressed_ba_resp *ba_resp = &pkt->u.compressed_ba; - int index; struct iwl_tx_queue *txq = NULL; struct iwl_ht_agg *agg; - DECLARE_MAC_BUF(mac); + int index; + int sta_id; + int tid; /* "flow" corresponds to Tx queue */ u16 scd_flow = le16_to_cpu(ba_resp->scd_flow); @@ -1482,17 +1533,19 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, } txq = &priv->txq[scd_flow]; - agg = &priv->stations[ba_resp->sta_id].tid[ba_resp->tid].agg; + sta_id = ba_resp->sta_id; + tid = ba_resp->tid; + agg = &priv->stations[sta_id].tid[tid].agg; /* Find index just before block-ack window */ index = iwl_queue_dec_wrap(ba_resp_scd_ssn & 0xff, txq->q.n_bd); /* TODO: Need to get this copy more safely - now good for debug */ - IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d]Received from %s, " + IWL_DEBUG_TX_REPLY("REPLY_COMPRESSED_BA [%d] Received from %pM, " "sta_id = %d\n", agg->wait_for_ba, - print_mac(mac, (u8 *) &ba_resp->sta_addr_lo32), + (u8 *) &ba_resp->sta_addr_lo32, ba_resp->sta_id); IWL_DEBUG_TX_REPLY("TID = %d, SeqCtl = %d, bitmap = 0x%llx, scd_flow = " "%d, scd_ssn = %d\n", @@ -1513,18 +1566,15 @@ void iwl_rx_reply_compressed_ba(struct iwl_priv *priv, * transmitted ... if not, it's too late anyway). */ if (txq->q.read_ptr != (ba_resp_scd_ssn & 0xff)) { /* calculate mac80211 ampdu sw queue to wake */ - int ampdu_q = - scd_flow - priv->hw_params.first_ampdu_q + priv->hw->queues; int freed = iwl_tx_queue_reclaim(priv, scd_flow, index); - priv->stations[ba_resp->sta_id]. - tid[ba_resp->tid].tfds_in_queue -= freed; - if (iwl_queue_space(&txq->q) > txq->q.low_mark && - priv->mac80211_registered && - agg->state != IWL_EMPTYING_HW_QUEUE_DELBA) - ieee80211_wake_queue(priv->hw, ampdu_q); - - iwl_txq_check_empty(priv, ba_resp->sta_id, - ba_resp->tid, scd_flow); + priv->stations[sta_id].tid[tid].tfds_in_queue -= freed; + + if ((iwl_queue_space(&txq->q) > txq->q.low_mark) && + priv->mac80211_registered && + (agg->state != IWL_EMPTYING_HW_QUEUE_DELBA)) + ieee80211_wake_queue(priv->hw, txq->swq_id); + + iwl_txq_check_empty(priv, sta_id, tid, scd_flow); } } EXPORT_SYMBOL(iwl_rx_reply_compressed_ba); diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 45a6b0c356953f1d88c32747b322d0dbc253756f..d64580805d6efbef7cb48a5bafec23ca02f55f6d 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c @@ -22,7 +22,7 @@ * file called LICENSE. * * Contact Information: - * James P. Ketrenos + * Intel Linux Wireless * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497 * *****************************************************************************/ @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -64,11 +65,10 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv, /* module parameters */ static int iwl3945_param_disable_hw_scan; /* def: 0 = use 3945's h/w scan */ -static int iwl3945_param_debug; /* def: 0 = minimal debug log messages */ +static u32 iwl3945_param_debug; /* def: 0 = minimal debug log messages */ static int iwl3945_param_disable; /* def: 0 = enable radio */ static int iwl3945_param_antenna; /* def: 0 = both antennas (use diversity) */ int iwl3945_param_hwcrypto; /* def: 0 = use software encryption */ -static int iwl3945_param_qos_enable = 1; /* def: 1 = use quality of service */ int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */ /* @@ -93,12 +93,13 @@ int iwl3945_param_queues_num = IWL39_MAX_NUM_QUEUES; /* def: 8 Tx queues */ #define IWLWIFI_VERSION "1.2.26k" VD VS #define DRV_COPYRIGHT "Copyright(c) 2003-2008 Intel Corporation" +#define DRV_AUTHOR "" #define DRV_VERSION IWLWIFI_VERSION MODULE_DESCRIPTION(DRV_DESCRIPTION); MODULE_VERSION(DRV_VERSION); -MODULE_AUTHOR(DRV_COPYRIGHT); +MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR); MODULE_LICENSE("GPL"); static const struct ieee80211_supported_band *iwl3945_get_band( @@ -107,46 +108,6 @@ static const struct ieee80211_supported_band *iwl3945_get_band( return priv->hw->wiphy->bands[band]; } -static int iwl3945_is_empty_essid(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - -static const char *iwl3945_escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (iwl3945_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else - *d++ = *s++; - } - *d = '\0'; - return escaped; -} - /*************** DMA-QUEUE-GENERAL-FUNCTIONS ***** * DMA services * @@ -446,7 +407,6 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 int index = IWL_INVALID_STATION; struct iwl3945_station_entry *station; unsigned long flags_spin; - DECLARE_MAC_BUF(mac); u8 rate; spin_lock_irqsave(&priv->sta_lock, flags_spin); @@ -480,7 +440,7 @@ u8 iwl3945_add_station(struct iwl3945_priv *priv, const u8 *addr, int is_ap, u8 return index; } - IWL_DEBUG_ASSOC("Add STA ID %d: %s\n", index, print_mac(mac, addr)); + IWL_DEBUG_ASSOC("Add STA ID %d: %pM\n", index, addr); station = &priv->stations[index]; station->used = 1; priv->num_stations++; @@ -559,7 +519,7 @@ static inline int iwl3945_is_ready_rf(struct iwl3945_priv *priv) /*************** HOST COMMAND QUEUE FUNCTIONS *****/ -#define IWL_CMD(x) case x : return #x +#define IWL_CMD(x) case x: return #x static const char *get_cmd_string(u8 cmd) { @@ -1063,7 +1023,6 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv) /* cast away the const for active_rxon in this function */ struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon; int rc = 0; - DECLARE_MAC_BUF(mac); if (!iwl3945_is_alive(priv)) return -1; @@ -1124,11 +1083,11 @@ static int iwl3945_commit_rxon(struct iwl3945_priv *priv) IWL_DEBUG_INFO("Sending RXON\n" "* with%s RXON_FILTER_ASSOC_MSK\n" "* channel = %d\n" - "* bssid = %s\n", + "* bssid = %pM\n", ((priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK) ? "" : "out"), le16_to_cpu(priv->staging_rxon.channel), - print_mac(mac, priv->staging_rxon.bssid_addr)); + priv->staging_rxon.bssid_addr); /* Apply the new configuration */ rc = iwl3945_send_cmd_pdu(priv, REPLY_RXON, @@ -1443,7 +1402,7 @@ static void iwl3945_free_frame(struct iwl3945_priv *priv, struct iwl3945_frame * unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, struct ieee80211_hdr *hdr, - const u8 *dest, int left) + int left) { if (!iwl3945_is_associated(priv) || !priv->ibss_beacon || @@ -1459,9 +1418,16 @@ unsigned int iwl3945_fill_beacon_frame(struct iwl3945_priv *priv, return priv->ibss_beacon->len; } -static u8 iwl3945_rate_get_lowest_plcp(int rate_mask) +static u8 iwl3945_rate_get_lowest_plcp(struct iwl3945_priv *priv) { u8 i; + int rate_mask; + + /* Set rate mask*/ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + rate_mask = priv->active_rate_basic & IWL_CCK_RATES_MASK; + else + rate_mask = priv->active_rate_basic & IWL_OFDM_RATES_MASK; for (i = IWL_RATE_1M_INDEX; i != IWL_RATE_INVALID; i = iwl3945_rates[i].next_ieee) { @@ -1469,7 +1435,11 @@ static u8 iwl3945_rate_get_lowest_plcp(int rate_mask) return iwl3945_rates[i].plcp; } - return IWL_RATE_INVALID; + /* No valid rate was found. Assign the lowest one */ + if (priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK) + return IWL_RATE_1M_PLCP; + else + return IWL_RATE_6M_PLCP; } static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv) @@ -1487,16 +1457,7 @@ static int iwl3945_send_beacon_cmd(struct iwl3945_priv *priv) return -ENOMEM; } - if (!(priv->staging_rxon.flags & RXON_FLG_BAND_24G_MSK)) { - rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & - 0xFF0); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_6M_PLCP; - } else { - rate = iwl3945_rate_get_lowest_plcp(priv->active_rate_basic & 0xF); - if (rate == IWL_INVALID_RATE) - rate = IWL_RATE_1M_PLCP; - } + rate = iwl3945_rate_get_lowest_plcp(priv); frame_size = iwl3945_hw_get_beacon_cmd(priv, frame, rate); @@ -1544,10 +1505,8 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv) { u16 *e = (u16 *)&priv->eeprom; u32 gp = iwl3945_read32(priv, CSR_EEPROM_GP); - u32 r; int sz = sizeof(priv->eeprom); - int rc; - int i; + int ret; u16 addr; /* The EEPROM structure has several padding buffers within it @@ -1562,29 +1521,28 @@ int iwl3945_eeprom_init(struct iwl3945_priv *priv) } /* Make sure driver (instead of uCode) is allowed to read EEPROM */ - rc = iwl3945_eeprom_acquire_semaphore(priv); - if (rc < 0) { + ret = iwl3945_eeprom_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)) { - _iwl3945_write32(priv, CSR_EEPROM_REG, addr << 1); - _iwl3945_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 = _iwl3945_read_direct32(priv, CSR_EEPROM_REG); - if (r & CSR_EEPROM_REG_READ_VALID_MSK) - break; - udelay(IWL_EEPROM_ACCESS_DELAY); - } + u32 r; - if (!(r & CSR_EEPROM_REG_READ_VALID_MSK)) { + _iwl3945_write32(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_MSK_ADDR & (addr << 1)); + _iwl3945_clear_bit(priv, CSR_EEPROM_REG, CSR_EEPROM_REG_BIT_CMD); + ret = iwl3945_poll_direct_bit(priv, CSR_EEPROM_REG, + CSR_EEPROM_REG_READ_VALID_MSK, + IWL_EEPROM_ACCESS_TIMEOUT); + if (ret < 0) { IWL_ERROR("Time out reading EEPROM[%d]\n", addr); - return -ETIMEDOUT; + return ret; } + + r = _iwl3945_read_direct32(priv, CSR_EEPROM_REG); e[addr / 2] = le16_to_cpu((__force __le16)(r >> 16)); } @@ -1634,7 +1592,7 @@ static u16 iwl3945_supported_rate_to_ie(u8 *ie, u16 supported_rate, */ static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv, struct ieee80211_mgmt *frame, - int left, int is_direct) + int left) { int len = 0; u8 *pos = NULL; @@ -1664,20 +1622,6 @@ static u16 iwl3945_fill_probe_req(struct iwl3945_priv *priv, *pos++ = WLAN_EID_SSID; *pos++ = 0; - /* fill in our direct SSID IE... */ - if (is_direct) { - /* ...next IE... */ - left -= 2 + priv->essid_len; - if (left < 0) - return 0; - /* ... fill it in... */ - *pos++ = WLAN_EID_SSID; - *pos++ = priv->essid_len; - memcpy(pos, priv->essid, priv->essid_len); - pos += priv->essid_len; - len += 2 + priv->essid_len; - } - /* fill in supported rate */ /* ...next IE... */ left -= 2; @@ -1746,17 +1690,21 @@ static void iwl3945_reset_qos(struct iwl3945_priv *priv) spin_lock_irqsave(&priv->lock, flags); priv->qos_data.qos_active = 0; - if (priv->iw_mode == NL80211_IFTYPE_ADHOC) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - if (!(priv->active_rate & 0xfff0)) { - cw_min = 31; - is_legacy = 1; - } - } else if (priv->iw_mode == NL80211_IFTYPE_AP) { - if (priv->qos_data.qos_enable) - priv->qos_data.qos_active = 1; - } else if (!(priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK)) { + /* QoS always active in AP and ADHOC mode + * In STA mode wait for association + */ + if (priv->iw_mode == NL80211_IFTYPE_ADHOC || + priv->iw_mode == NL80211_IFTYPE_AP) + priv->qos_data.qos_active = 1; + else + priv->qos_data.qos_active = 0; + + + /* check for legacy mode */ + if ((priv->iw_mode == NL80211_IFTYPE_ADHOC && + (priv->active_rate & IWL_OFDM_RATES_MASK) == 0) || + (priv->iw_mode == NL80211_IFTYPE_STATION && + (priv->staging_rxon.flags & RXON_FLG_SHORT_SLOT_MSK) == 0)) { cw_min = 31; is_legacy = 1; } @@ -1828,9 +1776,6 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; - if (!priv->qos_data.qos_enable) - return; - spin_lock_irqsave(&priv->lock, flags); priv->qos_data.def_qos_parm.qos_flags = 0; @@ -1846,7 +1791,7 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) spin_unlock_irqrestore(&priv->lock, flags); if (force || iwl3945_is_associated(priv)) { - IWL_DEBUG_QOS("send QoS cmd with Qos active %d \n", + IWL_DEBUG_QOS("send QoS cmd with QoS active %d \n", priv->qos_data.qos_active); iwl3945_send_qos_params_command(priv, @@ -1870,7 +1815,7 @@ static void iwl3945_activate_qos(struct iwl3945_priv *priv, u8 force) /* default power management (not Tx power) table values */ -/* for tim 0-10 */ +/* for TIM 0-10 */ static struct iwl3945_power_vec_entry range_0[IWL_POWER_AC] = { {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), SLP_VEC(1, 2, 3, 4, 4)}, 0}, @@ -1880,7 +1825,7 @@ static struct iwl3945_power_vec_entry range_0[IWL_POWER_AC] = { {{SLP, SLP_TIMEOUT(25), SLP_TIMEOUT(25), SLP_VEC(4, 7, 10, 10, 10)}, 1} }; -/* for tim > 10 */ +/* for TIM > 10 */ static struct iwl3945_power_vec_entry range_1[IWL_POWER_AC] = { {{NOSLP, SLP_TIMEOUT(0), SLP_TIMEOUT(0), SLP_VEC(0, 0, 0, 0, 0)}, 0}, {{SLP, SLP_TIMEOUT(200), SLP_TIMEOUT(500), @@ -2156,11 +2101,6 @@ static void iwl3945_setup_rxon_timing(struct iwl3945_priv *priv) static int iwl3945_scan_initiate(struct iwl3945_priv *priv) { - if (priv->iw_mode == NL80211_IFTYPE_AP) { - IWL_ERROR("APs don't scan.\n"); - return 0; - } - if (!iwl3945_is_ready_rf(priv)) { IWL_DEBUG_SCAN("Aborting scan due to not ready.\n"); return -EIO; @@ -2230,13 +2170,14 @@ static void iwl3945_set_flags_for_phymode(struct iwl3945_priv *priv, /* * initialize rxon structure with default values from eeprom */ -static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) +static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv, + int mode) { const struct iwl3945_channel_info *ch_info; memset(&priv->staging_rxon, 0, sizeof(priv->staging_rxon)); - switch (priv->iw_mode) { + switch (mode) { case NL80211_IFTYPE_AP: priv->staging_rxon.dev_type = RXON_DEV_TYPE_AP; break; @@ -2259,7 +2200,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) RXON_FILTER_CTL2HOST_MSK | RXON_FILTER_ACCEPT_GRP_MSK; break; default: - IWL_ERROR("Unsupported interface type %d\n", priv->iw_mode); + IWL_ERROR("Unsupported interface type %d\n", mode); break; } @@ -2282,8 +2223,7 @@ static void iwl3945_connection_init_rx_config(struct iwl3945_priv *priv) * in some case A channels are all non IBSS * in this case force B/G channel */ - if ((priv->iw_mode == NL80211_IFTYPE_ADHOC) && - !(is_channel_ibss(ch_info))) + if ((mode == NL80211_IFTYPE_ADHOC) && !(is_channel_ibss(ch_info))) ch_info = &priv->channel_info[0]; priv->staging_rxon.channel = cpu_to_le16(ch_info->channel); @@ -2316,14 +2256,12 @@ static int iwl3945_set_mode(struct iwl3945_priv *priv, int mode) } } - priv->iw_mode = mode; - - iwl3945_connection_init_rx_config(priv); + iwl3945_connection_init_rx_config(priv, mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); iwl3945_clear_stations_table(priv); - /* dont commit rxon if rf-kill is on*/ + /* don't commit rxon if rf-kill is on*/ if (!iwl3945_is_ready_rf(priv)) return -EAGAIN; @@ -2352,7 +2290,7 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl3945_priv *priv, case ALG_CCMP: cmd->cmd.tx.sec_ctl = TX_CMD_SEC_CCM; memcpy(cmd->cmd.tx.key, keyinfo->key, keyinfo->keylen); - IWL_DEBUG_TX("tx_cmd with aes hwcrypto\n"); + IWL_DEBUG_TX("tx_cmd with AES hwcrypto\n"); break; case ALG_TKIP: @@ -2397,6 +2335,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, { __le16 fc = hdr->frame_control; __le32 tx_flags = cmd->cmd.tx.tx_flags; + u8 rc_flags = info->control.rates[0].flags; cmd->cmd.tx.stop_time.life_time = TX_CMD_LIFE_TIME_INFINITE; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { @@ -2423,10 +2362,10 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv, tx_flags |= TX_CMD_FLG_SEQ_CTL_MSK; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { tx_flags |= TX_CMD_FLG_RTS_MSK; tx_flags &= ~TX_CMD_FLG_CTS_MSK; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { tx_flags &= ~TX_CMD_FLG_RTS_MSK; tx_flags |= TX_CMD_FLG_CTS_MSK; } @@ -2482,8 +2421,6 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h /* If this frame is going out to an IBSS network, find the station, * or create a new station table entry */ case NL80211_IFTYPE_ADHOC: { - DECLARE_MAC_BUF(mac); - /* Create new station table entry */ sta_id = iwl3945_hw_find_station(priv, hdr->addr1); if (sta_id != IWL_INVALID_STATION) @@ -2494,9 +2431,9 @@ static int iwl3945_get_sta_id(struct iwl3945_priv *priv, struct ieee80211_hdr *h if (sta_id != IWL_INVALID_STATION) return sta_id; - IWL_DEBUG_DROP("Station %s not in station map. " + IWL_DEBUG_DROP("Station %pM not in station map. " "Defaulting to broadcast...\n", - print_mac(mac, hdr->addr1)); + hdr->addr1); iwl3945_print_hex_dump(IWL_DL_DROP, (u8 *) hdr, sizeof(*hdr)); return priv->hw_setting.bcast_sta_id; } @@ -2579,10 +2516,8 @@ static int iwl3945_tx_skb(struct iwl3945_priv *priv, struct sk_buff *skb) /* Find (or create) index into station table for destination station */ sta_id = iwl3945_get_sta_id(priv, hdr); if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_DROP("Dropping - INVALID STATION: %s\n", - print_mac(mac, hdr->addr1)); + IWL_DEBUG_DROP("Dropping - INVALID STATION: %pM\n", + hdr->addr1); goto drop; } @@ -4019,8 +3954,6 @@ static int iwl3945_tx_queue_update_write_ptr(struct iwl3945_priv *priv, #ifdef CONFIG_IWL3945_DEBUG static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon) { - DECLARE_MAC_BUF(mac); - IWL_DEBUG_RADIO("RX CONFIG:\n"); iwl3945_print_hex_dump(IWL_DL_RADIO, (u8 *) rxon, sizeof(*rxon)); IWL_DEBUG_RADIO("u16 channel: 0x%x\n", le16_to_cpu(rxon->channel)); @@ -4031,10 +3964,8 @@ static void iwl3945_print_rx_config_cmd(struct iwl3945_rxon_cmd *rxon) IWL_DEBUG_RADIO("u8 ofdm_basic_rates: 0x%02x\n", rxon->ofdm_basic_rates); IWL_DEBUG_RADIO("u8 cck_basic_rates: 0x%02x\n", rxon->cck_basic_rates); - IWL_DEBUG_RADIO("u8[6] node_addr: %s\n", - print_mac(mac, rxon->node_addr)); - IWL_DEBUG_RADIO("u8[6] bssid_addr: %s\n", - print_mac(mac, rxon->bssid_addr)); + IWL_DEBUG_RADIO("u8[6] node_addr: %pM\n", rxon->node_addr); + IWL_DEBUG_RADIO("u8[6] bssid_addr: %pM\n", rxon->bssid_addr); IWL_DEBUG_RADIO("u16 assoc_id: 0x%x\n", le16_to_cpu(rxon->assoc_id)); } #endif @@ -4050,7 +3981,7 @@ static void iwl3945_enable_interrupts(struct iwl3945_priv *priv) /* call this function to flush any scheduled tasklet */ static inline void iwl_synchronize_irq(struct iwl3945_priv *priv) { - /* wait to make sure we flush pedding tasklet*/ + /* wait to make sure we flush pending tasklet*/ synchronize_irq(priv->pci_dev->irq); tasklet_kill(&priv->irq_tasklet); } @@ -4373,35 +4304,6 @@ static void iwl3945_irq_tasklet(struct iwl3945_priv *priv) /* Safely ignore these bits for debug checks below */ inta &= ~(CSR_INT_BIT_SCD | CSR_INT_BIT_ALIVE); - /* HW RF KILL switch toggled (4965 only) */ - if (inta & CSR_INT_BIT_RF_KILL) { - int hw_rf_kill = 0; - if (!(iwl3945_read32(priv, CSR_GP_CNTRL) & - CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW)) - hw_rf_kill = 1; - - IWL_DEBUG(IWL_DL_INFO | IWL_DL_RF_KILL | IWL_DL_ISR, - "RF_KILL bit toggled to %s.\n", - hw_rf_kill ? "disable radio":"enable radio"); - - /* 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 - * 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); - } - - handled |= CSR_INT_BIT_RF_KILL; - } - - /* Chip got too hot and stopped itself (4965 only) */ - if (inta & CSR_INT_BIT_CT_KILL) { - IWL_ERROR("Microcode CT kill error detected.\n"); - handled |= CSR_INT_BIT_CT_KILL; - } - /* Error detected by uCode */ if (inta & CSR_INT_BIT_SW_ERR) { IWL_ERROR("Microcode SW error detected. Restarting 0x%X.\n", @@ -4502,7 +4404,7 @@ static irqreturn_t iwl3945_isr(int irq, void *data) if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) { /* Hardware disappeared */ - IWL_WARNING("HARDWARE GONE?? INTA == 0x%080x\n", inta); + IWL_WARNING("HARDWARE GONE?? INTA == 0x%08x\n", inta); goto unplugged; } @@ -4805,7 +4707,7 @@ static void iwl3945_free_channel_map(struct iwl3945_priv *priv) #define IWL_PASSIVE_DWELL_BASE (100) #define IWL_CHANNEL_TUNE_TIME 5 -#define IWL_SCAN_PROBE_MASK(n) cpu_to_le32((BIT(n) | (BIT(n) - BIT(1)))) +#define IWL_SCAN_PROBE_MASK(n) (BIT(n) | (BIT(n) - BIT(1))) static inline u16 iwl3945_get_active_dwell_time(struct iwl3945_priv *priv, enum ieee80211_band band, @@ -4876,17 +4778,33 @@ static int iwl3945_get_channels_for_scan(struct iwl3945_priv *priv, continue; } + scan_ch->active_dwell = cpu_to_le16(active_dwell); + scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + /* If passive , set up for auto-switch + * and use long active_dwell time. + */ if (!is_active || is_channel_passive(ch_info) || - (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) + (channels[i].flags & IEEE80211_CHAN_PASSIVE_SCAN)) { scan_ch->type = 0; /* passive */ - else + if (IWL_UCODE_API(priv->ucode_ver) == 1) + scan_ch->active_dwell = cpu_to_le16(passive_dwell - 1); + } else { scan_ch->type = 1; /* active */ + } - if ((scan_ch->type & 1) && n_probes) - scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); - - scan_ch->active_dwell = cpu_to_le16(active_dwell); - scan_ch->passive_dwell = cpu_to_le16(passive_dwell); + /* Set direct probe bits. These may be used both for active + * scan channels (probes gets sent right away), + * or for passive channels (probes get se sent only after + * hearing clear Rx packet).*/ + if (IWL_UCODE_API(priv->ucode_ver) >= 2) { + if (n_probes) + scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); + } else { + /* uCode v1 does not allow setting direct probe bits on + * passive channel. */ + if ((scan_ch->type & 1) && n_probes) + scan_ch->type |= IWL_SCAN_PROBE_MASK(n_probes); + } /* Set txpower levels to defaults */ scan_ch->tpc.dsp_atten = 110; @@ -5387,25 +5305,41 @@ static void iwl3945_nic_start(struct iwl3945_priv *priv) static int iwl3945_read_ucode(struct iwl3945_priv *priv) { struct iwl3945_ucode *ucode; - int ret = 0; + int ret = -EINVAL, index; const struct firmware *ucode_raw; /* firmware file name contains uCode/driver compatibility version */ - const char *name = priv->cfg->fw_name; + const char *name_pre = priv->cfg->fw_name_pre; + const unsigned int api_max = priv->cfg->ucode_api_max; + const unsigned int api_min = priv->cfg->ucode_api_min; + char buf[25]; u8 *src; size_t len; - u32 ver, inst_size, data_size, init_size, init_data_size, boot_size; + u32 api_ver, inst_size, data_size, init_size, init_data_size, boot_size; /* Ask kernel firmware_class module to get the boot firmware off disk. * request_firmware() is synchronous, file is in memory on return. */ - ret = request_firmware(&ucode_raw, name, &priv->pci_dev->dev); - if (ret < 0) { - IWL_ERROR("%s firmware file req failed: Reason %d\n", - name, ret); - goto error; + for (index = api_max; index >= api_min; index--) { + sprintf(buf, "%s%u%s", name_pre, index, ".ucode"); + ret = request_firmware(&ucode_raw, buf, &priv->pci_dev->dev); + if (ret < 0) { + IWL_ERROR("%s firmware file req failed: Reason %d\n", + buf, ret); + if (ret == -ENOENT) + continue; + else + goto error; + } else { + if (index < api_max) + IWL_ERROR("Loaded firmware %s, which is deprecated. Please use API v%u instead.\n", + buf, api_max); + IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", + buf, ucode_raw->size); + break; + } } - IWL_DEBUG_INFO("Got firmware '%s' file (%zd bytes) from disk\n", - name, ucode_raw->size); + if (ret < 0) + goto error; /* Make sure that we got at least our header! */ if (ucode_raw->size < sizeof(*ucode)) { @@ -5417,20 +5351,46 @@ static int iwl3945_read_ucode(struct iwl3945_priv *priv) /* Data from ucode file: header followed by uCode images */ ucode = (void *)ucode_raw->data; - ver = le32_to_cpu(ucode->ver); + priv->ucode_ver = le32_to_cpu(ucode->ver); + api_ver = IWL_UCODE_API(priv->ucode_ver); inst_size = le32_to_cpu(ucode->inst_size); data_size = le32_to_cpu(ucode->data_size); init_size = le32_to_cpu(ucode->init_size); init_data_size = le32_to_cpu(ucode->init_data_size); boot_size = le32_to_cpu(ucode->boot_size); - IWL_DEBUG_INFO("f/w package hdr ucode version = 0x%x\n", ver); + /* api_ver should match the api version forming part of the + * firmware filename ... but we don't check for that and only rely + * on the API version read from firware header from here on forward */ + + if (api_ver < api_min || api_ver > api_max) { + IWL_ERROR("Driver unable to support your firmware API. " + "Driver supports v%u, firmware is v%u.\n", + api_max, api_ver); + priv->ucode_ver = 0; + ret = -EINVAL; + goto err_release; + } + if (api_ver != api_max) + IWL_ERROR("Firmware has old API version. Expected %u, " + "got %u. New firmware can be obtained " + "from http://www.intellinuxwireless.org.\n", + api_max, api_ver); + + printk(KERN_INFO DRV_NAME " loaded firmware version %u.%u.%u.%u\n", + IWL_UCODE_MAJOR(priv->ucode_ver), + IWL_UCODE_MINOR(priv->ucode_ver), + IWL_UCODE_API(priv->ucode_ver), + IWL_UCODE_SERIAL(priv->ucode_ver)); + IWL_DEBUG_INFO("f/w package hdr ucode version raw = 0x%x\n", + priv->ucode_ver); IWL_DEBUG_INFO("f/w package hdr runtime inst size = %u\n", inst_size); IWL_DEBUG_INFO("f/w package hdr runtime data size = %u\n", data_size); IWL_DEBUG_INFO("f/w package hdr init inst size = %u\n", init_size); IWL_DEBUG_INFO("f/w package hdr init data size = %u\n", init_data_size); IWL_DEBUG_INFO("f/w package hdr boot inst size = %u\n", boot_size); + /* Verify size of file vs. image size info in file's header */ if (ucode_raw->size < sizeof(*ucode) + inst_size + data_size + init_size + @@ -5607,7 +5567,7 @@ static int iwl3945_set_ucode_ptrs(struct iwl3945_priv *priv) iwl3945_write_prph(priv, BSM_DRAM_DATA_BYTECOUNT_REG, priv->ucode_data.len); - /* Inst bytecount must be last to set up, bit 31 signals uCode + /* Inst byte count must be last to set up, bit 31 signals uCode * that all new ptr/size info is in place */ iwl3945_write_prph(priv, BSM_DRAM_INST_BYTECOUNT_REG, priv->ucode_code.len | BSM_DRAM_INST_LOAD); @@ -5665,6 +5625,10 @@ static void iwl3945_init_alive_start(struct iwl3945_priv *priv) } +/* temporary */ +static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, + struct sk_buff *skb); + /** * iwl3945_alive_start - called after REPLY_ALIVE notification received * from protocol/runtime uCode (initialization uCode's @@ -5699,7 +5663,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) rc = iwl3945_grab_nic_access(priv); if (rc) { - IWL_WARNING("Can not read rfkill status from adapter\n"); + IWL_WARNING("Can not read RFKILL status from adapter\n"); return; } @@ -5709,7 +5673,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) if (rfkill & 0x1) { clear_bit(STATUS_RF_KILL_HW, &priv->status); - /* if rfkill is not on, then wait for thermal + /* if RFKILL is not on, then wait for thermal * sensor in adapter to kick in */ while (iwl3945_hw_get_temperature(priv) == 0) { thermal_spin++; @@ -5747,7 +5711,7 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK; } else { /* Initialize our rx_config data */ - iwl3945_connection_init_rx_config(priv); + iwl3945_connection_init_rx_config(priv, priv->iw_mode); memcpy(priv->staging_rxon.node_addr, priv->mac_addr, ETH_ALEN); } @@ -5768,6 +5732,14 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv) if (priv->error_recovering) iwl3945_error_recovery(priv); + /* reassociate for ADHOC mode */ + if (priv->vif && (priv->iw_mode == NL80211_IFTYPE_ADHOC)) { + struct sk_buff *beacon = ieee80211_beacon_get(priv->hw, + priv->vif); + if (beacon) + iwl3945_mac_beacon_update(priv->hw, beacon); + } + return; restart: @@ -5902,7 +5874,7 @@ static int __iwl3945_up(struct iwl3945_priv *priv) } if (!priv->ucode_data_backup.v_addr || !priv->ucode_data.v_addr) { - IWL_ERROR("ucode not available for device bringup\n"); + IWL_ERROR("ucode not available for device bring up\n"); return -EIO; } @@ -6046,24 +6018,6 @@ static void iwl3945_bg_rf_kill(struct work_struct *work) iwl3945_rfkill_set_hw_state(priv); } -static void iwl3945_bg_set_monitor(struct work_struct *work) -{ - struct iwl3945_priv *priv = container_of(work, - struct iwl3945_priv, set_monitor); - - IWL_DEBUG(IWL_DL_STATE, "setting monitor mode\n"); - - mutex_lock(&priv->mutex); - - if (!iwl3945_is_ready(priv)) - IWL_DEBUG(IWL_DL_STATE, "leave - not ready\n"); - else - if (iwl3945_set_mode(priv, NL80211_IFTYPE_MONITOR) != 0) - IWL_ERROR("iwl3945_set_mode() failed\n"); - - mutex_unlock(&priv->mutex); -} - #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ) static void iwl3945_bg_scan_check(struct work_struct *data) @@ -6101,6 +6055,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) struct ieee80211_conf *conf = NULL; u8 n_probes = 2; enum ieee80211_band band; + DECLARE_SSID_BUF(ssid); conf = ieee80211_get_hw_conf(priv->hw); @@ -6111,7 +6066,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) goto done; } - /* Make sure the scan wasn't cancelled before this queued work + /* Make sure the scan wasn't canceled before this queued work * was given the chance to run... */ if (!test_bit(STATUS_SCANNING, &priv->status)) goto done; @@ -6201,21 +6156,13 @@ static void iwl3945_bg_request_scan(struct work_struct *data) if (priv->one_direct_scan) { IWL_DEBUG_SCAN ("Kicking off one direct scan for '%s'\n", - iwl3945_escape_essid(priv->direct_ssid, - priv->direct_ssid_len)); + print_ssid(ssid, priv->direct_ssid, + priv->direct_ssid_len)); scan->direct_scan[0].id = WLAN_EID_SSID; scan->direct_scan[0].len = priv->direct_ssid_len; memcpy(scan->direct_scan[0].ssid, priv->direct_ssid, priv->direct_ssid_len); n_probes++; - } else if (!iwl3945_is_associated(priv) && priv->essid_len) { - IWL_DEBUG_SCAN - ("Kicking off one direct scan for '%s' when not associated\n", - iwl3945_escape_essid(priv->essid, priv->essid_len)); - scan->direct_scan[0].id = WLAN_EID_SSID; - scan->direct_scan[0].len = priv->essid_len; - memcpy(scan->direct_scan[0].ssid, priv->essid, priv->essid_len); - n_probes++; } else IWL_DEBUG_SCAN("Kicking off one indirect scan.\n"); @@ -6223,7 +6170,7 @@ static void iwl3945_bg_request_scan(struct work_struct *data) * that based on the direct_mask added to each channel entry */ scan->tx_cmd.len = cpu_to_le16( iwl3945_fill_probe_req(priv, (struct ieee80211_mgmt *)scan->data, - IWL_MAX_SCAN_SIZE - sizeof(*scan), 0)); + IWL_MAX_SCAN_SIZE - sizeof(*scan))); 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; @@ -6333,7 +6280,6 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) { int rc = 0; struct ieee80211_conf *conf = NULL; - DECLARE_MAC_BUF(mac); if (priv->iw_mode == NL80211_IFTYPE_AP) { IWL_ERROR("%s Should not be called in AP mode\n", __func__); @@ -6341,9 +6287,8 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) } - IWL_DEBUG_ASSOC("Associated as %d to: %s\n", - priv->assoc_id, - print_mac(mac, priv->active_rxon.bssid_addr)); + IWL_DEBUG_ASSOC("Associated as %d to: %pM\n", + priv->assoc_id, priv->active_rxon.bssid_addr); if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; @@ -6398,10 +6343,7 @@ static void iwl3945_post_associate(struct iwl3945_priv *priv) case NL80211_IFTYPE_ADHOC: - /* clear out the station table */ - iwl3945_clear_stations_table(priv); - - iwl3945_add_station(priv, iwl3945_broadcast_addr, 0, 0); + priv->assoc_id = 1; iwl3945_add_station(priv, priv->bssid, 0, 0); iwl3945_sync_sta(priv, IWL_STA_ID, (priv->band == IEEE80211_BAND_5GHZ) ? @@ -6439,7 +6381,7 @@ static void iwl3945_bg_abort_scan(struct work_struct *work) mutex_unlock(&priv->mutex); } -static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); +static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed); static void iwl3945_bg_scan_completed(struct work_struct *work) { @@ -6452,7 +6394,7 @@ static void iwl3945_bg_scan_completed(struct work_struct *work) return; if (test_bit(STATUS_CONF_PENDING, &priv->status)) - iwl3945_mac_config(priv->hw, ieee80211_get_hw_conf(priv->hw)); + iwl3945_mac_config(priv->hw, 0); ieee80211_scan_completed(priv->hw); @@ -6604,7 +6546,6 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, { struct iwl3945_priv *priv = hw->priv; unsigned long flags; - DECLARE_MAC_BUF(mac); IWL_DEBUG_MAC80211("enter: type %d\n", conf->type); @@ -6615,13 +6556,14 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, spin_lock_irqsave(&priv->lock, flags); priv->vif = conf->vif; + priv->iw_mode = conf->type; spin_unlock_irqrestore(&priv->lock, flags); mutex_lock(&priv->mutex); if (conf->mac_addr) { - IWL_DEBUG_MAC80211("Set: %s\n", print_mac(mac, conf->mac_addr)); + IWL_DEBUG_MAC80211("Set: %pM\n", conf->mac_addr); memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); } @@ -6641,10 +6583,11 @@ static int iwl3945_mac_add_interface(struct ieee80211_hw *hw, * be set inappropriately and the driver currently sets the hardware up to * use it whenever needed. */ -static int iwl3945_mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed) { struct iwl3945_priv *priv = hw->priv; const struct iwl3945_channel_info *ch_info; + struct ieee80211_conf *conf = &hw->conf; unsigned long flags; int ret = 0; @@ -6782,16 +6725,11 @@ static void iwl3945_config_ap(struct iwl3945_priv *priv) * clear sta table, add BCAST sta... */ } -/* temporary */ -static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *skb); - static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { struct iwl3945_priv *priv = hw->priv; - DECLARE_MAC_BUF(mac); - unsigned long flags; int rc; if (conf == NULL) @@ -6808,28 +6746,20 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, struct sk_buff *beacon = ieee80211_beacon_get(hw, vif); if (!beacon) return -ENOMEM; + mutex_lock(&priv->mutex); rc = iwl3945_mac_beacon_update(hw, beacon); + mutex_unlock(&priv->mutex); if (rc) return rc; } - /* XXX: this MUST use conf->mac_addr */ - - if ((priv->iw_mode == NL80211_IFTYPE_AP) && - (!conf->ssid_len)) { - IWL_DEBUG_MAC80211 - ("Leaving in AP mode because HostAPD is not ready.\n"); - return 0; - } - if (!iwl3945_is_alive(priv)) return -EAGAIN; mutex_lock(&priv->mutex); if (conf->bssid) - IWL_DEBUG_MAC80211("bssid: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid: %pM\n", conf->bssid); /* * very dubious code was here; the probe filtering flag is never set: @@ -6842,8 +6772,8 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, if (!conf->bssid) { conf->bssid = priv->mac_addr; memcpy(priv->bssid, priv->mac_addr, ETH_ALEN); - IWL_DEBUG_MAC80211("bssid was set to: %s\n", - print_mac(mac, conf->bssid)); + IWL_DEBUG_MAC80211("bssid was set to: %pM\n", + conf->bssid); } if (priv->ibss_beacon) dev_kfree_skb(priv->ibss_beacon); @@ -6889,15 +6819,6 @@ static int iwl3945_mac_config_interface(struct ieee80211_hw *hw, } done: - spin_lock_irqsave(&priv->lock, flags); - if (!conf->ssid_len) - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - else - memcpy(priv->essid, conf->ssid, conf->ssid_len); - - priv->essid_len = conf->ssid_len; - spin_unlock_irqrestore(&priv->lock, flags); - IWL_DEBUG_MAC80211("leave\n"); mutex_unlock(&priv->mutex); @@ -6910,16 +6831,43 @@ static void iwl3945_configure_filter(struct ieee80211_hw *hw, int mc_count, struct dev_addr_list *mc_list) { struct iwl3945_priv *priv = hw->priv; + __le32 *filter_flags = &priv->staging_rxon.filter_flags; - if (changed_flags & (*total_flags) & FIF_OTHER_BSS) { - IWL_DEBUG_MAC80211("Enter: type %d (0x%x, 0x%x)\n", - NL80211_IFTYPE_MONITOR, - changed_flags, *total_flags); - /* queue work 'cuz mac80211 is holding a lock which - * prevents us from issuing (synchronous) f/w cmds */ - queue_work(priv->workqueue, &priv->set_monitor); + IWL_DEBUG_MAC80211("Enter: changed: 0x%x, total: 0x%x\n", + changed_flags, *total_flags); + + if (changed_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) { + if (*total_flags & (FIF_OTHER_BSS | FIF_PROMISC_IN_BSS)) + *filter_flags |= RXON_FILTER_PROMISC_MSK; + else + *filter_flags &= ~RXON_FILTER_PROMISC_MSK; } - *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | + if (changed_flags & FIF_ALLMULTI) { + if (*total_flags & FIF_ALLMULTI) + *filter_flags |= RXON_FILTER_ACCEPT_GRP_MSK; + else + *filter_flags &= ~RXON_FILTER_ACCEPT_GRP_MSK; + } + if (changed_flags & FIF_CONTROL) { + if (*total_flags & FIF_CONTROL) + *filter_flags |= RXON_FILTER_CTL2HOST_MSK; + else + *filter_flags &= ~RXON_FILTER_CTL2HOST_MSK; + } + if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { + if (*total_flags & FIF_BCN_PRBRESP_PROMISC) + *filter_flags |= RXON_FILTER_BCON_AWARE_MSK; + else + *filter_flags &= ~RXON_FILTER_BCON_AWARE_MSK; + } + + /* We avoid iwl_commit_rxon here to commit the new filter flags + * since mac80211 will call ieee80211_hw_config immediately. + * (mc_list is not supported at this time). Otherwise, we need to + * queue a background iwl_commit_rxon work. + */ + + *total_flags &= FIF_OTHER_BSS | FIF_ALLMULTI | FIF_PROMISC_IN_BSS | FIF_BCN_PRBRESP_PROMISC | FIF_CONTROL; } @@ -6940,8 +6888,6 @@ static void iwl3945_mac_remove_interface(struct ieee80211_hw *hw, if (priv->vif == conf->vif) { priv->vif = NULL; memset(priv->bssid, 0, ETH_ALEN); - memset(priv->essid, 0, IW_ESSID_MAX_SIZE); - priv->essid_len = 0; } mutex_unlock(&priv->mutex); @@ -7010,6 +6956,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) int rc = 0; unsigned long flags; struct iwl3945_priv *priv = hw->priv; + DECLARE_SSID_BUF(ssid_buf); IWL_DEBUG_MAC80211("enter\n"); @@ -7022,12 +6969,6 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) goto out_unlock; } - if (priv->iw_mode == NL80211_IFTYPE_AP) { /* APs don't scan */ - rc = -EIO; - IWL_ERROR("ERROR: APs don't scan\n"); - goto out_unlock; - } - /* we don't schedule scan within next_scan_jiffies period */ if (priv->next_scan_jiffies && time_after(priv->next_scan_jiffies, jiffies)) { @@ -7043,7 +6984,7 @@ static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw, u8 *ssid, size_t len) } if (len) { IWL_DEBUG_SCAN("direct scan for %s [%d]\n ", - iwl3945_escape_essid(ssid, len), (int)len); + print_ssid(ssid_buf, ssid, len), (int)len); priv->one_direct_scan = 1; priv->direct_ssid_len = (u8) @@ -7084,10 +7025,8 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, sta_id = iwl3945_hw_find_station(priv, addr); if (sta_id == IWL_INVALID_STATION) { - DECLARE_MAC_BUF(mac); - - IWL_DEBUG_MAC80211("leave - %s not in station map.\n", - print_mac(mac, addr)); + IWL_DEBUG_MAC80211("leave - %pM not in station map.\n", + addr); return -EINVAL; } @@ -7143,11 +7082,6 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue, return 0; } - if (!priv->qos_data.qos_enable) { - priv->qos_data.qos_active = 0; - IWL_DEBUG_MAC80211("leave - qos not enabled\n"); - return 0; - } q = AC_NUM - 1 - queue; spin_lock_irqsave(&priv->lock, flags); @@ -7219,14 +7153,6 @@ static int iwl3945_mac_get_stats(struct ieee80211_hw *hw, return 0; } -static u64 iwl3945_mac_get_tsf(struct ieee80211_hw *hw) -{ - IWL_DEBUG_MAC80211("enter\n"); - IWL_DEBUG_MAC80211("leave\n"); - - return 0; -} - static void iwl3945_mac_reset_tsf(struct ieee80211_hw *hw) { struct iwl3945_priv *priv = hw->priv; @@ -7292,18 +7218,15 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk struct iwl3945_priv *priv = hw->priv; unsigned long flags; - mutex_lock(&priv->mutex); IWL_DEBUG_MAC80211("enter\n"); if (!iwl3945_is_ready_rf(priv)) { IWL_DEBUG_MAC80211("leave - RF not ready\n"); - mutex_unlock(&priv->mutex); return -EIO; } if (priv->iw_mode != NL80211_IFTYPE_ADHOC) { IWL_DEBUG_MAC80211("leave - not IBSS\n"); - mutex_unlock(&priv->mutex); return -EIO; } @@ -7323,7 +7246,6 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk iwl3945_post_associate(priv); - mutex_unlock(&priv->mutex); return 0; } @@ -7792,7 +7714,7 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log); /***************************************************************************** * - * driver setup and teardown + * driver setup and tear down * *****************************************************************************/ @@ -7810,7 +7732,6 @@ static void iwl3945_setup_deferred_work(struct iwl3945_priv *priv) INIT_WORK(&priv->abort_scan, iwl3945_bg_abort_scan); INIT_WORK(&priv->rf_kill, iwl3945_bg_rf_kill); INIT_WORK(&priv->beacon_update, iwl3945_bg_beacon_update); - INIT_WORK(&priv->set_monitor, iwl3945_bg_set_monitor); INIT_DELAYED_WORK(&priv->init_alive_start, iwl3945_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl3945_bg_alive_start); INIT_DELAYED_WORK(&priv->scan_check, iwl3945_bg_scan_check); @@ -7869,7 +7790,6 @@ static struct ieee80211_ops iwl3945_hw_ops = { .get_stats = iwl3945_mac_get_stats, .get_tx_stats = iwl3945_mac_get_tx_stats, .conf_tx = iwl3945_mac_conf_tx, - .get_tsf = iwl3945_mac_get_tsf, .reset_tsf = iwl3945_mac_reset_tsf, .bss_info_changed = iwl3945_bss_info_changed, .hw_scan = iwl3945_mac_hw_scan @@ -7882,7 +7802,10 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e struct ieee80211_hw *hw; struct iwl_3945_cfg *cfg = (struct iwl_3945_cfg *)(ent->driver_data); unsigned long flags; - DECLARE_MAC_BUF(mac); + + /*********************** + * 1. Allocating HW data + * ********************/ /* Disabling hardware scan means that mac80211 will perform scans * "the hard way", rather than using device's scan. */ @@ -7907,48 +7830,41 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e err = -ENOMEM; goto out; } - SET_IEEE80211_DEV(hw, &pdev->dev); - hw->rate_control_algorithm = "iwl-3945-rs"; - hw->sta_data_size = sizeof(struct iwl3945_sta_priv); + SET_IEEE80211_DEV(hw, &pdev->dev); - IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); priv = hw->priv; priv->hw = hw; - priv->pci_dev = pdev; priv->cfg = cfg; + IWL_DEBUG_INFO("*** LOAD DRIVER ***\n"); + hw->rate_control_algorithm = "iwl-3945-rs"; + hw->sta_data_size = sizeof(struct iwl3945_sta_priv); + /* Select antenna (may be helpful if only one antenna is connected) */ priv->antenna = (enum iwl3945_antenna)iwl3945_param_antenna; #ifdef CONFIG_IWL3945_DEBUG iwl3945_debug_level = iwl3945_param_debug; atomic_set(&priv->restrict_refcnt, 0); #endif - priv->retry_rate = 1; - - priv->ibss_beacon = NULL; /* Tell mac80211 our characteristics */ hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_ADHOC); + hw->wiphy->fw_handles_regulatory = true; + /* 4 EDCA QOS priorities */ hw->queues = 4; - spin_lock_init(&priv->lock); - spin_lock_init(&priv->power_data.lock); - spin_lock_init(&priv->sta_lock); - spin_lock_init(&priv->hcmd_lock); - - INIT_LIST_HEAD(&priv->free_frames); - - mutex_init(&priv->mutex); + /*************************** + * 2. Initializing PCI bus + * *************************/ if (pci_enable_device(pdev)) { err = -ENODEV; goto out_ieee80211_free_hw; @@ -7956,14 +7872,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e pci_set_master(pdev); - /* Clear the driver's (not device's) station table */ - iwl3945_clear_stations_table(priv); - - priv->data_retry_limit = -1; - priv->ieee_channels = NULL; - priv->ieee_rates = NULL; - priv->band = IEEE80211_BAND_2GHZ; - err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (!err) err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); @@ -7977,10 +7885,9 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e if (err) goto out_pci_disable_device; - /* We disable the RETRY_TIMEOUT register (0x41) to keep - * PCI Tx retries from interfering with C3 CPU state */ - pci_write_config_byte(pdev, 0x41, 0x00); - + /*********************** + * 3. Read REV Register + * ********************/ priv->hw_base = pci_iomap(pdev, 0, 0); if (!priv->hw_base) { err = -ENODEV; @@ -7991,97 +7898,144 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e (unsigned long long) pci_resource_len(pdev, 0)); IWL_DEBUG_INFO("pci_resource_base = %p\n", priv->hw_base); - /* Initialize module parameter values here */ + /* We disable the RETRY_TIMEOUT register (0x41) to keep + * PCI Tx retries from interfering with C3 CPU state */ + pci_write_config_byte(pdev, 0x41, 0x00); - /* Disable radio (SW RF KILL) via parameter when loading driver */ - if (iwl3945_param_disable) { - set_bit(STATUS_RF_KILL_SW, &priv->status); - IWL_DEBUG_INFO("Radio disabled.\n"); - } + /* nic init */ + iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, + CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - priv->iw_mode = NL80211_IFTYPE_STATION; + iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); + err = iwl3945_poll_direct_bit(priv, CSR_GP_CNTRL, + CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); + if (err < 0) { + IWL_DEBUG_INFO("Failed to init the card\n"); + goto out_remove_sysfs; + } - printk(KERN_INFO DRV_NAME - ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); + /*********************** + * 4. Read EEPROM + * ********************/ + /* Read the EEPROM */ + err = iwl3945_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_DEBUG_INFO("MAC address: %pM\n", priv->mac_addr); + SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr); + /*********************** + * 5. Setup HW Constants + * ********************/ /* Device-specific setup */ if (iwl3945_hw_set_hw_setting(priv)) { IWL_ERROR("failed to set hw settings\n"); goto out_iounmap; } - if (iwl3945_param_qos_enable) - priv->qos_data.qos_enable = 1; + /*********************** + * 6. Setup priv + * ********************/ + priv->retry_rate = 1; + priv->ibss_beacon = NULL; + + spin_lock_init(&priv->lock); + spin_lock_init(&priv->power_data.lock); + spin_lock_init(&priv->sta_lock); + spin_lock_init(&priv->hcmd_lock); + + INIT_LIST_HEAD(&priv->free_frames); + mutex_init(&priv->mutex); + + /* Clear the driver's (not device's) station table */ + iwl3945_clear_stations_table(priv); + + priv->data_retry_limit = -1; + priv->ieee_channels = NULL; + priv->ieee_rates = NULL; + priv->band = IEEE80211_BAND_2GHZ; + + priv->iw_mode = NL80211_IFTYPE_STATION; iwl3945_reset_qos(priv); priv->qos_data.qos_active = 0; priv->qos_data.qos_cap.val = 0; - iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); - iwl3945_setup_deferred_work(priv); - iwl3945_setup_rx_handlers(priv); priv->rates_mask = IWL_RATES_MASK; /* If power management is turned on, default to AC mode */ priv->power_mode = IWL_POWER_AC; priv->user_txpower_limit = IWL_DEFAULT_TX_POWER; - spin_lock_irqsave(&priv->lock, flags); - iwl3945_disable_interrupts(priv); - spin_unlock_irqrestore(&priv->lock, flags); - - err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); + err = iwl3945_init_channel_map(priv); if (err) { - IWL_ERROR("failed to create sysfs device attributes\n"); + IWL_ERROR("initializing regulatory failed: %d\n", err); goto out_release_irq; } - /* nic init */ - iwl3945_set_bit(priv, CSR_GIO_CHICKEN_BITS, - CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER); - - iwl3945_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE); - err = iwl3945_poll_bit(priv, CSR_GP_CNTRL, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, - CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000); - if (err < 0) { - IWL_DEBUG_INFO("Failed to init the card\n"); - goto out_remove_sysfs; - } - /* Read the EEPROM */ - err = iwl3945_eeprom_init(priv); + err = iwl3945_init_geos(priv); if (err) { - IWL_ERROR("Unable to init EEPROM\n"); - goto out_remove_sysfs; + IWL_ERROR("initializing geos failed: %d\n", err); + goto out_free_channel_map; } - /* MAC Address location in EEPROM same for 3945/4965 */ - get_eeprom_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); - err = iwl3945_init_channel_map(priv); - if (err) { - IWL_ERROR("initializing regulatory failed: %d\n", err); - goto out_remove_sysfs; + printk(KERN_INFO DRV_NAME + ": Detected Intel Wireless WiFi Link %s\n", priv->cfg->name); + + /*********************************** + * 7. Initialize Module Parameters + * **********************************/ + + /* Initialize module parameter values here */ + /* Disable radio (SW RF KILL) via parameter when loading driver */ + if (iwl3945_param_disable) { + set_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_INFO("Radio disabled.\n"); } - err = iwl3945_init_geos(priv); + + /*********************** + * 8. Setup Services + * ********************/ + + spin_lock_irqsave(&priv->lock, flags); + iwl3945_disable_interrupts(priv); + spin_unlock_irqrestore(&priv->lock, flags); + + err = sysfs_create_group(&pdev->dev.kobj, &iwl3945_attribute_group); if (err) { - IWL_ERROR("initializing geos failed: %d\n", err); - goto out_free_channel_map; + IWL_ERROR("failed to create sysfs device attributes\n"); + goto out_free_geos; } + iwl3945_set_rxon_channel(priv, IEEE80211_BAND_2GHZ, 6); + iwl3945_setup_deferred_work(priv); + iwl3945_setup_rx_handlers(priv); + + /*********************** + * 9. Conclude + * ********************/ + pci_save_state(pdev); + pci_disable_device(pdev); + + /********************************* + * 10. Setup and Register mac80211 + * *******************************/ + err = ieee80211_register_hw(priv->hw); if (err) { IWL_ERROR("Failed to register network device (error %d)\n", err); - goto out_free_geos; + goto out_remove_sysfs; } priv->hw->conf.beacon_int = 100; priv->mac80211_registered = 1; - pci_save_state(pdev); - pci_disable_device(pdev); + err = iwl3945_rfkill_init(priv); if (err) @@ -8090,12 +8044,13 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e return 0; + out_remove_sysfs: + sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); out_free_geos: iwl3945_free_geos(priv); out_free_channel_map: iwl3945_free_channel_map(priv); - out_remove_sysfs: - sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group); + out_release_irq: destroy_workqueue(priv->workqueue); @@ -8222,7 +8177,7 @@ static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state) if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return 0; - IWL_DEBUG_RF_KILL("we recieved soft RFKILL set to state %d\n", state); + IWL_DEBUG_RF_KILL("we received soft RFKILL set to state %d\n", state); mutex_lock(&priv->mutex); switch (state) { @@ -8237,7 +8192,7 @@ static int iwl3945_rfkill_soft_rf_kill(void *data, enum rfkill_state state) iwl3945_radio_kill_sw(priv, 1); break; default: - IWL_WARNING("we recieved unexpected RFKILL state %d\n", state); + IWL_WARNING("we received unexpected RFKILL state %d\n", state); break; } out_unlock: @@ -8379,7 +8334,7 @@ static void __exit iwl3945_exit(void) iwl3945_rate_control_unregister(); } -MODULE_FIRMWARE("iwlwifi-3945" IWL3945_UCODE_API ".ucode"); +MODULE_FIRMWARE(IWL3945_MODULE_FIRMWARE(IWL3945_UCODE_API_MAX)); module_param_named(antenna, iwl3945_param_antenna, int, 0444); MODULE_PARM_DESC(antenna, "select antenna (1=Main, 2=Aux, default 0 [both])"); @@ -8388,7 +8343,7 @@ MODULE_PARM_DESC(disable, "manually disable the radio (default 0 [radio on])"); module_param_named(hwcrypto, iwl3945_param_hwcrypto, int, 0444); MODULE_PARM_DESC(hwcrypto, "using hardware crypto engine (default 0 [software])\n"); -module_param_named(debug, iwl3945_param_debug, int, 0444); +module_param_named(debug, iwl3945_param_debug, uint, 0444); MODULE_PARM_DESC(debug, "debug output mask"); module_param_named(disable_hw_scan, iwl3945_param_disable_hw_scan, int, 0444); MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); @@ -8396,9 +8351,5 @@ MODULE_PARM_DESC(disable_hw_scan, "disable hardware scanning (default 0)"); module_param_named(queues_num, iwl3945_param_queues_num, int, 0444); MODULE_PARM_DESC(queues_num, "number of hw queues."); -/* QoS */ -module_param_named(qos_enable, iwl3945_param_qos_enable, int, 0444); -MODULE_PARM_DESC(qos_enable, "enable all QoS functionality"); - module_exit(iwl3945_exit); module_init(iwl3945_init); diff --git a/drivers/net/wireless/libertas/assoc.c b/drivers/net/wireless/libertas/assoc.c index 92be60415d043e041384bdaeea082f440a9123fb..a0e440cd8967ec55c53ae17b948d678d6c5b7959 100644 --- a/drivers/net/wireless/libertas/assoc.c +++ b/drivers/net/wireless/libertas/assoc.c @@ -1,6 +1,10 @@ /* Copyright (C) 2006, Red Hat, Inc. */ +#include #include +#include +#include +#include #include "assoc.h" #include "decl.h" @@ -151,18 +155,18 @@ static int lbs_adhoc_join(struct lbs_private *priv, struct cmd_ds_802_11_ad_hoc_join cmd; struct bss_descriptor *bss = &assoc_req->bss; u8 preamble = RADIO_PREAMBLE_LONG; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); u16 ratesize = 0; int ret = 0; lbs_deb_enter(LBS_DEB_ASSOC); lbs_deb_join("current SSID '%s', ssid length %u\n", - escape_essid(priv->curbssparams.ssid, + print_ssid(ssid, priv->curbssparams.ssid, priv->curbssparams.ssid_len), priv->curbssparams.ssid_len); lbs_deb_join("requested ssid '%s', ssid length %u\n", - escape_essid(bss->ssid, bss->ssid_len), + print_ssid(ssid, bss->ssid, bss->ssid_len), bss->ssid_len); /* check if the requested SSID is already joined */ @@ -226,8 +230,8 @@ static int lbs_adhoc_join(struct lbs_private *priv, bss->capability, CAPINFO_MASK); /* information on BSSID descriptor passed to FW */ - lbs_deb_join("ADHOC_J_CMD: BSSID = %s, SSID = '%s'\n", - print_mac(mac, cmd.bss.bssid), cmd.bss.ssid); + lbs_deb_join("ADHOC_J_CMD: BSSID = %pM, SSID = '%s'\n", + cmd.bss.bssid, cmd.bss.ssid); /* Only v8 and below support setting these */ if (priv->fwrelease < 0x09000000) { @@ -307,6 +311,7 @@ static int lbs_adhoc_start(struct lbs_private *priv, size_t ratesize = 0; u16 tmpcap = 0; int ret = 0; + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_ASSOC); @@ -326,7 +331,7 @@ static int lbs_adhoc_start(struct lbs_private *priv, memcpy(cmd.ssid, assoc_req->ssid, assoc_req->ssid_len); lbs_deb_join("ADHOC_START: SSID '%s', ssid length %u\n", - escape_essid(assoc_req->ssid, assoc_req->ssid_len), + print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len), assoc_req->ssid_len); cmd.bsstype = CMD_BSS_TYPE_IBSS; @@ -338,12 +343,12 @@ static int lbs_adhoc_start(struct lbs_private *priv, WARN_ON(!assoc_req->channel); /* set Physical parameter set */ - cmd.phyparamset.dsparamset.elementid = MFIE_TYPE_DS_SET; + cmd.phyparamset.dsparamset.elementid = WLAN_EID_DS_PARAMS; cmd.phyparamset.dsparamset.len = 1; cmd.phyparamset.dsparamset.currentchan = assoc_req->channel; /* set IBSS parameter set */ - cmd.ssparamset.ibssparamset.elementid = MFIE_TYPE_IBSS_SET; + cmd.ssparamset.ibssparamset.elementid = WLAN_EID_IBSS_PARAMS; cmd.ssparamset.ibssparamset.len = 2; cmd.ssparamset.ibssparamset.atimwindow = 0; @@ -427,8 +432,8 @@ static inline int match_bss_no_security(struct lbs_802_11_security *secinfo, { 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->wpa_ie[0] != WLAN_EID_GENERIC + && match_bss->rsn_ie[0] != WLAN_EID_RSN && !(match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else @@ -450,7 +455,7 @@ static inline int match_bss_wpa(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { if (!secinfo->wep_enabled && secinfo->WPAenabled - && (match_bss->wpa_ie[0] == MFIE_TYPE_GENERIC) + && (match_bss->wpa_ie[0] == WLAN_EID_GENERIC) /* privacy bit may NOT be set in some APs like LinkSys WRT54G && (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ ) @@ -463,7 +468,7 @@ static inline int match_bss_wpa2(struct lbs_802_11_security *secinfo, struct bss_descriptor *match_bss) { if (!secinfo->wep_enabled && secinfo->WPA2enabled && - (match_bss->rsn_ie[0] == MFIE_TYPE_RSN) + (match_bss->rsn_ie[0] == WLAN_EID_RSN) /* privacy bit may NOT be set in some APs like LinkSys WRT54G (match_bss->capability & WLAN_CAPABILITY_PRIVACY) */ ) @@ -477,8 +482,8 @@ static inline int match_bss_dynamic_wep(struct lbs_802_11_security *secinfo, { 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->wpa_ie[0] != WLAN_EID_GENERIC) + && (match_bss->rsn_ie[0] != WLAN_EID_RSN) && (match_bss->capability & WLAN_CAPABILITY_PRIVACY)) return 1; else @@ -694,6 +699,7 @@ static int assoc_helper_essid(struct lbs_private *priv, int ret = 0; struct bss_descriptor * bss; int channel = -1; + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_ASSOC); @@ -705,7 +711,7 @@ static int assoc_helper_essid(struct lbs_private *priv, channel = assoc_req->channel; lbs_deb_assoc("SSID '%s' requested\n", - escape_essid(assoc_req->ssid, assoc_req->ssid_len)); + print_ssid(ssid, 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); @@ -752,17 +758,15 @@ static int assoc_helper_bssid(struct lbs_private *priv, { int ret = 0; struct bss_descriptor * bss; - DECLARE_MAC_BUF(mac); - lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %s", - print_mac(mac, assoc_req->bssid)); + lbs_deb_enter_args(LBS_DEB_ASSOC, "BSSID %pM", assoc_req->bssid); /* Search for index position in list for requested MAC */ bss = lbs_find_bssid_in_list(priv, assoc_req->bssid, assoc_req->mode); if (bss == NULL) { - lbs_deb_assoc("ASSOC: WAP: BSSID %s not found, " - "cannot associate.\n", print_mac(mac, assoc_req->bssid)); + lbs_deb_assoc("ASSOC: WAP: BSSID %pM not found, " + "cannot associate.\n", assoc_req->bssid); goto out; } @@ -1208,7 +1212,7 @@ void lbs_association_worker(struct work_struct *work) struct assoc_request * assoc_req = NULL; int ret = 0; int find_any_ssid = 0; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_ASSOC); @@ -1228,13 +1232,13 @@ void lbs_association_worker(struct work_struct *work) " chann: %d\n" " band: %d\n" " mode: %d\n" - " BSSID: %s\n" + " BSSID: %pM\n" " secinfo: %s%s%s\n" " auth_mode: %d\n", assoc_req->flags, - escape_essid(assoc_req->ssid, assoc_req->ssid_len), + print_ssid(ssid, assoc_req->ssid, assoc_req->ssid_len), assoc_req->channel, assoc_req->band, assoc_req->mode, - print_mac(mac, assoc_req->bssid), + assoc_req->bssid, assoc_req->secinfo.WPAenabled ? " WPA" : "", assoc_req->secinfo.WPA2enabled ? " WPA2" : "", assoc_req->secinfo.wep_enabled ? " WEP" : "", @@ -1357,8 +1361,8 @@ void lbs_association_worker(struct work_struct *work) } if (success) { - lbs_deb_assoc("associated to %s\n", - print_mac(mac, priv->curbssparams.bssid)); + lbs_deb_assoc("associated to %pM\n", + priv->curbssparams.bssid); lbs_prepare_and_send_command(priv, CMD_802_11_RSSI, 0, CMD_OPTION_WAITFORRSP, 0, NULL); @@ -1478,7 +1482,6 @@ int lbs_cmd_80211_authenticate(struct lbs_private *priv, struct cmd_ds_802_11_authenticate *pauthenticate = &cmd->params.auth; int ret = -1; u8 *bssid = pdata_buf; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_JOIN); @@ -1505,8 +1508,8 @@ int lbs_cmd_80211_authenticate(struct lbs_private *priv, memcpy(pauthenticate->macaddr, bssid, ETH_ALEN); - lbs_deb_join("AUTH_CMD: BSSID %s, auth 0x%x\n", - print_mac(mac, bssid), pauthenticate->authtype); + lbs_deb_join("AUTH_CMD: BSSID %pM, auth 0x%x\n", + bssid, pauthenticate->authtype); ret = 0; out: @@ -1770,7 +1773,7 @@ static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) struct cmd_ds_802_11_ad_hoc_result *adhoc_resp; union iwreq_data wrqu; struct bss_descriptor *bss; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); lbs_deb_enter(LBS_DEB_JOIN); @@ -1819,9 +1822,9 @@ static int lbs_adhoc_post(struct lbs_private *priv, struct cmd_header *resp) wrqu.ap_addr.sa_family = ARPHRD_ETHER; wireless_send_event(priv->dev, SIOCGIWAP, &wrqu, NULL); - lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %s, channel %d\n", - escape_essid(bss->ssid, bss->ssid_len), - print_mac(mac, priv->curbssparams.bssid), + lbs_deb_join("ADHOC_RESP: Joined/started '%s', BSSID %pM, channel %d\n", + print_ssid(ssid, bss->ssid, bss->ssid_len), + priv->curbssparams.bssid, priv->curbssparams.channel); done: diff --git a/drivers/net/wireless/libertas/cmd.c b/drivers/net/wireless/libertas/cmd.c index 8265c7d25edcb9cbe51478e00828d93e8a26000c..639dd02d3d31d72e74ca916a772aa7406875612b 100644 --- a/drivers/net/wireless/libertas/cmd.c +++ b/drivers/net/wireless/libertas/cmd.c @@ -4,7 +4,7 @@ */ #include -#include +#include #include #include "host.h" #include "hostcmd.h" @@ -87,7 +87,6 @@ int lbs_update_hw_spec(struct lbs_private *priv) struct cmd_ds_get_hw_spec cmd; int ret = -1; u32 i; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_CMD); @@ -110,8 +109,8 @@ int lbs_update_hw_spec(struct lbs_private *priv) * CF card firmware 5.0.16p0: cap 0x00000303 * USB dongle firmware 5.110.17p2: cap 0x00000303 */ - lbs_pr_info("%s, fw %u.%u.%up%u, cap 0x%08x\n", - print_mac(mac, cmd.permanentaddr), + lbs_pr_info("%pM, fw %u.%u.%up%u, cap 0x%08x\n", + cmd.permanentaddr, priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 16 & 0xff, priv->fwrelease >> 8 & 0xff, @@ -160,7 +159,8 @@ out: return ret; } -int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria) +int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, + struct wol_config *p_wol_config) { struct cmd_ds_host_sleep cmd_config; int ret; @@ -170,10 +170,21 @@ int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria) cmd_config.gpio = priv->wol_gpio; cmd_config.gap = priv->wol_gap; + if (p_wol_config != NULL) + memcpy((uint8_t *)&cmd_config.wol_conf, (uint8_t *)p_wol_config, + sizeof(struct wol_config)); + else + cmd_config.wol_conf.action = CMD_ACT_ACTION_NONE; + ret = lbs_cmd_with_response(priv, CMD_802_11_HOST_SLEEP_CFG, &cmd_config); if (!ret) { - lbs_deb_cmd("Set WOL criteria to %x\n", criteria); - priv->wol_criteria = criteria; + if (criteria) { + lbs_deb_cmd("Set WOL criteria to %x\n", criteria); + priv->wol_criteria = criteria; + } else + memcpy((uint8_t *) p_wol_config, + (uint8_t *)&cmd_config.wol_conf, + sizeof(struct wol_config)); } else { lbs_pr_info("HOST_SLEEP_CFG failed %d\n", ret); } @@ -1063,6 +1074,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) { struct cmd_ds_mesh_config cmd; struct mrvl_meshie *ie; + DECLARE_SSID_BUF(ssid); memset(&cmd, 0, sizeof(cmd)); cmd.channel = cpu_to_le16(chan); @@ -1070,7 +1082,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) switch (action) { case CMD_ACT_MESH_CONFIG_START: - ie->hdr.id = MFIE_TYPE_GENERIC; + ie->id = WLAN_EID_GENERIC; ie->val.oui[0] = 0x00; ie->val.oui[1] = 0x50; ie->val.oui[2] = 0x43; @@ -1082,7 +1094,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) ie->val.mesh_capability = MARVELL_MESH_CAPABILITY; ie->val.mesh_id_len = priv->mesh_ssid_len; memcpy(ie->val.mesh_id, priv->mesh_ssid, priv->mesh_ssid_len); - ie->hdr.len = sizeof(struct mrvl_meshie_val) - + ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + priv->mesh_ssid_len; cmd.length = cpu_to_le16(sizeof(struct mrvl_meshie_val)); break; @@ -1093,7 +1105,7 @@ int lbs_mesh_config(struct lbs_private *priv, uint16_t action, uint16_t chan) } lbs_deb_cmd("mesh config action %d type %x channel %d SSID %s\n", action, priv->mesh_tlv, chan, - escape_essid(priv->mesh_ssid, priv->mesh_ssid_len)); + print_ssid(ssid, priv->mesh_ssid, priv->mesh_ssid_len)); return __lbs_mesh_config_send(priv, &cmd, action, priv->mesh_tlv); } diff --git a/drivers/net/wireless/libertas/cmd.h b/drivers/net/wireless/libertas/cmd.h index 36be4c9703e0b0c12fd4f0ee6f4b31db56bc8fe5..392e578ca0952fb5e2d35592844dd0833a469199 100644 --- a/drivers/net/wireless/libertas/cmd.h +++ b/drivers/net/wireless/libertas/cmd.h @@ -56,7 +56,8 @@ int lbs_mesh_config_send(struct lbs_private *priv, uint16_t action, uint16_t type); int lbs_mesh_config(struct lbs_private *priv, uint16_t enable, uint16_t chan); -int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria); +int lbs_host_sleep_cfg(struct lbs_private *priv, uint32_t criteria, + struct wol_config *p_wol_config); int lbs_suspend(struct lbs_private *priv); void lbs_resume(struct lbs_private *priv); diff --git a/drivers/net/wireless/libertas/debugfs.c b/drivers/net/wireless/libertas/debugfs.c index 0aa0ce3b2c425206262997ef1eacb163cb66c977..ec4efd7ff3c85064929fe67a6dee3c10f3c2148a 100644 --- a/drivers/net/wireless/libertas/debugfs.c +++ b/drivers/net/wireless/libertas/debugfs.c @@ -5,6 +5,7 @@ #include #include #include +#include #include "dev.h" #include "decl.h" @@ -65,7 +66,7 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, int numscansdone = 0, res; unsigned long addr = get_zeroed_page(GFP_KERNEL); char *buf = (char *)addr; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); struct bss_descriptor * iter_bss; pos += snprintf(buf+pos, len-pos, @@ -77,17 +78,17 @@ static ssize_t lbs_getscantable(struct file *file, char __user *userbuf, u16 privacy = (iter_bss->capability & WLAN_CAPABILITY_PRIVACY); u16 spectrum_mgmt = (iter_bss->capability & WLAN_CAPABILITY_SPECTRUM_MGMT); - pos += snprintf(buf+pos, len-pos, - "%02u| %03d | %04d | %s |", + pos += snprintf(buf+pos, len-pos, "%02u| %03d | %04d | %pM |", numscansdone, iter_bss->channel, iter_bss->rssi, - print_mac(mac, iter_bss->bssid)); + iter_bss->bssid); pos += snprintf(buf+pos, len-pos, " %04x-", iter_bss->capability); pos += snprintf(buf+pos, len-pos, "%c%c%c |", ibss ? 'A' : 'I', privacy ? 'P' : ' ', spectrum_mgmt ? 'S' : ' '); pos += snprintf(buf+pos, len-pos, " %04d |", SCAN_RSSI(iter_bss->rssi)); pos += snprintf(buf+pos, len-pos, " %s\n", - escape_essid(iter_bss->ssid, iter_bss->ssid_len)); + print_ssid(ssid, iter_bss->ssid, + iter_bss->ssid_len)); numscansdone++; } diff --git a/drivers/net/wireless/libertas/decl.h b/drivers/net/wireless/libertas/decl.h index 1a8888cceadc080bffd7d9b6dab1222c0529802e..0b84bdca0726129c98ccebbc0fe684a64a63c728 100644 --- a/drivers/net/wireless/libertas/decl.h +++ b/drivers/net/wireless/libertas/decl.h @@ -74,8 +74,4 @@ void lbs_host_to_card_done(struct lbs_private *priv); int lbs_update_channel(struct lbs_private *priv); -#ifndef CONFIG_IEEE80211 -const char *escape_essid(const char *essid, u8 essid_len); -#endif - #endif diff --git a/drivers/net/wireless/libertas/defs.h b/drivers/net/wireless/libertas/defs.h index 076a636e8f62165252b8f931f88312187e64c1bf..c364e4c01d1b7183f53290206a997e41051b6135 100644 --- a/drivers/net/wireless/libertas/defs.h +++ b/drivers/net/wireless/libertas/defs.h @@ -79,7 +79,7 @@ do { if ((lbs_debug & (grp)) == (grp)) \ #define lbs_deb_tx(fmt, args...) LBS_DEB_LL(LBS_DEB_TX, " tx", fmt, ##args) #define lbs_deb_fw(fmt, args...) LBS_DEB_LL(LBS_DEB_FW, " fw", fmt, ##args) #define lbs_deb_usb(fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usb", fmt, ##args) -#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, (dev)->bus_id, ##args) +#define lbs_deb_usbd(dev, fmt, args...) LBS_DEB_LL(LBS_DEB_USB, " usbd", "%s:" fmt, dev_name(dev), ##args) #define lbs_deb_cs(fmt, args...) LBS_DEB_LL(LBS_DEB_CS, " cs", fmt, ##args) #define lbs_deb_thread(fmt, args...) LBS_DEB_LL(LBS_DEB_THREAD, " thread", fmt, ##args) #define lbs_deb_sdio(fmt, args...) LBS_DEB_LL(LBS_DEB_SDIO, " sdio", fmt, ##args) @@ -149,6 +149,18 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in #define EHS_WAKE_ON_MAC_EVENT 0x0004 #define EHS_WAKE_ON_MULTICAST_DATA 0x0008 #define EHS_REMOVE_WAKEUP 0xFFFFFFFF +/* Wake rules for Host_Sleep_CFG command */ +#define WOL_RULE_NET_TYPE_INFRA_OR_IBSS 0x00 +#define WOL_RULE_NET_TYPE_MESH 0x10 +#define WOL_RULE_ADDR_TYPE_BCAST 0x01 +#define WOL_RULE_ADDR_TYPE_MCAST 0x08 +#define WOL_RULE_ADDR_TYPE_UCAST 0x02 +#define WOL_RULE_OP_AND 0x01 +#define WOL_RULE_OP_OR 0x02 +#define WOL_RULE_OP_INVALID 0xFF +#define WOL_RESULT_VALID_CMD 0 +#define WOL_RESULT_NOSPC_ERR 1 +#define WOL_RESULT_EEXIST_ERR 2 /** Misc constants */ /* This section defines 802.11 specific contants */ diff --git a/drivers/net/wireless/libertas/dev.h b/drivers/net/wireless/libertas/dev.h index f6f3753da303d80f26bc95d0f51ca52f03106814..dd682c4cfde816929425b3f68417de552e62b0b6 100644 --- a/drivers/net/wireless/libertas/dev.h +++ b/drivers/net/wireless/libertas/dev.h @@ -10,7 +10,6 @@ #include #include #include -#include #include "defs.h" #include "hostcmd.h" @@ -278,6 +277,12 @@ struct lbs_private { struct enc_key wpa_mcast_key; struct enc_key wpa_unicast_key; +/* + * In theory, the IE is limited to the IE length, 255, + * but in practice 64 bytes are enough. + */ +#define MAX_WPA_IE_LEN 64 + /** WPA Information Elements*/ u8 wpa_ie[MAX_WPA_IE_LEN]; u8 wpa_ie_len; diff --git a/drivers/net/wireless/libertas/ethtool.c b/drivers/net/wireless/libertas/ethtool.c index 688d60de55cb580d89cb3e188377be4203e887ef..61d2f50470c8e82f76e031cc82011846689f4723 100644 --- a/drivers/net/wireless/libertas/ethtool.c +++ b/drivers/net/wireless/libertas/ethtool.c @@ -23,7 +23,7 @@ static const char * mesh_stat_strings[]= { static void lbs_ethtool_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); snprintf(info->fw_version, 32, "%u.%u.%u.p%u", priv->fwrelease >> 24 & 0xff, @@ -47,7 +47,7 @@ static int lbs_ethtool_get_eeprom_len(struct net_device *dev) static int lbs_ethtool_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 * bytes) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct cmd_ds_802_11_eeprom_access cmd; int ret; @@ -76,7 +76,7 @@ out: static void lbs_ethtool_get_stats(struct net_device *dev, struct ethtool_stats *stats, uint64_t *data) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct cmd_ds_mesh_access mesh_access; int ret; @@ -113,7 +113,7 @@ static void lbs_ethtool_get_stats(struct net_device *dev, static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); if (sset == ETH_SS_STATS && dev == priv->mesh_dev) return MESH_STATS_NUM; @@ -143,7 +143,7 @@ static void lbs_ethtool_get_strings(struct net_device *dev, static void lbs_ethtool_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); if (priv->wol_criteria == 0xffffffff) { /* Interface driver didn't configure wake */ @@ -166,7 +166,7 @@ static void lbs_ethtool_get_wol(struct net_device *dev, static int lbs_ethtool_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); uint32_t criteria = 0; if (priv->wol_criteria == 0xffffffff && wol->wolopts) @@ -180,7 +180,7 @@ static int lbs_ethtool_set_wol(struct net_device *dev, if (wol->wolopts & WAKE_BCAST) criteria |= EHS_WAKE_ON_BROADCAST_DATA; if (wol->wolopts & WAKE_PHY) criteria |= EHS_WAKE_ON_MAC_EVENT; - return lbs_host_sleep_cfg(priv, criteria); + return lbs_host_sleep_cfg(priv, criteria, (struct wol_config *)NULL); } struct ethtool_ops lbs_ethtool_ops = { diff --git a/drivers/net/wireless/libertas/host.h b/drivers/net/wireless/libertas/host.h index 5004d7679c020471748790d41f40f6ba2f61ab5d..277ff1975bde8e22ea1009268cf45f94920f39f5 100644 --- a/drivers/net/wireless/libertas/host.h +++ b/drivers/net/wireless/libertas/host.h @@ -220,6 +220,14 @@ enum cmd_fwt_access_opts { CMD_ACT_FWT_ACCESS_TIME, }; +/* Define action or option for CMD_802_11_HOST_SLEEP_CFG */ +enum cmd_wol_cfg_opts { + CMD_ACT_ACTION_NONE = 0, + CMD_ACT_SET_WOL_RULE, + CMD_ACT_GET_WOL_RULE, + CMD_ACT_RESET_WOL_RULE, +}; + /* Define action or option for CMD_MESH_ACCESS */ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_TTL = 1, @@ -237,6 +245,7 @@ enum cmd_mesh_access_opts { CMD_ACT_MESH_GET_ROUTE_EXP, CMD_ACT_MESH_SET_AUTOSTART_ENABLED, CMD_ACT_MESH_GET_AUTOSTART_ENABLED, + CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT = 17, }; /* Define actions and types for CMD_MESH_CONFIG */ diff --git a/drivers/net/wireless/libertas/hostcmd.h b/drivers/net/wireless/libertas/hostcmd.h index d9f9a12a739e1f045c5d05452f5de4a11b4d293f..e173b1b46c232754efdaca10211af22fff489fe0 100644 --- a/drivers/net/wireless/libertas/hostcmd.h +++ b/drivers/net/wireless/libertas/hostcmd.h @@ -580,13 +580,37 @@ struct MrvlIEtype_keyParamSet { u8 key[32]; }; +#define MAX_WOL_RULES 16 + +struct host_wol_rule { + uint8_t rule_no; + uint8_t rule_ops; + __le16 sig_offset; + __le16 sig_length; + __le16 reserve; + __be32 sig_mask; + __be32 signature; +}; + +struct wol_config { + uint8_t action; + uint8_t pattern; + uint8_t no_rules_in_cmd; + uint8_t result; + struct host_wol_rule rule[MAX_WOL_RULES]; +}; + + struct cmd_ds_host_sleep { struct cmd_header hdr; __le32 criteria; uint8_t gpio; - uint8_t gap; + uint16_t gap; + struct wol_config wol_conf; } __attribute__ ((packed)); + + struct cmd_ds_802_11_key_material { struct cmd_header hdr; diff --git a/drivers/net/wireless/libertas/if_sdio.c b/drivers/net/wireless/libertas/if_sdio.c index b54e2ea8346bf26ae5071ed39bbfe450830a980d..4519d7314f47c37677df87ca51fc4b53bfeac2fe 100644 --- a/drivers/net/wireless/libertas/if_sdio.c +++ b/drivers/net/wireless/libertas/if_sdio.c @@ -26,6 +26,7 @@ * if_sdio_card_to_host() to pad the data. */ +#include #include #include #include @@ -581,7 +582,7 @@ static int if_sdio_prog_real(struct if_sdio_card *card) chunk_size, (chunk_size + 31) / 32 * 32); */ ret = sdio_writesb(card->func, card->ioport, - chunk_buffer, (chunk_size + 31) / 32 * 32); + chunk_buffer, roundup(chunk_size, 32)); if (ret) goto release; diff --git a/drivers/net/wireless/libertas/if_usb.c b/drivers/net/wireless/libertas/if_usb.c index cafbccb7414322e5013a3be370a5f656b8f7a8f9..2fc637ad85c741b84b94ba1a7f230f30077a4b8a 100644 --- a/drivers/net/wireless/libertas/if_usb.c +++ b/drivers/net/wireless/libertas/if_usb.c @@ -59,7 +59,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp); static ssize_t if_usb_firmware_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct if_usb_card *cardp = priv->card; char fwname[FIRMWARE_NAME_MAX]; int ret; @@ -86,7 +86,7 @@ static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set); static ssize_t if_usb_boot2_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct if_usb_card *cardp = priv->card; char fwname[FIRMWARE_NAME_MAX]; int ret; @@ -178,7 +178,8 @@ static void if_usb_setup_firmware(struct lbs_private *priv) priv->wol_gpio = 2; /* Wake via GPIO2... */ priv->wol_gap = 20; /* ... after 20ms */ - lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA); + lbs_host_sleep_cfg(priv, EHS_WAKE_ON_UNICAST_DATA, + (struct wol_config *) NULL); wake_method.hdr.size = cpu_to_le16(sizeof(wake_method)); wake_method.action = cpu_to_le16(CMD_ACT_GET); diff --git a/drivers/net/wireless/libertas/main.c b/drivers/net/wireless/libertas/main.c index 73dc8c72402a93fbfa85d1477869d370454c4cd2..3dba836794443b9cc39879df2462c1123d5156d1 100644 --- a/drivers/net/wireless/libertas/main.c +++ b/drivers/net/wireless/libertas/main.c @@ -12,9 +12,8 @@ #include #include #include - +#include #include -#include #include "host.h" #include "decl.h" @@ -223,7 +222,7 @@ u8 lbs_data_rate_to_fw_index(u32 rate) static ssize_t lbs_anycast_get(struct device *dev, struct device_attribute *attr, char * buf) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_access mesh_access; int ret; @@ -242,7 +241,7 @@ static ssize_t lbs_anycast_get(struct device *dev, static ssize_t lbs_anycast_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_access mesh_access; uint32_t datum; int ret; @@ -258,6 +257,58 @@ static ssize_t lbs_anycast_set(struct device *dev, return strlen(buf); } +/** + * @brief Get function for sysfs attribute prb_rsp_limit + */ +static ssize_t lbs_prb_rsp_limit_get(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); + struct cmd_ds_mesh_access mesh_access; + int ret; + u32 retry_limit; + + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(CMD_ACT_GET); + + ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, + &mesh_access); + if (ret) + return ret; + + retry_limit = le32_to_cpu(mesh_access.data[1]); + return snprintf(buf, 10, "%d\n", retry_limit); +} + +/** + * @brief Set function for sysfs attribute prb_rsp_limit + */ +static ssize_t lbs_prb_rsp_limit_set(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); + struct cmd_ds_mesh_access mesh_access; + int ret; + unsigned long retry_limit; + + memset(&mesh_access, 0, sizeof(mesh_access)); + mesh_access.data[0] = cpu_to_le32(CMD_ACT_SET); + + if (!strict_strtoul(buf, 10, &retry_limit)) + return -ENOTSUPP; + if (retry_limit > 15) + return -ENOTSUPP; + + mesh_access.data[1] = cpu_to_le32(retry_limit); + + ret = lbs_mesh_access(priv, CMD_ACT_MESH_SET_GET_PRB_RSP_LIMIT, + &mesh_access); + if (ret) + return ret; + + return strlen(buf); +} + static int lbs_add_rtap(struct lbs_private *priv); static void lbs_remove_rtap(struct lbs_private *priv); static int lbs_add_mesh(struct lbs_private *priv); @@ -270,7 +321,7 @@ static void lbs_remove_mesh(struct lbs_private *priv); static ssize_t lbs_rtap_get(struct device *dev, struct device_attribute *attr, char * buf) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); return snprintf(buf, 5, "0x%X\n", priv->monitormode); } @@ -281,7 +332,7 @@ static ssize_t lbs_rtap_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { int monitor_mode; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); sscanf(buf, "%x", &monitor_mode); if (monitor_mode) { @@ -332,7 +383,7 @@ static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set ); static ssize_t lbs_mesh_get(struct device *dev, struct device_attribute *attr, char * buf) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev); } @@ -342,7 +393,7 @@ static ssize_t lbs_mesh_get(struct device *dev, static ssize_t lbs_mesh_set(struct device *dev, struct device_attribute *attr, const char * buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); int enable; int ret, action = CMD_ACT_MESH_CONFIG_STOP; @@ -376,8 +427,16 @@ static DEVICE_ATTR(lbs_mesh, 0644, lbs_mesh_get, lbs_mesh_set); */ static DEVICE_ATTR(anycast_mask, 0644, lbs_anycast_get, lbs_anycast_set); +/** + * prb_rsp_limit attribute to be exported per mshX interface + * through sysfs (/sys/class/net/mshX/prb_rsp_limit) + */ +static DEVICE_ATTR(prb_rsp_limit, 0644, lbs_prb_rsp_limit_get, + lbs_prb_rsp_limit_set); + static struct attribute *lbs_mesh_sysfs_entries[] = { &dev_attr_anycast_mask.attr, + &dev_attr_prb_rsp_limit.attr, NULL, }; @@ -393,7 +452,7 @@ static struct attribute_group lbs_mesh_attr_group = { */ static int lbs_dev_open(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv ; + struct lbs_private *priv = netdev_priv(dev) ; int ret = 0; lbs_deb_enter(LBS_DEB_NET); @@ -435,7 +494,7 @@ static int lbs_dev_open(struct net_device *dev) */ static int lbs_mesh_stop(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) (dev->priv); + struct lbs_private *priv = dev->ml_priv; lbs_deb_enter(LBS_DEB_MESH); spin_lock_irq(&priv->driver_lock); @@ -462,7 +521,7 @@ static int lbs_mesh_stop(struct net_device *dev) */ static int lbs_eth_stop(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_NET); @@ -479,7 +538,7 @@ static int lbs_eth_stop(struct net_device *dev) static void lbs_tx_timeout(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_TX); @@ -531,7 +590,7 @@ EXPORT_SYMBOL_GPL(lbs_host_to_card_done); */ static struct net_device_stats *lbs_get_stats(struct net_device *dev) { - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_NET); return &priv->stats; @@ -540,7 +599,7 @@ static struct net_device_stats *lbs_get_stats(struct net_device *dev) static int lbs_set_mac_address(struct net_device *dev, void *addr) { int ret = 0; - struct lbs_private *priv = (struct lbs_private *) dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct sockaddr *phwaddr = addr; struct cmd_ds_802_11_mac_address cmd; @@ -588,7 +647,6 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, { int i = nr_addrs; struct dev_mc_list *mc_list; - DECLARE_MAC_BUF(mac); if ((dev->flags & (IFF_UP|IFF_MULTICAST)) != (IFF_UP|IFF_MULTICAST)) return nr_addrs; @@ -596,16 +654,16 @@ static int lbs_add_mcast_addrs(struct cmd_ds_mac_multicast_adr *cmd, netif_addr_lock_bh(dev); for (mc_list = dev->mc_list; mc_list; mc_list = mc_list->next) { if (mac_in_list(cmd->maclist, nr_addrs, mc_list->dmi_addr)) { - lbs_deb_net("mcast address %s:%s skipped\n", dev->name, - print_mac(mac, mc_list->dmi_addr)); + lbs_deb_net("mcast address %s:%pM skipped\n", dev->name, + mc_list->dmi_addr); continue; } if (i == MRVDRV_MAX_MULTICAST_LIST_SIZE) break; memcpy(&cmd->maclist[6*i], mc_list->dmi_addr, ETH_ALEN); - lbs_deb_net("mcast address %s:%s added to filter\n", dev->name, - print_mac(mac, mc_list->dmi_addr)); + lbs_deb_net("mcast address %s:%pM added to filter\n", dev->name, + mc_list->dmi_addr); i++; } netif_addr_unlock_bh(dev); @@ -674,7 +732,7 @@ static void lbs_set_mcast_worker(struct work_struct *work) static void lbs_set_multicast_list(struct net_device *dev) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); schedule_work(&priv->mcast_work); } @@ -690,7 +748,7 @@ static void lbs_set_multicast_list(struct net_device *dev) static int lbs_thread(void *data) { struct net_device *dev = data; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); wait_queue_t wait; lbs_deb_enter(LBS_DEB_THREAD); @@ -1125,7 +1183,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) lbs_pr_err("init ethX device failed\n"); goto done; } - priv = dev->priv; + priv = netdev_priv(dev); if (lbs_init_adapter(priv)) { lbs_pr_err("failed to initialize adapter structure.\n"); @@ -1378,7 +1436,7 @@ static int lbs_add_mesh(struct lbs_private *priv) ret = -ENOMEM; goto done; } - mesh_dev->priv = priv; + mesh_dev->ml_priv = priv; priv->mesh_dev = mesh_dev; mesh_dev->open = lbs_dev_open; @@ -1591,7 +1649,7 @@ static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = dev->ml_priv; lbs_deb_enter(LBS_DEB_NET); return &priv->stats; } @@ -1632,7 +1690,7 @@ static int lbs_add_rtap(struct lbs_private *priv) rtap_dev->stop = lbs_rtap_stop; rtap_dev->get_stats = lbs_rtap_get_stats; rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit; - rtap_dev->priv = priv; + rtap_dev->ml_priv = priv; SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent); ret = register_netdev(rtap_dev); @@ -1647,33 +1705,6 @@ out: return ret; } -#ifndef CONFIG_IEEE80211 -const char *escape_essid(const char *essid, u8 essid_len) -{ - static char escaped[IW_ESSID_MAX_SIZE * 2 + 1]; - const char *s = essid; - char *d = escaped; - - if (ieee80211_is_empty_essid(essid, essid_len)) { - memcpy(escaped, "", sizeof("")); - return escaped; - } - - essid_len = min(essid_len, (u8) IW_ESSID_MAX_SIZE); - while (essid_len--) { - if (*s == '\0') { - *d++ = '\\'; - *d++ = '0'; - s++; - } else { - *d++ = *s++; - } - } - *d = '\0'; - return escaped; -} -#endif - module_init(lbs_init_module); module_exit(lbs_exit_module); diff --git a/drivers/net/wireless/libertas/persistcfg.c b/drivers/net/wireless/libertas/persistcfg.c index 3309a9c3cfef3f66c84f5f1cb67388dda176c5e6..d42b7a5a1b3f32a564579771e19149429348db5b 100644 --- a/drivers/net/wireless/libertas/persistcfg.c +++ b/drivers/net/wireless/libertas/persistcfg.c @@ -18,7 +18,7 @@ static int mesh_get_default_parameters(struct device *dev, struct mrvl_mesh_defaults *defs) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; int ret; @@ -57,7 +57,7 @@ static ssize_t bootflag_get(struct device *dev, static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; @@ -100,7 +100,7 @@ static ssize_t boottime_get(struct device *dev, static ssize_t boottime_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; @@ -152,7 +152,7 @@ static ssize_t channel_get(struct device *dev, static ssize_t channel_set(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); struct cmd_ds_mesh_config cmd; uint32_t datum; int ret; @@ -210,7 +210,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); int len; int ret; @@ -233,7 +233,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr, /* SSID len */ ie->val.mesh_id_len = len; /* IE len */ - ie->hdr.len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; + ie->len = sizeof(struct mrvl_meshie_val) - IW_ESSID_MAX_SIZE + len; ret = lbs_mesh_config_send(priv, &cmd, CMD_ACT_MESH_CONFIG_SET, CMD_TYPE_MESH_SET_MESH_IE); @@ -269,7 +269,7 @@ static ssize_t protocol_id_set(struct device *dev, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); uint32_t datum; int ret; @@ -323,7 +323,7 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); uint32_t datum; int ret; @@ -377,7 +377,7 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr, struct cmd_ds_mesh_config cmd; struct mrvl_mesh_defaults defs; struct mrvl_meshie *ie; - struct lbs_private *priv = to_net_dev(dev)->priv; + struct lbs_private *priv = netdev_priv(to_net_dev(dev)); uint32_t datum; int ret; diff --git a/drivers/net/wireless/libertas/radiotap.h b/drivers/net/wireless/libertas/radiotap.h index 5d118f40cfbc43206369ec77082e220822318f11..f8eb9097ff0a013b06aa61d76033c622488f6a1b 100644 --- a/drivers/net/wireless/libertas/radiotap.h +++ b/drivers/net/wireless/libertas/radiotap.h @@ -6,9 +6,6 @@ struct tx_radiotap_hdr { u8 txpower; u8 rts_retries; u8 data_retries; -#if 0 - u8 pad[IEEE80211_RADIOTAP_HDRLEN - 12]; -#endif } __attribute__ ((packed)); #define TX_RADIOTAP_PRESENT ( \ diff --git a/drivers/net/wireless/libertas/scan.c b/drivers/net/wireless/libertas/scan.c index 22c4c611052147ef3c2e1b3d01f1d64026ad9bec..57f6c12cda2085a902a8fae4e1e950c138f34475 100644 --- a/drivers/net/wireless/libertas/scan.c +++ b/drivers/net/wireless/libertas/scan.c @@ -4,8 +4,11 @@ * IOCTL handlers as well as command preperation and response routines * for sending scan commands to the firmware. */ +#include #include +#include #include +#include #include "host.h" #include "decl.h" @@ -52,6 +55,8 @@ //! Scan time specified in the channel TLV for each channel for active scans #define MRVDRV_ACTIVE_SCAN_CHAN_TIME 100 +#define DEFAULT_MAX_SCAN_AGE (15 * HZ) + static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, struct cmd_header *resp); @@ -359,7 +364,7 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) #ifdef CONFIG_LIBERTAS_DEBUG struct bss_descriptor *iter; int i = 0; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); #endif lbs_deb_enter_args(LBS_DEB_SCAN, "full_scan %d", full_scan); @@ -451,9 +456,9 @@ int lbs_scan_networks(struct lbs_private *priv, int full_scan) mutex_lock(&priv->lock); 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), iter->rssi, - escape_essid(iter->ssid, iter->ssid_len)); + lbs_deb_scan("%02d: BSSID %pM, RSSI %d, SSID '%s'\n", + i++, iter->bssid, iter->rssi, + print_ssid(ssid, iter->ssid, iter->ssid_len)); mutex_unlock(&priv->lock); #endif @@ -512,7 +517,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, struct ieeetypes_dsparamset *pDS; struct ieeetypes_cfparamset *pCF; struct ieeetypes_ibssparamset *pibss; - DECLARE_MAC_BUF(mac); + DECLARE_SSID_BUF(ssid); struct ieeetypes_countryinfoset *pcountryinfo; uint8_t *pos, *end, *p; uint8_t n_ex_rates = 0, got_basic_rates = 0, n_basic_rates = 0; @@ -544,7 +549,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, *bytesleft -= beaconsize; memcpy(bss->bssid, pos, ETH_ALEN); - lbs_deb_scan("process_bss: BSSID %s\n", print_mac(mac, bss->bssid)); + lbs_deb_scan("process_bss: BSSID %pM\n", bss->bssid); pos += ETH_ALEN; if ((end - pos) < 12) { @@ -588,38 +593,36 @@ static int lbs_process_bss(struct bss_descriptor *bss, /* process variable IE */ while (pos <= end - 2) { - struct ieee80211_info_element * elem = (void *)pos; - - if (pos + elem->len > end) { + if (pos + pos[1] > end) { lbs_deb_scan("process_bss: error in processing IE, " "bytes left < IE length\n"); break; } - switch (elem->id) { - case MFIE_TYPE_SSID: - bss->ssid_len = min_t(int, 32, elem->len); - memcpy(bss->ssid, elem->data, bss->ssid_len); + switch (pos[0]) { + case WLAN_EID_SSID: + bss->ssid_len = min_t(int, IEEE80211_MAX_SSID_LEN, pos[1]); + memcpy(bss->ssid, pos + 2, bss->ssid_len); lbs_deb_scan("got SSID IE: '%s', len %u\n", - escape_essid(bss->ssid, bss->ssid_len), + print_ssid(ssid, bss->ssid, bss->ssid_len), bss->ssid_len); break; - case MFIE_TYPE_RATES: - n_basic_rates = min_t(uint8_t, MAX_RATES, elem->len); - memcpy(bss->rates, elem->data, n_basic_rates); + case WLAN_EID_SUPP_RATES: + n_basic_rates = min_t(uint8_t, MAX_RATES, pos[1]); + memcpy(bss->rates, pos + 2, n_basic_rates); got_basic_rates = 1; lbs_deb_scan("got RATES IE\n"); break; - case MFIE_TYPE_FH_SET: + case WLAN_EID_FH_PARAMS: pFH = (struct ieeetypes_fhparamset *) pos; memmove(&bss->phyparamset.fhparamset, pFH, sizeof(struct ieeetypes_fhparamset)); lbs_deb_scan("got FH IE\n"); break; - case MFIE_TYPE_DS_SET: + case WLAN_EID_DS_PARAMS: pDS = (struct ieeetypes_dsparamset *) pos; bss->channel = pDS->currentchan; memcpy(&bss->phyparamset.dsparamset, pDS, @@ -627,14 +630,14 @@ static int lbs_process_bss(struct bss_descriptor *bss, lbs_deb_scan("got DS IE, channel %d\n", bss->channel); break; - case MFIE_TYPE_CF_SET: + case WLAN_EID_CF_PARAMS: pCF = (struct ieeetypes_cfparamset *) pos; memcpy(&bss->ssparamset.cfparamset, pCF, sizeof(struct ieeetypes_cfparamset)); lbs_deb_scan("got CF IE\n"); break; - case MFIE_TYPE_IBSS_SET: + case WLAN_EID_IBSS_PARAMS: pibss = (struct ieeetypes_ibssparamset *) pos; bss->atimwindow = le16_to_cpu(pibss->atimwindow); memmove(&bss->ssparamset.ibssparamset, pibss, @@ -642,7 +645,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, lbs_deb_scan("got IBSS IE\n"); break; - case MFIE_TYPE_COUNTRY: + case WLAN_EID_COUNTRY: pcountryinfo = (struct ieeetypes_countryinfoset *) pos; lbs_deb_scan("got COUNTRY IE\n"); if (pcountryinfo->len < sizeof(pcountryinfo->countrycode) @@ -659,7 +662,7 @@ static int lbs_process_bss(struct bss_descriptor *bss, (int) (pcountryinfo->len + 2)); break; - case MFIE_TYPE_RATES_EX: + case WLAN_EID_EXT_SUPP_RATES: /* only process extended supported rate if data rate is * already found. Data rate IE should come before * extended supported rate IE @@ -670,50 +673,51 @@ static int lbs_process_bss(struct bss_descriptor *bss, break; } - n_ex_rates = elem->len; + n_ex_rates = pos[1]; if (n_basic_rates + n_ex_rates > MAX_RATES) n_ex_rates = MAX_RATES - n_basic_rates; p = bss->rates + n_basic_rates; - memcpy(p, elem->data, n_ex_rates); + memcpy(p, pos + 2, n_ex_rates); break; - 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); - memcpy(bss->wpa_ie, elem, bss->wpa_ie_len); + case WLAN_EID_GENERIC: + if (pos[1] >= 4 && + pos[2] == 0x00 && pos[3] == 0x50 && + pos[4] == 0xf2 && pos[5] == 0x01) { + bss->wpa_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); + memcpy(bss->wpa_ie, pos, bss->wpa_ie_len); lbs_deb_scan("got WPA IE\n"); - 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) { + lbs_deb_hex(LBS_DEB_SCAN, "WPA IE", bss->wpa_ie, + bss->wpa_ie_len); + } else if (pos[1] >= MARVELL_MESH_IE_LENGTH && + pos[2] == 0x00 && pos[3] == 0x50 && + pos[4] == 0x43 && pos[4] == 0x04) { lbs_deb_scan("got mesh IE\n"); bss->mesh = 1; } else { 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); + pos[2], pos[3], + pos[4], pos[5], + pos[1]); } break; - case MFIE_TYPE_RSN: + case WLAN_EID_RSN: lbs_deb_scan("got RSN IE\n"); - bss->rsn_ie_len = min(elem->len + 2, MAX_WPA_IE_LEN); - memcpy(bss->rsn_ie, elem, bss->rsn_ie_len); + bss->rsn_ie_len = min(pos[1] + 2, MAX_WPA_IE_LEN); + memcpy(bss->rsn_ie, pos, bss->rsn_ie_len); lbs_deb_hex(LBS_DEB_SCAN, "process_bss: RSN_IE", - bss->rsn_ie, elem->len); + bss->rsn_ie, bss->rsn_ie_len); break; default: lbs_deb_scan("got IE 0x%04x, len %d\n", - elem->id, elem->len); + pos[0], pos[1]); break; } - pos += elem->len + 2; + pos += pos[1] + 2; } /* Timestamp */ @@ -741,10 +745,11 @@ done: int lbs_send_specific_ssid_scan(struct lbs_private *priv, uint8_t *ssid, uint8_t ssid_len) { + DECLARE_SSID_BUF(ssid_buf); int ret = 0; lbs_deb_enter_args(LBS_DEB_SCAN, "SSID '%s'\n", - escape_essid(ssid, ssid_len)); + print_ssid(ssid_buf, ssid, ssid_len)); if (!ssid_len) goto out; @@ -939,7 +944,8 @@ out: int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct lbs_private *priv = dev->priv; + DECLARE_SSID_BUF(ssid); + struct lbs_private *priv = netdev_priv(dev); int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); @@ -968,7 +974,7 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info, 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)); + print_ssid(ssid, priv->scan_ssid, priv->scan_ssid_len)); } else { priv->scan_ssid_len = 0; } @@ -1002,7 +1008,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { #define SCAN_ITEM_SIZE 128 - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int err = 0; char *ev = extra; char *stop = ev + dwrq->length; @@ -1151,7 +1157,6 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, struct bss_descriptor new; 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)); @@ -1190,7 +1195,7 @@ static int lbs_ret_80211_scan(struct lbs_private *priv, unsigned long dummy, continue; } - lbs_deb_scan("SCAN_RESP: BSSID %s\n", print_mac(mac, new.bssid)); + lbs_deb_scan("SCAN_RESP: BSSID %pM\n", new.bssid); /* Copy the locally created newbssentry to the scan table */ memcpy(found, &new, offsetof(struct bss_descriptor, list)); diff --git a/drivers/net/wireless/libertas/scan.h b/drivers/net/wireless/libertas/scan.h index 9e07b0464a8e1e432d82cb787f9e34ec95afe68f..fab7d5d097fc73f5241117e35b4adc32b30a6c1c 100644 --- a/drivers/net/wireless/libertas/scan.h +++ b/drivers/net/wireless/libertas/scan.h @@ -7,6 +7,10 @@ #ifndef _LBS_SCAN_H #define _LBS_SCAN_H +#include + +#define MAX_NETWORK_COUNT 128 + /** * @brief Maximum number of channels that can be sent in a setuserscan ioctl */ diff --git a/drivers/net/wireless/libertas/tx.c b/drivers/net/wireless/libertas/tx.c index a4972fed294171dfacf99135e4de9cf7bd206371..dac462641170e6193da4f04cfd44e39222520ba3 100644 --- a/drivers/net/wireless/libertas/tx.c +++ b/drivers/net/wireless/libertas/tx.c @@ -60,7 +60,7 @@ static u32 convert_radiotap_rate_to_mv(u8 rate) int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { unsigned long flags; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct txpd *txpd; char *p802x_hdr; uint16_t pkt_len; diff --git a/drivers/net/wireless/libertas/types.h b/drivers/net/wireless/libertas/types.h index e0c2599da92f182c2e3a31b616d04fd9c2ac4323..fb7a2d1a2525e5efae1d78c9dcf0edec7ab1a76c 100644 --- a/drivers/net/wireless/libertas/types.h +++ b/drivers/net/wireless/libertas/types.h @@ -7,7 +7,6 @@ #include #include #include -#include struct ieeetypes_cfparamset { u8 elementid; @@ -258,7 +257,7 @@ struct mrvlietypes_ledbhv { * Note that the len member of the ieee80211_info_element varies depending on * the mesh_id_len */ struct mrvl_meshie_val { - uint8_t oui[P80211_OUI_LEN]; + uint8_t oui[3]; uint8_t type; uint8_t subtype; uint8_t version; @@ -270,7 +269,7 @@ struct mrvl_meshie_val { } __attribute__ ((packed)); struct mrvl_meshie { - struct ieee80211_info_element hdr; + u8 id, len; struct mrvl_meshie_val val; } __attribute__ ((packed)); diff --git a/drivers/net/wireless/libertas/wext.c b/drivers/net/wireless/libertas/wext.c index 82c3e5a50ea695602fa844b7cc5ce93493f1b0d3..c6102e08179e6ba7d9fcc09d7fb8a26da721024b 100644 --- a/drivers/net/wireless/libertas/wext.c +++ b/drivers/net/wireless/libertas/wext.c @@ -8,7 +8,7 @@ #include #include -#include +#include #include #include "host.h" @@ -163,7 +163,7 @@ static int lbs_get_name(struct net_device *dev, struct iw_request_info *info, static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct chan_freq_power *cfp; lbs_deb_enter(LBS_DEB_WEXT); @@ -189,7 +189,7 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info, static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -207,7 +207,7 @@ static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info, static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -231,7 +231,7 @@ static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info, static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -248,7 +248,7 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info, static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -273,7 +273,7 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); u32 val = vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); @@ -293,7 +293,7 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info, static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 val = 0; @@ -315,7 +315,7 @@ out: static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u32 val = vwrq->value; @@ -336,7 +336,7 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info, static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 val = 0; @@ -359,7 +359,7 @@ out: static int lbs_get_mode(struct net_device *dev, struct iw_request_info *info, u32 * uwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -385,7 +385,7 @@ static int lbs_get_txpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); s16 curlevel = 0; int ret = 0; @@ -418,7 +418,7 @@ out: static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 slimit = 0, llimit = 0; @@ -466,7 +466,7 @@ out: static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u16 val = 0; @@ -542,7 +542,7 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { int i, j; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct iw_range *range = (struct iw_range *)extra; struct chan_freq_power *cfp; u8 rates[MAX_RATES + 1]; @@ -708,7 +708,7 @@ out: static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -758,7 +758,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info, static int lbs_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -781,7 +781,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev) EXCELLENT = 95, PERFECT = 100 }; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); u32 rssi_qual; u32 tx_qual; u32 quality = 0; @@ -886,7 +886,7 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { int ret = -EINVAL; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct chan_freq_power *cfp; struct assoc_request * assoc_req; @@ -943,7 +943,7 @@ static int lbs_mesh_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *fwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct chan_freq_power *cfp; int ret = -EINVAL; @@ -994,7 +994,7 @@ out: static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); u8 new_rate = 0; int ret = -EINVAL; u8 rates[MAX_RATES + 1]; @@ -1054,7 +1054,7 @@ out: static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1079,7 +1079,7 @@ static int lbs_set_mode(struct net_device *dev, struct iw_request_info *info, u32 * uwrq, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; lbs_deb_enter(LBS_DEB_WEXT); @@ -1124,7 +1124,7 @@ static int lbs_get_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, u8 * extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; lbs_deb_enter(LBS_DEB_WEXT); @@ -1319,7 +1319,7 @@ static int lbs_set_encode(struct net_device *dev, struct iw_point *dwrq, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; u16 is_default = 0, index = 0, set_tx_key = 0; @@ -1395,7 +1395,7 @@ static int lbs_get_encodeext(struct net_device *dev, char *extra) { int ret = -EINVAL; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int index, max_key_len; @@ -1501,7 +1501,7 @@ static int lbs_set_encodeext(struct net_device *dev, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; int alg = ext->alg; struct assoc_request * assoc_req; @@ -1639,7 +1639,7 @@ static int lbs_set_genie(struct net_device *dev, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; struct assoc_request * assoc_req; @@ -1685,7 +1685,7 @@ static int lbs_get_genie(struct net_device *dev, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1713,7 +1713,7 @@ static int lbs_set_auth(struct net_device *dev, struct iw_param *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; int ret = 0; int updated = 0; @@ -1816,7 +1816,7 @@ static int lbs_get_auth(struct net_device *dev, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1857,7 +1857,7 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { int ret = 0; - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); s16 dbm = (s16) vwrq->value; lbs_deb_enter(LBS_DEB_WEXT); @@ -1936,7 +1936,7 @@ out: static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -1971,12 +1971,13 @@ static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info, static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; u8 ssid[IW_ESSID_MAX_SIZE]; u8 ssid_len = 0; struct assoc_request * assoc_req; int in_ssid_len = dwrq->length; + DECLARE_SSID_BUF(ssid_buf); lbs_deb_enter(LBS_DEB_WEXT); @@ -2005,7 +2006,7 @@ static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info, lbs_deb_wext("requested any SSID\n"); } else { lbs_deb_wext("requested SSID '%s'\n", - escape_essid(ssid, ssid_len)); + print_ssid(ssid_buf, ssid, ssid_len)); } out: @@ -2039,7 +2040,7 @@ static int lbs_mesh_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); lbs_deb_enter(LBS_DEB_WEXT); @@ -2057,7 +2058,7 @@ static int lbs_mesh_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *dwrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); int ret = 0; lbs_deb_enter(LBS_DEB_WEXT); @@ -2101,10 +2102,9 @@ static int lbs_mesh_set_essid(struct net_device *dev, static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *awrq, char *extra) { - struct lbs_private *priv = dev->priv; + struct lbs_private *priv = netdev_priv(dev); struct assoc_request * assoc_req; int ret = 0; - DECLARE_MAC_BUF(mac); lbs_deb_enter(LBS_DEB_WEXT); @@ -2114,7 +2114,7 @@ static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info, if (awrq->sa_family != ARPHRD_ETHER) return -EINVAL; - lbs_deb_wext("ASSOC: WAP: sa_data %s\n", print_mac(mac, awrq->sa_data)); + lbs_deb_wext("ASSOC: WAP: sa_data %pM\n", awrq->sa_data); mutex_lock(&priv->lock); diff --git a/drivers/net/wireless/libertas_tf/cmd.c b/drivers/net/wireless/libertas_tf/cmd.c index fdbcf8ba3e8a0c6bc02036c05d7c9bd7d9c19dc2..3d3914c83b145388c6d2afc6c6c6fc124f8b2469 100644 --- a/drivers/net/wireless/libertas_tf/cmd.c +++ b/drivers/net/wireless/libertas_tf/cmd.c @@ -79,7 +79,6 @@ int lbtf_update_hw_spec(struct lbtf_private *priv) struct cmd_ds_get_hw_spec cmd; int ret = -1; u32 i; - DECLARE_MAC_BUF(mac); memset(&cmd, 0, sizeof(cmd)); cmd.hdr.size = cpu_to_le16(sizeof(cmd)); @@ -96,8 +95,8 @@ int lbtf_update_hw_spec(struct lbtf_private *priv) priv->fwrelease = (priv->fwrelease << 8) | (priv->fwrelease >> 24 & 0xff); - printk(KERN_INFO "libertastf: %s, fw %u.%u.%up%u, cap 0x%08x\n", - print_mac(mac, cmd.permanentaddr), + printk(KERN_INFO "libertastf: %pM, fw %u.%u.%up%u, cap 0x%08x\n", + cmd.permanentaddr, priv->fwrelease >> 24 & 0xff, priv->fwrelease >> 16 & 0xff, priv->fwrelease >> 8 & 0xff, diff --git a/drivers/net/wireless/libertas_tf/main.c b/drivers/net/wireless/libertas_tf/main.c index feff945ad856368e737eac8a344352b947ad73c5..d1fc305de5fe03c755368b70690d3f81d5fe54ba 100644 --- a/drivers/net/wireless/libertas_tf/main.c +++ b/drivers/net/wireless/libertas_tf/main.c @@ -354,9 +354,11 @@ static void lbtf_op_remove_interface(struct ieee80211_hw *hw, priv->vif = NULL; } -static int lbtf_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int lbtf_op_config(struct ieee80211_hw *hw, u32 changed) { struct lbtf_private *priv = hw->priv; + struct ieee80211_conf *conf = &hw->conf; + if (conf->channel->center_freq != priv->cur_freq) { priv->cur_freq = conf->channel->center_freq; lbtf_set_channel(priv, conf->channel->hw_value); @@ -590,14 +592,14 @@ EXPORT_SYMBOL_GPL(lbtf_remove_card); void lbtf_send_tx_feedback(struct lbtf_private *priv, u8 retrycnt, u8 fail) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb); - memset(&info->status, 0, sizeof(info->status)); + + ieee80211_tx_info_clear_status(info); /* * Commented out, otherwise we never go beyond 1Mbit/s using mac80211 * default pid rc algorithm. * * info->status.retry_count = MRVL_DEFAULT_RETRIES - retrycnt; */ - info->status.excessive_retries = fail ? 1 : 0; if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !fail) info->flags |= IEEE80211_TX_STAT_ACK; skb_pull(priv->tx_skb, sizeof(struct txpd)); diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c index 1a019e98dac3ee8ef0b7be504a6cee8af6a36369..f83d69e813d3a23cf46c8aefd94833147ab05d9f 100644 --- a/drivers/net/wireless/mac80211_hwsim.c +++ b/drivers/net/wireless/mac80211_hwsim.c @@ -21,6 +21,7 @@ #include #include #include +#include MODULE_AUTHOR("Jouni Malinen"); MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211"); @@ -32,6 +33,9 @@ MODULE_PARM_DESC(radios, "Number of simulated radios"); struct hwsim_vif_priv { u32 magic; + u8 bssid[ETH_ALEN]; + bool assoc; + u16 aid; }; #define HWSIM_VIF_MAGIC 0x69537748 @@ -63,13 +67,13 @@ struct hwsim_sta_priv { static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta) { struct hwsim_sta_priv *sp = (void *)sta->drv_priv; - WARN_ON(sp->magic != HWSIM_VIF_MAGIC); + WARN_ON(sp->magic != HWSIM_STA_MAGIC); } static inline void hwsim_set_sta_magic(struct ieee80211_sta *sta) { struct hwsim_sta_priv *sp = (void *)sta->drv_priv; - sp->magic = HWSIM_VIF_MAGIC; + sp->magic = HWSIM_STA_MAGIC; } static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta) @@ -132,6 +136,12 @@ struct mac80211_hwsim_data { unsigned int rx_filter; int started; struct timer_list beacon_timer; + enum ps_mode { + PS_DISABLED, PS_ENABLED, PS_AUTO_POLL, PS_MANUAL_POLL + } ps; + bool ps_poll_pending; + struct dentry *debugfs; + struct dentry *debugfs_ps; }; @@ -196,6 +206,34 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw, } +static bool hwsim_ps_rx_ok(struct mac80211_hwsim_data *data, + struct sk_buff *skb) +{ + switch (data->ps) { + case PS_DISABLED: + return true; + case PS_ENABLED: + return false; + case PS_AUTO_POLL: + /* TODO: accept (some) Beacons by default and other frames only + * if pending PS-Poll has been sent */ + return true; + case PS_MANUAL_POLL: + /* Allow unicast frames to own address if there is a pending + * PS-Poll */ + if (data->ps_poll_pending && + memcmp(data->hw->wiphy->perm_addr, skb->data + 4, + ETH_ALEN) == 0) { + data->ps_poll_pending = false; + return true; + } + return false; + } + + return true; +} + + static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, struct sk_buff *skb) { @@ -209,9 +247,12 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, /* TODO: set mactime */ rx_status.freq = data->channel->center_freq; rx_status.band = data->channel->band; - rx_status.rate_idx = info->tx_rate_idx; + rx_status.rate_idx = info->control.rates[0].idx; /* TODO: simulate signal strength (and optional packet drop) */ + if (data->ps != PS_DISABLED) + hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM); + /* Copy skb to all enabled radios that are on the current frequency */ spin_lock(&hwsim_radio_lock); list_for_each_entry(data2, &hwsim_radios, list) { @@ -221,6 +262,7 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw, continue; if (!data2->started || !data2->radio_enabled || + !hwsim_ps_rx_ok(data2, skb) || data->channel->center_freq != data2->channel->center_freq) continue; @@ -269,13 +311,9 @@ static int mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (txi->control.sta) hwsim_check_sta_magic(txi->control.sta); - memset(&txi->status, 0, sizeof(txi->status)); - if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (ack) - txi->flags |= IEEE80211_TX_STAT_ACK; - else - txi->status.excessive_retries = 1; - } + ieee80211_tx_info_clear_status(txi); + if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack) + txi->flags |= IEEE80211_TX_STAT_ACK; ieee80211_tx_status_irqsafe(hw, skb); return NETDEV_TX_OK; } @@ -294,6 +332,7 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) { struct mac80211_hwsim_data *data = hw->priv; data->started = 0; + del_timer(&data->beacon_timer); printk(KERN_DEBUG "%s:%s\n", wiphy_name(hw->wiphy), __func__); } @@ -301,10 +340,9 @@ static void mac80211_hwsim_stop(struct ieee80211_hw *hw) static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", + printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", wiphy_name(hw->wiphy), __func__, conf->type, - print_mac(mac, conf->mac_addr)); + conf->mac_addr); hwsim_set_magic(conf->vif); return 0; } @@ -313,10 +351,9 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw, static void mac80211_hwsim_remove_interface( struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%s)\n", + printk(KERN_DEBUG "%s:%s (type=%d mac_addr=%pM)\n", wiphy_name(hw->wiphy), __func__, conf->type, - print_mac(mac, conf->mac_addr)); + conf->mac_addr); hwsim_check_magic(conf->vif); hwsim_clear_magic(conf->vif); } @@ -331,7 +368,8 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac, hwsim_check_magic(vif); - if (vif->type != NL80211_IFTYPE_AP) + if (vif->type != NL80211_IFTYPE_AP && + vif->type != NL80211_IFTYPE_MESH_POINT) return; skb = ieee80211_beacon_get(hw, vif); @@ -361,10 +399,10 @@ static void mac80211_hwsim_beacon(unsigned long arg) } -static int mac80211_hwsim_config(struct ieee80211_hw *hw, - struct ieee80211_conf *conf) +static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed) { struct mac80211_hwsim_data *data = hw->priv; + struct ieee80211_conf *conf = &hw->conf; printk(KERN_DEBUG "%s:%s (freq=%d radio_enabled=%d beacon_int=%d)\n", wiphy_name(hw->wiphy), __func__, @@ -409,7 +447,16 @@ static int mac80211_hwsim_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf) { + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + hwsim_check_magic(vif); + if (conf->changed & IEEE80211_IFCC_BSSID) { + DECLARE_MAC_BUF(mac); + printk(KERN_DEBUG "%s:%s: BSSID changed: %pM\n", + wiphy_name(hw->wiphy), __func__, + conf->bssid); + memcpy(vp->bssid, conf->bssid, ETH_ALEN); + } return 0; } @@ -418,7 +465,46 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw, struct ieee80211_bss_conf *info, u32 changed) { + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + hwsim_check_magic(vif); + + printk(KERN_DEBUG "%s:%s(changed=0x%x)\n", + wiphy_name(hw->wiphy), __func__, changed); + + if (changed & BSS_CHANGED_ASSOC) { + printk(KERN_DEBUG " %s: ASSOC: assoc=%d aid=%d\n", + wiphy_name(hw->wiphy), info->assoc, info->aid); + vp->assoc = info->assoc; + vp->aid = info->aid; + } + + if (changed & BSS_CHANGED_ERP_CTS_PROT) { + printk(KERN_DEBUG " %s: ERP_CTS_PROT: %d\n", + wiphy_name(hw->wiphy), info->use_cts_prot); + } + + if (changed & BSS_CHANGED_ERP_PREAMBLE) { + printk(KERN_DEBUG " %s: ERP_PREAMBLE: %d\n", + wiphy_name(hw->wiphy), info->use_short_preamble); + } + + if (changed & BSS_CHANGED_ERP_SLOT) { + printk(KERN_DEBUG " %s: ERP_SLOT: %d\n", + wiphy_name(hw->wiphy), info->use_short_slot); + } + + if (changed & BSS_CHANGED_HT) { + printk(KERN_DEBUG " %s: HT: op_mode=0x%x\n", + wiphy_name(hw->wiphy), + info->ht.operation_mode); + } + + if (changed & BSS_CHANGED_BASIC_RATES) { + printk(KERN_DEBUG " %s: BASIC_RATES: 0x%llx\n", + wiphy_name(hw->wiphy), + (unsigned long long) info->basic_rates); + } } static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, @@ -434,6 +520,10 @@ static void mac80211_hwsim_sta_notify(struct ieee80211_hw *hw, case STA_NOTIFY_REMOVE: hwsim_clear_sta_magic(sta); break; + case STA_NOTIFY_SLEEP: + case STA_NOTIFY_AWAKE: + /* TODO: make good use of these flags */ + break; } } @@ -445,6 +535,17 @@ static int mac80211_hwsim_set_tim(struct ieee80211_hw *hw, return 0; } +static int mac80211_hwsim_conf_tx( + struct ieee80211_hw *hw, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + printk(KERN_DEBUG "%s:%s (queue=%d txop=%d cw_min=%d cw_max=%d " + "aifs=%d)\n", + wiphy_name(hw->wiphy), __func__, queue, + params->txop, params->cw_min, params->cw_max, params->aifs); + return 0; +} + static const struct ieee80211_ops mac80211_hwsim_ops = { .tx = mac80211_hwsim_tx, @@ -458,6 +559,7 @@ static const struct ieee80211_ops mac80211_hwsim_ops = .bss_info_changed = mac80211_hwsim_bss_info_changed, .sta_notify = mac80211_hwsim_sta_notify, .set_tim = mac80211_hwsim_set_tim, + .conf_tx = mac80211_hwsim_conf_tx, }; @@ -474,6 +576,8 @@ static void mac80211_hwsim_free(void) spin_unlock_bh(&hwsim_radio_lock); list_for_each_entry(data, &tmplist, list) { + debugfs_remove(data->debugfs_ps); + debugfs_remove(data->debugfs); ieee80211_unregister_hw(data->hw); device_unregister(data->dev); ieee80211_free_hw(data->hw); @@ -499,13 +603,131 @@ static void hwsim_mon_setup(struct net_device *dev) } +static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + DECLARE_MAC_BUF(buf); + struct sk_buff *skb; + struct ieee80211_pspoll *pspoll; + + if (!vp->assoc) + return; + + printk(KERN_DEBUG "%s:%s: send PS-Poll to %pM for aid %d\n", + wiphy_name(data->hw->wiphy), __func__, vp->bssid, vp->aid); + + skb = dev_alloc_skb(sizeof(*pspoll)); + if (!skb) + return; + pspoll = (void *) skb_put(skb, sizeof(*pspoll)); + pspoll->frame_control = cpu_to_le16(IEEE80211_FTYPE_CTL | + IEEE80211_STYPE_PSPOLL | + IEEE80211_FCTL_PM); + pspoll->aid = cpu_to_le16(0xc000 | vp->aid); + memcpy(pspoll->bssid, vp->bssid, ETH_ALEN); + memcpy(pspoll->ta, mac, ETH_ALEN); + if (data->radio_enabled && + !mac80211_hwsim_tx_frame(data->hw, skb)) + printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__); + dev_kfree_skb(skb); +} + + +static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac, + struct ieee80211_vif *vif, int ps) +{ + struct hwsim_vif_priv *vp = (void *)vif->drv_priv; + DECLARE_MAC_BUF(buf); + struct sk_buff *skb; + struct ieee80211_hdr *hdr; + + if (!vp->assoc) + return; + + printk(KERN_DEBUG "%s:%s: send data::nullfunc to %pM ps=%d\n", + wiphy_name(data->hw->wiphy), __func__, vp->bssid, ps); + + skb = dev_alloc_skb(sizeof(*hdr)); + if (!skb) + return; + hdr = (void *) skb_put(skb, sizeof(*hdr) - ETH_ALEN); + hdr->frame_control = cpu_to_le16(IEEE80211_FTYPE_DATA | + IEEE80211_STYPE_NULLFUNC | + (ps ? IEEE80211_FCTL_PM : 0)); + hdr->duration_id = cpu_to_le16(0); + memcpy(hdr->addr1, vp->bssid, ETH_ALEN); + memcpy(hdr->addr2, mac, ETH_ALEN); + memcpy(hdr->addr3, vp->bssid, ETH_ALEN); + if (data->radio_enabled && + !mac80211_hwsim_tx_frame(data->hw, skb)) + printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__); + dev_kfree_skb(skb); +} + + +static void hwsim_send_nullfunc_ps(void *dat, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + hwsim_send_nullfunc(data, mac, vif, 1); +} + + +static void hwsim_send_nullfunc_no_ps(void *dat, u8 *mac, + struct ieee80211_vif *vif) +{ + struct mac80211_hwsim_data *data = dat; + hwsim_send_nullfunc(data, mac, vif, 0); +} + + +static int hwsim_fops_ps_read(void *dat, u64 *val) +{ + struct mac80211_hwsim_data *data = dat; + *val = data->ps; + return 0; +} + +static int hwsim_fops_ps_write(void *dat, u64 val) +{ + struct mac80211_hwsim_data *data = dat; + enum ps_mode old_ps; + + if (val != PS_DISABLED && val != PS_ENABLED && val != PS_AUTO_POLL && + val != PS_MANUAL_POLL) + return -EINVAL; + + old_ps = data->ps; + data->ps = val; + + if (val == PS_MANUAL_POLL) { + ieee80211_iterate_active_interfaces(data->hw, + hwsim_send_ps_poll, data); + data->ps_poll_pending = true; + } else if (old_ps == PS_DISABLED && val != PS_DISABLED) { + ieee80211_iterate_active_interfaces(data->hw, + hwsim_send_nullfunc_ps, + data); + } else if (old_ps != PS_DISABLED && val == PS_DISABLED) { + ieee80211_iterate_active_interfaces(data->hw, + hwsim_send_nullfunc_no_ps, + data); + } + + return 0; +} + +DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_ps, hwsim_fops_ps_read, hwsim_fops_ps_write, + "%llu\n"); + + static int __init init_mac80211_hwsim(void) { int i, err = 0; u8 addr[ETH_ALEN]; struct mac80211_hwsim_data *data; struct ieee80211_hw *hw; - DECLARE_MAC_BUF(mac); if (radios < 1 || radios > 100) return -EINVAL; @@ -553,7 +775,8 @@ static int __init init_mac80211_hwsim(void) hw->queues = 4; hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_AP); + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT); hw->ampdu_queues = 1; /* ask mac80211 to reserve space for magic */ @@ -566,19 +789,18 @@ static int __init init_mac80211_hwsim(void) data->band.n_channels = ARRAY_SIZE(hwsim_channels); data->band.bitrates = data->rates; data->band.n_bitrates = ARRAY_SIZE(hwsim_rates); - data->band.ht_info.ht_supported = 1; - data->band.ht_info.cap = IEEE80211_HT_CAP_SUP_WIDTH | + data->band.ht_cap.ht_supported = true; + data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 | IEEE80211_HT_CAP_GRN_FLD | IEEE80211_HT_CAP_SGI_40 | IEEE80211_HT_CAP_DSSSCCK40; - data->band.ht_info.ampdu_factor = 0x3; - data->band.ht_info.ampdu_density = 0x6; - memset(data->band.ht_info.supp_mcs_set, 0, - sizeof(data->band.ht_info.supp_mcs_set)); - data->band.ht_info.supp_mcs_set[0] = 0xff; - data->band.ht_info.supp_mcs_set[1] = 0xff; - data->band.ht_info.supp_mcs_set[12] = - IEEE80211_HT_CAP_MCS_TX_DEFINED; + data->band.ht_cap.ampdu_factor = 0x3; + data->band.ht_cap.ampdu_density = 0x6; + memset(&data->band.ht_cap.mcs, 0, + sizeof(data->band.ht_cap.mcs)); + data->band.ht_cap.mcs.rx_mask[0] = 0xff; + data->band.ht_cap.mcs.rx_mask[1] = 0xff; + data->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED; hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band; err = ieee80211_register_hw(hw); @@ -588,9 +810,15 @@ static int __init init_mac80211_hwsim(void) goto failed_hw; } - printk(KERN_DEBUG "%s: hwaddr %s registered\n", + printk(KERN_DEBUG "%s: hwaddr %pM registered\n", wiphy_name(hw->wiphy), - print_mac(mac, hw->wiphy->perm_addr)); + hw->wiphy->perm_addr); + + data->debugfs = debugfs_create_dir("hwsim", + hw->wiphy->debugfsdir); + data->debugfs_ps = debugfs_create_file("ps", 0666, + data->debugfs, data, + &hwsim_fops_ps); setup_timer(&data->beacon_timer, mac80211_hwsim_beacon, (unsigned long) hw); diff --git a/drivers/net/wireless/netwave_cs.c b/drivers/net/wireless/netwave_cs.c index a670f36b5f3f3c1e3222d0e45c27491132caed7d..24caec6caf1fc0f98cdbffb1141ee6c57dd123aa 100644 --- a/drivers/net/wireless/netwave_cs.c +++ b/drivers/net/wireless/netwave_cs.c @@ -737,7 +737,6 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { win_req_t req; memreq_t mem; u_char __iomem *ramBase = NULL; - DECLARE_MAC_BUF(mac); DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link); @@ -808,12 +807,12 @@ static int netwave_pcmcia_config(struct pcmcia_device *link) { dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i); printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx, " - "id %c%c, hw_addr %s\n", + "id %c%c, hw_addr %pM\n", dev->name, dev->base_addr, dev->irq, (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI), (int) readb(ramBase+NETWAVE_EREG_NI+1), - print_mac(mac, dev->dev_addr)); + dev->dev_addr); /* get revision words */ printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", @@ -1308,7 +1307,6 @@ static int netwave_rx(struct net_device *dev) /* Queue packet for network layer */ netif_rx(skb); - dev->last_rx = jiffies; priv->stats.rx_packets++; priv->stats.rx_bytes += rcvLen; diff --git a/drivers/net/wireless/orinoco/Makefile b/drivers/net/wireless/orinoco/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..791366e08c501dac79c1becf88e056d8afa5c7df --- /dev/null +++ b/drivers/net/wireless/orinoco/Makefile @@ -0,0 +1,12 @@ +# +# Makefile for the orinoco wireless device drivers. +# + +obj-$(CONFIG_HERMES) += orinoco.o hermes.o hermes_dld.o +obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o +obj-$(CONFIG_APPLE_AIRPORT) += airport.o +obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o +obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o +obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o +obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o +obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o diff --git a/drivers/net/wireless/airport.c b/drivers/net/wireless/orinoco/airport.c similarity index 99% rename from drivers/net/wireless/airport.c rename to drivers/net/wireless/orinoco/airport.c index ce03a2e865fabafbc6b04b0eee3022a4a6b1a20d..28f1cae48439ec787b13fdd424c2e4f065455fd1 100644 --- a/drivers/net/wireless/airport.c +++ b/drivers/net/wireless/orinoco/airport.c @@ -279,7 +279,7 @@ init_airport(void) static void __exit exit_airport(void) { - return macio_unregister_driver(&airport_driver); + macio_unregister_driver(&airport_driver); } module_init(init_airport); diff --git a/drivers/net/wireless/hermes.c b/drivers/net/wireless/orinoco/hermes.c similarity index 100% rename from drivers/net/wireless/hermes.c rename to drivers/net/wireless/orinoco/hermes.c diff --git a/drivers/net/wireless/hermes.h b/drivers/net/wireless/orinoco/hermes.h similarity index 100% rename from drivers/net/wireless/hermes.h rename to drivers/net/wireless/orinoco/hermes.h diff --git a/drivers/net/wireless/hermes_dld.c b/drivers/net/wireless/orinoco/hermes_dld.c similarity index 100% rename from drivers/net/wireless/hermes_dld.c rename to drivers/net/wireless/orinoco/hermes_dld.c diff --git a/drivers/net/wireless/hermes_dld.h b/drivers/net/wireless/orinoco/hermes_dld.h similarity index 100% rename from drivers/net/wireless/hermes_dld.h rename to drivers/net/wireless/orinoco/hermes_dld.h diff --git a/drivers/net/wireless/hermes_rid.h b/drivers/net/wireless/orinoco/hermes_rid.h similarity index 100% rename from drivers/net/wireless/hermes_rid.h rename to drivers/net/wireless/orinoco/hermes_rid.h diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco/orinoco.c similarity index 96% rename from drivers/net/wireless/orinoco.c rename to drivers/net/wireless/orinoco/orinoco.c index e0512e49d6d374052af6401c020d30ad22ca122b..bc84e2792f8a887838f42c02bbe5ed4f68c500af 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco/orinoco.c @@ -84,10 +84,11 @@ #include #include #include +#include #include #include +#include #include -#include #include #include @@ -143,7 +144,7 @@ static const u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00}; #define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2) #define ORINOCO_MIN_MTU 256 -#define ORINOCO_MAX_MTU (IEEE80211_DATA_LEN - ENCAPS_OVERHEAD) +#define ORINOCO_MAX_MTU (IEEE80211_MAX_DATA_LEN - ENCAPS_OVERHEAD) #define SYMBOL_MAX_VER_LEN (14) #define USER_BAP 0 @@ -392,7 +393,7 @@ static void orinoco_bss_data_init(struct orinoco_private *priv) } static inline u8 *orinoco_get_ie(u8 *data, size_t len, - enum ieee80211_mfie eid) + enum ieee80211_eid eid) { u8 *p = data; while ((p + 2) < (data + len)) { @@ -409,7 +410,7 @@ static inline u8 *orinoco_get_wpa_ie(u8 *data, size_t len) { u8 *p = data; while ((p + 2 + WPA_SELECTOR_LEN) < (data + len)) { - if ((p[0] == MFIE_TYPE_GENERIC) && + if ((p[0] == WLAN_EID_GENERIC) && (memcmp(&p[2], WPA_OUI_TYPE, WPA_SELECTOR_LEN) == 0)) return p; p += p[1] + 2; @@ -431,9 +432,9 @@ struct fw_info { }; const static struct fw_info orinoco_fw[] = { - { "", "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, - { "", "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, - { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", "", 0x00003100, 512 } + { NULL, "agere_sta_fw.bin", "agere_ap_fw.bin", 0x00390000, 1000 }, + { NULL, "prism_sta_fw.bin", "prism_ap_fw.bin", 0, 1024 }, + { "symbol_sp24t_prim_fw", "symbol_sp24t_sec_fw", NULL, 0x00003100, 512 } }; /* Structure used to access fields in FW @@ -487,13 +488,17 @@ orinoco_dl_firmware(struct orinoco_private *priv, if (err) goto free; - err = request_firmware(&fw_entry, firmware, priv->dev); - if (err) { - printk(KERN_ERR "%s: Cannot find firmware %s\n", - dev->name, firmware); - err = -ENOENT; - goto free; - } + if (!priv->cached_fw) { + err = request_firmware(&fw_entry, firmware, priv->dev); + + if (err) { + printk(KERN_ERR "%s: Cannot find firmware %s\n", + dev->name, firmware); + err = -ENOENT; + goto free; + } + } else + fw_entry = priv->cached_fw; hdr = (const struct orinoco_fw_header *) fw_entry->data; @@ -535,7 +540,9 @@ orinoco_dl_firmware(struct orinoco_private *priv, dev->name, hermes_present(hw)); abort: - release_firmware(fw_entry); + /* If we requested the firmware, release it. */ + if (!priv->cached_fw) + release_firmware(fw_entry); free: kfree(pda); @@ -639,34 +646,41 @@ symbol_dl_firmware(struct orinoco_private *priv, int ret; const struct firmware *fw_entry; - if (request_firmware(&fw_entry, fw->pri_fw, - priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->pri_fw); - return -ENOENT; - } + if (!priv->cached_pri_fw) { + if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->pri_fw); + return -ENOENT; + } + } else + fw_entry = priv->cached_pri_fw; /* Load primary firmware */ ret = symbol_dl_image(priv, fw, fw_entry->data, fw_entry->data + fw_entry->size, 0); - release_firmware(fw_entry); + + if (!priv->cached_pri_fw) + release_firmware(fw_entry); if (ret) { printk(KERN_ERR "%s: Primary firmware download failed\n", dev->name); return ret; } - if (request_firmware(&fw_entry, fw->sta_fw, - priv->dev) != 0) { - printk(KERN_ERR "%s: Cannot find firmware: %s\n", - dev->name, fw->sta_fw); - return -ENOENT; - } + if (!priv->cached_fw) { + if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) { + printk(KERN_ERR "%s: Cannot find firmware: %s\n", + dev->name, fw->sta_fw); + return -ENOENT; + } + } else + fw_entry = priv->cached_fw; /* Load secondary firmware */ ret = symbol_dl_image(priv, fw, fw_entry->data, fw_entry->data + fw_entry->size, 1); - release_firmware(fw_entry); + if (!priv->cached_fw) + release_firmware(fw_entry); if (ret) { printk(KERN_ERR "%s: Secondary firmware download failed\n", dev->name); @@ -699,6 +713,45 @@ static int orinoco_download(struct orinoco_private *priv) return err; } +#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP) +static void orinoco_cache_fw(struct orinoco_private *priv, int ap) +{ + const struct firmware *fw_entry = NULL; + const char *pri_fw; + const char *fw; + + pri_fw = orinoco_fw[priv->firmware_type].pri_fw; + if (ap) + fw = orinoco_fw[priv->firmware_type].ap_fw; + else + fw = orinoco_fw[priv->firmware_type].sta_fw; + + if (pri_fw) { + if (request_firmware(&fw_entry, pri_fw, priv->dev) == 0) + priv->cached_pri_fw = fw_entry; + } + + if (fw) { + if (request_firmware(&fw_entry, fw, priv->dev) == 0) + priv->cached_fw = fw_entry; + } +} + +static void orinoco_uncache_fw(struct orinoco_private *priv) +{ + if (priv->cached_pri_fw) + release_firmware(priv->cached_pri_fw); + if (priv->cached_fw) + release_firmware(priv->cached_fw); + + priv->cached_pri_fw = NULL; + priv->cached_fw = NULL; +} +#else +#define orinoco_cache_fw(priv, ap) +#define orinoco_uncache_fw(priv) +#endif + /********************************************************************/ /* Device methods */ /********************************************************************/ @@ -800,7 +853,7 @@ static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) wstats->qual.qual = (int)le16_to_cpu(cq.qual); wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; - wstats->qual.updated = 7; + wstats->qual.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; } } @@ -830,7 +883,8 @@ static int orinoco_change_mtu(struct net_device *dev, int new_mtu) if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) return -EINVAL; - if ( (new_mtu + ENCAPS_OVERHEAD + IEEE80211_HLEN) > + /* MTU + encapsulation + header length */ + if ( (new_mtu + ENCAPS_OVERHEAD + sizeof(struct ieee80211_hdr)) > (priv->nicbuf_size - ETH_HLEN) ) return -EINVAL; @@ -1158,7 +1212,7 @@ static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, wstats.level = level - 0x95; wstats.noise = noise - 0x95; wstats.qual = (level > noise) ? (level - noise) : 0; - wstats.updated = 7; + wstats.updated = IW_QUAL_ALL_UPDATED | IW_QUAL_DBM; /* Update spy records */ wireless_spy_update(dev, mac, &wstats); } @@ -1245,7 +1299,7 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, } /* sanity check the length */ - if (datalen > IEEE80211_DATA_LEN + 12) { + if (datalen > IEEE80211_MAX_DATA_LEN + 12) { printk(KERN_DEBUG "%s: oversized monitor frame, " "data length = %d\n", dev->name, datalen); stats->rx_length_errors++; @@ -1280,7 +1334,6 @@ static void orinoco_rx_monitor(struct net_device *dev, u16 rxfid, skb->pkt_type = PACKET_OTHERHOST; skb->protocol = __constant_htons(ETH_P_802_2); - dev->last_rx = jiffies; stats->rx_packets++; stats->rx_bytes += skb->len; @@ -1374,7 +1427,7 @@ static void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) data. */ goto out; } - if (length > IEEE80211_DATA_LEN) { + if (length > IEEE80211_MAX_DATA_LEN) { printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", dev->name, length); stats->rx_length_errors++; @@ -1477,12 +1530,11 @@ static void orinoco_rx(struct net_device *dev, MICHAEL_MIC_LEN)) { union iwreq_data wrqu; struct iw_michaelmicfailure wxmic; - DECLARE_MAC_BUF(mac); printk(KERN_WARNING "%s: " - "Invalid Michael MIC in data frame from %s, " + "Invalid Michael MIC in data frame from %pM, " "using key %i\n", - dev->name, print_mac(mac, src), key_id); + dev->name, src, key_id); /* TODO: update stats */ @@ -1530,7 +1582,6 @@ static void orinoco_rx(struct net_device *dev, else memcpy(hdr->h_source, desc->addr2, ETH_ALEN); - dev->last_rx = jiffies; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_NONE; if (fc & IEEE80211_FCTL_TODS) @@ -1699,7 +1750,7 @@ static void orinoco_send_bssid_wevent(struct orinoco_private *priv) union iwreq_data wrqu; int err; - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, ETH_ALEN, NULL, wrqu.ap_addr.sa_data); if (err != 0) return; @@ -1722,7 +1773,7 @@ static void orinoco_send_assocreqie_wevent(struct orinoco_private *priv) if (!priv->has_wpa) return; - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_REQ_INFO, sizeof(buf), NULL, &buf); if (err != 0) return; @@ -1752,7 +1803,7 @@ static void orinoco_send_assocrespie_wevent(struct orinoco_private *priv) if (!priv->has_wpa) return; - err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO, + err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENT_ASSOC_RESP_INFO, sizeof(buf), NULL, &buf); if (err != 0) return; @@ -2301,6 +2352,11 @@ int orinoco_reinit_firmware(struct net_device *dev) int err; err = hermes_init(hw); + if (priv->do_fw_download && !err) { + err = orinoco_download(priv); + if (err) + priv->do_fw_download = 0; + } if (!err) err = orinoco_allocate_fid(dev); @@ -2926,12 +2982,6 @@ static void orinoco_reset(struct work_struct *work) } } - if (priv->do_fw_download) { - err = orinoco_download(priv); - if (err) - priv->do_fw_download = 0; - } - err = orinoco_reinit_firmware(dev); if (err) { printk(KERN_ERR "%s: orinoco_reset: Error %d re-initializing firmware\n", @@ -3055,6 +3105,50 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id) return IRQ_HANDLED; } +/********************************************************************/ +/* Power management */ +/********************************************************************/ +#if defined(CONFIG_PM_SLEEP) && !defined(CONFIG_HERMES_CACHE_FW_ON_INIT) +static int orinoco_pm_notifier(struct notifier_block *notifier, + unsigned long pm_event, + void *unused) +{ + struct orinoco_private *priv = container_of(notifier, + struct orinoco_private, + pm_notifier); + + /* All we need to do is cache the firmware before suspend, and + * release it when we come out. + * + * Only need to do this if we're downloading firmware. */ + if (!priv->do_fw_download) + return NOTIFY_DONE; + + switch (pm_event) { + case PM_HIBERNATION_PREPARE: + case PM_SUSPEND_PREPARE: + orinoco_cache_fw(priv, 0); + break; + + case PM_POST_RESTORE: + /* Restore from hibernation failed. We need to clean + * up in exactly the same way, so fall through. */ + case PM_POST_HIBERNATION: + case PM_POST_SUSPEND: + orinoco_uncache_fw(priv); + break; + + case PM_RESTORE_PREPARE: + default: + break; + } + + return NOTIFY_DONE; +} +#else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */ +#define orinoco_pm_notifier NULL +#endif + /********************************************************************/ /* Initialization */ /********************************************************************/ @@ -3277,11 +3371,10 @@ static int orinoco_init(struct net_device *dev) struct hermes_idstring nickbuf; u16 reclen; int len; - DECLARE_MAC_BUF(mac); /* No need to lock, the hw_unavailable flag is already set in * alloc_orinocodev() */ - priv->nicbuf_size = IEEE80211_FRAME_LEN + ETH_HLEN; + priv->nicbuf_size = IEEE80211_MAX_FRAME_LEN + ETH_HLEN; /* Initialize the firmware */ err = hermes_init(hw); @@ -3299,6 +3392,10 @@ static int orinoco_init(struct net_device *dev) } if (priv->do_fw_download) { +#ifdef CONFIG_HERMES_CACHE_FW_ON_INIT + orinoco_cache_fw(priv, 0); +#endif + err = orinoco_download(priv); if (err) priv->do_fw_download = 0; @@ -3348,8 +3445,8 @@ static int orinoco_init(struct net_device *dev) goto out; } - printk(KERN_DEBUG "%s: MAC address %s\n", - dev->name, print_mac(mac, dev->dev_addr)); + printk(KERN_DEBUG "%s: MAC address %pM\n", + dev->name, dev->dev_addr); /* Get the station name */ err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, @@ -3535,6 +3632,13 @@ struct net_device netif_carrier_off(dev); priv->last_linkstatus = 0xffff; + priv->cached_pri_fw = NULL; + priv->cached_fw = NULL; + + /* Register PM notifiers */ + priv->pm_notifier.notifier_call = orinoco_pm_notifier; + register_pm_notifier(&priv->pm_notifier); + return dev; } @@ -3546,6 +3650,10 @@ void free_orinocodev(struct net_device *dev) * when we call tasklet_kill it will run one final time, * emptying the list */ tasklet_kill(&priv->rx_tasklet); + + unregister_pm_notifier(&priv->pm_notifier); + orinoco_uncache_fw(priv); + priv->wpa_ie_len = 0; kfree(priv->wpa_ie); orinoco_mic_free(priv); @@ -4672,7 +4780,7 @@ static int orinoco_ioctl_set_encodeext(struct net_device *dev, /* Determine and validate the key index */ idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if ((idx < 1) || (idx > WEP_KEYS)) + if ((idx < 1) || (idx > 4)) goto out; idx--; } else @@ -4777,7 +4885,7 @@ static int orinoco_ioctl_get_encodeext(struct net_device *dev, idx = encoding->flags & IW_ENCODE_INDEX; if (idx) { - if ((idx < 1) || (idx > WEP_KEYS)) + if ((idx < 1) || (idx > 4)) goto out; idx--; } else @@ -4940,7 +5048,8 @@ static int orinoco_ioctl_set_genie(struct net_device *dev, unsigned long flags; int err = 0; - if ((wrqu->data.length > MAX_WPA_IE_LEN) || + /* cut off at IEEE80211_MAX_DATA_LEN */ + if ((wrqu->data.length > IEEE80211_MAX_DATA_LEN) || (wrqu->data.length && (extra == NULL))) return -EINVAL; @@ -5433,7 +5542,7 @@ static inline char *orinoco_translate_scan(struct net_device *dev, char *current_ev, char *end_buf, union hermes_scan_info *bss, - unsigned int last_scanned) + unsigned long last_scanned) { struct orinoco_private *priv = netdev_priv(dev); u16 capabilities; @@ -5580,7 +5689,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, char *current_ev, char *end_buf, struct agere_ext_scan_info *bss, - unsigned int last_scanned) + unsigned long last_scanned) { u16 capabilities; u16 channel; @@ -5623,7 +5732,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, &iwe, IW_EV_UINT_LEN); } - ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_DS_SET); + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_DS_PARAMS); channel = ie ? ie[2] : 0; if ((channel >= 1) && (channel <= NUM_CHANNELS)) { /* Add channel and frequency */ @@ -5673,7 +5782,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, } /* RSN IE */ - ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RSN); + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_RSN); if (ie) { iwe.cmd = IWEVGENIE; iwe.u.data.length = ie[1] + 2; @@ -5681,7 +5790,7 @@ static inline char *orinoco_translate_ext_scan(struct net_device *dev, &iwe, ie); } - ie = orinoco_get_ie(bss->data, sizeof(bss->data), MFIE_TYPE_RATES); + ie = orinoco_get_ie(bss->data, sizeof(bss->data), WLAN_EID_SUPP_RATES); if (ie) { char *p = current_ev + iwe_stream_lcp_len(info); int i; @@ -5976,7 +6085,7 @@ static void orinoco_get_drvinfo(struct net_device *dev, strncpy(info->version, DRIVER_VERSION, sizeof(info->version) - 1); strncpy(info->fw_version, priv->fw_name, sizeof(info->fw_version) - 1); if (dev->dev.parent) - strncpy(info->bus_info, dev->dev.parent->bus_id, + strncpy(info->bus_info, dev_name(dev->dev.parent), sizeof(info->bus_info) - 1); else snprintf(info->bus_info, sizeof(info->bus_info) - 1, diff --git a/drivers/net/wireless/orinoco.h b/drivers/net/wireless/orinoco/orinoco.h similarity index 96% rename from drivers/net/wireless/orinoco.h rename to drivers/net/wireless/orinoco/orinoco.h index 981570bd3b9d660b6c403840a09a1b98d4eb67c7..00750c8ba7db4019a5ea36a6c46632cbd1aad1db 100644 --- a/drivers/net/wireless/orinoco.h +++ b/drivers/net/wireless/orinoco/orinoco.h @@ -10,6 +10,7 @@ #define DRIVER_VERSION "0.15" #include +#include #include #include #include @@ -66,6 +67,8 @@ struct orinoco_rx_data { struct list_head list; }; +struct firmware; + struct orinoco_private { void *card; /* Pointer to card dependent structure */ struct device *dev; @@ -164,6 +167,12 @@ struct orinoco_private { unsigned int wpa_enabled:1; unsigned int tkip_cm_active:1; unsigned int key_mgmt:3; + + /* Cached in memory firmware to use during ->resume. */ + const struct firmware *cached_pri_fw; + const struct firmware *cached_fw; + + struct notifier_block pm_notifier; }; #ifdef ORINOCO_DEBUG diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco/orinoco_cs.c similarity index 98% rename from drivers/net/wireless/orinoco_cs.c rename to drivers/net/wireless/orinoco/orinoco_cs.c index 6fcf2bda7cdfbe5e0e356ab5adfee8982a2f6b27..f127602670ece436e88b80345cde5917ee729082 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco/orinoco_cs.c @@ -178,13 +178,17 @@ static int orinoco_cs_config_check(struct pcmcia_device *p_dev, /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } @@ -308,7 +312,7 @@ orinoco_cs_config(struct pcmcia_device *link) /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, + "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent), link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); return 0; diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco/orinoco_nortel.c similarity index 100% rename from drivers/net/wireless/orinoco_nortel.c rename to drivers/net/wireless/orinoco/orinoco_nortel.c diff --git a/drivers/net/wireless/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c similarity index 100% rename from drivers/net/wireless/orinoco_pci.c rename to drivers/net/wireless/orinoco/orinoco_pci.c diff --git a/drivers/net/wireless/orinoco_pci.h b/drivers/net/wireless/orinoco/orinoco_pci.h similarity index 100% rename from drivers/net/wireless/orinoco_pci.h rename to drivers/net/wireless/orinoco/orinoco_pci.h diff --git a/drivers/net/wireless/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c similarity index 100% rename from drivers/net/wireless/orinoco_plx.c rename to drivers/net/wireless/orinoco/orinoco_plx.c diff --git a/drivers/net/wireless/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c similarity index 100% rename from drivers/net/wireless/orinoco_tmd.c rename to drivers/net/wireless/orinoco/orinoco_tmd.c diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/orinoco/spectrum_cs.c similarity index 95% rename from drivers/net/wireless/spectrum_cs.c rename to drivers/net/wireless/orinoco/spectrum_cs.c index 852789ad34b3e33e0094bbc2bce4496096e00209..b2ca2e39c2cbd41943ca878895f7e55001cd4b13 100644 --- a/drivers/net/wireless/spectrum_cs.c +++ b/drivers/net/wireless/orinoco/spectrum_cs.c @@ -248,13 +248,17 @@ static int spectrum_cs_config_check(struct pcmcia_device *p_dev, /* Note that the CIS values need to be rescaled */ if (cfg->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != cfg->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + cfg->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } } else if (dflt->vcc.present & (1 << CISTPL_POWER_VNOM)) { if (vcc != dflt->vcc.param[CISTPL_POWER_VNOM] / 10000) { - DEBUG(2, "spectrum_cs_config: Vcc mismatch (vcc = %d, CIS = %d)\n", vcc, dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); + DEBUG(2, "%s: Vcc mismatch (vcc = %d, CIS = %d)\n", + __func__, vcc, + dflt->vcc.param[CISTPL_POWER_VNOM] / 10000); if (!ignore_cis_vcc) goto next_entry; } @@ -383,7 +387,7 @@ spectrum_cs_config(struct pcmcia_device *link) /* Finally, report what we've done */ printk(KERN_DEBUG "%s: " DRIVER_NAME " at %s, irq %d, io " - "0x%04x-0x%04x\n", dev->name, dev->dev.parent->bus_id, + "0x%04x-0x%04x\n", dev->name, dev_name(dev->dev.parent), link->irq.AssignedIRQ, link->io.BasePort1, link->io.BasePort1 + link->io.NumPorts1 - 1); @@ -450,10 +454,29 @@ spectrum_cs_resume(struct pcmcia_device *link) { struct net_device *dev = link->priv; struct orinoco_private *priv = netdev_priv(dev); + unsigned long flags; + int err; + + err = orinoco_reinit_firmware(dev); + if (err) { + printk(KERN_ERR "%s: Error %d re-initializing firmware\n", + dev->name, err); + return -EIO; + } + + spin_lock_irqsave(&priv->lock, flags); netif_device_attach(dev); priv->hw_unavailable--; - schedule_work(&priv->reset_work); + + if (priv->open && !priv->hw_unavailable) { + err = __orinoco_up(dev); + if (err) + printk(KERN_ERR "%s: Error %d restarting card\n", + dev->name, err); + } + + spin_unlock_irqrestore(&priv->lock, flags); return 0; } diff --git a/drivers/net/wireless/p54/p54.h b/drivers/net/wireless/p54/p54.h index 1d0704fe146fb72ed0691271a7bd8491096481b2..ab79e32f0b27c495c3c20eb43310882ff1aaa8b9 100644 --- a/drivers/net/wireless/p54/p54.h +++ b/drivers/net/wireless/p54/p54.h @@ -14,17 +14,17 @@ * published by the Free Software Foundation. */ -enum control_frame_types { - P54_CONTROL_TYPE_FILTER_SET = 0, - P54_CONTROL_TYPE_CHANNEL_CHANGE, - P54_CONTROL_TYPE_FREQDONE, +enum p54_control_frame_types { + P54_CONTROL_TYPE_SETUP = 0, + P54_CONTROL_TYPE_SCAN, + P54_CONTROL_TYPE_TRAP, P54_CONTROL_TYPE_DCFINIT, - P54_CONTROL_TYPE_ENCRYPTION, + P54_CONTROL_TYPE_RX_KEYCACHE, P54_CONTROL_TYPE_TIM, - P54_CONTROL_TYPE_POWERMGT, - P54_CONTROL_TYPE_FREEQUEUE, + P54_CONTROL_TYPE_PSM, + P54_CONTROL_TYPE_TXCANCEL, P54_CONTROL_TYPE_TXDONE, - P54_CONTROL_TYPE_PING, + P54_CONTROL_TYPE_BURST, P54_CONTROL_TYPE_STAT_READBACK, P54_CONTROL_TYPE_BBP, P54_CONTROL_TYPE_EEPROM_READBACK, @@ -37,18 +37,44 @@ enum control_frame_types { P54_CONTROL_TYPE_XBOW_SYNTH_CFG, P54_CONTROL_TYPE_CCE_QUIET, P54_CONTROL_TYPE_PSM_STA_UNLOCK, + P54_CONTROL_TYPE_PCS, + P54_CONTROL_TYPE_BT_BALANCER = 28, + P54_CONTROL_TYPE_GROUP_ADDRESS_TABLE = 30, + P54_CONTROL_TYPE_ARPTABLE = 31, + P54_CONTROL_TYPE_BT_OPTIONS = 35 }; -struct p54_control_hdr { - __le16 magic1; +#define P54_HDR_FLAG_CONTROL BIT(15) +#define P54_HDR_FLAG_CONTROL_OPSET (BIT(15) + BIT(0)) + +struct p54_hdr { + __le16 flags; __le16 len; __le32 req_id; - __le16 type; /* enum control_frame_types */ - u8 retry1; - u8 retry2; + __le16 type; /* enum p54_control_frame_types */ + u8 rts_tries; + u8 tries; u8 data[0]; } __attribute__ ((packed)); +#define FREE_AFTER_TX(skb) \ + ((((struct p54_hdr *) ((struct sk_buff *) skb)->data)-> \ + flags) == cpu_to_le16(P54_HDR_FLAG_CONTROL_OPSET)) + +struct p54_edcf_queue_param { + __le16 aifs; + __le16 cwmin; + __le16 cwmax; + __le16 txop; +} __attribute__ ((packed)); + +struct p54_rssi_linear_approximation { + s16 mul; + s16 add; + s16 longbow_unkn; + s16 longbow_unk2; +}; + #define EEPROM_READBACK_LEN 0x3fc #define ISL38XX_DEV_FIRMWARE_ADDR 0x20000 @@ -59,49 +85,53 @@ struct p54_control_hdr { #define FW_LM20 0x4c4d3230 struct p54_common { + struct ieee80211_hw *hw; u32 rx_start; u32 rx_end; struct sk_buff_head tx_queue; - void (*tx)(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx); + void (*tx)(struct ieee80211_hw *dev, struct sk_buff *skb); int (*open)(struct ieee80211_hw *dev); void (*stop)(struct ieee80211_hw *dev); int mode; - u16 seqno; u16 rx_mtu; u8 headroom; u8 tailroom; struct mutex conf_mutex; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; - __le16 filter_type; struct pda_iq_autocal_entry *iq_autocal; unsigned int iq_autocal_len; struct pda_channel_output_limit *output_limit; unsigned int output_limit_len; struct pda_pa_curve_data *curve_data; + struct p54_rssi_linear_approximation rssical_db[IEEE80211_NUM_BANDS]; unsigned int filter_flags; + bool use_short_slot; u16 rxhw; u8 version; - u8 rx_antenna; unsigned int tx_hdr_len; - void *cached_vdcf; unsigned int fw_var; unsigned int fw_interface; unsigned int output_power; u32 tsf_low32; u32 tsf_high32; + u64 basic_rate_mask; + u16 wakeup_timer; + u16 aid; struct ieee80211_tx_queue_stats tx_stats[8]; + struct p54_edcf_queue_param qos_params[8]; struct ieee80211_low_level_stats stats; - struct timer_list stats_timer; - struct completion stats_comp; - void *cached_stats; + struct delayed_work work; + struct sk_buff *cached_beacon; int noise; void *eeprom; struct completion eeprom_comp; + u8 privacy_caps; + u8 rx_keycache_size; }; int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); +void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb); int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw); int p54_read_eeprom(struct ieee80211_hw *dev); struct ieee80211_hw *p54_init_common(size_t priv_data_len); diff --git a/drivers/net/wireless/p54/p54common.c b/drivers/net/wireless/p54/p54common.c index 827ca0384a4ca220151a048528964ffcbf172ee3..82354b974a04773e752307f45f393bed8a89763c 100644 --- a/drivers/net/wireless/p54/p54common.c +++ b/drivers/net/wireless/p54/p54common.c @@ -1,12 +1,15 @@ - /* * Common code for mac80211 Prism54 drivers * * Copyright (c) 2006, Michael Wu * Copyright (c) 2007, Christian Lamparter + * Copyright 2008, Johannes Berg * - * Based on the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * - stlc45xx driver + * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies). * * 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 @@ -22,6 +25,9 @@ #include "p54.h" #include "p54common.h" +static int modparam_nohwcrypt; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Softmac Prism54 common code"); MODULE_LICENSE("GPL"); @@ -152,21 +158,21 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->fw_interface = be32_to_cpup((__be32 *) bootrec->data); switch (priv->fw_interface) { - case FW_FMAC: - printk(KERN_INFO "p54: FreeMAC firmware\n"); - break; - case FW_LM20: - printk(KERN_INFO "p54: LM20 firmware\n"); - break; case FW_LM86: - printk(KERN_INFO "p54: LM86 firmware\n"); - break; - case FW_LM87: - printk(KERN_INFO "p54: LM87 firmware\n"); + case FW_LM20: + case FW_LM87: { + char *iftype = (char *)bootrec->data; + printk(KERN_INFO "%s: p54 detected a LM%c%c " + "firmware\n", + wiphy_name(dev->wiphy), + iftype[2], iftype[3]); break; + } + case FW_FMAC: default: - printk(KERN_INFO "p54: unknown firmware\n"); - break; + printk(KERN_ERR "%s: unsupported firmware\n", + wiphy_name(dev->wiphy)); + return -ENODEV; } break; case BR_CODE_COMPONENT_VERSION: @@ -182,8 +188,10 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) priv->rx_end = le32_to_cpu(desc->rx_end) - 0x3500; priv->headroom = desc->headroom; priv->tailroom = desc->tailroom; + priv->privacy_caps = desc->privacy_caps; + priv->rx_keycache_size = desc->rx_keycache_size; if (le32_to_cpu(bootrec->len) == 11) - priv->rx_mtu = le16_to_cpu(bootrec->rx_mtu); + priv->rx_mtu = le16_to_cpu(desc->rx_mtu); else priv->rx_mtu = (size_t) 0x620 - priv->tx_hdr_len; @@ -208,18 +216,35 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw) } if (fw_version) - printk(KERN_INFO "p54: FW rev %s - Softmac protocol %x.%x\n", - fw_version, priv->fw_var >> 8, priv->fw_var & 0xff); + printk(KERN_INFO "%s: FW rev %s - Softmac protocol %x.%x\n", + wiphy_name(dev->wiphy), fw_version, + priv->fw_var >> 8, priv->fw_var & 0xff); + + if (priv->fw_var < 0x500) + printk(KERN_INFO "%s: you are using an obsolete firmware. " + "visit http://wireless.kernel.org/en/users/Drivers/p54 " + "and grab one for \"kernel >= 2.6.28\"!\n", + wiphy_name(dev->wiphy)); if (priv->fw_var >= 0x300) { /* Firmware supports QoS, use it! */ - priv->tx_stats[4].limit = 3; - priv->tx_stats[5].limit = 4; - priv->tx_stats[6].limit = 3; - priv->tx_stats[7].limit = 1; + priv->tx_stats[4].limit = 3; /* AC_VO */ + priv->tx_stats[5].limit = 4; /* AC_VI */ + priv->tx_stats[6].limit = 3; /* AC_BE */ + priv->tx_stats[7].limit = 2; /* AC_BK */ dev->queues = 4; } + if (!modparam_nohwcrypt) + printk(KERN_INFO "%s: cryptographic accelerator " + "WEP:%s, TKIP:%s, CCMP:%s\n", + wiphy_name(dev->wiphy), + (priv->privacy_caps & BR_DESC_PRIV_CAP_WEP) ? "YES" : + "no", (priv->privacy_caps & (BR_DESC_PRIV_CAP_TKIP | + BR_DESC_PRIV_CAP_MICHAEL)) ? "YES" : "no", + (priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP) ? + "YES" : "no"); + return 0; } EXPORT_SYMBOL_GPL(p54_parse_firmware); @@ -310,6 +335,36 @@ static const char *p54_rf_chips[] = { "NULL", "Duette3", "Duette2", "Frisbee", "Xbow", "Longbow", "NULL", "NULL" }; static int p54_init_xbow_synth(struct ieee80211_hw *dev); +static void p54_parse_rssical(struct ieee80211_hw *dev, void *data, int len, + u16 type) +{ + struct p54_common *priv = dev->priv; + int offset = (type == PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED) ? 2 : 0; + int entry_size = sizeof(struct pda_rssi_cal_entry) + offset; + int num_entries = (type == PDR_RSSI_LINEAR_APPROXIMATION) ? 1 : 2; + int i; + + if (len != (entry_size * num_entries)) { + printk(KERN_ERR "%s: unknown rssi calibration data packing " + " type:(%x) len:%d.\n", + wiphy_name(dev->wiphy), type, len); + + print_hex_dump_bytes("rssical:", DUMP_PREFIX_NONE, + data, len); + + printk(KERN_ERR "%s: please report this issue.\n", + wiphy_name(dev->wiphy)); + return; + } + + for (i = 0; i < num_entries; i++) { + struct pda_rssi_cal_entry *cal = data + + (offset + i * entry_size); + priv->rssical_db[i].mul = (s16) le16_to_cpu(cal->mul); + priv->rssical_db[i].add = (s16) le16_to_cpu(cal->add); + } +} + static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) { struct p54_common *priv = dev->priv; @@ -320,7 +375,6 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) int err; u8 *end = (u8 *)eeprom + len; u16 synth = 0; - DECLARE_MAC_BUF(mac); wrap = (struct eeprom_pda_wrap *) eeprom; entry = (void *)wrap->data + le16_to_cpu(wrap->len); @@ -377,8 +431,9 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) err = p54_convert_rev1(dev, curve_data); break; default: - printk(KERN_ERR "p54: unknown curve data " + printk(KERN_ERR "%s: unknown curve data " "revision %d\n", + wiphy_name(dev->wiphy), curve_data->cal_method_rev); err = -ENODEV; break; @@ -409,12 +464,40 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) case PDR_HARDWARE_PLATFORM_COMPONENT_ID: priv->version = *(u8 *)(entry->data + 1); break; + case PDR_RSSI_LINEAR_APPROXIMATION: + case PDR_RSSI_LINEAR_APPROXIMATION_DUAL_BAND: + case PDR_RSSI_LINEAR_APPROXIMATION_EXTENDED: + p54_parse_rssical(dev, entry->data, data_len, + le16_to_cpu(entry->code)); + break; case PDR_END: /* make it overrun */ entry_len = len; break; + case PDR_MANUFACTURING_PART_NUMBER: + case PDR_PDA_VERSION: + case PDR_NIC_SERIAL_NUMBER: + case PDR_REGULATORY_DOMAIN_LIST: + case PDR_TEMPERATURE_TYPE: + case PDR_PRISM_PCI_IDENTIFIER: + case PDR_COUNTRY_INFORMATION: + case PDR_OEM_NAME: + case PDR_PRODUCT_NAME: + case PDR_UTF8_OEM_NAME: + case PDR_UTF8_PRODUCT_NAME: + case PDR_COUNTRY_LIST: + case PDR_DEFAULT_COUNTRY: + case PDR_ANTENNA_GAIN: + case PDR_PRISM_INDIGO_PA_CALIBRATION_DATA: + case PDR_REGULATORY_POWER_LIMITS: + case PDR_RADIATED_TRANSMISSION_CORRECTION: + case PDR_PRISM_TX_IQ_CALIBRATION: + case PDR_BASEBAND_REGISTERS: + case PDR_PER_CHANNEL_BASEBAND_REGISTERS: + break; default: - printk(KERN_INFO "p54: unknown eeprom code : 0x%x\n", + printk(KERN_INFO "%s: unknown eeprom code : 0x%x\n", + wiphy_name(dev->wiphy), le16_to_cpu(entry->code)); break; } @@ -424,17 +507,18 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) if (!synth || !priv->iq_autocal || !priv->output_limit || !priv->curve_data) { - printk(KERN_ERR "p54: not all required entries found in eeprom!\n"); + printk(KERN_ERR "%s: not all required entries found in eeprom!\n", + wiphy_name(dev->wiphy)); err = -EINVAL; goto err; } - priv->rxhw = synth & 0x07; + priv->rxhw = synth & PDR_SYNTH_FRONTEND_MASK; if (priv->rxhw == 4) p54_init_xbow_synth(dev); - if (!(synth & 0x40)) + if (!(synth & PDR_SYNTH_24_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &band_2GHz; - if (!(synth & 0x80)) + if (!(synth & PDR_SYNTH_5_GHZ_DISABLED)) dev->wiphy->bands[IEEE80211_BAND_5GHZ] = &band_5GHz; if (!is_valid_ether_addr(dev->wiphy->perm_addr)) { @@ -446,9 +530,9 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) SET_IEEE80211_PERM_ADDR(dev, perm_addr); } - printk(KERN_INFO "%s: hwaddr %s, MAC:isl38%02x RF:%s\n", + printk(KERN_INFO "%s: hwaddr %pM, MAC:isl38%02x RF:%s\n", wiphy_name(dev->wiphy), - print_mac(mac, dev->wiphy->perm_addr), + dev->wiphy->perm_addr, priv->version, p54_rf_chips[priv->rxhw]); return 0; @@ -469,36 +553,56 @@ static int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len) priv->curve_data = NULL; } - printk(KERN_ERR "p54: eeprom parse failed!\n"); + printk(KERN_ERR "%s: eeprom parse failed!\n", + wiphy_name(dev->wiphy)); return err; } static int p54_rssi_to_dbm(struct ieee80211_hw *dev, int rssi) { - /* TODO: get the rssi_add & rssi_mul data from the eeprom */ - return ((rssi * 0x83) / 64 - 400) / 4; + struct p54_common *priv = dev->priv; + int band = dev->conf.channel->band; + + return ((rssi * priv->rssical_db[band].mul) / 64 + + priv->rssical_db[band].add) / 4; } static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_rx_hdr *hdr = (struct p54_rx_hdr *) skb->data; + struct p54_rx_data *hdr = (struct p54_rx_data *) skb->data; struct ieee80211_rx_status rx_status = {0}; u16 freq = le16_to_cpu(hdr->freq); size_t header_len = sizeof(*hdr); u32 tsf32; - if (!(hdr->magic & cpu_to_le16(0x0001))) { + /* + * If the device is in a unspecified state we have to + * ignore all data frames. Else we could end up with a + * nasty crash. + */ + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return 0; + + if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) { if (priv->filter_flags & FIF_FCSFAIL) rx_status.flag |= RX_FLAG_FAILED_FCS_CRC; else return 0; } + if (hdr->decrypt_status == P54_DECRYPT_OK) + rx_status.flag |= RX_FLAG_DECRYPTED; + if ((hdr->decrypt_status == P54_DECRYPT_FAIL_MICHAEL) || + (hdr->decrypt_status == P54_DECRYPT_FAIL_TKIP)) + rx_status.flag |= RX_FLAG_MMIC_ERROR; + rx_status.signal = p54_rssi_to_dbm(dev, hdr->rssi); rx_status.noise = priv->noise; /* XX correct? */ rx_status.qual = (100 * hdr->rssi) / 127; + if (hdr->rate & 0x10) + rx_status.flag |= RX_FLAG_SHORTPRE; rx_status.rate_idx = (dev->conf.channel->band == IEEE80211_BAND_2GHZ ? hdr->rate : (hdr->rate - 4)) & 0xf; rx_status.freq = freq; @@ -513,7 +617,7 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) rx_status.flag |= RX_FLAG_TSFT; - if (hdr->magic & cpu_to_le16(0x4000)) + if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) header_len += hdr->align[0]; skb_pull(skb, header_len); @@ -521,6 +625,9 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb) ieee80211_rx_irqsafe(dev, skb, &rx_status); + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_STATISTICS_UPDATE)); + return -1; } @@ -529,88 +636,197 @@ static void inline p54_wake_free_queues(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; int i; + if (priv->mode == NL80211_IFTYPE_UNSPECIFIED) + return ; + for (i = 0; i < dev->queues; i++) if (priv->tx_stats[i + 4].len < priv->tx_stats[i + 4].limit) ieee80211_wake_queue(dev, i); } +void p54_free_skb(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_common *priv = dev->priv; + struct ieee80211_tx_info *info; + struct memrecord *range; + unsigned long flags; + u32 freed = 0, last_addr = priv->rx_start; + + if (unlikely(!skb || !dev || !skb_queue_len(&priv->tx_queue))) + return; + + /* + * don't try to free an already unlinked skb + */ + if (unlikely((!skb->next) || (!skb->prev))) + return; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + info = IEEE80211_SKB_CB(skb); + range = (void *)info->rate_driver_data; + if (skb->prev != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(skb->prev); + mr = (struct memrecord *)ni->rate_driver_data; + last_addr = mr->end_addr; + } + if (skb->next != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(skb->next); + mr = (struct memrecord *)ni->rate_driver_data; + freed = mr->start_addr - last_addr; + } else + freed = priv->rx_end - last_addr; + __skb_unlink(skb, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + dev_kfree_skb_any(skb); + + if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) + p54_wake_free_queues(dev); +} +EXPORT_SYMBOL_GPL(p54_free_skb); + +static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev, + __le32 req_id) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *entry = priv->tx_queue.next; + unsigned long flags; + + spin_lock_irqsave(&priv->tx_queue.lock, flags); + while (entry != (struct sk_buff *)&priv->tx_queue) { + struct p54_hdr *hdr = (struct p54_hdr *) entry->data; + + if (hdr->req_id == req_id) { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return entry; + } + entry = entry->next; + } + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return NULL; +} + static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; - struct p54_frame_sent_hdr *payload = (struct p54_frame_sent_hdr *) hdr->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data; struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next; u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom; struct memrecord *range = NULL; u32 freed = 0; u32 last_addr = priv->rx_start; unsigned long flags; + int count, idx; spin_lock_irqsave(&priv->tx_queue.lock, flags); while (entry != (struct sk_buff *)&priv->tx_queue) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - range = (void *)info->driver_data; - if (range->start_addr == addr) { - struct p54_control_hdr *entry_hdr; - struct p54_tx_control_allocdata *entry_data; - int pad = 0; - - if (entry->next != (struct sk_buff *)&priv->tx_queue) { - struct ieee80211_tx_info *ni; - struct memrecord *mr; - - ni = IEEE80211_SKB_CB(entry->next); - mr = (struct memrecord *)ni->driver_data; - freed = mr->start_addr - last_addr; - } else - freed = priv->rx_end - last_addr; + struct p54_hdr *entry_hdr; + struct p54_tx_data *entry_data; + int pad = 0; + range = (void *)info->rate_driver_data; + if (range->start_addr != addr) { last_addr = range->end_addr; - __skb_unlink(entry, &priv->tx_queue); - spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + entry = entry->next; + continue; + } - memset(&info->status, 0, sizeof(info->status)); - entry_hdr = (struct p54_control_hdr *) entry->data; - entry_data = (struct p54_tx_control_allocdata *) entry_hdr->data; - if ((entry_hdr->magic1 & cpu_to_le16(0x4000)) != 0) - pad = entry_data->align[0]; - - priv->tx_stats[entry_data->hw_queue].len--; - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (!(payload->status & 0x01)) - info->flags |= IEEE80211_TX_STAT_ACK; - else - info->status.excessive_retries = 1; - } - info->status.retry_count = payload->retries - 1; - info->status.ack_signal = p54_rssi_to_dbm(dev, - le16_to_cpu(payload->ack_rssi)); - skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); - ieee80211_tx_status_irqsafe(dev, entry); - goto out; + if (entry->next != (struct sk_buff *)&priv->tx_queue) { + struct ieee80211_tx_info *ni; + struct memrecord *mr; + + ni = IEEE80211_SKB_CB(entry->next); + mr = (struct memrecord *)ni->rate_driver_data; + freed = mr->start_addr - last_addr; } else - last_addr = range->end_addr; - entry = entry->next; + freed = priv->rx_end - last_addr; + + last_addr = range->end_addr; + __skb_unlink(entry, &priv->tx_queue); + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + + entry_hdr = (struct p54_hdr *) entry->data; + entry_data = (struct p54_tx_data *) entry_hdr->data; + priv->tx_stats[entry_data->hw_queue].len--; + priv->stats.dot11ACKFailureCount += payload->tries - 1; + + if (unlikely(entry == priv->cached_beacon)) { + kfree_skb(entry); + priv->cached_beacon = NULL; + goto out; + } + + /* + * Clear manually, ieee80211_tx_info_clear_status would + * clear the counts too and we need them. + */ + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, + status.ampdu_ack_len) != 23); + + if (entry_hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN)) + pad = entry_data->align[0]; + + /* walk through the rates array and adjust the counts */ + count = payload->tries; + for (idx = 0; idx < 4; idx++) { + if (count >= info->status.rates[idx].count) { + count -= info->status.rates[idx].count; + } else if (count > 0) { + info->status.rates[idx].count = count; + count = 0; + } else { + info->status.rates[idx].idx = -1; + info->status.rates[idx].count = 0; + } + } + + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (!payload->status)) + info->flags |= IEEE80211_TX_STAT_ACK; + if (payload->status & P54_TX_PSM_CANCELLED) + info->flags |= IEEE80211_TX_STAT_TX_FILTERED; + info->status.ack_signal = p54_rssi_to_dbm(dev, + (int)payload->ack_rssi); + skb_pull(entry, sizeof(*hdr) + pad + sizeof(*entry_data)); + ieee80211_tx_status_irqsafe(dev, entry); + goto out; } spin_unlock_irqrestore(&priv->tx_queue.lock, flags); out: - if (freed >= IEEE80211_MAX_RTS_THRESHOLD + 0x170 + - sizeof(struct p54_control_hdr)) + if (freed >= priv->headroom + sizeof(struct p54_hdr) + 48 + + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) p54_wake_free_queues(dev); } static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, struct sk_buff *skb) { - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_eeprom_lm86 *eeprom = (struct p54_eeprom_lm86 *) hdr->data; struct p54_common *priv = dev->priv; if (!priv->eeprom) return ; - memcpy(priv->eeprom, eeprom->data, le16_to_cpu(eeprom->len)); + if (priv->fw_var >= 0x509) { + memcpy(priv->eeprom, eeprom->v2.data, + le16_to_cpu(eeprom->v2.len)); + } else { + memcpy(priv->eeprom, eeprom->v1.data, + le16_to_cpu(eeprom->v1.len)); + } complete(&priv->eeprom_comp); } @@ -618,10 +834,14 @@ static void p54_rx_eeprom_readback(struct ieee80211_hw *dev, static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; struct p54_statistics *stats = (struct p54_statistics *) hdr->data; - u32 tsf32 = le32_to_cpu(stats->tsf32); + u32 tsf32; + + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; + tsf32 = le32_to_cpu(stats->tsf32); if (tsf32 < priv->tsf_low32) priv->tsf_high32++; priv->tsf_low32 = tsf32; @@ -631,19 +851,50 @@ static void p54_rx_stats(struct ieee80211_hw *dev, struct sk_buff *skb) priv->stats.dot11FCSErrorCount = le32_to_cpu(stats->rx_bad_fcs); priv->noise = p54_rssi_to_dbm(dev, le32_to_cpu(stats->noise)); - complete(&priv->stats_comp); - mod_timer(&priv->stats_timer, jiffies + 5 * HZ); + p54_free_skb(dev, p54_find_tx_entry(dev, hdr->req_id)); +} + +static void p54_rx_trap(struct ieee80211_hw *dev, struct sk_buff *skb) +{ + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; + struct p54_trap *trap = (struct p54_trap *) hdr->data; + u16 event = le16_to_cpu(trap->event); + u16 freq = le16_to_cpu(trap->frequency); + + switch (event) { + case P54_TRAP_BEACON_TX: + break; + case P54_TRAP_RADAR: + printk(KERN_INFO "%s: radar (freq:%d MHz)\n", + wiphy_name(dev->wiphy), freq); + break; + case P54_TRAP_NO_BEACON: + break; + case P54_TRAP_SCAN: + break; + case P54_TRAP_TBTT: + break; + case P54_TRAP_TIMER: + break; + default: + printk(KERN_INFO "%s: received event:%x freq:%d\n", + wiphy_name(dev->wiphy), event, freq); + break; + } } static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) { - struct p54_control_hdr *hdr = (struct p54_control_hdr *) skb->data; + struct p54_hdr *hdr = (struct p54_hdr *) skb->data; switch (le16_to_cpu(hdr->type)) { case P54_CONTROL_TYPE_TXDONE: p54_rx_frame_sent(dev, skb); break; + case P54_CONTROL_TYPE_TRAP: + p54_rx_trap(dev, skb); + break; case P54_CONTROL_TYPE_BBP: break; case P54_CONTROL_TYPE_STAT_READBACK: @@ -664,9 +915,9 @@ static int p54_rx_control(struct ieee80211_hw *dev, struct sk_buff *skb) /* returns zero if skb can be reused */ int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb) { - u8 type = le16_to_cpu(*((__le16 *)skb->data)) >> 8; + u16 type = le16_to_cpu(*((__le16 *)skb->data)); - if (type == 0x80) + if (type & P54_HDR_FLAG_CONTROL) return p54_rx_control(dev, skb); else return p54_rx_data(dev, skb); @@ -682,12 +933,14 @@ EXPORT_SYMBOL_GPL(p54_rx); * marks allocated areas as reserved if necessary. p54_rx_frame_sent frees * allocated areas. */ -static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, - struct p54_control_hdr *data, u32 len) +static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, + struct p54_hdr *data, u32 len) { struct p54_common *priv = dev->priv; struct sk_buff *entry = priv->tx_queue.next; struct sk_buff *target_skb = NULL; + struct ieee80211_tx_info *info; + struct memrecord *range; u32 last_addr = priv->rx_start; u32 largest_hole = 0; u32 target_addr = priv->rx_start; @@ -695,12 +948,37 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, unsigned int left; len = (len + priv->headroom + priv->tailroom + 3) & ~0x3; + if (!skb) + return -EINVAL; + spin_lock_irqsave(&priv->tx_queue.lock, flags); + left = skb_queue_len(&priv->tx_queue); + if (unlikely(left >= 28)) { + /* + * The tx_queue is nearly full! + * We have throttle normal data traffic, because we must + * have a few spare slots for control frames left. + */ + ieee80211_stop_queues(dev); + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_TX_TIMEOUT)); + + if (unlikely(left == 32)) { + /* + * The tx_queue is now really full. + * + * TODO: check if the device has crashed and reset it. + */ + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + return -ENOSPC; + } + } + while (left--) { u32 hole_size; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry); - struct memrecord *range = (void *)info->driver_data; + info = IEEE80211_SKB_CB(entry); + range = (void *)info->rate_driver_data; hole_size = range->start_addr - last_addr; if (!target_skb && hole_size >= len) { target_skb = entry->prev; @@ -715,64 +993,102 @@ static void p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb, target_skb = priv->tx_queue.prev; largest_hole = max(largest_hole, priv->rx_end - last_addr - len); if (!skb_queue_empty(&priv->tx_queue)) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(target_skb); - struct memrecord *range = (void *)info->driver_data; + info = IEEE80211_SKB_CB(target_skb); + range = (void *)info->rate_driver_data; target_addr = range->end_addr; } } else largest_hole = max(largest_hole, priv->rx_end - last_addr); - if (skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct memrecord *range = (void *)info->driver_data; - range->start_addr = target_addr; - range->end_addr = target_addr + len; - __skb_queue_after(&priv->tx_queue, target_skb, skb); - if (largest_hole < priv->rx_mtu + priv->headroom + - priv->tailroom + - sizeof(struct p54_control_hdr)) - ieee80211_stop_queues(dev); + if (!target_skb) { + spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + ieee80211_stop_queues(dev); + return -ENOSPC; } + + info = IEEE80211_SKB_CB(skb); + range = (void *)info->rate_driver_data; + range->start_addr = target_addr; + range->end_addr = target_addr + len; + __skb_queue_after(&priv->tx_queue, target_skb, skb); spin_unlock_irqrestore(&priv->tx_queue.lock, flags); + if (largest_hole < priv->headroom + sizeof(struct p54_hdr) + + 48 + IEEE80211_MAX_RTS_THRESHOLD + priv->tailroom) + ieee80211_stop_queues(dev); + data->req_id = cpu_to_le32(target_addr + priv->headroom); + return 0; +} + +static struct sk_buff *p54_alloc_skb(struct ieee80211_hw *dev, + u16 hdr_flags, u16 len, u16 type, gfp_t memflags) +{ + struct p54_common *priv = dev->priv; + struct p54_hdr *hdr; + struct sk_buff *skb; + + skb = __dev_alloc_skb(len + priv->tx_hdr_len, memflags); + if (!skb) + return NULL; + skb_reserve(skb, priv->tx_hdr_len); + + hdr = (struct p54_hdr *) skb_put(skb, sizeof(*hdr)); + hdr->flags = cpu_to_le16(hdr_flags); + hdr->len = cpu_to_le16(len - sizeof(*hdr)); + hdr->type = cpu_to_le16(type); + hdr->tries = hdr->rts_tries = 0; + + if (unlikely(p54_assign_address(dev, skb, hdr, len))) { + kfree_skb(skb); + return NULL; + } + return skb; } int p54_read_eeprom(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr = NULL; + struct p54_hdr *hdr = NULL; struct p54_eeprom_lm86 *eeprom_hdr; - size_t eeprom_size = 0x2020, offset = 0, blocksize; + struct sk_buff *skb; + size_t eeprom_size = 0x2020, offset = 0, blocksize, maxblocksize; int ret = -ENOMEM; void *eeprom = NULL; - hdr = (struct p54_control_hdr *)kzalloc(sizeof(*hdr) + - sizeof(*eeprom_hdr) + EEPROM_READBACK_LEN, GFP_KERNEL); - if (!hdr) - goto free; + maxblocksize = EEPROM_READBACK_LEN; + if (priv->fw_var >= 0x509) + maxblocksize -= 0xc; + else + maxblocksize -= 0x4; + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(*hdr) + + sizeof(*eeprom_hdr) + maxblocksize, + P54_CONTROL_TYPE_EEPROM_READBACK, GFP_KERNEL); + if (!skb) + goto free; priv->eeprom = kzalloc(EEPROM_READBACK_LEN, GFP_KERNEL); if (!priv->eeprom) goto free; - eeprom = kzalloc(eeprom_size, GFP_KERNEL); if (!eeprom) goto free; - hdr->magic1 = cpu_to_le16(0x8000); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_EEPROM_READBACK); - hdr->retry1 = hdr->retry2 = 0; - eeprom_hdr = (struct p54_eeprom_lm86 *) hdr->data; + eeprom_hdr = (struct p54_eeprom_lm86 *) skb_put(skb, + sizeof(*eeprom_hdr) + maxblocksize); while (eeprom_size) { - blocksize = min(eeprom_size, (size_t)EEPROM_READBACK_LEN); - hdr->len = cpu_to_le16(blocksize + sizeof(*eeprom_hdr)); - eeprom_hdr->offset = cpu_to_le16(offset); - eeprom_hdr->len = cpu_to_le16(blocksize); - p54_assign_address(dev, NULL, hdr, le16_to_cpu(hdr->len) + - sizeof(*hdr)); - priv->tx(dev, hdr, le16_to_cpu(hdr->len) + sizeof(*hdr), 0); + blocksize = min(eeprom_size, maxblocksize); + if (priv->fw_var < 0x509) { + eeprom_hdr->v1.offset = cpu_to_le16(offset); + eeprom_hdr->v1.len = cpu_to_le16(blocksize); + } else { + eeprom_hdr->v2.offset = cpu_to_le32(offset); + eeprom_hdr->v2.len = cpu_to_le16(blocksize); + eeprom_hdr->v2.magic2 = 0xf; + memcpy(eeprom_hdr->v2.magic, (const char *)"LOCK", 4); + } + priv->tx(dev, skb); if (!wait_for_completion_interruptible_timeout(&priv->eeprom_comp, HZ)) { printk(KERN_ERR "%s: device does not respond!\n", @@ -790,166 +1106,422 @@ int p54_read_eeprom(struct ieee80211_hw *dev) free: kfree(priv->eeprom); priv->eeprom = NULL; - kfree(hdr); + p54_free_skb(dev, skb); kfree(eeprom); return ret; } EXPORT_SYMBOL_GPL(p54_read_eeprom); +static int p54_set_tim(struct ieee80211_hw *dev, struct ieee80211_sta *sta, + bool set) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_tim *tim; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*tim), + P54_CONTROL_TYPE_TIM, GFP_KERNEL); + if (!skb) + return -ENOMEM; + + tim = (struct p54_tim *) skb_put(skb, sizeof(*tim)); + tim->count = 1; + tim->entry[0] = cpu_to_le16(set ? (sta->aid | 0x8000) : sta->aid); + priv->tx(dev, skb); + return 0; +} + +static int p54_sta_unlock(struct ieee80211_hw *dev, u8 *addr) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_sta_unlock *sta; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*sta), + P54_CONTROL_TYPE_PSM_STA_UNLOCK, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + sta = (struct p54_sta_unlock *)skb_put(skb, sizeof(*sta)); + memcpy(sta->addr, addr, ETH_ALEN); + priv->tx(dev, skb); + return 0; +} + +static void p54_sta_notify(struct ieee80211_hw *dev, struct ieee80211_vif *vif, + enum sta_notify_cmd notify_cmd, + struct ieee80211_sta *sta) +{ + switch (notify_cmd) { + case STA_NOTIFY_ADD: + case STA_NOTIFY_REMOVE: + /* + * Notify the firmware that we don't want or we don't + * need to buffer frames for this station anymore. + */ + + p54_sta_unlock(dev, sta->addr); + break; + case STA_NOTIFY_AWAKE: + /* update the firmware's filter table */ + p54_sta_unlock(dev, sta->addr); + break; + default: + break; + } +} + +static int p54_tx_cancel(struct ieee80211_hw *dev, struct sk_buff *entry) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_hdr *hdr; + struct p54_txcancel *cancel; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, + sizeof(struct p54_hdr) + sizeof(*cancel), + P54_CONTROL_TYPE_TXCANCEL, GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + hdr = (void *)entry->data; + cancel = (struct p54_txcancel *)skb_put(skb, sizeof(*cancel)); + cancel->req_id = hdr->req_id; + priv->tx(dev, skb); + return 0; +} + +static int p54_tx_fill(struct ieee80211_hw *dev, struct sk_buff *skb, + struct ieee80211_tx_info *info, u8 *queue, size_t *extra_len, + u16 *flags, u16 *aid) +{ + struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; + struct p54_common *priv = dev->priv; + int ret = 0; + + if (unlikely(ieee80211_is_mgmt(hdr->frame_control))) { + if (ieee80211_is_beacon(hdr->frame_control)) { + *aid = 0; + *queue = 0; + *extra_len = IEEE80211_MAX_TIM_LEN; + *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP; + return 0; + } else if (ieee80211_is_probe_resp(hdr->frame_control)) { + *aid = 0; + *queue = 2; + *flags = P54_HDR_FLAG_DATA_OUT_TIMESTAMP | + P54_HDR_FLAG_DATA_OUT_NOCANCEL; + return 0; + } else { + *queue = 2; + ret = 0; + } + } else { + *queue += 4; + ret = 1; + } + + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + *aid = 1; + break; + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + if (info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) { + *aid = 0; + *queue = 3; + return 0; + } + if (info->control.sta) + *aid = info->control.sta->aid; + else + *flags |= P54_HDR_FLAG_DATA_OUT_NOCANCEL; + } + return ret; +} + +static u8 p54_convert_algo(enum ieee80211_key_alg alg) +{ + switch (alg) { + case ALG_WEP: + return P54_CRYPTO_WEP; + case ALG_TKIP: + return P54_CRYPTO_TKIPMICHAEL; + case ALG_CCMP: + return P54_CRYPTO_AESCCMP; + default: + return 0; + } +} + static int p54_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_queue_stats *current_queue; + struct ieee80211_tx_queue_stats *current_queue = NULL; struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; - struct p54_tx_control_allocdata *txhdr; - size_t padding, len; - u8 rate; + struct p54_hdr *hdr; + struct p54_tx_data *txhdr; + size_t padding, len, tim_len = 0; + int i, j, ridx, ret; + u16 hdr_flags = 0, aid = 0; + u8 rate, queue, crypt_offset = 0; u8 cts_rate = 0x20; + u8 rc_flags; + u8 calculated_tries[4]; + u8 nrates = 0, nremaining = 8; - current_queue = &priv->tx_stats[skb_get_queue_mapping(skb) + 4]; - if (unlikely(current_queue->len > current_queue->limit)) + queue = skb_get_queue_mapping(skb); + + ret = p54_tx_fill(dev, skb, info, &queue, &tim_len, &hdr_flags, &aid); + current_queue = &priv->tx_stats[queue]; + if (unlikely((current_queue->len > current_queue->limit) && ret)) return NETDEV_TX_BUSY; current_queue->len++; current_queue->count++; - if (current_queue->len == current_queue->limit) + if ((current_queue->len == current_queue->limit) && ret) ieee80211_stop_queue(dev, skb_get_queue_mapping(skb)); padding = (unsigned long)(skb->data - (sizeof(*hdr) + sizeof(*txhdr))) & 3; len = skb->len; - txhdr = (struct p54_tx_control_allocdata *) - skb_push(skb, sizeof(*txhdr) + padding); - hdr = (struct p54_control_hdr *) skb_push(skb, sizeof(*hdr)); + if (info->control.hw_key) { + crypt_offset = ieee80211_get_hdrlen_from_skb(skb); + if (info->control.hw_key->alg == ALG_TKIP) { + u8 *iv = (u8 *)(skb->data + crypt_offset); + /* + * The firmware excepts that the IV has to have + * this special format + */ + iv[1] = iv[0]; + iv[0] = iv[2]; + iv[2] = 0; + } + } + + txhdr = (struct p54_tx_data *) skb_push(skb, sizeof(*txhdr) + padding); + hdr = (struct p54_hdr *) skb_push(skb, sizeof(*hdr)); if (padding) - hdr->magic1 = cpu_to_le16(0x4010); - else - hdr->magic1 = cpu_to_le16(0x0010); - hdr->len = cpu_to_le16(len); - hdr->type = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? 0 : cpu_to_le16(1); - hdr->retry1 = hdr->retry2 = info->control.retry_limit; - - /* TODO: add support for alternate retry TX rates */ - rate = ieee80211_get_tx_rate(dev, info)->hw_value; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) { - rate |= 0x10; - cts_rate |= 0x10; + hdr_flags |= P54_HDR_FLAG_DATA_ALIGN; + hdr->type = cpu_to_le16(aid); + hdr->rts_tries = info->control.rates[0].count; + + /* + * we register the rates in perfect order, and + * RTS/CTS won't happen on 5 GHz + */ + cts_rate = info->control.rts_cts_rate_idx; + + memset(&txhdr->rateset, 0, sizeof(txhdr->rateset)); + + /* see how many rates got used */ + for (i = 0; i < 4; i++) { + if (info->control.rates[i].idx < 0) + break; + nrates++; + } + + /* limit tries to 8/nrates per rate */ + for (i = 0; i < nrates; i++) { + /* + * The magic expression here is equivalent to 8/nrates for + * all values that matter, but avoids division and jumps. + * Note that nrates can only take the values 1 through 4. + */ + calculated_tries[i] = min_t(int, ((15 >> nrates) | 1) + 1, + info->control.rates[i].count); + nremaining -= calculated_tries[i]; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { - rate |= 0x40; - cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { - rate |= 0x20; - cts_rate |= ieee80211_get_rts_cts_rate(dev, info)->hw_value; + + /* if there are tries left, distribute from back to front */ + for (i = nrates - 1; nremaining > 0 && i >= 0; i--) { + int tmp = info->control.rates[i].count - calculated_tries[i]; + + if (tmp <= 0) + continue; + /* RC requested more tries at this rate */ + + tmp = min_t(int, tmp, nremaining); + calculated_tries[i] += tmp; + nremaining -= tmp; + } + + ridx = 0; + for (i = 0; i < nrates && ridx < 8; i++) { + /* we register the rates in perfect order */ + rate = info->control.rates[i].idx; + if (info->band == IEEE80211_BAND_5GHZ) + rate += 4; + + /* store the count we actually calculated for TX status */ + info->control.rates[i].count = calculated_tries[i]; + + rc_flags = info->control.rates[i].flags; + if (rc_flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) { + rate |= 0x10; + cts_rate |= 0x10; + } + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) + rate |= 0x40; + else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) + rate |= 0x20; + for (j = 0; j < calculated_tries[i] && ridx < 8; j++) { + txhdr->rateset[ridx] = rate; + ridx++; + } + } + + if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) + hdr_flags |= P54_HDR_FLAG_DATA_OUT_SEQNR; + + /* TODO: enable bursting */ + hdr->flags = cpu_to_le16(hdr_flags); + hdr->tries = ridx; + txhdr->rts_rate_idx = 0; + if (info->control.hw_key) { + crypt_offset += info->control.hw_key->iv_len; + txhdr->key_type = p54_convert_algo(info->control.hw_key->alg); + txhdr->key_len = min((u8)16, info->control.hw_key->keylen); + memcpy(txhdr->key, info->control.hw_key->key, txhdr->key_len); + if (info->control.hw_key->alg == ALG_TKIP) { + if (unlikely(skb_tailroom(skb) < 12)) + goto err; + /* reserve space for the MIC key */ + len += 8; + memcpy(skb_put(skb, 8), &(info->control.hw_key->key + [NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY]), 8); + } + /* reserve some space for ICV */ + len += info->control.hw_key->icv_len; + } else { + txhdr->key_type = 0; + txhdr->key_len = 0; } - memset(txhdr->rateset, rate, 8); - txhdr->key_type = 0; - txhdr->key_len = 0; - txhdr->hw_queue = skb_get_queue_mapping(skb) + 4; + txhdr->crypt_offset = crypt_offset; + txhdr->hw_queue = queue; + if (current_queue) + txhdr->backlog = current_queue->len; + else + txhdr->backlog = 0; + memset(txhdr->durations, 0, sizeof(txhdr->durations)); txhdr->tx_antenna = (info->antenna_sel_tx == 0) ? 2 : info->antenna_sel_tx - 1; txhdr->output_power = priv->output_power; - txhdr->cts_rate = (info->flags & IEEE80211_TX_CTL_NO_ACK) ? - 0 : cts_rate; + txhdr->cts_rate = cts_rate; if (padding) txhdr->align[0] = padding; - /* FIXME: The sequence that follows is needed for this driver to - * work with mac80211 since "mac80211: fix TX sequence numbers". - * As with the temporary code in rt2x00, changes will be needed - * to get proper sequence numbers on beacons. In addition, this - * patch places the sequence number in the hardware state, which - * limits us to a single virtual state. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - priv->seqno += 0x10; - ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno); - } + hdr->len = cpu_to_le16(len); /* modifies skb->cb and with it info, so must be last! */ - p54_assign_address(dev, skb, hdr, skb->len); + if (unlikely(p54_assign_address(dev, skb, hdr, skb->len + tim_len))) + goto err; + priv->tx(dev, skb); + + queue_delayed_work(dev->workqueue, &priv->work, + msecs_to_jiffies(P54_TX_FRAME_LIFETIME)); - priv->tx(dev, hdr, skb->len, 0); return 0; + + err: + skb_pull(skb, sizeof(*hdr) + sizeof(*txhdr) + padding); + if (current_queue) { + current_queue->len--; + current_queue->count--; + } + return NETDEV_TX_BUSY; } -static int p54_set_filter(struct ieee80211_hw *dev, u16 filter_type, - const u8 *bssid) +static int p54_setup_mac(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_filter *filter; - size_t data_len; + struct sk_buff *skb; + struct p54_setup_mac *setup; + u16 mode; - hdr = kzalloc(sizeof(*hdr) + sizeof(*filter) + - priv->tx_hdr_len, GFP_ATOMIC); - if (!hdr) + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*setup) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SETUP, + GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - - filter = (struct p54_tx_control_filter *) hdr->data; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_FILTER_SET); - - priv->filter_type = filter->filter_type = cpu_to_le16(filter_type); - memcpy(filter->mac_addr, priv->mac_addr, ETH_ALEN); - if (!bssid) - memset(filter->bssid, ~0, ETH_ALEN); - else - memcpy(filter->bssid, bssid, ETH_ALEN); - - filter->rx_antenna = priv->rx_antenna; + setup = (struct p54_setup_mac *) skb_put(skb, sizeof(*setup)); + if (dev->conf.radio_enabled) { + switch (priv->mode) { + case NL80211_IFTYPE_STATION: + mode = P54_FILTER_TYPE_STATION; + break; + case NL80211_IFTYPE_AP: + mode = P54_FILTER_TYPE_AP; + break; + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_MESH_POINT: + mode = P54_FILTER_TYPE_IBSS; + break; + default: + mode = P54_FILTER_TYPE_NONE; + break; + } + if (priv->filter_flags & FIF_PROMISC_IN_BSS) + mode |= P54_FILTER_TYPE_TRANSPARENT; + } else + mode = P54_FILTER_TYPE_RX_DISABLED; + setup->mac_mode = cpu_to_le16(mode); + memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN); + memcpy(setup->bssid, priv->bssid, ETH_ALEN); + setup->rx_antenna = 2; /* automatic */ + setup->rx_align = 0; if (priv->fw_var < 0x500) { - data_len = P54_TX_CONTROL_FILTER_V1_LEN; - filter->v1.basic_rate_mask = cpu_to_le32(0x15F); - filter->v1.rx_addr = cpu_to_le32(priv->rx_end); - filter->v1.max_rx = cpu_to_le16(priv->rx_mtu); - filter->v1.rxhw = cpu_to_le16(priv->rxhw); - filter->v1.wakeup_timer = cpu_to_le16(500); + setup->v1.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + memset(setup->v1.rts_rates, 0, 8); + setup->v1.rx_addr = cpu_to_le32(priv->rx_end); + setup->v1.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v1.rxhw = cpu_to_le16(priv->rxhw); + setup->v1.wakeup_timer = cpu_to_le16(priv->wakeup_timer); + setup->v1.unalloc0 = cpu_to_le16(0); } else { - data_len = P54_TX_CONTROL_FILTER_V2_LEN; - filter->v2.rx_addr = cpu_to_le32(priv->rx_end); - filter->v2.max_rx = cpu_to_le16(priv->rx_mtu); - filter->v2.rxhw = cpu_to_le16(priv->rxhw); - filter->v2.timer = cpu_to_le16(1000); + setup->v2.rx_addr = cpu_to_le32(priv->rx_end); + setup->v2.max_rx = cpu_to_le16(priv->rx_mtu); + setup->v2.rxhw = cpu_to_le16(priv->rxhw); + setup->v2.timer = cpu_to_le16(priv->wakeup_timer); + setup->v2.truncate = cpu_to_le16(48896); + setup->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + setup->v2.sbss_offset = 0; + setup->v2.mcast_window = 0; + setup->v2.rx_rssi_threshold = 0; + setup->v2.rx_ed_threshold = 0; + setup->v2.ref_clock = cpu_to_le32(644245094); + setup->v2.lpf_bandwidth = cpu_to_le16(65535); + setup->v2.osc_start_delay = cpu_to_le16(65535); } - - hdr->len = cpu_to_le16(data_len); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); - priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); + priv->tx(dev, skb); return 0; } -static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) +static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_channel *chan; + struct sk_buff *skb; + struct p54_scan *chan; unsigned int i; - size_t data_len; void *entry; + __le16 freq = cpu_to_le16(dev->conf.channel->center_freq); + int band = dev->conf.channel->band; - hdr = kzalloc(sizeof(*hdr) + sizeof(*chan) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*chan) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_SCAN, + GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - - chan = (struct p54_tx_control_channel *) hdr->data; - - hdr->magic1 = cpu_to_le16(0x8001); - - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_CHANNEL_CHANGE); - - chan->flags = cpu_to_le16(0x1); - chan->dwell = cpu_to_le16(0x0); + chan = (struct p54_scan *) skb_put(skb, sizeof(*chan)); + memset(chan->padding1, 0, sizeof(chan->padding1)); + chan->mode = cpu_to_le16(mode); + chan->dwell = cpu_to_le16(dwell); for (i = 0; i < priv->iq_autocal_len; i++) { if (priv->iq_autocal[i].freq != freq) @@ -990,61 +1562,50 @@ static int p54_set_freq(struct ieee80211_hw *dev, __le16 freq) } entry += sizeof(__le16); - chan->pa_points_per_curve = - min(priv->curve_data->points_per_channel, (u8) 8); - - memcpy(chan->curve_data, entry, sizeof(*chan->curve_data) * - chan->pa_points_per_curve); + chan->pa_points_per_curve = 8; + memset(chan->curve_data, 0, sizeof(*chan->curve_data)); + memcpy(chan->curve_data, entry, + sizeof(struct p54_pa_curve_data_sample) * + min((u8)8, priv->curve_data->points_per_channel)); break; } if (priv->fw_var < 0x500) { - data_len = P54_TX_CONTROL_CHANNEL_V1_LEN; - chan->v1.rssical_mul = cpu_to_le16(130); - chan->v1.rssical_add = cpu_to_le16(0xfe70); + chan->v1_rssi.mul = cpu_to_le16(priv->rssical_db[band].mul); + chan->v1_rssi.add = cpu_to_le16(priv->rssical_db[band].add); } else { - data_len = P54_TX_CONTROL_CHANNEL_V2_LEN; - chan->v2.rssical_mul = cpu_to_le16(130); - chan->v2.rssical_add = cpu_to_le16(0xfe70); - chan->v2.basic_rate_mask = cpu_to_le32(0x15f); + chan->v2.rssi.mul = cpu_to_le16(priv->rssical_db[band].mul); + chan->v2.rssi.add = cpu_to_le16(priv->rssical_db[band].add); + chan->v2.basic_rate_mask = cpu_to_le32(priv->basic_rate_mask); + memset(chan->v2.rts_rates, 0, 8); } - - hdr->len = cpu_to_le16(data_len); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + data_len); - priv->tx(dev, hdr, sizeof(*hdr) + data_len, 1); + priv->tx(dev, skb); return 0; err: printk(KERN_ERR "%s: frequency change failed\n", wiphy_name(dev->wiphy)); - kfree(hdr); + kfree_skb(skb); return -EINVAL; } static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_led *led; + struct sk_buff *skb; + struct p54_led *led; - hdr = kzalloc(sizeof(*hdr) + sizeof(*led) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*led) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_LED, + GFP_ATOMIC); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*led)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_LED); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*led)); - - led = (struct p54_tx_control_led *) hdr->data; + led = (struct p54_led *)skb_put(skb, sizeof(*led)); led->mode = cpu_to_le16(mode); led->led_permanent = cpu_to_le16(link); led->led_temporary = cpu_to_le16(act); led->duration = cpu_to_le16(1000); - - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*led), 1); - + priv->tx(dev, skb); return 0; } @@ -1056,88 +1617,144 @@ do { \ queue.txop = cpu_to_le16(_txop); \ } while(0) -static void p54_init_vdcf(struct ieee80211_hw *dev) +static int p54_set_edcf(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_vdcf *vdcf; - - /* all USB V1 adapters need a extra headroom */ - hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*vdcf)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_DCFINIT); - hdr->req_id = cpu_to_le32(priv->rx_start); - - vdcf = (struct p54_tx_control_vdcf *) hdr->data; - - 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); + struct sk_buff *skb; + struct p54_edcf *edcf; + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*edcf) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_DCFINIT, + GFP_ATOMIC); + if (!skb) + return -ENOMEM; + + edcf = (struct p54_edcf *)skb_put(skb, sizeof(*edcf)); + if (priv->use_short_slot) { + edcf->slottime = 9; + edcf->sifs = 0x10; + edcf->eofpad = 0x00; + } else { + edcf->slottime = 20; + edcf->sifs = 0x0a; + edcf->eofpad = 0x06; + } + /* (see prism54/isl_oid.h for further details) */ + edcf->frameburst = cpu_to_le16(0); + edcf->round_trip_delay = cpu_to_le16(0); + edcf->flags = 0; + memset(edcf->mapping, 0, sizeof(edcf->mapping)); + memcpy(edcf->queue, priv->qos_params, sizeof(edcf->queue)); + priv->tx(dev, skb); + return 0; } -static void p54_set_vdcf(struct ieee80211_hw *dev) +static int p54_beacon_tim(struct sk_buff *skb) { - struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_vdcf *vdcf; + /* + * the good excuse for this mess is ... the firmware. + * The dummy TIM MUST be at the end of the beacon frame, + * because it'll be overwritten! + */ - hdr = (void *)priv->cached_vdcf + priv->tx_hdr_len; + struct ieee80211_mgmt *mgmt = (void *)skb->data; + u8 *pos, *end; - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*vdcf)); + if (skb->len <= sizeof(mgmt)) + return -EINVAL; - vdcf = (struct p54_tx_control_vdcf *) hdr->data; + pos = (u8 *)mgmt->u.beacon.variable; + end = skb->data + skb->len; + while (pos < end) { + if (pos + 2 + pos[1] > end) + return -EINVAL; - if (dev->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) { - vdcf->slottime = 9; - vdcf->magic1 = 0x10; - vdcf->magic2 = 0x00; - } else { - vdcf->slottime = 20; - vdcf->magic1 = 0x0a; - vdcf->magic2 = 0x06; - } + if (pos[0] == WLAN_EID_TIM) { + u8 dtim_len = pos[1]; + u8 dtim_period = pos[3]; + u8 *next = pos + 2 + dtim_len; - /* (see prism54/isl_oid.h for further details) */ - vdcf->frameburst = cpu_to_le16(0); + if (dtim_len < 3) + return -EINVAL; + + memmove(pos, next, end - next); - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*vdcf), 0); + if (dtim_len > 3) + skb_trim(skb, skb->len - (dtim_len - 3)); + + pos = end - (dtim_len + 2); + + /* add the dummy at the end */ + pos[0] = WLAN_EID_TIM; + pos[1] = 3; + pos[2] = 0; + pos[3] = dtim_period; + pos[4] = 0; + return 0; + } + pos += 2 + pos[1]; + } + return 0; } -static int p54_start(struct ieee80211_hw *dev) +static int p54_beacon_update(struct ieee80211_hw *dev, + struct ieee80211_vif *vif) { struct p54_common *priv = dev->priv; - int err; - - if (!priv->cached_vdcf) { - priv->cached_vdcf = kzalloc(sizeof(struct p54_tx_control_vdcf)+ - priv->tx_hdr_len + sizeof(struct p54_control_hdr), - GFP_KERNEL); + struct sk_buff *beacon; + int ret; - if (!priv->cached_vdcf) - return -ENOMEM; + if (priv->cached_beacon) { + p54_tx_cancel(dev, priv->cached_beacon); + /* wait for the last beacon the be freed */ + msleep(10); } - if (!priv->cached_stats) { - priv->cached_stats = kzalloc(sizeof(struct p54_statistics) + - priv->tx_hdr_len + sizeof(struct p54_control_hdr), - GFP_KERNEL); + beacon = ieee80211_beacon_get(dev, vif); + if (!beacon) + return -ENOMEM; + ret = p54_beacon_tim(beacon); + if (ret) + return ret; + ret = p54_tx(dev, beacon); + if (ret) + return ret; + priv->cached_beacon = beacon; + priv->tsf_high32 = 0; + priv->tsf_low32 = 0; - if (!priv->cached_stats) { - kfree(priv->cached_vdcf); - priv->cached_vdcf = NULL; - return -ENOMEM; - } - } + return 0; +} +static int p54_start(struct ieee80211_hw *dev) +{ + struct p54_common *priv = dev->priv; + int err; + + mutex_lock(&priv->conf_mutex); err = priv->open(dev); - if (!err) - priv->mode = NL80211_IFTYPE_MONITOR; + if (err) + goto out; + P54_SET_QUEUE(priv->qos_params[0], 0x0002, 0x0003, 0x0007, 47); + P54_SET_QUEUE(priv->qos_params[1], 0x0002, 0x0007, 0x000f, 94); + P54_SET_QUEUE(priv->qos_params[2], 0x0003, 0x000f, 0x03ff, 0); + P54_SET_QUEUE(priv->qos_params[3], 0x0007, 0x000f, 0x03ff, 0); + err = p54_set_edcf(dev); + if (err) + goto out; + + memset(priv->bssid, ~0, ETH_ALEN); + priv->mode = NL80211_IFTYPE_MONITOR; + err = p54_setup_mac(dev); + if (err) { + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + goto out; + } - p54_init_vdcf(dev); + queue_delayed_work(dev->workqueue, &priv->work, 0); - mod_timer(&priv->stats_timer, jiffies + HZ); +out: + mutex_unlock(&priv->conf_mutex); return err; } @@ -1146,12 +1763,18 @@ static void p54_stop(struct ieee80211_hw *dev) struct p54_common *priv = dev->priv; struct sk_buff *skb; - del_timer(&priv->stats_timer); + mutex_lock(&priv->conf_mutex); + priv->mode = NL80211_IFTYPE_UNSPECIFIED; + cancel_delayed_work_sync(&priv->work); + if (priv->cached_beacon) + p54_tx_cancel(dev, priv->cached_beacon); + + priv->stop(dev); while ((skb = skb_dequeue(&priv->tx_queue))) kfree_skb(skb); - priv->stop(dev); + priv->cached_beacon = NULL; priv->tsf_high32 = priv->tsf_low32 = 0; - priv->mode = NL80211_IFTYPE_UNSPECIFIED; + mutex_unlock(&priv->conf_mutex); } static int p54_add_interface(struct ieee80211_hw *dev, @@ -1159,32 +1782,28 @@ static int p54_add_interface(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - if (priv->mode != NL80211_IFTYPE_MONITOR) + mutex_lock(&priv->conf_mutex); + if (priv->mode != NL80211_IFTYPE_MONITOR) { + mutex_unlock(&priv->conf_mutex); return -EOPNOTSUPP; + } switch (conf->type) { case NL80211_IFTYPE_STATION: + case NL80211_IFTYPE_ADHOC: + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_MESH_POINT: priv->mode = conf->type; break; default: + mutex_unlock(&priv->conf_mutex); return -EOPNOTSUPP; } memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); - - p54_set_filter(dev, 0, NULL); - - switch (conf->type) { - case NL80211_IFTYPE_STATION: - p54_set_filter(dev, 1, NULL); - break; - default: - BUG(); /* impossible */ - break; - } - + p54_setup_mac(dev); p54_set_leds(dev, 1, 0, 0); - + mutex_unlock(&priv->conf_mutex); return 0; } @@ -1192,22 +1811,38 @@ static void p54_remove_interface(struct ieee80211_hw *dev, struct ieee80211_if_init_conf *conf) { struct p54_common *priv = dev->priv; + + mutex_lock(&priv->conf_mutex); + if (priv->cached_beacon) + p54_tx_cancel(dev, priv->cached_beacon); priv->mode = NL80211_IFTYPE_MONITOR; memset(priv->mac_addr, 0, ETH_ALEN); - p54_set_filter(dev, 0, NULL); + memset(priv->bssid, 0, ETH_ALEN); + p54_setup_mac(dev); + mutex_unlock(&priv->conf_mutex); } -static int p54_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int p54_config(struct ieee80211_hw *dev, u32 changed) { int ret; struct p54_common *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; mutex_lock(&priv->conf_mutex); - priv->rx_antenna = (conf->antenna_sel_rx == 0) ? - 2 : conf->antenna_sel_tx - 1; - priv->output_power = conf->power_level << 2; - ret = p54_set_freq(dev, cpu_to_le16(conf->channel->center_freq)); - p54_set_vdcf(dev); + if (changed & IEEE80211_CONF_CHANGE_POWER) + priv->output_power = conf->power_level << 2; + if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) { + ret = p54_setup_mac(dev); + if (ret) + goto out; + } + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) { + ret = p54_scan(dev, P54_SCAN_EXIT, 0); + if (ret) + goto out; + } + +out: mutex_unlock(&priv->conf_mutex); return ret; } @@ -1217,13 +1852,36 @@ static int p54_config_interface(struct ieee80211_hw *dev, struct ieee80211_if_conf *conf) { struct p54_common *priv = dev->priv; + int ret = 0; mutex_lock(&priv->conf_mutex); - p54_set_filter(dev, 0, conf->bssid); - p54_set_leds(dev, 1, !is_multicast_ether_addr(conf->bssid), 0); - memcpy(priv->bssid, conf->bssid, ETH_ALEN); + if (conf->changed & IEEE80211_IFCC_BSSID) { + memcpy(priv->bssid, conf->bssid, ETH_ALEN); + ret = p54_setup_mac(dev); + if (ret) + goto out; + } + + if (conf->changed & IEEE80211_IFCC_BEACON) { + ret = p54_scan(dev, P54_SCAN_EXIT, 0); + if (ret) + goto out; + ret = p54_setup_mac(dev); + if (ret) + goto out; + ret = p54_beacon_update(dev, vif); + if (ret) + goto out; + ret = p54_set_edcf(dev); + if (ret) + goto out; + } + + ret = p54_set_leds(dev, 1, !is_multicast_ether_addr(priv->bssid), 0); + +out: mutex_unlock(&priv->conf_mutex); - return 0; + return ret; } static void p54_configure_filter(struct ieee80211_hw *dev, @@ -1233,94 +1891,78 @@ static void p54_configure_filter(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - *total_flags &= FIF_BCN_PRBRESP_PROMISC | - FIF_PROMISC_IN_BSS | - FIF_FCSFAIL; + *total_flags &= FIF_PROMISC_IN_BSS | + (*total_flags & FIF_PROMISC_IN_BSS) ? + FIF_FCSFAIL : 0; priv->filter_flags = *total_flags; - if (changed_flags & FIF_BCN_PRBRESP_PROMISC) { - if (*total_flags & FIF_BCN_PRBRESP_PROMISC) - p54_set_filter(dev, le16_to_cpu(priv->filter_type), - NULL); - else - p54_set_filter(dev, le16_to_cpu(priv->filter_type), - priv->bssid); - } - - if (changed_flags & FIF_PROMISC_IN_BSS) { - if (*total_flags & FIF_PROMISC_IN_BSS) - p54_set_filter(dev, le16_to_cpu(priv->filter_type) | - 0x8, NULL); - else - p54_set_filter(dev, le16_to_cpu(priv->filter_type) & - ~0x8, priv->bssid); - } + if (changed_flags & FIF_PROMISC_IN_BSS) + p54_setup_mac(dev); } static int p54_conf_tx(struct ieee80211_hw *dev, u16 queue, const struct ieee80211_tx_queue_params *params) { struct p54_common *priv = dev->priv; - struct p54_tx_control_vdcf *vdcf; - - vdcf = (struct p54_tx_control_vdcf *)(((struct p54_control_hdr *) - ((void *)priv->cached_vdcf + priv->tx_hdr_len))->data); + int ret; + mutex_lock(&priv->conf_mutex); if ((params) && !(queue > 4)) { - P54_SET_QUEUE(vdcf->queue[queue], params->aifs, + P54_SET_QUEUE(priv->qos_params[queue], params->aifs, params->cw_min, params->cw_max, params->txop); + ret = p54_set_edcf(dev); } else - return -EINVAL; - - p54_set_vdcf(dev); - - return 0; + ret = -EINVAL; + mutex_unlock(&priv->conf_mutex); + return ret; } static int p54_init_xbow_synth(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_tx_control_xbow_synth *xbow; + struct sk_buff *skb; + struct p54_xbow_synth *xbow; - hdr = kzalloc(sizeof(*hdr) + sizeof(*xbow) + - priv->tx_hdr_len, GFP_KERNEL); - if (!hdr) + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*xbow) + + sizeof(struct p54_hdr), + P54_CONTROL_TYPE_XBOW_SYNTH_CFG, + GFP_KERNEL); + if (!skb) return -ENOMEM; - hdr = (void *)hdr + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8001); - hdr->len = cpu_to_le16(sizeof(*xbow)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_XBOW_SYNTH_CFG); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*xbow)); - - xbow = (struct p54_tx_control_xbow_synth *) hdr->data; + xbow = (struct p54_xbow_synth *)skb_put(skb, sizeof(*xbow)); xbow->magic1 = cpu_to_le16(0x1); xbow->magic2 = cpu_to_le16(0x2); xbow->freq = cpu_to_le16(5390); - - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*xbow), 1); - + memset(xbow->padding, 0, sizeof(xbow->padding)); + priv->tx(dev, skb); return 0; } -static void p54_statistics_timer(unsigned long data) +static void p54_work(struct work_struct *work) { - struct ieee80211_hw *dev = (struct ieee80211_hw *) data; - struct p54_common *priv = dev->priv; - struct p54_control_hdr *hdr; - struct p54_statistics *stats; + struct p54_common *priv = container_of(work, struct p54_common, + work.work); + struct ieee80211_hw *dev = priv->hw; + struct sk_buff *skb; - BUG_ON(!priv->cached_stats); + if (unlikely(priv->mode == NL80211_IFTYPE_UNSPECIFIED)) + return ; - hdr = (void *)priv->cached_stats + priv->tx_hdr_len; - hdr->magic1 = cpu_to_le16(0x8000); - hdr->len = cpu_to_le16(sizeof(*stats)); - hdr->type = cpu_to_le16(P54_CONTROL_TYPE_STAT_READBACK); - p54_assign_address(dev, NULL, hdr, sizeof(*hdr) + sizeof(*stats)); + /* + * TODO: walk through tx_queue and do the following tasks + * 1. initiate bursts. + * 2. cancel stuck frames / reset the device if necessary. + */ + + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL, sizeof(struct p54_hdr) + + sizeof(struct p54_statistics), + P54_CONTROL_TYPE_STAT_READBACK, GFP_KERNEL); + if (!skb) + return ; - priv->tx(dev, hdr, sizeof(*hdr) + sizeof(*stats), 0); + priv->tx(dev, skb); } static int p54_get_stats(struct ieee80211_hw *dev, @@ -1328,17 +1970,7 @@ static int p54_get_stats(struct ieee80211_hw *dev, { struct p54_common *priv = dev->priv; - del_timer(&priv->stats_timer); - p54_statistics_timer((unsigned long)dev); - - if (!wait_for_completion_interruptible_timeout(&priv->stats_comp, HZ)) { - printk(KERN_ERR "%s: device does not respond!\n", - wiphy_name(dev->wiphy)); - return -EBUSY; - } - memcpy(stats, &priv->stats, sizeof(*stats)); - return 0; } @@ -1352,14 +1984,133 @@ static int p54_get_tx_stats(struct ieee80211_hw *dev, return 0; } +static void p54_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct p54_common *priv = dev->priv; + + if (changed & BSS_CHANGED_ERP_SLOT) { + priv->use_short_slot = info->use_short_slot; + p54_set_edcf(dev); + } + if (changed & BSS_CHANGED_BASIC_RATES) { + if (dev->conf.channel->band == IEEE80211_BAND_5GHZ) + priv->basic_rate_mask = (info->basic_rates << 4); + else + priv->basic_rate_mask = info->basic_rates; + p54_setup_mac(dev); + if (priv->fw_var >= 0x500) + p54_scan(dev, P54_SCAN_EXIT, 0); + } + if (changed & BSS_CHANGED_ASSOC) { + if (info->assoc) { + priv->aid = info->aid; + priv->wakeup_timer = info->beacon_int * + info->dtim_period * 5; + p54_setup_mac(dev); + } + } + +} + +static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, + const u8 *local_address, const u8 *address, + struct ieee80211_key_conf *key) +{ + struct p54_common *priv = dev->priv; + struct sk_buff *skb; + struct p54_keycache *rxkey; + u8 algo = 0; + + if (modparam_nohwcrypt) + return -EOPNOTSUPP; + + if (cmd == DISABLE_KEY) + algo = 0; + else { + switch (key->alg) { + case ALG_TKIP: + if (!(priv->privacy_caps & (BR_DESC_PRIV_CAP_MICHAEL | + BR_DESC_PRIV_CAP_TKIP))) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_TKIPMICHAEL; + break; + case ALG_WEP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_WEP)) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_WEP; + break; + case ALG_CCMP: + if (!(priv->privacy_caps & BR_DESC_PRIV_CAP_AESCCMP)) + return -EOPNOTSUPP; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + algo = P54_CRYPTO_AESCCMP; + break; + default: + return -EINVAL; + } + } + + if (key->keyidx > priv->rx_keycache_size) { + /* + * The device supports the choosen algorithm, but the firmware + * does not provide enough key slots to store all of them. + * So, incoming frames have to be decoded by the mac80211 stack, + * but we can still offload encryption for outgoing frames. + */ + + return 0; + } + + mutex_lock(&priv->conf_mutex); + skb = p54_alloc_skb(dev, P54_HDR_FLAG_CONTROL_OPSET, sizeof(*rxkey) + + sizeof(struct p54_hdr), P54_CONTROL_TYPE_RX_KEYCACHE, + GFP_ATOMIC); + if (!skb) { + mutex_unlock(&priv->conf_mutex); + return -ENOMEM; + } + + /* TODO: some devices have 4 more free slots for rx keys */ + rxkey = (struct p54_keycache *)skb_put(skb, sizeof(*rxkey)); + rxkey->entry = key->keyidx; + rxkey->key_id = key->keyidx; + rxkey->key_type = algo; + if (address) + memcpy(rxkey->mac, address, ETH_ALEN); + else + memset(rxkey->mac, ~0, ETH_ALEN); + if (key->alg != ALG_TKIP) { + rxkey->key_len = min((u8)16, key->keylen); + memcpy(rxkey->key, key->key, rxkey->key_len); + } else { + rxkey->key_len = 24; + memcpy(rxkey->key, key->key, 16); + memcpy(&(rxkey->key[16]), &(key->key + [NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY]), 8); + } + + priv->tx(dev, skb); + mutex_unlock(&priv->conf_mutex); + return 0; +} + static const struct ieee80211_ops p54_ops = { .tx = p54_tx, .start = p54_start, .stop = p54_stop, .add_interface = p54_add_interface, .remove_interface = p54_remove_interface, + .set_tim = p54_set_tim, + .sta_notify = p54_sta_notify, + .set_key = p54_set_key, .config = p54_config, .config_interface = p54_config_interface, + .bss_info_changed = p54_bss_info_changed, .configure_filter = p54_configure_filter, .conf_tx = p54_conf_tx, .get_stats = p54_get_stats, @@ -1376,32 +2127,43 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len) return NULL; priv = dev->priv; + priv->hw = dev; priv->mode = NL80211_IFTYPE_UNSPECIFIED; + priv->basic_rate_mask = 0x15f; skb_queue_head_init(&priv->tx_queue); - dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | /* not sure */ - IEEE80211_HW_RX_INCLUDES_FCS | + dev->flags = IEEE80211_HW_RX_INCLUDES_FCS | IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM; - dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP) | + BIT(NL80211_IFTYPE_MESH_POINT); dev->channel_change_time = 1000; /* TODO: find actual value */ - - priv->tx_stats[0].limit = 1; - priv->tx_stats[1].limit = 1; - priv->tx_stats[2].limit = 1; - priv->tx_stats[3].limit = 1; - priv->tx_stats[4].limit = 5; + priv->tx_stats[0].limit = 1; /* Beacon queue */ + priv->tx_stats[1].limit = 1; /* Probe queue for HW scan */ + priv->tx_stats[2].limit = 3; /* queue for MLMEs */ + priv->tx_stats[3].limit = 3; /* Broadcast / MC queue */ + priv->tx_stats[4].limit = 5; /* Data */ dev->queues = 1; priv->noise = -94; - dev->extra_tx_headroom = sizeof(struct p54_control_hdr) + 4 + - sizeof(struct p54_tx_control_allocdata); + /* + * We support at most 8 tries no matter which rate they're at, + * we cannot support max_rates * max_rate_tries as we set it + * here, but setting it correctly to 4/2 or so would limit us + * artificially if the RC algorithm wants just two rates, so + * let's say 4/7, we'll redistribute it at TX time, see the + * comments there. + */ + dev->max_rates = 4; + dev->max_rate_tries = 7; + dev->extra_tx_headroom = sizeof(struct p54_hdr) + 4 + + sizeof(struct p54_tx_data); mutex_init(&priv->conf_mutex); init_completion(&priv->eeprom_comp); - init_completion(&priv->stats_comp); - setup_timer(&priv->stats_timer, p54_statistics_timer, - (unsigned long)dev); + INIT_DELAYED_WORK(&priv->work, p54_work); return dev; } @@ -1410,11 +2172,9 @@ EXPORT_SYMBOL_GPL(p54_init_common); void p54_free_common(struct ieee80211_hw *dev) { struct p54_common *priv = dev->priv; - kfree(priv->cached_stats); kfree(priv->iq_autocal); kfree(priv->output_limit); kfree(priv->curve_data); - kfree(priv->cached_vdcf); } EXPORT_SYMBOL_GPL(p54_free_common); diff --git a/drivers/net/wireless/p54/p54common.h b/drivers/net/wireless/p54/p54common.h index 2fa994cfcfed413cfdf08f9d6c043cec89b7536a..f5729de83fe118eaeb36ea55c9f9cecdacd2c40b 100644 --- a/drivers/net/wireless/p54/p54common.h +++ b/drivers/net/wireless/p54/p54common.h @@ -7,8 +7,12 @@ * Copyright (c) 2006, Michael Wu * Copyright (c) 2007, Christian Lamparter * - * Based on the islsm (softmac prism54) driver, which is: - * Copyright 2004-2006 Jean-Baptiste Note , et al. + * Based on: + * - the islsm (softmac prism54) driver, which is: + * Copyright 2004-2006 Jean-Baptiste Note , et al. + * + * - LMAC API interface header file for STLC4560 (lmac_longbow.h) + * Copyright (C) 2007 Conexant Systems, 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 @@ -19,9 +23,24 @@ struct bootrec { __le32 code; __le32 len; u32 data[10]; - __le16 rx_mtu; } __attribute__((packed)); +#define PDR_SYNTH_FRONTEND_MASK 0x0007 +#define PDR_SYNTH_IQ_CAL_MASK 0x0018 +#define PDR_SYNTH_IQ_CAL_PA_DETECTOR 0x0000 +#define PDR_SYNTH_IQ_CAL_DISABLED 0x0008 +#define PDR_SYNTH_IQ_CAL_ZIF 0x0010 +#define PDR_SYNTH_FAA_SWITCH_MASK 0x0020 +#define PDR_SYNTH_FAA_SWITCH_ENABLED 0x0001 +#define PDR_SYNTH_24_GHZ_MASK 0x0040 +#define PDR_SYNTH_24_GHZ_DISABLED 0x0040 +#define PDR_SYNTH_5_GHZ_MASK 0x0080 +#define PDR_SYNTH_5_GHZ_DISABLED 0x0080 +#define PDR_SYNTH_RX_DIV_MASK 0x0100 +#define PDR_SYNTH_RX_DIV_SUPPORTED 0x0100 +#define PDR_SYNTH_TX_DIV_MASK 0x0200 +#define PDR_SYNTH_TX_DIV_SUPPORTED 0x0200 + struct bootrec_exp_if { __le16 role; __le16 if_id; @@ -30,6 +49,13 @@ struct bootrec_exp_if { __le16 top_compat; } __attribute__((packed)); +#define BR_DESC_PRIV_CAP_WEP BIT(0) +#define BR_DESC_PRIV_CAP_TKIP BIT(1) +#define BR_DESC_PRIV_CAP_MICHAEL BIT(2) +#define BR_DESC_PRIV_CAP_CCX_CP BIT(3) +#define BR_DESC_PRIV_CAP_CCX_MIC BIT(4) +#define BR_DESC_PRIV_CAP_AESCCMP BIT(5) + struct bootrec_desc { __le16 modes; __le16 flags; @@ -37,8 +63,15 @@ struct bootrec_desc { __le32 rx_end; u8 headroom; u8 tailroom; - u8 unimportant[6]; + u8 tx_queues; + u8 tx_depth; + u8 privacy_caps; + u8 rx_keycache_size; + u8 time_size; + u8 padding; u8 rates[16]; + u8 padding2[4]; + __le16 rx_mtu; } __attribute__((packed)); #define BR_CODE_MIN 0x80000000 @@ -51,6 +84,31 @@ struct bootrec_desc { #define BR_CODE_END_OF_BRA 0xFF0000FF #define LEGACY_BR_CODE_END_OF_BRA 0xFFFFFFFF +#define P54_HDR_FLAG_DATA_ALIGN BIT(14) +#define P54_HDR_FLAG_DATA_OUT_PROMISC BIT(0) +#define P54_HDR_FLAG_DATA_OUT_TIMESTAMP BIT(1) +#define P54_HDR_FLAG_DATA_OUT_SEQNR BIT(2) +#define P54_HDR_FLAG_DATA_OUT_BIT3 BIT(3) +#define P54_HDR_FLAG_DATA_OUT_BURST BIT(4) +#define P54_HDR_FLAG_DATA_OUT_NOCANCEL BIT(5) +#define P54_HDR_FLAG_DATA_OUT_CLEARTIM BIT(6) +#define P54_HDR_FLAG_DATA_OUT_HITCHHIKE BIT(7) +#define P54_HDR_FLAG_DATA_OUT_COMPRESS BIT(8) +#define P54_HDR_FLAG_DATA_OUT_CONCAT BIT(9) +#define P54_HDR_FLAG_DATA_OUT_PCS_ACCEPT BIT(10) +#define P54_HDR_FLAG_DATA_OUT_WAITEOSP BIT(11) + +#define P54_HDR_FLAG_DATA_IN_FCS_GOOD BIT(0) +#define P54_HDR_FLAG_DATA_IN_MATCH_MAC BIT(1) +#define P54_HDR_FLAG_DATA_IN_MCBC BIT(2) +#define P54_HDR_FLAG_DATA_IN_BEACON BIT(3) +#define P54_HDR_FLAG_DATA_IN_MATCH_BSS BIT(4) +#define P54_HDR_FLAG_DATA_IN_BCAST_BSS BIT(5) +#define P54_HDR_FLAG_DATA_IN_DATA BIT(6) +#define P54_HDR_FLAG_DATA_IN_TRUNCATED BIT(7) +#define P54_HDR_FLAG_DATA_IN_BIT8 BIT(8) +#define P54_HDR_FLAG_DATA_IN_TRANSPARENT BIT(9) + /* PDA defines are Copyright (C) 2005 Nokia Corporation (taken from islsm_pda.h) */ struct pda_entry { @@ -117,6 +175,11 @@ struct pda_pa_curve_data { u8 data[0]; } __attribute__ ((packed)); +struct pda_rssi_cal_entry { + __le16 mul; + __le16 add; +} __attribute__ ((packed)); + /* * this defines the PDR codes used to build PDAs as defined in document * number 553155. The current implementation mirrors version 1.1 of the @@ -165,6 +228,19 @@ struct pda_pa_curve_data { #define PDR_BASEBAND_REGISTERS 0x8000 #define PDR_PER_CHANNEL_BASEBAND_REGISTERS 0x8001 +/* PDR definitions for default country & country list */ +#define PDR_COUNTRY_CERT_CODE 0x80 +#define PDR_COUNTRY_CERT_CODE_REAL 0x00 +#define PDR_COUNTRY_CERT_CODE_PSEUDO 0x80 +#define PDR_COUNTRY_CERT_BAND 0x40 +#define PDR_COUNTRY_CERT_BAND_2GHZ 0x00 +#define PDR_COUNTRY_CERT_BAND_5GHZ 0x40 +#define PDR_COUNTRY_CERT_IODOOR 0x30 +#define PDR_COUNTRY_CERT_IODOOR_BOTH 0x00 +#define PDR_COUNTRY_CERT_IODOOR_INDOOR 0x20 +#define PDR_COUNTRY_CERT_IODOOR_OUTDOOR 0x30 +#define PDR_COUNTRY_CERT_INDEX 0x0F + /* stored in skb->cb */ struct memrecord { u32 start_addr; @@ -172,41 +248,108 @@ struct memrecord { }; struct p54_eeprom_lm86 { - __le16 offset; - __le16 len; - u8 data[0]; + union { + struct { + __le16 offset; + __le16 len; + u8 data[0]; + } v1; + struct { + __le32 offset; + __le16 len; + u8 magic2; + u8 pad; + u8 magic[4]; + u8 data[0]; + } v2; + } __attribute__ ((packed)); } __attribute__ ((packed)); -struct p54_rx_hdr { - __le16 magic; +enum p54_rx_decrypt_status { + P54_DECRYPT_NONE = 0, + P54_DECRYPT_OK, + P54_DECRYPT_NOKEY, + P54_DECRYPT_NOMICHAEL, + P54_DECRYPT_NOCKIPMIC, + P54_DECRYPT_FAIL_WEP, + P54_DECRYPT_FAIL_TKIP, + P54_DECRYPT_FAIL_MICHAEL, + P54_DECRYPT_FAIL_CKIPKP, + P54_DECRYPT_FAIL_CKIPMIC, + P54_DECRYPT_FAIL_AESCCMP +}; + +struct p54_rx_data { + __le16 flags; __le16 len; __le16 freq; u8 antenna; u8 rate; u8 rssi; u8 quality; - u16 unknown2; + u8 decrypt_status; + u8 rssi_raw; __le32 tsf32; __le32 unalloc0; u8 align[0]; } __attribute__ ((packed)); -struct p54_frame_sent_hdr { +enum p54_trap_type { + P54_TRAP_SCAN = 0, + P54_TRAP_TIMER, + P54_TRAP_BEACON_TX, + P54_TRAP_FAA_RADIO_ON, + P54_TRAP_FAA_RADIO_OFF, + P54_TRAP_RADAR, + P54_TRAP_NO_BEACON, + P54_TRAP_TBTT, + P54_TRAP_SCO_ENTER, + P54_TRAP_SCO_EXIT +}; + +struct p54_trap { + __le16 event; + __le16 frequency; +} __attribute__ ((packed)); + +enum p54_frame_sent_status { + P54_TX_OK = 0, + P54_TX_FAILED, + P54_TX_PSM, + P54_TX_PSM_CANCELLED = 4 +}; + +struct p54_frame_sent { u8 status; - u8 retries; - __le16 ack_rssi; + u8 tries; + u8 ack_rssi; + u8 quality; __le16 seq; - u16 rate; + u8 antenna; + u8 padding; } __attribute__ ((packed)); -struct p54_tx_control_allocdata { +enum p54_tx_data_crypt { + P54_CRYPTO_NONE = 0, + P54_CRYPTO_WEP, + P54_CRYPTO_TKIP, + P54_CRYPTO_TKIPMICHAEL, + P54_CRYPTO_CCX_WEPMIC, + P54_CRYPTO_CCX_KPMIC, + P54_CRYPTO_CCX_KP, + P54_CRYPTO_AESCCMP +}; + +struct p54_tx_data { u8 rateset[8]; - u8 unalloc0[2]; + u8 rts_rate_idx; + u8 crypt_offset; u8 key_type; u8 key_len; u8 key[16]; u8 hw_queue; - u8 unalloc1[9]; + u8 backlog; + __le16 durations[4]; u8 tx_antenna; u8 output_power; u8 cts_rate; @@ -214,8 +357,23 @@ struct p54_tx_control_allocdata { u8 align[0]; } __attribute__ ((packed)); -struct p54_tx_control_filter { - __le16 filter_type; +/* unit is ms */ +#define P54_TX_FRAME_LIFETIME 2000 +#define P54_TX_TIMEOUT 4000 +#define P54_STATISTICS_UPDATE 5000 + +#define P54_FILTER_TYPE_NONE 0 +#define P54_FILTER_TYPE_STATION BIT(0) +#define P54_FILTER_TYPE_IBSS BIT(1) +#define P54_FILTER_TYPE_AP BIT(2) +#define P54_FILTER_TYPE_TRANSPARENT BIT(3) +#define P54_FILTER_TYPE_PROMISCUOUS BIT(4) +#define P54_FILTER_TYPE_HIBERNATE BIT(5) +#define P54_FILTER_TYPE_NOACK BIT(6) +#define P54_FILTER_TYPE_RX_DISABLED BIT(7) + +struct p54_setup_mac { + __le16 mac_mode; u8 mac_addr[ETH_ALEN]; u8 bssid[ETH_ALEN]; u8 rx_antenna; @@ -235,17 +393,29 @@ struct p54_tx_control_filter { __le16 max_rx; __le16 rxhw; __le16 timer; - __le16 unalloc0; - __le32 unalloc1; + __le16 truncate; + __le32 basic_rate_mask; + u8 sbss_offset; + u8 mcast_window; + u8 rx_rssi_threshold; + u8 rx_ed_threshold; + __le32 ref_clock; + __le16 lpf_bandwidth; + __le16 osc_start_delay; } v2 __attribute__ ((packed)); } __attribute__ ((packed)); } __attribute__ ((packed)); -#define P54_TX_CONTROL_FILTER_V1_LEN (sizeof(struct p54_tx_control_filter)) -#define P54_TX_CONTROL_FILTER_V2_LEN (sizeof(struct p54_tx_control_filter)-8) +#define P54_SETUP_V1_LEN 40 +#define P54_SETUP_V2_LEN (sizeof(struct p54_setup_mac)) -struct p54_tx_control_channel { - __le16 flags; +#define P54_SCAN_EXIT BIT(0) +#define P54_SCAN_TRAP BIT(1) +#define P54_SCAN_ACTIVE BIT(2) +#define P54_SCAN_FILTER BIT(3) + +struct p54_scan { + __le16 mode; __le16 dwell; u8 padding1[20]; struct pda_iq_autocal_entry iq_autocal; @@ -261,45 +431,35 @@ struct p54_tx_control_channel { u8 dup_16qam; u8 dup_64qam; union { - struct { - __le16 rssical_mul; - __le16 rssical_add; - } v1 __attribute__ ((packed)); + struct pda_rssi_cal_entry v1_rssi; struct { __le32 basic_rate_mask; - u8 rts_rates[8]; - __le16 rssical_mul; - __le16 rssical_add; + u8 rts_rates[8]; + struct pda_rssi_cal_entry rssi; } v2 __attribute__ ((packed)); } __attribute__ ((packed)); } __attribute__ ((packed)); -#define P54_TX_CONTROL_CHANNEL_V1_LEN (sizeof(struct p54_tx_control_channel)-12) -#define P54_TX_CONTROL_CHANNEL_V2_LEN (sizeof(struct p54_tx_control_channel)) +#define P54_SCAN_V1_LEN 0x70 +#define P54_SCAN_V2_LEN 0x7c -struct p54_tx_control_led { +struct p54_led { __le16 mode; __le16 led_temporary; __le16 led_permanent; __le16 duration; } __attribute__ ((packed)); -struct p54_tx_vdcf_queues { - __le16 aifs; - __le16 cwmin; - __le16 cwmax; - __le16 txop; -} __attribute__ ((packed)); - -struct p54_tx_control_vdcf { - u8 padding; +struct p54_edcf { + u8 flags; u8 slottime; - u8 magic1; - u8 magic2; - struct p54_tx_vdcf_queues queue[8]; - u8 pad2[4]; + u8 sifs; + u8 eofpad; + struct p54_edcf_queue_param queue[8]; + u8 mapping[4]; __le16 frameburst; + __le16 round_trip_delay; } __attribute__ ((packed)); struct p54_statistics { @@ -312,14 +472,103 @@ struct p54_statistics { __le32 tsf32; __le32 airtime; __le32 noise; - __le32 unkn[10]; /* CCE / CCA / RADAR */ + __le32 sample_noise[8]; + __le32 sample_cca; + __le32 sample_tx; } __attribute__ ((packed)); -struct p54_tx_control_xbow_synth { +struct p54_xbow_synth { __le16 magic1; __le16 magic2; __le16 freq; u32 padding[5]; } __attribute__ ((packed)); +struct p54_timer { + __le32 interval; +} __attribute__ ((packed)); + +struct p54_keycache { + u8 entry; + u8 key_id; + u8 mac[ETH_ALEN]; + u8 padding[2]; + u8 key_type; + u8 key_len; + u8 key[24]; +} __attribute__ ((packed)); + +struct p54_burst { + u8 flags; + u8 queue; + u8 backlog; + u8 pad; + __le16 durations[32]; +} __attribute__ ((packed)); + +struct p54_psm_interval { + __le16 interval; + __le16 periods; +} __attribute__ ((packed)); + +#define P54_PSM BIT(0) +#define P54_PSM_DTIM BIT(1) +#define P54_PSM_MCBC BIT(2) +#define P54_PSM_CHECKSUM BIT(3) +#define P54_PSM_SKIP_MORE_DATA BIT(4) +#define P54_PSM_BEACON_TIMEOUT BIT(5) +#define P54_PSM_HFOSLEEP BIT(6) +#define P54_PSM_AUTOSWITCH_SLEEP BIT(7) +#define P54_PSM_LPIT BIT(8) +#define P54_PSM_BF_UCAST_SKIP BIT(9) +#define P54_PSM_BF_MCAST_SKIP BIT(10) + +struct p54_psm { + __le16 mode; + __le16 aid; + struct p54_psm_interval intervals[4]; + u8 beacon_rssi_skip_max; + u8 rssi_delta_threshold; + u8 nr; + u8 exclude[1]; +} __attribute__ ((packed)); + +#define MC_FILTER_ADDRESS_NUM 4 + +struct p54_group_address_table { + __le16 filter_enable; + __le16 num_address; + u8 mac_list[MC_FILTER_ADDRESS_NUM][ETH_ALEN]; +} __attribute__ ((packed)); + +struct p54_txcancel { + __le32 req_id; +} __attribute__ ((packed)); + +struct p54_sta_unlock { + u8 addr[ETH_ALEN]; + u16 padding; +} __attribute__ ((packed)); + +#define P54_TIM_CLEAR BIT(15) +struct p54_tim { + u8 count; + u8 padding[3]; + __le16 entry[8]; +} __attribute__ ((packed)); + +struct p54_cce_quiet { + __le32 period; +} __attribute__ ((packed)); + +struct p54_bt_balancer { + __le16 prio_thresh; + __le16 acl_thresh; +} __attribute__ ((packed)); + +struct p54_arp_table { + __le16 filter_enable; + u8 ipv4_addr[4]; +} __attribute__ ((packed)); + #endif /* P54COMMON_H */ diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c index 88b3cad8b65e0c72b18bcde9d02c2dc11f2f0b97..aa367a0ddc49139ac51a097730a0f464d97c24e0 100644 --- a/drivers/net/wireless/p54/p54pci.c +++ b/drivers/net/wireless/p54/p54pci.c @@ -28,6 +28,7 @@ MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Prism54 PCI wireless driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54pci"); +MODULE_FIRMWARE("isl3886pci"); static struct pci_device_id p54p_table[] __devinitdata = { /* Intersil PRISM Duette/Prism GT Wireless LAN adapter */ @@ -46,7 +47,6 @@ MODULE_DEVICE_TABLE(pci, p54p_table); static int p54p_upload_firmware(struct ieee80211_hw *dev) { struct p54p_priv *priv = dev->priv; - const struct firmware *fw_entry = NULL; __le32 reg; int err; __le32 *data; @@ -72,21 +72,15 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_WRITE(ctrl_stat, reg); wmb(); - err = request_firmware(&fw_entry, "isl3886", &priv->pdev->dev); - if (err) { - printk(KERN_ERR "%s (p54pci): cannot find firmware " - "(isl3886)\n", pci_name(priv->pdev)); - return err; - } + /* wait for the firmware to reset properly */ + mdelay(10); - err = p54_parse_firmware(dev, fw_entry); - if (err) { - release_firmware(fw_entry); + err = p54_parse_firmware(dev, priv->firmware); + if (err) return err; - } - data = (__le32 *) fw_entry->data; - remains = fw_entry->size; + data = (__le32 *) priv->firmware->data; + remains = priv->firmware->size; device_addr = ISL38XX_DEV_FIRMWARE_ADDR; while (remains) { u32 i = 0; @@ -104,8 +98,6 @@ static int p54p_upload_firmware(struct ieee80211_hw *dev) P54P_READ(int_enable); } - release_firmware(fw_entry); - reg = P54P_READ(ctrl_stat); reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_CLKRUN); reg &= cpu_to_le32(~ISL38XX_CTRL_STAT_RESET); @@ -235,7 +227,9 @@ static void p54p_check_tx_ring(struct ieee80211_hw *dev, u32 *index, while (i != idx) { desc = &ring[i]; - kfree(tx_buf[i]); + if (tx_buf[i]) + if (FREE_AFTER_TX((struct sk_buff *) tx_buf[i])) + p54_free_skb(dev, tx_buf[i]); tx_buf[i] = NULL; pci_unmap_single(priv->pdev, le32_to_cpu(desc->host_addr), @@ -306,8 +300,7 @@ static irqreturn_t p54p_interrupt(int irq, void *dev_id) return reg ? IRQ_HANDLED : IRQ_NONE; } -static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54p_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54p_priv *priv = dev->priv; struct p54p_ring_control *ring_control = priv->ring_control; @@ -322,28 +315,21 @@ static void p54p_tx(struct ieee80211_hw *dev, struct p54_control_hdr *data, idx = le32_to_cpu(ring_control->host_idx[1]); i = idx % ARRAY_SIZE(ring_control->tx_data); - mapping = pci_map_single(priv->pdev, data, len, PCI_DMA_TODEVICE); + priv->tx_buf_data[i] = skb; + mapping = pci_map_single(priv->pdev, skb->data, skb->len, + PCI_DMA_TODEVICE); desc = &ring_control->tx_data[i]; desc->host_addr = cpu_to_le32(mapping); - desc->device_addr = data->req_id; - desc->len = cpu_to_le16(len); + desc->device_addr = ((struct p54_hdr *)skb->data)->req_id; + desc->len = cpu_to_le16(skb->len); desc->flags = 0; wmb(); ring_control->host_idx[1] = cpu_to_le32(idx + 1); - - if (free_on_tx) - priv->tx_buf_data[i] = data; - spin_unlock_irqrestore(&priv->lock, flags); P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_UPDATE)); P54P_READ(dev_int); - - /* FIXME: unlikely to happen because the device usually runs out of - memory before we fill the ring up, but we can make it impossible */ - if (idx - device_idx > ARRAY_SIZE(ring_control->tx_data) - 2) - printk(KERN_INFO "%s: tx overflow.\n", wiphy_name(dev->wiphy)); } static void p54p_stop(struct ieee80211_hw *dev) @@ -393,7 +379,7 @@ static void p54p_stop(struct ieee80211_hw *dev) le16_to_cpu(desc->len), PCI_DMA_TODEVICE); - kfree(priv->tx_buf_data[i]); + p54_free_skb(dev, priv->tx_buf_data[i]); priv->tx_buf_data[i] = NULL; } @@ -405,7 +391,7 @@ static void p54p_stop(struct ieee80211_hw *dev) le16_to_cpu(desc->len), PCI_DMA_TODEVICE); - kfree(priv->tx_buf_mgmt[i]); + p54_free_skb(dev, priv->tx_buf_mgmt[i]); priv->tx_buf_mgmt[i] = NULL; } @@ -481,7 +467,6 @@ static int __devinit p54p_probe(struct pci_dev *pdev, struct ieee80211_hw *dev; unsigned long mem_addr, mem_len; int err; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if (err) { @@ -495,15 +480,14 @@ static int __devinit p54p_probe(struct pci_dev *pdev, if (mem_len < sizeof(struct p54p_csr)) { printk(KERN_ERR "%s (p54pci): Too short PCI resources\n", pci_name(pdev)); - pci_disable_device(pdev); - return err; + goto err_disable_dev; } err = pci_request_regions(pdev, "p54pci"); if (err) { printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n", pci_name(pdev)); - return err; + goto err_disable_dev; } if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) || @@ -556,6 +540,17 @@ static int __devinit p54p_probe(struct pci_dev *pdev, spin_lock_init(&priv->lock); tasklet_init(&priv->rx_tasklet, p54p_rx_tasklet, (unsigned long)dev); + err = request_firmware(&priv->firmware, "isl3886pci", + &priv->pdev->dev); + if (err) { + printk(KERN_ERR "%s (p54pci): cannot find firmware " + "(isl3886pci)\n", pci_name(priv->pdev)); + err = request_firmware(&priv->firmware, "isl3886", + &priv->pdev->dev); + if (err) + goto err_free_common; + } + err = p54p_open(dev); if (err) goto err_free_common; @@ -574,6 +569,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, return 0; err_free_common: + release_firmware(priv->firmware); p54_free_common(dev); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); @@ -587,6 +583,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev, err_free_reg: pci_release_regions(pdev); + err_disable_dev: pci_disable_device(pdev); return err; } @@ -601,6 +598,7 @@ static void __devexit p54p_remove(struct pci_dev *pdev) ieee80211_unregister_hw(dev); priv = dev->priv; + release_firmware(priv->firmware); pci_free_consistent(pdev, sizeof(*priv->ring_control), priv->ring_control, priv->ring_control_dma); p54_free_common(dev); diff --git a/drivers/net/wireless/p54/p54pci.h b/drivers/net/wireless/p54/p54pci.h index 4a6778070afc1fc3da1a2cbc9c9d598db9d07e75..fbb683953fb258b8949627398fff499fd21355fd 100644 --- a/drivers/net/wireless/p54/p54pci.h +++ b/drivers/net/wireless/p54/p54pci.h @@ -93,7 +93,7 @@ struct p54p_priv { struct pci_dev *pdev; struct p54p_csr __iomem *map; struct tasklet_struct rx_tasklet; - + const struct firmware *firmware; spinlock_t lock; struct p54p_ring_control *ring_control; dma_addr_t ring_control_dma; diff --git a/drivers/net/wireless/p54/p54usb.c b/drivers/net/wireless/p54/p54usb.c index 75d749bccb0d13e17104b67e348c3723bbb1032b..c44a200059d21c4ce0aae4a6f66b2e61af73984e 100644 --- a/drivers/net/wireless/p54/p54usb.c +++ b/drivers/net/wireless/p54/p54usb.c @@ -28,6 +28,8 @@ MODULE_AUTHOR("Michael Wu "); MODULE_DESCRIPTION("Prism54 USB wireless driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("prism54usb"); +MODULE_FIRMWARE("isl3886usb"); +MODULE_FIRMWARE("isl3887usb"); static struct usb_device_id p54u_table[] __devinitdata = { /* Version 1 devices (pci chip + net2280) */ @@ -84,13 +86,13 @@ static void p54u_rx_cb(struct urb *urb) struct ieee80211_hw *dev = info->dev; struct p54u_priv *priv = dev->priv; + skb_unlink(skb, &priv->rx_queue); + if (unlikely(urb->status)) { - info->urb = NULL; - usb_free_urb(urb); + dev_kfree_skb_irq(skb); return; } - skb_unlink(skb, &priv->rx_queue); skb_put(skb, urb->actual_length); if (priv->hw_type == P54U_NET2280) @@ -103,7 +105,6 @@ static void p54u_rx_cb(struct urb *urb) if (p54_rx(dev, skb)) { skb = dev_alloc_skb(priv->common.rx_mtu + 32); if (unlikely(!skb)) { - usb_free_urb(urb); /* TODO check rx queue length and refill *somewhere* */ return; } @@ -113,7 +114,6 @@ static void p54u_rx_cb(struct urb *urb) info->dev = dev; urb->transfer_buffer = skb_tail_pointer(skb); urb->context = skb; - skb_queue_tail(&priv->rx_queue, skb); } else { if (priv->hw_type == P54U_NET2280) skb_push(skb, priv->common.tx_hdr_len); @@ -128,40 +128,56 @@ static void p54u_rx_cb(struct urb *urb) WARN_ON(1); urb->transfer_buffer = skb_tail_pointer(skb); } - - skb_queue_tail(&priv->rx_queue, skb); } - - usb_submit_urb(urb, GFP_ATOMIC); + skb_queue_tail(&priv->rx_queue, skb); + usb_anchor_urb(urb, &priv->submitted); + if (usb_submit_urb(urb, GFP_ATOMIC)) { + skb_unlink(skb, &priv->rx_queue); + usb_unanchor_urb(urb); + dev_kfree_skb_irq(skb); + } } static void p54u_tx_cb(struct urb *urb) { - usb_free_urb(urb); + struct sk_buff *skb = urb->context; + struct ieee80211_hw *dev = (struct ieee80211_hw *) + usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0)); + struct p54u_priv *priv = dev->priv; + + skb_pull(skb, priv->common.tx_hdr_len); + if (FREE_AFTER_TX(skb)) + p54_free_skb(dev, skb); } -static void p54u_tx_free_cb(struct urb *urb) +static void p54u_tx_dummy_cb(struct urb *urb) { } + +static void p54u_free_urbs(struct ieee80211_hw *dev) { - kfree(urb->transfer_buffer); - usb_free_urb(urb); + struct p54u_priv *priv = dev->priv; + usb_kill_anchored_urbs(&priv->submitted); } static int p54u_init_urbs(struct ieee80211_hw *dev) { struct p54u_priv *priv = dev->priv; - struct urb *entry; + struct urb *entry = NULL; struct sk_buff *skb; struct p54u_rx_info *info; + int ret = 0; while (skb_queue_len(&priv->rx_queue) < 32) { skb = __dev_alloc_skb(priv->common.rx_mtu + 32, GFP_KERNEL); - if (!skb) - break; + if (!skb) { + ret = -ENOMEM; + goto err; + } entry = usb_alloc_urb(0, GFP_KERNEL); if (!entry) { - kfree_skb(skb); - break; + ret = -ENOMEM; + goto err; } + usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), skb_tail_pointer(skb), @@ -170,33 +186,32 @@ static int p54u_init_urbs(struct ieee80211_hw *dev) info->urb = entry; info->dev = dev; skb_queue_tail(&priv->rx_queue, skb); - usb_submit_urb(entry, GFP_KERNEL); + + usb_anchor_urb(entry, &priv->submitted); + ret = usb_submit_urb(entry, GFP_KERNEL); + if (ret) { + skb_unlink(skb, &priv->rx_queue); + usb_unanchor_urb(entry); + goto err; + } + usb_free_urb(entry); + entry = NULL; } return 0; -} - -static void p54u_free_urbs(struct ieee80211_hw *dev) -{ - struct p54u_priv *priv = dev->priv; - struct p54u_rx_info *info; - struct sk_buff *skb; - while ((skb = skb_dequeue(&priv->rx_queue))) { - info = (struct p54u_rx_info *) skb->cb; - if (!info->urb) - continue; - - usb_kill_urb(info->urb); - kfree_skb(skb); - } + err: + usb_free_urb(entry); + kfree_skb(skb); + p54u_free_urbs(dev); + return ret; } -static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_3887(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *addr_urb, *data_urb; + int err = 0; addr_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!addr_urb) @@ -209,59 +224,85 @@ static void p54u_tx_3887(struct ieee80211_hw *dev, struct p54_control_hdr *data, } usb_fill_bulk_urb(addr_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), &data->req_id, - sizeof(data->req_id), p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + &((struct p54_hdr *)skb->data)->req_id, 4, + p54u_tx_dummy_cb, dev); usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), data, len, - free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, p54u_tx_cb, skb); + + usb_anchor_urb(addr_urb, &priv->submitted); + err = usb_submit_urb(addr_urb, GFP_ATOMIC); + if (err) { + usb_unanchor_urb(addr_urb); + goto out; + } - usb_submit_urb(addr_urb, GFP_ATOMIC); - usb_submit_urb(data_urb, GFP_ATOMIC); + usb_anchor_urb(addr_urb, &priv->submitted); + err = usb_submit_urb(data_urb, GFP_ATOMIC); + if (err) + usb_unanchor_urb(data_urb); + + out: + usb_free_urb(addr_urb); + usb_free_urb(data_urb); + + if (err) + p54_free_skb(dev, skb); } -static __le32 p54u_lm87_chksum(const u32 *data, size_t length) +static __le32 p54u_lm87_chksum(const __le32 *data, size_t length) { u32 chk = 0; length >>= 2; while (length--) { - chk ^= *data++; + chk ^= le32_to_cpu(*data++); chk = (chk >> 5) ^ (chk << 3); } return cpu_to_le32(chk); } -static void p54u_tx_lm87(struct ieee80211_hw *dev, - struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_lm87(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *data_urb; - struct lm87_tx_hdr *hdr = (void *)data - sizeof(*hdr); + struct lm87_tx_hdr *hdr; + __le32 checksum; + __le32 addr = ((struct p54_hdr *)skb->data)->req_id; data_urb = usb_alloc_urb(0, GFP_ATOMIC); if (!data_urb) return; - hdr->chksum = p54u_lm87_chksum((u32 *)data, len); - hdr->device_addr = data->req_id; + checksum = p54u_lm87_chksum((__le32 *)skb->data, skb->len); + hdr = (struct lm87_tx_hdr *)skb_push(skb, sizeof(*hdr)); + hdr->chksum = checksum; + hdr->device_addr = addr; usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, - len + sizeof(*hdr), free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, - dev); - - usb_submit_urb(data_urb, GFP_ATOMIC); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, p54u_tx_cb, skb); + + usb_anchor_urb(data_urb, &priv->submitted); + if (usb_submit_urb(data_urb, GFP_ATOMIC)) { + usb_unanchor_urb(data_urb); + skb_pull(skb, sizeof(*hdr)); + p54_free_skb(dev, skb); + } + usb_free_urb(data_urb); } -static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *data, - size_t len, int free_on_tx) +static void p54u_tx_net2280(struct ieee80211_hw *dev, struct sk_buff *skb) { struct p54u_priv *priv = dev->priv; struct urb *int_urb, *data_urb; struct net2280_tx_hdr *hdr; struct net2280_reg_write *reg; + int err = 0; + __le32 addr = ((struct p54_hdr *) skb->data)->req_id; + __le16 len = cpu_to_le16(skb->len); reg = kmalloc(sizeof(*reg), GFP_ATOMIC); if (!reg) @@ -284,21 +325,47 @@ static void p54u_tx_net2280(struct ieee80211_hw *dev, struct p54_control_hdr *da reg->addr = cpu_to_le32(P54U_DEV_BASE); reg->val = cpu_to_le32(ISL38XX_DEV_INT_DATA); - len += sizeof(*data); - hdr = (void *)data - sizeof(*hdr); + hdr = (void *)skb_push(skb, sizeof(*hdr)); memset(hdr, 0, sizeof(*hdr)); - hdr->device_addr = data->req_id; - hdr->len = cpu_to_le16(len); + hdr->len = len; + hdr->device_addr = addr; usb_fill_bulk_urb(int_urb, priv->udev, usb_sndbulkpipe(priv->udev, P54U_PIPE_DEV), reg, sizeof(*reg), - p54u_tx_free_cb, dev); - usb_submit_urb(int_urb, GFP_ATOMIC); + p54u_tx_dummy_cb, dev); + + /* + * This flag triggers a code path in the USB subsystem that will + * free what's inside the transfer_buffer after the callback routine + * has completed. + */ + int_urb->transfer_flags |= URB_FREE_BUFFER; usb_fill_bulk_urb(data_urb, priv->udev, - usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), hdr, len + sizeof(*hdr), - free_on_tx ? p54u_tx_free_cb : p54u_tx_cb, dev); - usb_submit_urb(data_urb, GFP_ATOMIC); + usb_sndbulkpipe(priv->udev, P54U_PIPE_DATA), + skb->data, skb->len, p54u_tx_cb, skb); + + usb_anchor_urb(int_urb, &priv->submitted); + err = usb_submit_urb(int_urb, GFP_ATOMIC); + if (err) { + usb_unanchor_urb(int_urb); + goto out; + } + + usb_anchor_urb(data_urb, &priv->submitted); + err = usb_submit_urb(data_urb, GFP_ATOMIC); + if (err) { + usb_unanchor_urb(data_urb); + goto out; + } + out: + usb_free_urb(int_urb); + usb_free_urb(data_urb); + + if (err) { + skb_pull(skb, sizeof(*hdr)); + p54_free_skb(dev, skb); + } } static int p54u_write(struct p54u_priv *priv, @@ -375,7 +442,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) tmp = buf = kmalloc(P54U_FW_BLOCK, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "p54usb: cannot allocate firmware upload buffer!\n"); + dev_err(&priv->udev->dev, "(p54usb) cannot allocate firmware" + "upload buffer!\n"); err = -ENOMEM; goto err_bufalloc; } @@ -383,14 +451,18 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) memcpy(buf, start_string, 4); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 4); if (err) { - printk(KERN_ERR "p54usb: reset failed! (%d)\n", err); + dev_err(&priv->udev->dev, "(p54usb) reset failed! (%d)\n", err); goto err_reset; } - err = request_firmware(&fw_entry, "isl3887usb_bare", &priv->udev->dev); + err = request_firmware(&fw_entry, "isl3887usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3887usb_bare)!\n"); - goto err_req_fw_failed; + dev_err(&priv->udev->dev, "p54usb: cannot find firmware " + "(isl3887usb)\n"); + err = request_firmware(&fw_entry, "isl3887usb_bare", + &priv->udev->dev); + if (err) + goto err_req_fw_failed; } err = p54_parse_firmware(dev, fw_entry); @@ -441,7 +513,8 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_size); if (err) { - printk(KERN_ERR "p54usb: firmware upload failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware " + "upload failed!\n"); goto err_upload_failed; } @@ -452,10 +525,9 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) *((__le32 *)buf) = cpu_to_le32(~crc32_le(~0, fw_entry->data, fw_entry->size)); err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, sizeof(u32)); if (err) { - printk(KERN_ERR "p54usb: firmware upload failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); goto err_upload_failed; } - timeout = jiffies + msecs_to_jiffies(1000); while (!(err = usb_bulk_msg(priv->udev, usb_rcvbulkpipe(priv->udev, P54U_PIPE_DATA), buf, 128, &alen, 1000))) { @@ -463,25 +535,27 @@ static int p54u_upload_firmware_3887(struct ieee80211_hw *dev) break; if (alen > 5 && !memcmp(buf, "ERROR", 5)) { - printk(KERN_INFO "p54usb: firmware upload failed!\n"); err = -EINVAL; break; } if (time_after(jiffies, timeout)) { - printk(KERN_ERR "p54usb: firmware boot timed out!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware boot " + "timed out!\n"); err = -ETIMEDOUT; break; } } - if (err) + if (err) { + dev_err(&priv->udev->dev, "(p54usb) firmware upload failed!\n"); goto err_upload_failed; + } buf[0] = 'g'; buf[1] = '\r'; err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, 2); if (err) { - printk(KERN_ERR "p54usb: firmware boot failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware boot failed!\n"); goto err_upload_failed; } @@ -521,15 +595,21 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) buf = kmalloc(512, GFP_KERNEL); if (!buf) { - printk(KERN_ERR "p54usb: firmware buffer alloc failed!\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware buffer " + "alloc failed!\n"); return -ENOMEM; } - err = request_firmware(&fw_entry, "isl3890usb", &priv->udev->dev); + err = request_firmware(&fw_entry, "isl3886usb", &priv->udev->dev); if (err) { - printk(KERN_ERR "p54usb: cannot find firmware (isl3890usb)!\n"); - kfree(buf); - return err; + dev_err(&priv->udev->dev, "(p54usb) cannot find firmware " + "(isl3886usb)\n"); + err = request_firmware(&fw_entry, "isl3890usb", + &priv->udev->dev); + if (err) { + kfree(buf); + return err; + } } err = p54_parse_firmware(dev, fw_entry); @@ -648,8 +728,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) err = p54u_bulk_msg(priv, P54U_PIPE_DATA, buf, block_len); if (err) { - printk(KERN_ERR "p54usb: firmware block upload " - "failed\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware block " + "upload failed\n"); goto fail; } @@ -682,8 +762,8 @@ static int p54u_upload_firmware_net2280(struct ieee80211_hw *dev) 0x002C | (unsigned long)&devreg->direct_mem_win); if (!(reg & cpu_to_le32(ISL38XX_DMA_STATUS_DONE)) || !(reg & cpu_to_le32(ISL38XX_DMA_STATUS_READY))) { - printk(KERN_ERR "p54usb: firmware DMA transfer " - "failed\n"); + dev_err(&priv->udev->dev, "(p54usb) firmware DMA " + "transfer failed\n"); goto fail; } @@ -786,11 +866,11 @@ static int __devinit p54u_probe(struct usb_interface *intf, struct p54u_priv *priv; int err; unsigned int i, recognized_pipes; - DECLARE_MAC_BUF(mac); dev = p54_init_common(sizeof(*priv)); + if (!dev) { - printk(KERN_ERR "p54usb: ieee80211 alloc failed\n"); + dev_err(&udev->dev, "(p54usb) ieee80211 alloc failed\n"); return -ENOMEM; } @@ -842,6 +922,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, goto err_free_dev; skb_queue_head_init(&priv->rx_queue); + init_usb_anchor(&priv->submitted); p54u_open(dev); err = p54_read_eeprom(dev); @@ -851,7 +932,7 @@ static int __devinit p54u_probe(struct usb_interface *intf, err = ieee80211_register_hw(dev); if (err) { - printk(KERN_ERR "p54usb: Cannot register netdevice\n"); + dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n"); goto err_free_dev; } diff --git a/drivers/net/wireless/p54/p54usb.h b/drivers/net/wireless/p54/p54usb.h index 5b8fe91379c36e947ad3ff23bc8b2bfddaf512c5..54ee738bf2af66c8503ea549d21ff1797b0de4b7 100644 --- a/drivers/net/wireless/p54/p54usb.h +++ b/drivers/net/wireless/p54/p54usb.h @@ -133,6 +133,7 @@ struct p54u_priv { spinlock_t lock; struct sk_buff_head rx_queue; + struct usb_anchor submitted; }; #endif /* P54USB_H */ diff --git a/drivers/net/wireless/prism54/isl_ioctl.c b/drivers/net/wireless/prism54/isl_ioctl.c index 16e68f4b654a94370433cd928c23405f4a5be950..57a150a22de5c6544bee00f7799e5b2caf9164e6 100644 --- a/drivers/net/wireless/prism54/isl_ioctl.c +++ b/drivers/net/wireless/prism54/isl_ioctl.c @@ -2028,12 +2028,11 @@ static void format_event(islpci_private *priv, char *dest, const char *str, const struct obj_mlme *mlme, u16 *length, int error) { - DECLARE_MAC_BUF(mac); int n = snprintf(dest, IW_CUSTOM_MAX, - "%s %s %s %s (%2.2X)", + "%s %s %pM %s (%2.2X)", str, ((priv->iw_mode == IW_MODE_MASTER) ? "from" : "to"), - print_mac(mac, mlme->address), + mlme->address, (error ? (mlme->code ? " : REJECTED " : " : ACCEPTED ") : ""), mlme->code); BUG_ON(n > IW_CUSTOM_MAX); @@ -2113,7 +2112,6 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, { struct list_head *ptr; struct islpci_bss_wpa_ie *bss = NULL; - DECLARE_MAC_BUF(mac); if (wpa_ie_len > MAX_WPA_IE_LEN) wpa_ie_len = MAX_WPA_IE_LEN; @@ -2154,7 +2152,7 @@ prism54_wpa_bss_ie_add(islpci_private *priv, u8 *bssid, bss->last_update = jiffies; } else { printk(KERN_DEBUG "Failed to add BSS WPA entry for " - "%s\n", print_mac(mac, bssid)); + "%pM\n", bssid); } /* expire old entries from WPA list */ @@ -2219,7 +2217,6 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, { struct ieee80211_beacon_phdr *hdr; u8 *pos, *end; - DECLARE_MAC_BUF(mac); if (!priv->wpa) return; @@ -2230,7 +2227,7 @@ prism54_process_bss_data(islpci_private *priv, u32 oid, u8 *addr, while (pos < end) { if (pos + 2 + pos[1] > end) { printk(KERN_DEBUG "Parsing Beacon/ProbeResp failed " - "for %s\n", print_mac(mac, addr)); + "for %pM\n", addr); return; } if (pos[0] == WLAN_EID_GENERIC && pos[1] >= 4 && @@ -2269,7 +2266,6 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, size_t len = 0; /* u16, better? */ u8 *payload = NULL, *pos = NULL; int ret; - DECLARE_MAC_BUF(mac); /* I think all trapable objects are listed here. * Some oids have a EX version. The difference is that they are emitted @@ -2358,8 +2354,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, break; memcpy(&confirm->address, mlmeex->address, ETH_ALEN); - printk(KERN_DEBUG "Authenticate from: address:\t%s\n", - print_mac(mac, mlmeex->address)); + printk(KERN_DEBUG "Authenticate from: address:\t%pM\n", + mlmeex->address); confirm->id = -1; /* or mlmeex->id ? */ confirm->state = 0; /* not used */ confirm->code = 0; @@ -2404,8 +2400,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from address:\t%s\n", - print_mac(mac, mlmeex->address)); + printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", + mlmeex->address); kfree(confirm); break; } @@ -2441,8 +2437,8 @@ prism54_process_trap_helper(islpci_private *priv, enum oid_num_t oid, wpa_ie_len = prism54_wpa_bss_ie_get(priv, mlmeex->address, wpa_ie); if (!wpa_ie_len) { - printk(KERN_DEBUG "No WPA IE found from address:\t%s\n", - print_mac(mac, mlmeex->address)); + printk(KERN_DEBUG "No WPA IE found from address:\t%pM\n", + mlmeex->address); kfree(confirm); break; } diff --git a/drivers/net/wireless/prism54/islpci_hotplug.c b/drivers/net/wireless/prism54/islpci_hotplug.c index af2e4f2405f2577ae0f047d37827c6eb532054f8..9a72b1e3e163bb597a075a11c65e9a66a3958312 100644 --- a/drivers/net/wireless/prism54/islpci_hotplug.c +++ b/drivers/net/wireless/prism54/islpci_hotplug.c @@ -93,7 +93,7 @@ static struct pci_driver prism54_driver = { Module initialization functions ******************************************************************************/ -int +static int prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct net_device *ndev; @@ -216,7 +216,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id) static volatile int __in_cleanup_module = 0; /* this one removes one(!!) instance only */ -void +static void prism54_remove(struct pci_dev *pdev) { struct net_device *ndev = pci_get_drvdata(pdev); @@ -259,7 +259,7 @@ prism54_remove(struct pci_dev *pdev) pci_disable_device(pdev); } -int +static int prism54_suspend(struct pci_dev *pdev, pm_message_t state) { struct net_device *ndev = pci_get_drvdata(pdev); @@ -282,7 +282,7 @@ prism54_suspend(struct pci_dev *pdev, pm_message_t state) return 0; } -int +static int prism54_resume(struct pci_dev *pdev) { struct net_device *ndev = pci_get_drvdata(pdev); diff --git a/drivers/net/wireless/ray_cs.c b/drivers/net/wireless/ray_cs.c index 1404a57175207f71d39ac28b12ad78651610d0c1..99ec7d62251813e95caf0c72bac8c1c0439fe3fe 100644 --- a/drivers/net/wireless/ray_cs.c +++ b/drivers/net/wireless/ray_cs.c @@ -414,7 +414,6 @@ static int ray_config(struct pcmcia_device *link) memreq_t mem; struct net_device *dev = (struct net_device *)link->priv; ray_dev_t *local = netdev_priv(dev); - DECLARE_MAC_BUF(mac); DEBUG(1, "ray_config(0x%p)\n", link); @@ -485,8 +484,8 @@ static int ray_config(struct pcmcia_device *link) strcpy(local->node.dev_name, dev->name); link->dev_node = &local->node; - printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %s\n", - dev->name, dev->irq, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n", + dev->name, dev->irq, dev->dev_addr); return 0; @@ -829,7 +828,7 @@ static int ray_resume(struct pcmcia_device *link) } /*===========================================================================*/ -int ray_dev_init(struct net_device *dev) +static int ray_dev_init(struct net_device *dev) { #ifdef RAY_IMMEDIATE_INIT int i; @@ -2285,7 +2284,6 @@ static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned i skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; local->stats.rx_packets++; local->stats.rx_bytes += total_len; @@ -2595,7 +2593,6 @@ static int ray_cs_proc_show(struct seq_file *m, void *v) UCHAR *p; struct freq_hop_element *pfh; UCHAR c[33]; - DECLARE_MAC_BUF(mac); link = this_device; if (!link) @@ -2623,8 +2620,7 @@ static int ray_cs_proc_show(struct seq_file *m, void *v) nettype[local->sparm.b5.a_network_type], c); p = local->bss_id; - seq_printf(m, "BSSID = %s\n", - print_mac(mac, p)); + seq_printf(m, "BSSID = %pM\n", p); seq_printf(m, "Country code = %d\n", local->sparm.b5.a_curr_country_code); diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c index 2b414899dfa08107f8c2faba4be42e0aa2ffde79..607ce9f61b5400fa0e43d0bd675bfd0674dec406 100644 --- a/drivers/net/wireless/rndis_wlan.c +++ b/drivers/net/wireless/rndis_wlan.c @@ -37,11 +37,11 @@ #include #include #include +#include #include #include #include #include -#include #include #include @@ -1104,7 +1104,7 @@ static int rndis_iw_get_range(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_range *range = (struct iw_range *)extra; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int len, ret, i, j, num, has_80211g_rates; u8 rates[8]; @@ -1210,7 +1210,7 @@ static int rndis_iw_get_range(struct net_device *dev, static int rndis_iw_get_name(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); strcpy(wrqu->name, priv->name); @@ -1223,7 +1223,7 @@ static int rndis_iw_set_essid(struct net_device *dev, { struct ndis_80211_ssid ssid; int length = wrqu->essid.length; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); devdbg(usbdev, "SIOCSIWESSID: [flags:%d,len:%d] '%.32s'", wrqu->essid.flags, wrqu->essid.length, essid); @@ -1250,7 +1250,7 @@ static int rndis_iw_get_essid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *essid) { struct ndis_80211_ssid ssid; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); int ret; ret = get_essid(usbdev, &ssid); @@ -1273,15 +1273,14 @@ static int rndis_iw_get_essid(struct net_device *dev, static int rndis_iw_get_bssid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); unsigned char bssid[ETH_ALEN]; int ret; - DECLARE_MAC_BUF(mac); ret = get_bssid(usbdev, bssid); if (ret == 0) - devdbg(usbdev, "SIOCGIWAP: %s", print_mac(mac, bssid)); + devdbg(usbdev, "SIOCGIWAP: %pM", bssid); else devdbg(usbdev, "SIOCGIWAP: "); @@ -1295,12 +1294,11 @@ static int rndis_iw_get_bssid(struct net_device *dev, static int rndis_iw_set_bssid(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); u8 *bssid = (u8 *)wrqu->ap_addr.sa_data; - DECLARE_MAC_BUF(mac); int ret; - devdbg(usbdev, "SIOCSIWAP: %s", print_mac(mac, bssid)); + devdbg(usbdev, "SIOCSIWAP: %pM", bssid); ret = rndis_set_oid(usbdev, OID_802_11_BSSID, bssid, ETH_ALEN); @@ -1318,7 +1316,7 @@ static int rndis_iw_set_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int ret = -ENOTSUPP; @@ -1399,7 +1397,7 @@ static int rndis_iw_get_auth(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_param *p = &wrqu->param; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); switch (p->flags & IW_AUTH_INDEX) { @@ -1431,7 +1429,7 @@ static int rndis_iw_get_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); switch (priv->infra_mode) { @@ -1454,7 +1452,7 @@ static int rndis_iw_get_mode(struct net_device *dev, static int rndis_iw_set_mode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); int mode; devdbg(usbdev, "SIOCSIWMODE: %08x", wrqu->mode); @@ -1479,7 +1477,7 @@ static int rndis_iw_set_mode(struct net_device *dev, static int rndis_iw_set_encode(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int ret, index, key_len; u8 *key; @@ -1542,7 +1540,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); struct ndis_80211_key ndis_key; int keyidx, ret; @@ -1627,7 +1625,7 @@ static int rndis_iw_set_encode_ext(struct net_device *dev, static int rndis_iw_set_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); union iwreq_data evt; int ret = -EINVAL; __le32 tmp; @@ -1652,19 +1650,18 @@ static char *rndis_translate_scan(struct net_device *dev, struct ndis_80211_bssid_ex *bssid) { #ifdef DEBUG - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); #endif - struct ieee80211_info_element *ie; + u8 *ie; char *current_val; int bssid_len, ie_len, i; u32 beacon, atim; struct iw_event iwe; unsigned char sbuf[32]; - DECLARE_MAC_BUF(mac); bssid_len = le32_to_cpu(bssid->length); - devdbg(usbdev, "BSSID %s", print_mac(mac, bssid->mac)); + devdbg(usbdev, "BSSID %pM", bssid->mac); iwe.cmd = SIOCGIWAP; iwe.u.ap_addr.sa_family = ARPHRD_ETHER; memcpy(iwe.u.ap_addr.sa_data, bssid->mac, ETH_ALEN); @@ -1753,20 +1750,20 @@ static char *rndis_translate_scan(struct net_device *dev, ie_len = min(bssid_len - (int)sizeof(*bssid), (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) || - ie->id == MFIE_TYPE_RSN) { + while (ie_len >= 2 && 2 + ie[1] <= ie_len) { + if ((ie[0] == WLAN_EID_GENERIC && ie[1] >= 4 && + memcmp(ie + 2, "\x00\x50\xf2\x01", 4) == 0) || + ie[0] == WLAN_EID_RSN) { devdbg(usbdev, "IE: WPA%d", - (ie->id == MFIE_TYPE_RSN) ? 2 : 1); + (ie[0] == WLAN_EID_RSN) ? 2 : 1); iwe.cmd = IWEVGENIE; - iwe.u.data.length = min(ie->len + 2, MAX_WPA_IE_LEN); - cev = iwe_stream_add_point(info, cev, end_buf, &iwe, - (u8 *)ie); + /* arbitrary cut-off at 64 */ + iwe.u.data.length = min(ie[1] + 2, 64); + cev = iwe_stream_add_point(info, cev, end_buf, &iwe, ie); } - ie_len -= sizeof(*ie) + ie->len; - ie = (struct ieee80211_info_element *)&ie->data[ie->len]; + ie_len -= 2 + ie[1]; + ie += 2 + ie[1]; } return cev; @@ -1776,7 +1773,7 @@ static char *rndis_translate_scan(struct net_device *dev, static int rndis_iw_get_scan(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); void *buf = NULL; char *cev = extra; struct ndis_80211_bssid_list_ex *bssid_list; @@ -1822,7 +1819,7 @@ out: static int rndis_iw_set_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); int ret = 0; @@ -1856,7 +1853,7 @@ static int rndis_iw_set_genie(struct net_device *dev, static int rndis_iw_get_genie(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); devdbg(usbdev, "SIOCGIWGENIE"); @@ -1879,7 +1876,7 @@ static int rndis_iw_get_genie(struct net_device *dev, static int rndis_iw_set_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; devdbg(usbdev, "SIOCSIWRTS"); @@ -1892,7 +1889,7 @@ static int rndis_iw_set_rts(struct net_device *dev, static int rndis_iw_get_rts(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; int len, ret; @@ -1913,7 +1910,7 @@ static int rndis_iw_get_rts(struct net_device *dev, static int rndis_iw_set_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; devdbg(usbdev, "SIOCSIWFRAG"); @@ -1927,7 +1924,7 @@ static int rndis_iw_set_frag(struct net_device *dev, static int rndis_iw_get_frag(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; int len, ret; @@ -1947,7 +1944,7 @@ static int rndis_iw_get_frag(struct net_device *dev, static int rndis_iw_set_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); devdbg(usbdev, "SIOCSIWNICK"); @@ -1964,7 +1961,7 @@ static int rndis_iw_set_nick(struct net_device *dev, static int rndis_iw_get_nick(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); wrqu->data.flags = 1; @@ -1980,7 +1977,7 @@ static int rndis_iw_get_nick(struct net_device *dev, static int rndis_iw_set_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct ndis_80211_conf config; unsigned int dsconfig; int len, ret; @@ -2011,7 +2008,7 @@ static int rndis_iw_set_freq(struct net_device *dev, static int rndis_iw_get_freq(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct ndis_80211_conf config; int len, ret; @@ -2028,7 +2025,7 @@ static int rndis_iw_get_freq(struct net_device *dev, static int rndis_iw_get_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); __le32 tx_power; int ret = 0, len; @@ -2062,7 +2059,7 @@ static int rndis_iw_get_txpower(struct net_device *dev, static int rndis_iw_set_txpower(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); __le32 tx_power = 0; int ret = 0; @@ -2114,7 +2111,7 @@ static int rndis_iw_set_txpower(struct net_device *dev, static int rndis_iw_get_rate(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); __le32 tmp; int ret, len; @@ -2132,7 +2129,7 @@ static int rndis_iw_get_rate(struct net_device *dev, static int rndis_iw_set_mlme(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); struct iw_mlme *mlme = (struct iw_mlme *)extra; unsigned char bssid[ETH_ALEN]; @@ -2157,7 +2154,7 @@ static int rndis_iw_set_mlme(struct net_device *dev, static struct iw_statistics *rndis_get_wireless_stats(struct net_device *dev) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); unsigned long flags; @@ -2287,7 +2284,7 @@ get_bssid: static void rndis_wext_set_multicast_list(struct net_device *dev) { - struct usbnet *usbdev = dev->priv; + struct usbnet *usbdev = netdev_priv(dev); struct rndis_wext_private *priv = get_rndis_wext_priv(usbdev); if (test_bit(WORK_SET_MULTICAST_LIST, &priv->work_pending)) diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig index 95511ac2247054de571fa2aeb896ba10936681eb..178b313293b4537a45d3f00f7e6a9b6078802439 100644 --- a/drivers/net/wireless/rt2x00/Kconfig +++ b/drivers/net/wireless/rt2x00/Kconfig @@ -57,6 +57,7 @@ config RT2500USB tristate "Ralink rt2500 (USB) support" depends on USB select RT2X00_LIB_USB + select RT2X00_LIB_CRYPTO ---help--- This adds support for rt2500 wireless chipset family. Supported chips: RT2571 & RT2572. diff --git a/drivers/net/wireless/rt2x00/rt2400pci.c b/drivers/net/wireless/rt2x00/rt2400pci.c index 08cb9eec16a6bca16c3e5dc30c467db1e600a3af..6a977679124d549a954eb78a27b89b9cf7c304c3 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.c +++ b/drivers/net/wireless/rt2x00/rt2400pci.c @@ -49,45 +49,33 @@ * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt2400pci_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, BBPCSR, ®); - if (!rt2x00_get_field32(reg, BBPCSR_BUSY)) - break; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg)) static void rt2400pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the data into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_VALUE, value); - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_VALUE, value); + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + } - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -95,66 +83,58 @@ static void rt2400pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the request into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); - /* - * Wait until the BBP becomes ready. - */ - reg = rt2400pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - *value = 0xff; - return; + WAIT_FOR_BBP(rt2x00dev, ®); } *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, RFCSR, ®); - if (!rt2x00_get_field32(reg, RFCSR_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } - - ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); - return; + mutex_lock(&rt2x00dev->csr_mutex); -rf_write: - reg = 0; - rt2x00_set_field32(®, RFCSR_VALUE, value); - rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); - rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); - rt2x00_set_field32(®, RFCSR_BUSY, 1); + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RFCSR_VALUE, value); + rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); + rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); + rt2x00_set_field32(®, RFCSR_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RFCSR, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } - rt2x00pci_register_write(rt2x00dev, RFCSR, reg); - rt2x00_rf_write(rt2x00dev, word, value); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2400pci_eepromregister_read(struct eeprom_93cx6 *eeprom) @@ -188,43 +168,34 @@ static void rt2400pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt2400pci_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); -} - -static void rt2400pci_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); -} - static const struct rt2x00debug rt2400pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2400pci_read_csr, - .write = rt2400pci_write_csr, + .read = rt2x00pci_register_read, + .write = rt2x00pci_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt2400pci_bbp_read, .write = rt2400pci_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt2400pci_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, @@ -331,7 +302,7 @@ static void rt2400pci_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable beacon config */ - bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + 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); @@ -376,32 +347,94 @@ static void rt2400pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10)); rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20)); rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55)); rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); + + rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates); + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_read(rt2x00dev, CSR18, ®); + rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); + rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); + rt2x00pci_register_write(rt2x00dev, CSR18, reg); + + rt2x00pci_register_read(rt2x00dev, CSR19, ®); + rt2x00_set_field32(®, CSR19_DIFS, erp->difs); + rt2x00_set_field32(®, CSR19_EIFS, erp->eifs); + rt2x00pci_register_write(rt2x00dev, CSR19, reg); } -static void rt2400pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) +static void rt2400pci_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { - rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask); + 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); + + /* + * Configure the TX antenna. + */ + switch (ant->tx) { + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); + break; + case ANTENNA_B: + default: + rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); + break; + } + + /* + * Configure the RX antenna. + */ + switch (ant->rx) { + case ANTENNA_HW_DIVERSITY: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); + break; + case ANTENNA_A: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); + break; + case ANTENNA_B: + default: + rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); + break; + } + + rt2400pci_bbp_write(rt2x00dev, 4, r4); + rt2400pci_bbp_write(rt2x00dev, 1, r1); } static void rt2400pci_config_channel(struct rt2x00_dev *rt2x00dev, @@ -460,56 +493,17 @@ static void rt2400pci_config_txpower(struct rt2x00_dev *rt2x00dev, int txpower) rt2400pci_bbp_write(rt2x00dev, 3, TXPOWER_TO_DEV(txpower)); } -static void rt2400pci_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt2400pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) { - 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); - - /* - * Configure the TX antenna. - */ - switch (ant->tx) { - case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 1); - break; - case ANTENNA_A: - rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 0); - break; - case ANTENNA_B: - default: - rt2x00_set_field8(&r1, BBP_R1_TX_ANTENNA, 2); - break; - } - - /* - * Configure the RX antenna. - */ - switch (ant->rx) { - case ANTENNA_HW_DIVERSITY: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 1); - break; - case ANTENNA_A: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 0); - break; - case ANTENNA_B: - default: - rt2x00_set_field8(&r4, BBP_R4_RX_ANTENNA, 2); - break; - } + u32 reg; - rt2400pci_bbp_write(rt2x00dev, 4, r4); - rt2400pci_bbp_write(rt2x00dev, 1, r1); + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_LONG_RETRY, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, CSR11_SHORT_RETRY, + libconf->conf->short_frame_max_tx_count); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); } static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, @@ -517,20 +511,6 @@ static void rt2400pci_config_duration(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_SLOT_TIME, libconf->slot_time); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - rt2x00pci_register_read(rt2x00dev, CSR18, ®); - rt2x00_set_field32(®, CSR18_SIFS, libconf->sifs); - rt2x00_set_field32(®, CSR18_PIFS, libconf->pifs); - rt2x00pci_register_write(rt2x00dev, CSR18, reg); - - rt2x00pci_register_read(rt2x00dev, CSR19, ®); - rt2x00_set_field32(®, CSR19_DIFS, libconf->difs); - rt2x00_set_field32(®, CSR19_EIFS, libconf->eifs); - rt2x00pci_register_write(rt2x00dev, CSR19, reg); - rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); @@ -548,16 +528,14 @@ static void rt2400pci_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { - if (flags & CONFIG_UPDATE_PHYMODE) - rt2400pci_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2400pci_config_channel(rt2x00dev, &libconf->rf); - if (flags & CONFIG_UPDATE_TXPOWER) + if (flags & IEEE80211_CONF_CHANGE_POWER) rt2400pci_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt2400pci_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt2400pci_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt2400pci_config_duration(rt2x00dev, libconf); } @@ -628,36 +606,47 @@ static void rt2400pci_link_tuner(struct rt2x00_dev *rt2x00dev) /* * Initialization functions. */ -static void rt2400pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static bool rt2400pci_get_entry_state(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 2, &word); - rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len); - rt2x00_desc_write(entry_priv->desc, 2, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); - rt2x00_desc_write(entry_priv->desc, 1, word); + return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(entry_priv->desc, 0, word); + return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(word, TXD_W0_VALID)); + } } -static void rt2400pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt2400pci_clear_entry(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(entry_priv->desc, 0, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 2, &word); + rt2x00_set_field32(&word, RXD_W2_BUFFER_LENGTH, entry->skb->len); + rt2x00_desc_write(entry_priv->desc, 2, word); + + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(entry_priv->desc, 0, word); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(entry_priv->desc, 0, word); + } } static int rt2400pci_init_queues(struct rt2x00_dev *rt2x00dev) @@ -1313,10 +1302,8 @@ static int rt2400pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); @@ -1504,20 +1491,6 @@ static int rt2400pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt2400pci_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_LONG_RETRY, long_retry); - rt2x00_set_field32(®, CSR11_SHORT_RETRY, short_retry); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - return 0; -} - static int rt2400pci_conf_tx(struct ieee80211_hw *hw, u16 queue, const struct ieee80211_tx_queue_params *params) { @@ -1576,7 +1549,6 @@ static const struct ieee80211_ops rt2400pci_mac80211_ops = { .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt2400pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2400pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -1589,8 +1561,8 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .probe_hw = rt2400pci_probe_hw, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, - .init_rxentry = rt2400pci_init_rxentry, - .init_txentry = rt2400pci_init_txentry, + .get_entry_state = rt2400pci_get_entry_state, + .clear_entry = rt2400pci_clear_entry, .set_device_state = rt2400pci_set_device_state, .rfkill_poll = rt2400pci_rfkill_poll, .link_stats = rt2400pci_link_stats, @@ -1604,6 +1576,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = { .config_filter = rt2400pci_config_filter, .config_intf = rt2400pci_config_intf, .config_erp = rt2400pci_config_erp, + .config_ant = rt2400pci_config_ant, .config = rt2400pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2400pci.h b/drivers/net/wireless/rt2x00/rt2400pci.h index bbff381ce3963d11e28b9b261c5c44ab88d3da5b..9aefda4ab3c263c4163543fff32a7853b8139ec8 100644 --- a/drivers/net/wireless/rt2x00/rt2400pci.h +++ b/drivers/net/wireless/rt2x00/rt2400pci.h @@ -46,7 +46,9 @@ #define CSR_REG_SIZE 0x014c #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0100 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0020 +#define RF_BASE 0x0000 #define RF_SIZE 0x0010 /* diff --git a/drivers/net/wireless/rt2x00/rt2500pci.c b/drivers/net/wireless/rt2x00/rt2500pci.c index ef42cc04a2d736428d112bdc28caa4af58aeeca4..d3bc218ec85cc2debcd5dfd52e8c00fcdf4124bf 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.c +++ b/drivers/net/wireless/rt2x00/rt2500pci.c @@ -49,45 +49,33 @@ * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt2500pci_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, BBPCSR, ®); - if (!rt2x00_get_field32(reg, BBPCSR_BUSY)) - break; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), BBPCSR, BBPCSR_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), RFCSR, RFCSR_BUSY, (__reg)) static void rt2500pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Write failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the data into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_VALUE, value); - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_VALUE, value); + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 1); + + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + } - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -95,66 +83,58 @@ static void rt2500pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the request into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = 0; - rt2x00_set_field32(®, BBPCSR_REGNUM, word); - rt2x00_set_field32(®, BBPCSR_BUSY, 1); - rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, BBPCSR_REGNUM, word); + rt2x00_set_field32(®, BBPCSR_BUSY, 1); + rt2x00_set_field32(®, BBPCSR_WRITE_CONTROL, 0); - rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); + rt2x00pci_register_write(rt2x00dev, BBPCSR, reg); - /* - * Wait until the BBP becomes ready. - */ - reg = rt2500pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, BBPCSR_BUSY)) { - ERROR(rt2x00dev, "BBPCSR register busy. Read failed.\n"); - *value = 0xff; - return; + WAIT_FOR_BBP(rt2x00dev, ®); } *value = rt2x00_get_field32(reg, BBPCSR_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, RFCSR, ®); - if (!rt2x00_get_field32(reg, RFCSR_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } - - ERROR(rt2x00dev, "RFCSR register busy. Write failed.\n"); - return; + mutex_lock(&rt2x00dev->csr_mutex); -rf_write: - reg = 0; - rt2x00_set_field32(®, RFCSR_VALUE, value); - rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); - rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); - rt2x00_set_field32(®, RFCSR_BUSY, 1); + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, RFCSR_VALUE, value); + rt2x00_set_field32(®, RFCSR_NUMBER_OF_BITS, 20); + rt2x00_set_field32(®, RFCSR_IF_SELECT, 0); + rt2x00_set_field32(®, RFCSR_BUSY, 1); + + rt2x00pci_register_write(rt2x00dev, RFCSR, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } - rt2x00pci_register_write(rt2x00dev, RFCSR, reg); - rt2x00_rf_write(rt2x00dev, word, value); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500pci_eepromregister_read(struct eeprom_93cx6 *eeprom) @@ -188,43 +168,34 @@ static void rt2500pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt2500pci_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); -} - -static void rt2500pci_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); -} - static const struct rt2x00debug rt2500pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2500pci_read_csr, - .write = rt2500pci_write_csr, + .read = rt2x00pci_register_read, + .write = rt2x00pci_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt2500pci_bbp_read, .write = rt2500pci_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt2500pci_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, @@ -336,7 +307,7 @@ static void rt2500pci_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable beacon config */ - bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + 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); @@ -382,32 +353,114 @@ static void rt2500pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00pci_register_read(rt2x00dev, ARCSR2, ®); rt2x00_set_field32(®, ARCSR2_SIGNAL, 0x00); rt2x00_set_field32(®, ARCSR2_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 10)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 10)); rt2x00pci_register_write(rt2x00dev, ARCSR2, reg); rt2x00pci_register_read(rt2x00dev, ARCSR3, ®); rt2x00_set_field32(®, ARCSR3_SIGNAL, 0x01 | preamble_mask); rt2x00_set_field32(®, ARCSR3_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 20)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 20)); rt2x00pci_register_write(rt2x00dev, ARCSR3, reg); rt2x00pci_register_read(rt2x00dev, ARCSR4, ®); rt2x00_set_field32(®, ARCSR4_SIGNAL, 0x02 | preamble_mask); rt2x00_set_field32(®, ARCSR4_SERVICE, 0x04); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 55)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 55)); rt2x00pci_register_write(rt2x00dev, ARCSR4, reg); rt2x00pci_register_read(rt2x00dev, ARCSR5, ®); rt2x00_set_field32(®, ARCSR5_SIGNAL, 0x03 | preamble_mask); rt2x00_set_field32(®, ARCSR5_SERVICE, 0x84); - rt2x00_set_field32(®, ARCSR2_LENGTH, get_duration(ACK_SIZE, 110)); + rt2x00_set_field32(®, ARCSR2_LENGTH, GET_DURATION(ACK_SIZE, 110)); rt2x00pci_register_write(rt2x00dev, ARCSR5, reg); + + rt2x00pci_register_write(rt2x00dev, ARCSR1, erp->basic_rates); + + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_SLOT_TIME, erp->slot_time); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); + + rt2x00pci_register_read(rt2x00dev, CSR18, ®); + rt2x00_set_field32(®, CSR18_SIFS, erp->sifs); + rt2x00_set_field32(®, CSR18_PIFS, erp->pifs); + rt2x00pci_register_write(rt2x00dev, CSR18, reg); + + rt2x00pci_register_read(rt2x00dev, CSR19, ®); + rt2x00_set_field32(®, CSR19_DIFS, erp->difs); + rt2x00_set_field32(®, CSR19_EIFS, erp->eifs); + rt2x00pci_register_write(rt2x00dev, CSR19, reg); } -static void rt2500pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) +static void rt2500pci_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { - rt2x00pci_register_write(rt2x00dev, ARCSR1, basic_rate_mask); + u32 reg; + 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); + + /* + * Configure the TX antenna. + */ + switch (ant->tx) { + case ANTENNA_A: + rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); + rt2x00_set_field32(®, BBPCSR1_CCK, 0); + rt2x00_set_field32(®, BBPCSR1_OFDM, 0); + break; + 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); + break; + } + + /* + * Configure the RX antenna. + */ + switch (ant->rx) { + case ANTENNA_A: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); + break; + case ANTENNA_B: + default: + rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); + break; + } + + /* + * RT2525E and RT5222 need to flip TX I/Q + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || + rt2x00_rf(&rt2x00dev->chip, RF5222)) { + rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); + rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 1); + rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 1); + + /* + * RT2525E does not need RX I/Q Flip. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) + rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); + } else { + rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 0); + rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 0); + } + + rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg); + rt2500pci_bbp_write(rt2x00dev, 14, r14); + rt2500pci_bbp_write(rt2x00dev, 2, r2); } static void rt2500pci_config_channel(struct rt2x00_dev *rt2x00dev, @@ -489,76 +542,17 @@ static void rt2500pci_config_txpower(struct rt2x00_dev *rt2x00dev, rt2500pci_rf_write(rt2x00dev, 3, rf3); } -static void rt2500pci_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt2500pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) { u32 reg; - 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); - - /* - * Configure the TX antenna. - */ - switch (ant->tx) { - case ANTENNA_A: - rt2x00_set_field8(&r2, BBP_R2_TX_ANTENNA, 0); - rt2x00_set_field32(®, BBPCSR1_CCK, 0); - rt2x00_set_field32(®, BBPCSR1_OFDM, 0); - break; - 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); - break; - } - - /* - * Configure the RX antenna. - */ - switch (ant->rx) { - case ANTENNA_A: - rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 0); - break; - case ANTENNA_B: - default: - rt2x00_set_field8(&r14, BBP_R14_RX_ANTENNA, 2); - break; - } - - /* - * RT2525E and RT5222 need to flip TX I/Q - */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E) || - rt2x00_rf(&rt2x00dev->chip, RF5222)) { - rt2x00_set_field8(&r2, BBP_R2_TX_IQ_FLIP, 1); - rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 1); - rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 1); - /* - * RT2525E does not need RX I/Q Flip. - */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) - rt2x00_set_field8(&r14, BBP_R14_RX_IQ_FLIP, 0); - } else { - rt2x00_set_field32(®, BBPCSR1_CCK_FLIP, 0); - rt2x00_set_field32(®, BBPCSR1_OFDM_FLIP, 0); - } - - rt2x00pci_register_write(rt2x00dev, BBPCSR1, reg); - rt2500pci_bbp_write(rt2x00dev, 14, r14); - rt2500pci_bbp_write(rt2x00dev, 2, r2); + rt2x00pci_register_read(rt2x00dev, CSR11, ®); + rt2x00_set_field32(®, CSR11_LONG_RETRY, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, CSR11_SHORT_RETRY, + libconf->conf->short_frame_max_tx_count); + rt2x00pci_register_write(rt2x00dev, CSR11, reg); } static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, @@ -566,20 +560,6 @@ static void rt2500pci_config_duration(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_SLOT_TIME, libconf->slot_time); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - rt2x00pci_register_read(rt2x00dev, CSR18, ®); - rt2x00_set_field32(®, CSR18_SIFS, libconf->sifs); - rt2x00_set_field32(®, CSR18_PIFS, libconf->pifs); - rt2x00pci_register_write(rt2x00dev, CSR18, reg); - - rt2x00pci_register_read(rt2x00dev, CSR19, ®); - rt2x00_set_field32(®, CSR19_DIFS, libconf->difs); - rt2x00_set_field32(®, CSR19_EIFS, libconf->eifs); - rt2x00pci_register_write(rt2x00dev, CSR19, reg); - rt2x00pci_register_read(rt2x00dev, TXCSR1, ®); rt2x00_set_field32(®, TXCSR1_TSF_OFFSET, IEEE80211_HEADER); rt2x00_set_field32(®, TXCSR1_AUTORESPONDER, 1); @@ -597,17 +577,16 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { - if (flags & CONFIG_UPDATE_PHYMODE) - rt2500pci_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2500pci_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt2500pci_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt2500pci_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt2500pci_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt2500pci_config_duration(rt2x00dev, libconf); } @@ -723,32 +702,43 @@ dynamic_cca_tune: /* * Initialization functions. */ -static void rt2500pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static bool rt2500pci_get_entry_state(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 1, &word); - rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); - rt2x00_desc_write(entry_priv->desc, 1, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 0, &word); + + return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(entry_priv->desc, 0, word); + return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(word, TXD_W0_VALID)); + } } -static void rt2500pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt2500pci_clear_entry(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(entry_priv->desc, 0, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 1, &word); + rt2x00_set_field32(&word, RXD_W1_BUFFER_ADDRESS, skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 1, word); + + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(entry_priv->desc, 0, word); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(entry_priv->desc, 0, word); + } } static int rt2500pci_init_queues(struct rt2x00_dev *rt2x00dev) @@ -1451,11 +1441,8 @@ static int rt2500pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", - print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); @@ -1830,20 +1817,6 @@ static int rt2500pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt2500pci_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt2x00pci_register_read(rt2x00dev, CSR11, ®); - rt2x00_set_field32(®, CSR11_LONG_RETRY, long_retry); - rt2x00_set_field32(®, CSR11_SHORT_RETRY, short_retry); - rt2x00pci_register_write(rt2x00dev, CSR11, reg); - - return 0; -} - static u64 rt2500pci_get_tsf(struct ieee80211_hw *hw) { struct rt2x00_dev *rt2x00dev = hw->priv; @@ -1877,7 +1850,6 @@ static const struct ieee80211_ops rt2500pci_mac80211_ops = { .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt2500pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -1890,8 +1862,8 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .probe_hw = rt2500pci_probe_hw, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, - .init_rxentry = rt2500pci_init_rxentry, - .init_txentry = rt2500pci_init_txentry, + .get_entry_state = rt2500pci_get_entry_state, + .clear_entry = rt2500pci_clear_entry, .set_device_state = rt2500pci_set_device_state, .rfkill_poll = rt2500pci_rfkill_poll, .link_stats = rt2500pci_link_stats, @@ -1905,6 +1877,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = { .config_filter = rt2500pci_config_filter, .config_intf = rt2500pci_config_intf, .config_erp = rt2500pci_config_erp, + .config_ant = rt2500pci_config_ant, .config = rt2500pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500pci.h b/drivers/net/wireless/rt2x00/rt2500pci.h index 8c26bef6cf49cc23d0eecafe635e20f93b89f052..e135247f7f89d6aae25fefc4bdb7673e54bfc706 100644 --- a/drivers/net/wireless/rt2x00/rt2500pci.h +++ b/drivers/net/wireless/rt2x00/rt2500pci.h @@ -57,7 +57,9 @@ #define CSR_REG_SIZE 0x0174 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0200 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0040 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* diff --git a/drivers/net/wireless/rt2x00/rt2500usb.c b/drivers/net/wireless/rt2x00/rt2500usb.c index d3bf7bba611ac02111b05df14a523148648796e5..30028e2422fcfde7706b285042b7a4b9b12863c9 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.c +++ b/drivers/net/wireless/rt2x00/rt2500usb.c @@ -35,6 +35,13 @@ #include "rt2x00usb.h" #include "rt2500usb.h" +/* + * Allow hardware encryption to be disabled. + */ +static int modparam_nohwcrypt = 1; +module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO); +MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); + /* * Register access. * All access to the CSR registers will go through the methods @@ -47,7 +54,7 @@ * between each attampt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. - * If the usb_cache_mutex is already held then the _lock variants must + * If the csr_mutex is already held then the _lock variants must * be used instead. */ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, @@ -57,7 +64,7 @@ static inline void rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, __le16 reg; rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); *value = le16_to_cpu(reg); } @@ -68,7 +75,7 @@ static inline void rt2500usb_register_read_lock(struct rt2x00_dev *rt2x00dev, __le16 reg; rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); *value = le16_to_cpu(reg); } @@ -89,7 +96,7 @@ static inline void rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, __le16 reg = cpu_to_le16(value); rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); } static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev, @@ -99,7 +106,7 @@ static inline void rt2500usb_register_write_lock(struct rt2x00_dev *rt2x00dev, __le16 reg = cpu_to_le16(value); rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u16), REGISTER_TIMEOUT); + ®, sizeof(reg), REGISTER_TIMEOUT); } static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, @@ -112,53 +119,53 @@ static inline void rt2500usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, REGISTER_TIMEOUT16(length)); } -static u16 rt2500usb_bbp_check(struct rt2x00_dev *rt2x00dev) +static int rt2500usb_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field16 field, + u16 *reg) { - u16 reg; unsigned int i; for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2500usb_register_read_lock(rt2x00dev, PHY_CSR8, ®); - if (!rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - break; + rt2500usb_register_read_lock(rt2x00dev, offset, reg); + if (!rt2x00_get_field16(*reg, field)) + return 1; udelay(REGISTER_BUSY_DELAY); } - return reg; + ERROR(rt2x00dev, "Indirect register access failed: " + "offset=0x%.08x, value=0x%.08x\n", offset, *reg); + *reg = ~0; + + return 0; } +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2500usb_regbusy_read((__dev), PHY_CSR8, PHY_CSR8_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2500usb_regbusy_read((__dev), PHY_CSR10, PHY_CSR10_RF_BUSY, (__reg)) + static void rt2500usb_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u16 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = rt2500usb_bbp_check(rt2x00dev); - if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - goto exit_fail; - - /* - * Write the data into the BBP. - */ - reg = 0; - rt2x00_set_field16(®, PHY_CSR7_DATA, value); - rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); - rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 0); - - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); - - mutex_unlock(&rt2x00dev->usb_cache_mutex); - - return; + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field16(®, PHY_CSR7_DATA, value); + rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); + rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 0); -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); + } - ERROR(rt2x00dev, "PHY_CSR8 register busy. Write failed.\n"); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -166,122 +173,107 @@ static void rt2500usb_bbp_read(struct rt2x00_dev *rt2x00dev, { u16 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = rt2500usb_bbp_check(rt2x00dev); - if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - goto exit_fail; - - /* - * Write the request into the BBP. - */ - reg = 0; - rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); - rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 1); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field16(®, PHY_CSR7_REG_ID, word); + rt2x00_set_field16(®, PHY_CSR7_READ_CONTROL, 1); - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR7, reg); - /* - * Wait until the BBP becomes ready. - */ - reg = rt2500usb_bbp_check(rt2x00dev); - if (rt2x00_get_field16(reg, PHY_CSR8_BUSY)) - goto exit_fail; + if (WAIT_FOR_BBP(rt2x00dev, ®)) + rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®); + } - rt2500usb_register_read_lock(rt2x00dev, PHY_CSR7, ®); *value = rt2x00_get_field16(reg, PHY_CSR7_DATA); - mutex_unlock(&rt2x00dev->usb_cache_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); - - ERROR(rt2x00dev, "PHY_CSR8 register busy. Read failed.\n"); - *value = 0xff; + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u16 reg; - unsigned int i; if (!word) return; - mutex_lock(&rt2x00dev->usb_cache_mutex); - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2500usb_register_read_lock(rt2x00dev, PHY_CSR10, ®); - if (!rt2x00_get_field16(reg, PHY_CSR10_RF_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } + mutex_lock(&rt2x00dev->csr_mutex); - mutex_unlock(&rt2x00dev->usb_cache_mutex); - ERROR(rt2x00dev, "PHY_CSR10 register busy. Write failed.\n"); - return; - -rf_write: - reg = 0; - rt2x00_set_field16(®, PHY_CSR9_RF_VALUE, value); - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg); + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field16(®, PHY_CSR9_RF_VALUE, value); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR9, reg); - reg = 0; - rt2x00_set_field16(®, PHY_CSR10_RF_VALUE, value >> 16); - rt2x00_set_field16(®, PHY_CSR10_RF_NUMBER_OF_BITS, 20); - rt2x00_set_field16(®, PHY_CSR10_RF_IF_SELECT, 0); - rt2x00_set_field16(®, PHY_CSR10_RF_BUSY, 1); + reg = 0; + rt2x00_set_field16(®, PHY_CSR10_RF_VALUE, value >> 16); + rt2x00_set_field16(®, PHY_CSR10_RF_NUMBER_OF_BITS, 20); + rt2x00_set_field16(®, PHY_CSR10_RF_IF_SELECT, 0); + rt2x00_set_field16(®, PHY_CSR10_RF_BUSY, 1); - rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg); - rt2x00_rf_write(rt2x00dev, word, value); + rt2500usb_register_write_lock(rt2x00dev, PHY_CSR10, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u16)) ) - -static void rt2500usb_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) +static void _rt2500usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) { - rt2500usb_register_read(rt2x00dev, CSR_OFFSET(word), (u16 *) data); + rt2500usb_register_read(rt2x00dev, offset, (u16 *)value); } -static void rt2500usb_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) +static void _rt2500usb_register_write(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) { - rt2500usb_register_write(rt2x00dev, CSR_OFFSET(word), data); + rt2500usb_register_write(rt2x00dev, offset, value); } static const struct rt2x00debug rt2500usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt2500usb_read_csr, - .write = rt2500usb_write_csr, + .read = _rt2500usb_register_read, + .write = _rt2500usb_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u16), .word_count = CSR_REG_SIZE / sizeof(u16), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt2500usb_bbp_read, .write = rt2500usb_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt2500usb_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, @@ -338,6 +330,82 @@ static void rt2500usb_init_led(struct rt2x00_dev *rt2x00dev, /* * Configuration handlers. */ + +/* + * rt2500usb does not differentiate between shared and pairwise + * keys, so we should use the same function for both key types. + */ +static int rt2500usb_config_key(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_crypto *crypto, + struct ieee80211_key_conf *key) +{ + int timeout; + u32 mask; + u16 reg; + + if (crypto->cmd == SET_KEY) { + /* + * Pairwise key will always be entry 0, but this + * could collide with a shared key on the same + * position... + */ + mask = TXRX_CSR0_KEY_ID.bit_mask; + + rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + reg &= mask; + + if (reg && reg == mask) + return -ENOSPC; + + reg = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID); + + key->hw_key_idx += reg ? ffz(reg) : 0; + + /* + * The encryption key doesn't fit within the CSR cache, + * this means we should allocate it seperately and use + * rt2x00usb_vendor_request() to send the key to the hardware. + */ + reg = KEY_ENTRY(key->hw_key_idx); + timeout = REGISTER_TIMEOUT32(sizeof(crypto->key)); + rt2x00usb_vendor_request_large_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, reg, + crypto->key, + sizeof(crypto->key), + timeout); + + /* + * The driver does not support the IV/EIV generation + * in hardware. However it doesn't support the IV/EIV + * inside the ieee80211 frame either, but requires it + * to be provided seperately for the descriptor. + * rt2x00lib will cut the IV/EIV data out of all frames + * given to us by mac80211, but we must tell mac80211 + * to generate the IV/EIV data. + */ + key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV; + key->flags |= IEEE80211_KEY_FLAG_GENERATE_MMIC; + } + + /* + * TXRX_CSR0_KEY_ID contains only single-bit fields to indicate + * a particular key is valid. + */ + rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00_set_field16(®, TXRX_CSR0_ALGORITHM, crypto->cipher); + rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); + + mask = rt2x00_get_field16(reg, TXRX_CSR0_KEY_ID); + if (crypto->cmd == SET_KEY) + mask |= 1 << key->hw_key_idx; + else if (crypto->cmd == DISABLE_KEY) + mask &= ~(1 << key->hw_key_idx); + rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, mask); + rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg); + + return 0; +} + static void rt2500usb_config_filter(struct rt2x00_dev *rt2x00dev, const unsigned int filter_flags) { @@ -380,7 +448,7 @@ static void rt2500usb_config_intf(struct rt2x00_dev *rt2x00dev, /* * Enable beacon config */ - bcn_preload = PREAMBLE + get_duration(IEEE80211_HEADER, 20); + 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, @@ -423,57 +491,16 @@ static void rt2500usb_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field16(®, TXRX_CSR10_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2500usb_register_write(rt2x00dev, TXRX_CSR10, reg); -} - -static void rt2500usb_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) -{ - rt2500usb_register_write(rt2x00dev, TXRX_CSR11, basic_rate_mask); -} - -static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, const int txpower) -{ - /* - * Set TXpower. - */ - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - - /* - * For RT2525E we should first set the channel to half band higher. - */ - if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { - static const u32 vals[] = { - 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2, - 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba, - 0x000008ba, 0x000008be, 0x000008b7, 0x00000902, - 0x00000902, 0x00000906 - }; - - rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]); - if (rf->rf4) - rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); - } - - rt2500usb_rf_write(rt2x00dev, 1, rf->rf1); - rt2500usb_rf_write(rt2x00dev, 2, rf->rf2); - rt2500usb_rf_write(rt2x00dev, 3, rf->rf3); - if (rf->rf4) - rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); -} -static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, - const int txpower) -{ - u32 rf3; + rt2500usb_register_write(rt2x00dev, TXRX_CSR11, erp->basic_rates); - rt2x00_rf_read(rt2x00dev, 3, &rf3); - rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - rt2500usb_rf_write(rt2x00dev, 3, rf3); + rt2500usb_register_write(rt2x00dev, MAC_CSR10, erp->slot_time); + rt2500usb_register_write(rt2x00dev, MAC_CSR11, erp->sifs); + rt2500usb_register_write(rt2x00dev, MAC_CSR12, erp->eifs); } -static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt2500usb_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { u8 r2; u8 r14; @@ -555,15 +582,52 @@ static void rt2500usb_config_antenna(struct rt2x00_dev *rt2x00dev, rt2500usb_register_write(rt2x00dev, PHY_CSR6, csr6); } +static void rt2500usb_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) +{ + /* + * Set TXpower. + */ + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + + /* + * For RT2525E we should first set the channel to half band higher. + */ + if (rt2x00_rf(&rt2x00dev->chip, RF2525E)) { + static const u32 vals[] = { + 0x000008aa, 0x000008ae, 0x000008ae, 0x000008b2, + 0x000008b2, 0x000008b6, 0x000008b6, 0x000008ba, + 0x000008ba, 0x000008be, 0x000008b7, 0x00000902, + 0x00000902, 0x00000906 + }; + + rt2500usb_rf_write(rt2x00dev, 2, vals[rf->channel - 1]); + if (rf->rf4) + rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); + } + + rt2500usb_rf_write(rt2x00dev, 1, rf->rf1); + rt2500usb_rf_write(rt2x00dev, 2, rf->rf2); + rt2500usb_rf_write(rt2x00dev, 3, rf->rf3); + if (rf->rf4) + rt2500usb_rf_write(rt2x00dev, 4, rf->rf4); +} + +static void rt2500usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + u32 rf3; + + rt2x00_rf_read(rt2x00dev, 3, &rf3); + rt2x00_set_field32(&rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2500usb_rf_write(rt2x00dev, 3, rf3); +} + static void rt2500usb_config_duration(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { 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, libconf->conf->beacon_int * 4); @@ -574,17 +638,14 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf, const unsigned int flags) { - if (flags & CONFIG_UPDATE_PHYMODE) - rt2500usb_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2500usb_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt2500usb_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt2500usb_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt2500usb_config_duration(rt2x00dev, libconf); } @@ -866,7 +927,7 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2500usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field16(®, TXRX_CSR0_IV_OFFSET, IEEE80211_HEADER); - rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, 0xff); + rt2x00_set_field16(®, TXRX_CSR0_KEY_ID, 0); rt2500usb_register_write(rt2x00dev, TXRX_CSR0, reg); rt2500usb_register_read(rt2x00dev, MAC_CSR18, ®); @@ -1088,7 +1149,7 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, * Start writing the descriptor words. */ rt2x00_desc_read(txd, 1, &word); - rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, IEEE80211_HEADER); + rt2x00_set_field32(&word, TXD_W1_IV_OFFSET, txdesc->iv_offset); 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); @@ -1101,6 +1162,11 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(&word, TXD_W2_PLCP_LENGTH_HIGH, txdesc->length_high); rt2x00_desc_write(txd, 2, word); + if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { + _rt2x00_desc_write(txd, 3, skbdesc->iv[0]); + _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); + } + rt2x00_desc_read(txd, 0, &word); rt2x00_set_field32(&word, TXD_W0_RETRY_LIMIT, txdesc->retry_limit); rt2x00_set_field32(&word, TXD_W0_MORE_FRAG, @@ -1115,7 +1181,8 @@ static void rt2500usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags)); rt2x00_set_field32(&word, TXD_W0_IFS, txdesc->ifs); rt2x00_set_field32(&word, TXD_W0_DATABYTE_COUNT, skb->len); - rt2x00_set_field32(&word, TXD_W0_CIPHER, CIPHER_NONE); + rt2x00_set_field32(&word, TXD_W0_CIPHER, txdesc->cipher); + rt2x00_set_field32(&word, TXD_W0_KEY_ID, txdesc->key_idx); rt2x00_desc_write(txd, 0, word); } @@ -1130,7 +1197,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); struct queue_entry_priv_usb_bcn *bcn_priv = entry->priv_data; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); - int pipe = usb_sndbulkpipe(usb_dev, 1); + int pipe = usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint); int length; u16 reg; @@ -1156,7 +1223,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) * length of the data to usb_fill_bulk_urb. Pass the skb * to the driver to determine what the length should be. */ - length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb); + length = rt2x00dev->ops->lib->get_tx_data_len(entry); usb_fill_bulk_urb(bcn_priv->urb, usb_dev, pipe, entry->skb->data, length, rt2500usb_beacondone, @@ -1178,8 +1245,7 @@ static void rt2500usb_write_beacon(struct queue_entry *entry) usb_submit_urb(bcn_priv->guardian_urb, GFP_ATOMIC); } -static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb) +static int rt2500usb_get_tx_data_len(struct queue_entry *entry) { int length; @@ -1187,8 +1253,8 @@ static int rt2500usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, * The length _must_ be a multiple of 2, * but it must _not_ be a multiple of the USB packet size. */ - length = roundup(skb->len, 2); - length += (2 * !(length % rt2x00dev->usb_maxpacket)); + length = roundup(entry->skb->len, 2); + length += (2 * !(length % entry->queue->usb_maxpacket)); return length; } @@ -1227,6 +1293,7 @@ static void rt2500usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, static void rt2500usb_fill_rxdone(struct queue_entry *entry, struct rxdone_entry_desc *rxdesc) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_usb *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); __le32 *rxd = @@ -1254,6 +1321,33 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, if (rt2x00_get_field32(word0, RXD_W0_PHYSICAL_ERROR)) rxdesc->flags |= RX_FLAG_FAILED_PLCP_CRC; + if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { + rxdesc->cipher = rt2x00_get_field32(word0, RXD_W0_CIPHER); + if (rt2x00_get_field32(word0, RXD_W0_CIPHER_ERROR)) + rxdesc->cipher_status = RX_CRYPTO_FAIL_KEY; + } + + if (rxdesc->cipher != CIPHER_NONE) { + _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); + _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); + rxdesc->dev_flags |= RXDONE_CRYPTO_IV; + + /* ICV is located at the end of frame */ + + /* + * Hardware has stripped IV/EIV data from 802.11 frame during + * decryption. It has provided the data seperately but rt2x00lib + * should decide if it should be reinserted. + */ + rxdesc->flags |= RX_FLAG_IV_STRIPPED; + if (rxdesc->cipher != CIPHER_TKIP) + rxdesc->flags |= RX_FLAG_MMIC_STRIPPED; + if (rxdesc->cipher_status == RX_CRYPTO_SUCCESS) + rxdesc->flags |= RX_FLAG_DECRYPTED; + else if (rxdesc->cipher_status == RX_CRYPTO_FAIL_MIC) + rxdesc->flags |= RX_FLAG_MMIC_ERROR; + } + /* * Obtain the status about this packet. * When frame was received with an OFDM bitrate, @@ -1261,8 +1355,8 @@ static void rt2500usb_fill_rxdone(struct queue_entry *entry, * a CCK bitrate the signal is the rate in 100kbit/s. */ rxdesc->signal = rt2x00_get_field32(word1, RXD_W1_SIGNAL); - rxdesc->rssi = rt2x00_get_field32(word1, RXD_W1_RSSI) - - entry->queue->rt2x00dev->rssi_offset; + rxdesc->rssi = + rt2x00_get_field32(word1, RXD_W1_RSSI) - rt2x00dev->rssi_offset; rxdesc->size = rt2x00_get_field32(word0, RXD_W0_DATABYTE_COUNT); if (rt2x00_get_field32(word0, RXD_W0_OFDM)) @@ -1319,10 +1413,8 @@ static int rt2500usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); @@ -1752,6 +1844,10 @@ static int rt2500usb_probe_hw(struct rt2x00_dev *rt2x00dev) __set_bit(DRIVER_REQUIRE_ATIM_QUEUE, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_BEACON_GUARD, &rt2x00dev->flags); __set_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags); + if (!modparam_nohwcrypt) { + __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags); + __set_bit(CONFIG_CRYPTO_COPY_IV, &rt2x00dev->flags); + } __set_bit(CONFIG_DISABLE_LINK_TUNING, &rt2x00dev->flags); /* @@ -1771,6 +1867,7 @@ static const struct ieee80211_ops rt2500usb_mac80211_ops = { .config = rt2x00mac_config, .config_interface = rt2x00mac_config_interface, .configure_filter = rt2x00mac_configure_filter, + .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt2x00mac_conf_tx, @@ -1781,8 +1878,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .probe_hw = rt2500usb_probe_hw, .initialize = rt2x00usb_initialize, .uninitialize = rt2x00usb_uninitialize, - .init_rxentry = rt2x00usb_init_rxentry, - .init_txentry = rt2x00usb_init_txentry, + .clear_entry = rt2x00usb_clear_entry, .set_device_state = rt2500usb_set_device_state, .link_stats = rt2500usb_link_stats, .reset_tuner = rt2500usb_reset_tuner, @@ -1793,9 +1889,12 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = { .get_tx_data_len = rt2500usb_get_tx_data_len, .kick_tx_queue = rt2500usb_kick_tx_queue, .fill_rxdone = rt2500usb_fill_rxdone, + .config_shared_key = rt2500usb_config_key, + .config_pairwise_key = rt2500usb_config_key, .config_filter = rt2500usb_config_filter, .config_intf = rt2500usb_config_intf, .config_erp = rt2500usb_config_erp, + .config_ant = rt2500usb_config_ant, .config = rt2500usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt2500usb.h b/drivers/net/wireless/rt2x00/rt2500usb.h index 89e5ed24e4f7906a95ae0feaacc992e022840e34..4347dfdabcd4f0525a1e9f2cbed5457848cf1d2b 100644 --- a/drivers/net/wireless/rt2x00/rt2500usb.h +++ b/drivers/net/wireless/rt2x00/rt2500usb.h @@ -57,7 +57,9 @@ #define CSR_REG_SIZE 0x0100 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x006a +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0060 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* @@ -445,6 +447,9 @@ #define SEC_CSR30 0x04bc #define SEC_CSR31 0x04be +#define KEY_ENTRY(__idx) \ + ( SEC_CSR0 + ((__idx) * 16) ) + /* * PHY control registers. */ diff --git a/drivers/net/wireless/rt2x00/rt2x00.h b/drivers/net/wireless/rt2x00/rt2x00.h index 1359a3768404b89b70e3908f2f297a46d9f30745..39ecf3b82ca1ca0b6895be3eb266c883b9e2e42f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00.h +++ b/drivers/net/wireless/rt2x00/rt2x00.h @@ -44,7 +44,7 @@ /* * Module information. */ -#define DRV_VERSION "2.2.1" +#define DRV_VERSION "2.2.3" #define DRV_PROJECT "http://rt2x00.serialmonkey.com" /* @@ -91,6 +91,16 @@ #define EEPROM(__dev, __msg, __args...) \ DEBUG_PRINTK(__dev, KERN_DEBUG, "EEPROM recovery", __msg, ##__args) +/* + * Duration calculations + * The rate variable passed is: 100kbs. + * To convert from bytes to bits we multiply size with 8, + * then the size is multiplied with 10 to make the + * real rate -> rate argument correction. + */ +#define GET_DURATION(__size, __rate) (((__size) * 8 * 10) / (__rate)) +#define GET_DURATION_RES(__size, __rate)(((__size) * 8 * 10) % (__rate)) + /* * Standard timing and size defines. * These values should follow the ieee80211 specifications. @@ -109,9 +119,9 @@ #define DIFS ( PIFS + SLOT_TIME ) #define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME ) #define EIFS ( SIFS + DIFS + \ - (8 * (IEEE80211_HEADER + ACK_SIZE)) ) + GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) #define SHORT_EIFS ( SIFS + SHORT_DIFS + \ - (8 * (IEEE80211_HEADER + ACK_SIZE)) ) + GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) ) /* * Chipset identification @@ -347,13 +357,6 @@ struct rt2x00_intf { */ spinlock_t lock; - /* - * BSS configuration. Copied from the structure - * passed to us through the bss_info_changed() - * callback funtion. - */ - struct ieee80211_bss_conf conf; - /* * MAC of the device. */ @@ -433,18 +436,6 @@ struct rt2x00lib_conf { struct rf_channel rf; struct channel_info channel; - - struct antenna_setup ant; - - enum ieee80211_band band; - - u32 basic_rates; - u32 slot_time; - - short sifs; - short pifs; - short difs; - short eifs; }; /* @@ -456,6 +447,15 @@ struct rt2x00lib_erp { int ack_timeout; int ack_consume_time; + + u64 basic_rates; + + int slot_time; + + short sifs; + short pifs; + short difs; + short eifs; }; /* @@ -533,10 +533,8 @@ struct rt2x00lib_ops { /* * queue initialization handlers */ - void (*init_rxentry) (struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); - void (*init_txentry) (struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); + bool (*get_entry_state) (struct queue_entry *entry); + void (*clear_entry) (struct queue_entry *entry); /* * Radio control handlers. @@ -557,8 +555,7 @@ struct rt2x00lib_ops { struct txentry_desc *txdesc); int (*write_tx_data) (struct queue_entry *entry); void (*write_beacon) (struct queue_entry *entry); - int (*get_tx_data_len) (struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb); + int (*get_tx_data_len) (struct queue_entry *entry); void (*kick_tx_queue) (struct rt2x00_dev *rt2x00dev, const enum data_queue_qid queue); @@ -589,16 +586,11 @@ struct rt2x00lib_ops { void (*config_erp) (struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp); + void (*config_ant) (struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant); 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 ) -#define CONFIG_UPDATE_ANTENNA ( 1 << 4 ) -#define CONFIG_UPDATE_SLOT_TIME ( 1 << 5 ) -#define CONFIG_UPDATE_BEACON_INT ( 1 << 6 ) -#define CONFIG_UPDATE_ALL 0xffff + const unsigned int changed_flags); }; /* @@ -661,6 +653,7 @@ enum rt2x00_flags { CONFIG_EXTERNAL_LNA_BG, CONFIG_DOUBLE_ANTENNA, CONFIG_DISABLE_LINK_TUNING, + CONFIG_CRYPTO_COPY_IV, }; /* @@ -738,8 +731,7 @@ struct rt2x00_dev { /* * This is the default TX/RX antenna setup as indicated - * by the device's EEPROM. When mac80211 sets its - * antenna value to 0 we should be using these values. + * by the device's EEPROM. */ struct antenna_setup default_ant; @@ -754,16 +746,15 @@ struct rt2x00_dev { } csr; /* - * Mutex to protect register accesses on USB devices. - * There are 2 reasons this is needed, one is to ensure - * use of the csr_cache (for USB devices) by one thread - * isn't corrupted by another thread trying to access it. - * The other is that access to BBP and RF registers - * require multiple BUS transactions and if another thread - * attempted to access one of those registers at the same - * time one of the writes could silently fail. + * Mutex to protect register accesses. + * For PCI and USB devices it protects against concurrent indirect + * register access (BBP, RF, MCU) since accessing those + * registers require multiple calls to the CSR registers. + * For USB devices it also protects the csr_cache since that + * field is used for normal CSR access and it cannot support + * multiple callers simultaneously. */ - struct mutex usb_cache_mutex; + struct mutex csr_mutex; /* * Current packet filter configuration for the device. @@ -808,14 +799,15 @@ struct rt2x00_dev { short lna_gain; /* - * USB Max frame size (for rt2500usb & rt73usb). + * Current TX power value. */ - u16 usb_maxpacket; + u16 tx_power; /* - * Current TX power value. + * Current retry values. */ - u16 tx_power; + u8 short_retry; + u8 long_retry; /* * Rssi <-> Dbm offset @@ -938,23 +930,6 @@ static inline u16 rt2x00_check_rev(const struct rt2x00_chip *chipset, !!(chipset->rev & 0x0000f)); } -/* - * Duration calculations - * The rate variable passed is: 100kbs. - * To convert from bytes to bits we multiply size with 8, - * then the size is multiplied with 10 to make the - * real rate -> rate argument correction. - */ -static inline u16 get_duration(const unsigned int size, const u8 rate) -{ - return ((size * 8 * 10) / rate); -} - -static inline u16 get_duration_res(const unsigned int size, const u8 rate) -{ - return ((size * 8 * 10) % rate); -} - /** * rt2x00queue_map_txskb - Map a skb into DMA for TX purposes. * @rt2x00dev: Pointer to &struct rt2x00_dev. @@ -997,7 +972,7 @@ int rt2x00mac_add_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); void rt2x00mac_remove_interface(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); -int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf); +int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed); int rt2x00mac_config_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c index 4d5e87b015a079f065acd0f4215ec91a94f37d0e..e66fb316cd61fda7fae8add82217d06e01213628 100644 --- a/drivers/net/wireless/rt2x00/rt2x00config.c +++ b/drivers/net/wireless/rt2x00/rt2x00config.c @@ -86,13 +86,14 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.short_preamble = bss_conf->use_short_preamble; erp.cts_protection = bss_conf->use_cts_prot; - erp.ack_timeout = PLCP + get_duration(ACK_SIZE, 10); - erp.ack_consume_time = SIFS + PLCP + get_duration(ACK_SIZE, 10); + erp.slot_time = bss_conf->use_short_slot ? SHORT_SLOT_TIME : SLOT_TIME; + erp.sifs = SIFS; + erp.pifs = bss_conf->use_short_slot ? SHORT_PIFS : PIFS; + erp.difs = bss_conf->use_short_slot ? SHORT_DIFS : DIFS; + erp.eifs = bss_conf->use_short_slot ? SHORT_EIFS : EIFS; - if (rt2x00dev->hw->conf.flags & IEEE80211_CONF_SHORT_SLOT_TIME) - erp.ack_timeout += SHORT_DIFS; - else - erp.ack_timeout += DIFS; + erp.ack_timeout = PLCP + erp.difs + GET_DURATION(ACK_SIZE, 10); + erp.ack_consume_time = SIFS + PLCP + GET_DURATION(ACK_SIZE, 10); if (bss_conf->use_short_preamble) { erp.ack_timeout += SHORT_PREAMBLE; @@ -102,19 +103,39 @@ void rt2x00lib_config_erp(struct rt2x00_dev *rt2x00dev, erp.ack_consume_time += PREAMBLE; } + erp.basic_rates = bss_conf->basic_rates; + rt2x00dev->ops->lib->config_erp(rt2x00dev, &erp); } +static inline +enum antenna rt2x00lib_config_antenna_check(enum antenna current_ant, + enum antenna default_ant) +{ + if (current_ant != ANTENNA_SW_DIVERSITY) + return current_ant; + return (default_ant != ANTENNA_SW_DIVERSITY) ? default_ant : ANTENNA_B; +} + void rt2x00lib_config_antenna(struct rt2x00_dev *rt2x00dev, - enum antenna rx, enum antenna tx) + struct antenna_setup *ant) { - struct rt2x00lib_conf libconf; + struct antenna_setup *def = &rt2x00dev->default_ant; + struct antenna_setup *active = &rt2x00dev->link.ant.active; - libconf.ant.rx = rx; - libconf.ant.tx = tx; + /* + * Failsafe: Make sure we are not sending the + * ANTENNA_SW_DIVERSITY state to the driver. + * If that happes fallback to hardware default, + * or our own default. + * The calls to rt2x00lib_config_antenna_check() + * might have caused that we restore back to the already + * active setting. If that has happened we can quit. + */ + ant->rx = rt2x00lib_config_antenna_check(ant->rx, def->rx); + ant->tx = rt2x00lib_config_antenna_check(ant->tx, def->tx); - if (rx == rt2x00dev->link.ant.active.rx && - tx == rt2x00dev->link.ant.active.tx) + if (ant->rx == active->rx && ant->tx == active->tx) return; /* @@ -129,119 +150,28 @@ 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, &libconf, CONFIG_UPDATE_ANTENNA); + rt2x00dev->ops->lib->config_ant(rt2x00dev, ant); + rt2x00lib_reset_link_tuner(rt2x00dev); rt2x00_reset_link_ant_rssi(&rt2x00dev->link); - rt2x00dev->link.ant.active.rx = libconf.ant.rx; - rt2x00dev->link.ant.active.tx = libconf.ant.tx; + memcpy(active, ant, sizeof(*ant)); if (test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 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 ieee80211_conf *conf, + unsigned int ieee80211_flags) { struct rt2x00lib_conf libconf; - 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; - int short_slot_time; - - /* - * In some situations we want to force all configurations - * to be reloaded (When resuming for instance). - */ - if (force_config) { - flags = CONFIG_UPDATE_ALL; - goto config; - } - /* - * Check which configuration options have been - * updated and should be send to the device. - */ - if (rt2x00dev->rx_status.band != conf->channel->band) - flags |= CONFIG_UPDATE_PHYMODE; - if (rt2x00dev->rx_status.freq != conf->channel->center_freq) - flags |= CONFIG_UPDATE_CHANNEL; - if (rt2x00dev->tx_power != conf->power_level) - flags |= CONFIG_UPDATE_TXPOWER; - - /* - * Determining changes in the antenna setups request several checks: - * antenna_sel_{r,t}x = 0 - * -> Does active_{r,t}x match default_{r,t}x - * -> Is default_{r,t}x SW_DIVERSITY - * antenna_sel_{r,t}x = 1/2 - * -> Does active_{r,t}x match antenna_sel_{r,t}x - * The reason for not updating the antenna while SW diversity - * should be used is simple: Software diversity means that - * we should switch between the antenna's based on the - * quality. This means that the current antenna is good enough - * to work with untill the link tuner decides that an antenna - * switch should be performed. - */ - if (!conf->antenna_sel_rx && - default_ant->rx != ANTENNA_SW_DIVERSITY && - default_ant->rx != active_ant->rx) - flags |= CONFIG_UPDATE_ANTENNA; - else if (conf->antenna_sel_rx && - conf->antenna_sel_rx != active_ant->rx) - flags |= CONFIG_UPDATE_ANTENNA; - else if (active_ant->rx == ANTENNA_SW_DIVERSITY) - flags |= CONFIG_UPDATE_ANTENNA; - - if (!conf->antenna_sel_tx && - default_ant->tx != ANTENNA_SW_DIVERSITY && - default_ant->tx != active_ant->tx) - flags |= CONFIG_UPDATE_ANTENNA; - else if (conf->antenna_sel_tx && - conf->antenna_sel_tx != active_ant->tx) - flags |= CONFIG_UPDATE_ANTENNA; - else if (active_ant->tx == ANTENNA_SW_DIVERSITY) - flags |= CONFIG_UPDATE_ANTENNA; - - /* - * The following configuration options are never - * stored anywhere and will always be updated. - */ - flags |= CONFIG_UPDATE_SLOT_TIME; - flags |= CONFIG_UPDATE_BEACON_INT; - - /* - * We have determined what options should be updated, - * now precalculate device configuration values depending - * on what configuration options need to be updated. - */ -config: memset(&libconf, 0, sizeof(libconf)); - if (flags & CONFIG_UPDATE_PHYMODE) { - band = &rt2x00dev->bands[conf->channel->band]; - - libconf.band = conf->channel->band; - libconf.basic_rates = rt2x00lib_get_basic_rates(band); - } + libconf.conf = conf; - if (flags & CONFIG_UPDATE_CHANNEL) { + if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) { memcpy(&libconf.rf, &rt2x00dev->spec.channels[conf->channel->hw_value], sizeof(libconf.rf)); @@ -251,61 +181,23 @@ config: sizeof(libconf.channel)); } - if (flags & CONFIG_UPDATE_ANTENNA) { - if (conf->antenna_sel_rx) - libconf.ant.rx = conf->antenna_sel_rx; - else if (default_ant->rx != ANTENNA_SW_DIVERSITY) - libconf.ant.rx = default_ant->rx; - else if (active_ant->rx == ANTENNA_SW_DIVERSITY) - libconf.ant.rx = ANTENNA_B; - else - libconf.ant.rx = active_ant->rx; - - if (conf->antenna_sel_tx) - libconf.ant.tx = conf->antenna_sel_tx; - else if (default_ant->tx != ANTENNA_SW_DIVERSITY) - libconf.ant.tx = default_ant->tx; - else if (active_ant->tx == ANTENNA_SW_DIVERSITY) - libconf.ant.tx = ANTENNA_B; - else - libconf.ant.tx = active_ant->tx; - } - - if (flags & CONFIG_UPDATE_SLOT_TIME) { - short_slot_time = conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME; - - libconf.slot_time = - short_slot_time ? SHORT_SLOT_TIME : SLOT_TIME; - libconf.sifs = SIFS; - libconf.pifs = short_slot_time ? SHORT_PIFS : PIFS; - libconf.difs = short_slot_time ? SHORT_DIFS : DIFS; - libconf.eifs = short_slot_time ? SHORT_EIFS : EIFS; - } - - libconf.conf = conf; - /* * Start configuration. */ - rt2x00dev->ops->lib->config(rt2x00dev, &libconf, flags); + rt2x00dev->ops->lib->config(rt2x00dev, &libconf, ieee80211_flags); /* * Some configuration changes affect the link quality * which means we need to reset the link tuner. */ - if (flags & (CONFIG_UPDATE_CHANNEL | CONFIG_UPDATE_ANTENNA)) + if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL) rt2x00lib_reset_link_tuner(rt2x00dev); - if (flags & CONFIG_UPDATE_PHYMODE) { - rt2x00dev->curr_band = conf->channel->band; - rt2x00dev->rx_status.band = conf->channel->band; - } - - rt2x00dev->rx_status.freq = conf->channel->center_freq; + rt2x00dev->curr_band = conf->channel->band; rt2x00dev->tx_power = conf->power_level; + rt2x00dev->short_retry = conf->short_frame_max_tx_count; + rt2x00dev->long_retry = conf->long_frame_max_tx_count; - if (flags & CONFIG_UPDATE_ANTENNA) { - rt2x00dev->link.ant.active.rx = libconf.ant.rx; - rt2x00dev->link.ant.active.tx = libconf.ant.tx; - } + rt2x00dev->rx_status.band = conf->channel->band; + rt2x00dev->rx_status.freq = conf->channel->center_freq; } diff --git a/drivers/net/wireless/rt2x00/rt2x00crypto.c b/drivers/net/wireless/rt2x00/rt2x00crypto.c index 5a858e5106c4c618969080242cf524b345923d0e..37ad0d2fb64c46c0210d17ee5f8fb4462187ad60 100644 --- a/drivers/net/wireless/rt2x00/rt2x00crypto.c +++ b/drivers/net/wireless/rt2x00/rt2x00crypto.c @@ -46,6 +46,29 @@ enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key) } } +void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc) +{ + struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; + + __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); + + txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key); + + if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE) + __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags); + + txdesc->key_idx = hw_key->hw_key_idx; + txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb); + + if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) + __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags); + + if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) + __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags); +} + unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) { struct ieee80211_key_conf *key = tx_info->control.hw_key; @@ -69,6 +92,18 @@ unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) return overhead; } +void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len) +{ + struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); + unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); + + if (unlikely(!iv_len)) + return; + + /* Copy IV/EIV data */ + memcpy(skbdesc->iv, skb->data + header_length, iv_len); +} + void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) { struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); @@ -78,10 +113,7 @@ void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) return; /* Copy IV/EIV data */ - if (iv_len >= 4) - memcpy(&skbdesc->iv, skb->data + header_length, 4); - if (iv_len >= 8) - memcpy(&skbdesc->eiv, skb->data + header_length + 4, 4); + memcpy(skbdesc->iv, skb->data + header_length, iv_len); /* Move ieee80211 header */ memmove(skb->data + iv_len, skb->data, header_length); @@ -98,7 +130,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) struct skb_frame_desc *skbdesc = get_skb_frame_desc(skb); unsigned int header_length = ieee80211_get_hdrlen_from_skb(skb); const unsigned int iv_len = - ((!!(skbdesc->iv)) * 4) + ((!!(skbdesc->eiv)) * 4); + ((!!(skbdesc->iv[0])) * 4) + ((!!(skbdesc->iv[1])) * 4); if (!(skbdesc->flags & FRAME_DESC_IV_STRIPPED)) return; @@ -109,10 +141,7 @@ void rt2x00crypto_tx_insert_iv(struct sk_buff *skb) memmove(skb->data, skb->data + iv_len, header_length); /* Copy IV/EIV data */ - if (iv_len >= 4) - memcpy(skb->data + header_length, &skbdesc->iv, 4); - if (iv_len >= 8) - memcpy(skb->data + header_length + 4, &skbdesc->eiv, 4); + memcpy(skb->data + header_length, skbdesc->iv, iv_len); /* IV/EIV data has returned into the frame */ skbdesc->flags &= ~FRAME_DESC_IV_STRIPPED; @@ -172,17 +201,9 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, header_length); transfer += header_length; - /* Copy IV data */ - if (iv_len >= 4) { - memcpy(skb->data + transfer, &rxdesc->iv, 4); - transfer += 4; - } - - /* Copy EIV data */ - if (iv_len >= 8) { - memcpy(skb->data + transfer, &rxdesc->eiv, 4); - transfer += 4; - } + /* Copy IV/EIV data */ + memcpy(skb->data + transfer, rxdesc->iv, iv_len); + transfer += iv_len; /* Move payload */ if (align) { @@ -198,16 +219,14 @@ void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, */ transfer += payload_len; - /* Copy ICV data */ - if (icv_len >= 4) { - memcpy(skb->data + transfer, &rxdesc->icv, 4); - /* - * AES appends 8 bytes, we can't fill the upper - * 4 bytes, but mac80211 doesn't care about what - * we provide here anyway and strips it immediately. - */ - transfer += icv_len; - } + /* + * Copy ICV data + * AES appends 8 bytes, we can't fill the upper + * 4 bytes, but mac80211 doesn't care about what + * we provide here anyway and strips it immediately. + */ + memcpy(skb->data + transfer, &rxdesc->icv, 4); + transfer += icv_len; /* IV/EIV/ICV has been inserted into frame */ rxdesc->size = transfer; diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 5cf4c859e39d741ec6dfe4595523065ee25e5125..54dd10060bf1a56a8b318ee5e135463b796cc358 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c @@ -285,7 +285,7 @@ exit: } static unsigned int rt2x00debug_poll_queue_dump(struct file *file, - poll_table *wait) + poll_table *wait) { struct rt2x00debug_intf *intf = file->private_data; @@ -377,7 +377,7 @@ static ssize_t rt2x00debug_read_crypto_stats(struct file *file, if (*offset) return 0; - data = kzalloc((1 + CIPHER_MAX)* MAX_LINE_LENGTH, GFP_KERNEL); + data = kzalloc((1 + CIPHER_MAX) * MAX_LINE_LENGTH, GFP_KERNEL); if (!data) return -ENOMEM; @@ -424,16 +424,21 @@ static ssize_t rt2x00debug_read_##__name(struct file *file, \ const struct rt2x00debug *debug = intf->debug; \ char line[16]; \ size_t size; \ + unsigned int index = intf->offset_##__name; \ __type value; \ \ if (*offset) \ return 0; \ \ - if (intf->offset_##__name >= debug->__name.word_count) \ + if (index >= debug->__name.word_count) \ return -EINVAL; \ \ - debug->__name.read(intf->rt2x00dev, \ - intf->offset_##__name, &value); \ + if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ + index *= debug->__name.word_size; \ + \ + index += debug->__name.word_base; \ + \ + debug->__name.read(intf->rt2x00dev, index, &value); \ \ size = sprintf(line, __format, value); \ \ @@ -454,12 +459,13 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ const struct rt2x00debug *debug = intf->debug; \ char line[16]; \ size_t size; \ + unsigned int index = intf->offset_##__name; \ __type value; \ \ if (*offset) \ return 0; \ \ - if (intf->offset_##__name >= debug->__name.word_count) \ + if (index >= debug->__name.word_count) \ return -EINVAL; \ \ if (copy_from_user(line, buf, length)) \ @@ -468,8 +474,12 @@ static ssize_t rt2x00debug_write_##__name(struct file *file, \ size = strlen(line); \ value = simple_strtoul(line, NULL, 0); \ \ - debug->__name.write(intf->rt2x00dev, \ - intf->offset_##__name, value); \ + if (debug->__name.flags & RT2X00DEBUGFS_OFFSET) \ + index *= debug->__name.word_size; \ + \ + index += debug->__name.word_base; \ + \ + debug->__name.write(intf->rt2x00dev, index, value); \ \ *offset += size; \ return size; \ @@ -587,29 +597,29 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) intf->driver_folder = debugfs_create_dir(intf->rt2x00dev->ops->name, rt2x00dev->hw->wiphy->debugfsdir); - if (IS_ERR(intf->driver_folder)) + if (IS_ERR(intf->driver_folder) || !intf->driver_folder) goto exit; intf->driver_entry = rt2x00debug_create_file_driver("driver", intf, &intf->driver_blob); - if (IS_ERR(intf->driver_entry)) + if (IS_ERR(intf->driver_entry) || !intf->driver_entry) goto exit; intf->chipset_entry = rt2x00debug_create_file_chipset("chipset", intf, &intf->chipset_blob); - if (IS_ERR(intf->chipset_entry)) + if (IS_ERR(intf->chipset_entry) || !intf->chipset_entry) goto exit; intf->dev_flags = debugfs_create_file("dev_flags", S_IRUSR, intf->driver_folder, intf, &rt2x00debug_fop_dev_flags); - if (IS_ERR(intf->dev_flags)) + if (IS_ERR(intf->dev_flags) || !intf->dev_flags) goto exit; intf->register_folder = debugfs_create_dir("register", intf->driver_folder); - if (IS_ERR(intf->register_folder)) + if (IS_ERR(intf->register_folder) || !intf->register_folder) goto exit; #define RT2X00DEBUGFS_CREATE_REGISTER_ENTRY(__intf, __name) \ @@ -619,7 +629,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) S_IRUSR | S_IWUSR, \ (__intf)->register_folder, \ &(__intf)->offset_##__name); \ - if (IS_ERR((__intf)->__name##_off_entry)) \ + if (IS_ERR((__intf)->__name##_off_entry) \ + || !(__intf)->__name##_off_entry) \ goto exit; \ \ (__intf)->__name##_val_entry = \ @@ -627,7 +638,8 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) S_IRUSR | S_IWUSR, \ (__intf)->register_folder, \ (__intf), &rt2x00debug_fop_##__name);\ - if (IS_ERR((__intf)->__name##_val_entry)) \ + if (IS_ERR((__intf)->__name##_val_entry) \ + || !(__intf)->__name##_val_entry) \ goto exit; \ }) @@ -640,13 +652,14 @@ void rt2x00debug_register(struct rt2x00_dev *rt2x00dev) intf->queue_folder = debugfs_create_dir("queue", intf->driver_folder); - if (IS_ERR(intf->queue_folder)) + if (IS_ERR(intf->queue_folder) || !intf->queue_folder) goto exit; intf->queue_frame_dump_entry = debugfs_create_file("dump", S_IRUSR, intf->queue_folder, intf, &rt2x00debug_fop_queue_dump); - if (IS_ERR(intf->queue_frame_dump_entry)) + if (IS_ERR(intf->queue_frame_dump_entry) + || !intf->queue_frame_dump_entry) goto exit; skb_queue_head_init(&intf->frame_dump_skbqueue); diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.h b/drivers/net/wireless/rt2x00/rt2x00debug.h index c4ce895aa1c70776100b66536fe54064d2368125..a92104dfee9a6836d90b7ee2270b3c407fc873e8 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.h +++ b/drivers/net/wireless/rt2x00/rt2x00debug.h @@ -28,6 +28,16 @@ struct rt2x00_dev; +/** + * enum rt2x00debugfs_entry_flags: Flags for debugfs registry entry + * + * @RT2X00DEBUGFS_OFFSET: rt2x00lib should pass the register offset + * as argument when using the callback function read()/write() + */ +enum rt2x00debugfs_entry_flags { + RT2X00DEBUGFS_OFFSET = (1 << 0), +}; + #define RT2X00DEBUGFS_REGISTER_ENTRY(__name, __type) \ struct reg##__name { \ void (*read)(struct rt2x00_dev *rt2x00dev, \ @@ -35,6 +45,9 @@ struct reg##__name { \ void (*write)(struct rt2x00_dev *rt2x00dev, \ const unsigned int word, __type data); \ \ + unsigned int flags; \ + \ + unsigned int word_base; \ unsigned int word_size; \ unsigned int word_count; \ } __name diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c index 86840e3585e82e7825072641f112a679434e4c0a..6d92542fcf0da8c509846726e230b0a40d839d84 100644 --- a/drivers/net/wireless/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/rt2x00/rt2x00dev.c @@ -101,8 +101,7 @@ int rt2x00lib_enable_radio(struct rt2x00_dev *rt2x00dev) /* * Initialize all data queues. */ - rt2x00queue_init_rx(rt2x00dev); - rt2x00queue_init_tx(rt2x00dev); + rt2x00queue_init_queues(rt2x00dev); /* * Enable radio. @@ -176,13 +175,14 @@ void rt2x00lib_toggle_rx(struct rt2x00_dev *rt2x00dev, enum dev_state state) static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev) { - enum antenna rx = rt2x00dev->link.ant.active.rx; - enum antenna tx = rt2x00dev->link.ant.active.tx; + struct antenna_setup ant; int sample_a = rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_A); int sample_b = rt2x00_get_link_ant_rssi_history(&rt2x00dev->link, ANTENNA_B); + memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant)); + /* * We are done sampling. Now we should evaluate the results. */ @@ -200,21 +200,22 @@ static void rt2x00lib_evaluate_antenna_sample(struct rt2x00_dev *rt2x00dev) return; if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) - rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; + ant.rx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) - tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; + ant.tx = (sample_a > sample_b) ? ANTENNA_A : ANTENNA_B; - rt2x00lib_config_antenna(rt2x00dev, rx, tx); + rt2x00lib_config_antenna(rt2x00dev, &ant); } static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev) { - enum antenna rx = rt2x00dev->link.ant.active.rx; - enum antenna tx = rt2x00dev->link.ant.active.tx; + struct antenna_setup ant; int rssi_curr = rt2x00_get_link_ant_rssi(&rt2x00dev->link); int rssi_old = rt2x00_update_ant_rssi(&rt2x00dev->link, rssi_curr); + memcpy(&ant, &rt2x00dev->link.ant.active, sizeof(ant)); + /* * Legacy driver indicates that we should swap antenna's * when the difference in RSSI is greater that 5. This @@ -230,12 +231,12 @@ static void rt2x00lib_evaluate_antenna_eval(struct rt2x00_dev *rt2x00dev) rt2x00dev->link.ant.flags |= ANTENNA_MODE_SAMPLE; if (rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) - rx = (rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; + ant.rx = (ant.rx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; if (rt2x00dev->link.ant.flags & ANTENNA_TX_DIVERSITY) - tx = (tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; + ant.tx = (ant.tx == ANTENNA_A) ? ANTENNA_B : ANTENNA_A; - rt2x00lib_config_antenna(rt2x00dev, rx, tx); + rt2x00lib_config_antenna(rt2x00dev, &ant); } static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev) @@ -249,11 +250,9 @@ static void rt2x00lib_evaluate_antenna(struct rt2x00_dev *rt2x00dev) rt2x00dev->link.ant.flags &= ~ANTENNA_RX_DIVERSITY; rt2x00dev->link.ant.flags &= ~ANTENNA_TX_DIVERSITY; - if (rt2x00dev->hw->conf.antenna_sel_rx == 0 && - rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) + if (rt2x00dev->default_ant.rx == ANTENNA_SW_DIVERSITY) rt2x00dev->link.ant.flags |= ANTENNA_RX_DIVERSITY; - if (rt2x00dev->hw->conf.antenna_sel_tx == 0 && - rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) + if (rt2x00dev->default_ant.tx == ANTENNA_SW_DIVERSITY) rt2x00dev->link.ant.flags |= ANTENNA_TX_DIVERSITY; if (!(rt2x00dev->link.ant.flags & ANTENNA_RX_DIVERSITY) && @@ -419,7 +418,7 @@ static void rt2x00lib_intf_scheduled_iter(void *data, u8 *mac, */ spin_lock(&intf->lock); - memcpy(&conf, &intf->conf, sizeof(conf)); + memcpy(&conf, &vif->bss_conf, sizeof(conf)); delayed_flags = intf->delayed_flags; intf->delayed_flags = 0; @@ -500,7 +499,9 @@ void rt2x00lib_txdone(struct queue_entry *entry, { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb); + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); enum data_queue_qid qid = skb_get_queue_mapping(entry->skb); + u8 rate_idx, rate_flags; /* * Unmap the skb. @@ -530,14 +531,18 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->link.qual.tx_failed += test_bit(TXDONE_FAILURE, &txdesc->flags); + rate_idx = skbdesc->tx_rate_idx; + rate_flags = skbdesc->tx_rate_flags; + /* * Initialize TX status */ memset(&tx_info->status, 0, sizeof(tx_info->status)); tx_info->status.ack_signal = 0; - tx_info->status.excessive_retries = - test_bit(TXDONE_EXCESSIVE_RETRY, &txdesc->flags); - tx_info->status.retry_count = txdesc->retry; + tx_info->status.rates[0].idx = rate_idx; + tx_info->status.rates[0].flags = rate_flags; + tx_info->status.rates[0].count = txdesc->retry + 1; + tx_info->status.rates[1].idx = -1; /* terminate */ if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) @@ -546,7 +551,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, rt2x00dev->low_level_stats.dot11ACKFailureCount++; } - if (tx_info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (rate_flags & IEEE80211_TX_RC_USE_RTS_CTS) { if (test_bit(TXDONE_SUCCESS, &txdesc->flags)) rt2x00dev->low_level_stats.dot11RTSSuccessCount++; else if (test_bit(TXDONE_FAILURE, &txdesc->flags)) @@ -570,7 +575,7 @@ void rt2x00lib_txdone(struct queue_entry *entry, entry->skb = NULL; entry->flags = 0; - rt2x00dev->ops->lib->init_txentry(rt2x00dev, entry); + rt2x00dev->ops->lib->clear_entry(entry); clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); rt2x00queue_index_inc(entry->queue, Q_INDEX_DONE); @@ -631,7 +636,8 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, * provided seperately (through hardware descriptor) * in which case we should reinsert the data into the frame. */ - if ((rxdesc.flags & RX_FLAG_IV_STRIPPED)) { + if ((rxdesc.dev_flags & RXDONE_CRYPTO_IV) && + (rxdesc.flags & RX_FLAG_IV_STRIPPED)) { rt2x00crypto_rx_insert_iv(entry->skb, align, header_length, &rxdesc); } else if (align) { @@ -702,7 +708,7 @@ void rt2x00lib_rxdone(struct rt2x00_dev *rt2x00dev, entry->skb = skb; entry->flags = 0; - rt2x00dev->ops->lib->init_rxentry(rt2x00dev, entry); + rt2x00dev->ops->lib->clear_entry(entry); rt2x00queue_index_inc(entry->queue, Q_INDEX); } @@ -713,31 +719,31 @@ EXPORT_SYMBOL_GPL(rt2x00lib_rxdone); */ const struct rt2x00_rate rt2x00_supported_rates[12] = { { - .flags = DEV_RATE_CCK | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK, .bitrate = 10, .ratemask = BIT(0), .plcp = 0x00, }, { - .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 20, .ratemask = BIT(1), .plcp = 0x01, }, { - .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 55, .ratemask = BIT(2), .plcp = 0x02, }, { - .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE | DEV_RATE_BASIC, + .flags = DEV_RATE_CCK | DEV_RATE_SHORT_PREAMBLE, .bitrate = 110, .ratemask = BIT(3), .plcp = 0x03, }, { - .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .flags = DEV_RATE_OFDM, .bitrate = 60, .ratemask = BIT(4), .plcp = 0x0b, @@ -749,7 +755,7 @@ const struct rt2x00_rate rt2x00_supported_rates[12] = { .plcp = 0x0f, }, { - .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .flags = DEV_RATE_OFDM, .bitrate = 120, .ratemask = BIT(6), .plcp = 0x0a, @@ -761,7 +767,7 @@ const struct rt2x00_rate rt2x00_supported_rates[12] = { .plcp = 0x0e, }, { - .flags = DEV_RATE_OFDM | DEV_RATE_BASIC, + .flags = DEV_RATE_OFDM, .bitrate = 240, .ratemask = BIT(8), .plcp = 0x09, @@ -1046,16 +1052,24 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) { int retval = -ENOMEM; + mutex_init(&rt2x00dev->csr_mutex); + /* * Make room for rt2x00_intf inside the per-interface * structure ieee80211_vif. */ rt2x00dev->hw->vif_data_size = sizeof(struct rt2x00_intf); - rt2x00dev->hw->wiphy->interface_modes = - BIT(NL80211_IFTYPE_AP) | - BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC); + /* + * Determine which operating modes are supported, all modes + * which require beaconing, depend on the availability of + * beacon entries. + */ + rt2x00dev->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); + if (rt2x00dev->ops->bcn->entry_num > 0) + rt2x00dev->hw->wiphy->interface_modes |= + BIT(NL80211_IFTYPE_ADHOC) | + BIT(NL80211_IFTYPE_AP); /* * Let the driver probe the device to detect the capabilities. @@ -1247,7 +1261,7 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev) /* * Reconfigure device. */ - retval = rt2x00mac_config(rt2x00dev->hw, &rt2x00dev->hw->conf); + retval = rt2x00mac_config(rt2x00dev->hw, ~0); if (retval) goto exit; diff --git a/drivers/net/wireless/rt2x00/rt2x00leds.c b/drivers/net/wireless/rt2x00/rt2x00leds.c index b362a1cf3f8dcac64d0de1e34b4cb956a73c0312..68f4e0fc35b9e057043b8423a5e752c4e3eb2441 100644 --- a/drivers/net/wireless/rt2x00/rt2x00leds.c +++ b/drivers/net/wireless/rt2x00/rt2x00leds.c @@ -72,49 +72,33 @@ void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi) } } -void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled) +static void rt2x00led_led_simple(struct rt2x00_led *led, bool enabled) { - struct rt2x00_led *led = &rt2x00dev->led_qual; - unsigned int brightness; + unsigned int brightness = enabled ? LED_FULL : LED_OFF; - if ((led->type != LED_TYPE_ACTIVITY) || !(led->flags & LED_REGISTERED)) + if (!(led->flags & LED_REGISTERED)) return; - brightness = enabled ? LED_FULL : LED_OFF; - if (brightness != led->led_dev.brightness) { - led->led_dev.brightness_set(&led->led_dev, brightness); - led->led_dev.brightness = brightness; - } + led->led_dev.brightness_set(&led->led_dev, brightness); + led->led_dev.brightness = brightness; } -void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled) +void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled) { - struct rt2x00_led *led = &rt2x00dev->led_assoc; - unsigned int brightness; - - if ((led->type != LED_TYPE_ASSOC) || !(led->flags & LED_REGISTERED)) - return; + if (rt2x00dev->led_qual.type == LED_TYPE_ACTIVITY) + rt2x00led_led_simple(&rt2x00dev->led_qual, enabled); +} - brightness = enabled ? LED_FULL : LED_OFF; - if (brightness != led->led_dev.brightness) { - led->led_dev.brightness_set(&led->led_dev, brightness); - led->led_dev.brightness = brightness; - } +void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled) +{ + if (rt2x00dev->led_assoc.type == LED_TYPE_ASSOC) + rt2x00led_led_simple(&rt2x00dev->led_assoc, enabled); } void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled) { - struct rt2x00_led *led = &rt2x00dev->led_radio; - unsigned int brightness; - - if ((led->type != LED_TYPE_RADIO) || !(led->flags & LED_REGISTERED)) - return; - - brightness = enabled ? LED_FULL : LED_OFF; - if (brightness != led->led_dev.brightness) { - led->led_dev.brightness_set(&led->led_dev, brightness); - led->led_dev.brightness = brightness; - } + if (rt2x00dev->led_radio.type == LED_TYPE_ASSOC) + rt2x00led_led_simple(&rt2x00dev->led_radio, enabled); } static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, @@ -125,6 +109,7 @@ static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, int retval; led->led_dev.name = name; + led->led_dev.brightness = LED_OFF; retval = led_classdev_register(device, &led->led_dev); if (retval) { @@ -199,7 +184,16 @@ exit_fail: static void rt2x00leds_unregister_led(struct rt2x00_led *led) { led_classdev_unregister(&led->led_dev); - led->led_dev.brightness_set(&led->led_dev, LED_OFF); + + /* + * This might look weird, but when we are unregistering while + * suspended the led is already off, and since we haven't + * fully resumed yet, access to the device might not be + * possible yet. + */ + if (!(led->led_dev.flags & LED_SUSPENDED)) + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->flags &= ~LED_REGISTERED; } @@ -213,22 +207,40 @@ void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev) rt2x00leds_unregister_led(&rt2x00dev->led_radio); } +static inline void rt2x00leds_suspend_led(struct rt2x00_led *led) +{ + led_classdev_suspend(&led->led_dev); + + /* This shouldn't be needed, but just to be safe */ + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->led_dev.brightness = LED_OFF; +} + void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev) { if (rt2x00dev->led_qual.flags & LED_REGISTERED) - led_classdev_suspend(&rt2x00dev->led_qual.led_dev); + rt2x00leds_suspend_led(&rt2x00dev->led_qual); if (rt2x00dev->led_assoc.flags & LED_REGISTERED) - led_classdev_suspend(&rt2x00dev->led_assoc.led_dev); + rt2x00leds_suspend_led(&rt2x00dev->led_assoc); if (rt2x00dev->led_radio.flags & LED_REGISTERED) - led_classdev_suspend(&rt2x00dev->led_radio.led_dev); + rt2x00leds_suspend_led(&rt2x00dev->led_radio); +} + +static inline void rt2x00leds_resume_led(struct rt2x00_led *led) +{ + led_classdev_resume(&led->led_dev); + + /* Device might have enabled the LEDS during resume */ + led->led_dev.brightness_set(&led->led_dev, LED_OFF); + led->led_dev.brightness = LED_OFF; } void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev) { if (rt2x00dev->led_radio.flags & LED_REGISTERED) - led_classdev_resume(&rt2x00dev->led_radio.led_dev); + rt2x00leds_resume_led(&rt2x00dev->led_radio); if (rt2x00dev->led_assoc.flags & LED_REGISTERED) - led_classdev_resume(&rt2x00dev->led_assoc.led_dev); + rt2x00leds_resume_led(&rt2x00dev->led_assoc); if (rt2x00dev->led_qual.flags & LED_REGISTERED) - led_classdev_resume(&rt2x00dev->led_qual.led_dev); + rt2x00leds_resume_led(&rt2x00dev->led_qual); } diff --git a/drivers/net/wireless/rt2x00/rt2x00lib.h b/drivers/net/wireless/rt2x00/rt2x00lib.h index 797eb619aa0af918d9591fc56a9b4281448720b0..03024327767be6c83f23343914bed7e208840377 100644 --- a/drivers/net/wireless/rt2x00/rt2x00lib.h +++ b/drivers/net/wireless/rt2x00/rt2x00lib.h @@ -43,7 +43,6 @@ struct rt2x00_rate { #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; @@ -94,9 +93,10 @@ 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); + struct antenna_setup *ant); void rt2x00lib_config(struct rt2x00_dev *rt2x00dev, - struct ieee80211_conf *conf, const int force_config); + struct ieee80211_conf *conf, + const unsigned int changed_flags); /** * DOC: Queue handlers @@ -150,8 +150,16 @@ int rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev, */ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index); -void rt2x00queue_init_rx(struct rt2x00_dev *rt2x00dev); -void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev); +/** + * rt2x00queue_init_queues - Initialize all data queues + * @rt2x00dev: Pointer to &struct rt2x00_dev. + * + * This function will loop through all available queues to clear all + * index numbers and set the queue entry to the correct initialization + * state. + */ +void rt2x00queue_init_queues(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); @@ -210,7 +218,10 @@ static inline void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, */ #ifdef CONFIG_RT2X00_LIB_CRYPTO enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf *key); +void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc); unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info); +void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, unsigned int iv_len); void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len); void rt2x00crypto_tx_insert_iv(struct sk_buff *skb); void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, unsigned int align, @@ -222,11 +233,21 @@ static inline enum cipher rt2x00crypto_key_to_cipher(struct ieee80211_key_conf * return CIPHER_NONE; } +static inline void rt2x00crypto_create_tx_descriptor(struct queue_entry *entry, + struct txentry_desc *txdesc) +{ +} + static inline unsigned int rt2x00crypto_tx_overhead(struct ieee80211_tx_info *tx_info) { return 0; } +static inline void rt2x00crypto_tx_copy_iv(struct sk_buff *skb, + unsigned int iv_len) +{ +} + static inline void rt2x00crypto_tx_remove_iv(struct sk_buff *skb, unsigned int iv_len) { @@ -242,7 +263,7 @@ static inline void rt2x00crypto_rx_insert_iv(struct sk_buff *skb, struct rxdone_entry_desc *rxdesc) { } -#endif +#endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* * RFkill handlers. diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c index 2c6cc5c374ff3be765b681e07d17fede815a3d22..38edee5fe1683c1022e3739efa808e0292f61eea 100644 --- a/drivers/net/wireless/rt2x00/rt2x00mac.c +++ b/drivers/net/wireless/rt2x00/rt2x00mac.c @@ -39,7 +39,7 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, unsigned int data_length; int retval = 0; - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) data_length = sizeof(struct ieee80211_cts); else data_length = sizeof(struct ieee80211_rts); @@ -64,11 +64,11 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, */ memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); rts_info = IEEE80211_SKB_CB(skb); - rts_info->flags &= ~IEEE80211_TX_CTL_USE_RTS_CTS; - rts_info->flags &= ~IEEE80211_TX_CTL_USE_CTS_PROTECT; + rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; + rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT; rts_info->flags &= ~IEEE80211_TX_CTL_REQ_TX_STATUS; - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) rts_info->flags |= IEEE80211_TX_CTL_NO_ACK; else rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; @@ -79,12 +79,10 @@ static int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, * RTS/CTS frame should use the length of the frame plus any * encryption overhead that will be added by the hardware. */ -#ifdef CONFIG_RT2X00_LIB_CRYPTO if (!frag_skb->do_not_encrypt) data_length += rt2x00crypto_tx_overhead(tx_info); -#endif /* CONFIG_RT2X00_LIB_CRYPTO */ - if (tx_info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, frag_skb->data, data_length, tx_info, (struct ieee80211_cts *)(skb->data)); @@ -132,8 +130,7 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) ERROR(rt2x00dev, "Attempt to send packet over invalid queue %d.\n" "Please file bug report to %s.\n", qid, DRV_PROJECT); - dev_kfree_skb_any(skb); - return NETDEV_TX_OK; + goto exit_fail; } /* @@ -146,8 +143,8 @@ int rt2x00mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb) * inside the hardware. */ frame_control = le16_to_cpu(ieee80211hdr->frame_control); - if ((tx_info->flags & (IEEE80211_TX_CTL_USE_RTS_CTS | - IEEE80211_TX_CTL_USE_CTS_PROTECT)) && + if ((tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS | + IEEE80211_TX_RC_USE_CTS_PROTECT)) && !rt2x00dev->ops->hw->set_rts_threshold) { if (rt2x00queue_available(queue) <= 1) goto exit_fail; @@ -335,10 +332,10 @@ void rt2x00mac_remove_interface(struct ieee80211_hw *hw, } EXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); -int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) { struct rt2x00_dev *rt2x00dev = hw->priv; - int radio_on; + struct ieee80211_conf *conf = &hw->conf; int status; /* @@ -355,7 +352,6 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * some configuration parameters (e.g. channel and antenna values) can * only be set when the radio is enabled. */ - radio_on = test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags); if (conf->radio_enabled) { /* For programming the values, we have to turn RX off */ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_OFF); @@ -369,7 +365,18 @@ int rt2x00mac_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) * When we've just turned on the radio, we want to reprogram * everything to ensure a consistent state */ - rt2x00lib_config(rt2x00dev, conf, !radio_on); + rt2x00lib_config(rt2x00dev, conf, changed); + + /* + * The radio was enabled, configure the antenna to the + * default settings, the link tuner will later start + * continue configuring the antenna based on the software + * diversity. But for non-diversity configurations, we need + * to have configured the correct state now. + */ + if (changed & IEEE80211_CONF_CHANGE_RADIO_ENABLED) + rt2x00lib_config_antenna(rt2x00dev, + &rt2x00dev->default_ant); /* Turn RX back on */ rt2x00lib_toggle_rx(rt2x00dev, STATE_RADIO_RX_ON); @@ -480,12 +487,15 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, struct ieee80211_key_conf *key) { struct rt2x00_dev *rt2x00dev = hw->priv; + struct ieee80211_sta *sta; int (*set_key) (struct rt2x00_dev *rt2x00dev, struct rt2x00lib_crypto *crypto, struct ieee80211_key_conf *key); struct rt2x00lib_crypto crypto; - if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) + if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) + return 0; + else if (!test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) return -EOPNOTSUPP; else if (key->keylen > 32) return -ENOSPC; @@ -527,6 +537,17 @@ int rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, } else memcpy(&crypto.key, &key->key[0], key->keylen); + /* + * Discover the Association ID from mac80211. + * Some drivers need this information when updating the + * hardware key (either adding or removing). + */ + rcu_read_lock(); + sta = ieee80211_find_sta(hw, address); + if (sta) + crypto.aid = sta->aid; + rcu_read_unlock(); + /* * Each BSS has a maximum of 4 shared keys. * Shared key index values: @@ -625,7 +646,7 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, * 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 | BSS_CHANGED_ERP_CTS_PROT)) { + if (changes & ~(BSS_CHANGED_ASSOC | BSS_CHANGED_HT)) { if (!test_bit(DRIVER_REQUIRE_SCHEDULED, &rt2x00dev->flags)) rt2x00lib_config_erp(rt2x00dev, intf, bss_conf); else @@ -633,7 +654,6 @@ void rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, } spin_lock(&intf->lock); - memcpy(&intf->conf, bss_conf, sizeof(*bss_conf)); if (delayed) { intf->delayed_flags |= delayed; schedule_work(&rt2x00dev->intf_work); diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.c b/drivers/net/wireless/rt2x00/rt2x00pci.c index adf2876ed8ab77de00d5c3676b781d4c62edeabf..d52b22b82d1fb4662184b653efe50f99b43fec13 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.c +++ b/drivers/net/wireless/rt2x00/rt2x00pci.c @@ -31,25 +31,47 @@ #include "rt2x00.h" #include "rt2x00pci.h" +/* + * Register access. + */ +int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const struct rt2x00_field32 field, + u32 *reg) +{ + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00pci_register_read(rt2x00dev, offset, reg); + if (!rt2x00_get_field32(*reg, field)) + return 1; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "Indirect register access failed: " + "offset=0x%.08x, value=0x%.08x\n", offset, *reg); + *reg = ~0; + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00pci_regbusy_read); + /* * TX data handlers. */ int rt2x00pci_write_tx_data(struct queue_entry *entry) { + struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_pci *entry_priv = entry->priv_data; struct skb_frame_desc *skbdesc; - u32 word; - - rt2x00_desc_read(entry_priv->desc, 0, &word); /* * This should not happen, we already checked the entry * was ours. When the hardware disagrees there has been * a queue corruption! */ - if (unlikely(rt2x00_get_field32(word, TXD_ENTRY_OWNER_NIC) || - rt2x00_get_field32(word, TXD_ENTRY_VALID))) { - ERROR(entry->queue->rt2x00dev, + if (unlikely(rt2x00dev->ops->lib->get_entry_state(entry))) { + ERROR(rt2x00dev, "Corrupt queue %d, accessing entry which is not ours.\n" "Please file bug report to %s.\n", entry->queue->qid, DRV_PROJECT); @@ -76,14 +98,12 @@ void rt2x00pci_rxdone(struct rt2x00_dev *rt2x00dev) struct queue_entry *entry; struct queue_entry_priv_pci *entry_priv; struct skb_frame_desc *skbdesc; - u32 word; while (1) { entry = rt2x00queue_get_entry(queue, Q_INDEX); entry_priv = entry->priv_data; - rt2x00_desc_read(entry_priv->desc, 0, &word); - if (rt2x00_get_field32(word, RXD_ENTRY_OWNER_NIC)) + if (rt2x00dev->ops->lib->get_entry_state(entry)) break; /* @@ -222,8 +242,7 @@ static int rt2x00pci_alloc_reg(struct rt2x00_dev *rt2x00dev) { struct pci_dev *pci_dev = to_pci_dev(rt2x00dev->dev); - rt2x00dev->csr.base = ioremap(pci_resource_start(pci_dev, 0), - pci_resource_len(pci_dev, 0)); + rt2x00dev->csr.base = pci_ioremap_bar(pci_dev, 0); if (!rt2x00dev->csr.base) goto exit; diff --git a/drivers/net/wireless/rt2x00/rt2x00pci.h b/drivers/net/wireless/rt2x00/rt2x00pci.h index 80bf97c03e2d159395f46d9933db3be0275948c8..9c0a4d77bc1be1e16ab79940c3c2cb0aa65859c2 100644 --- a/drivers/net/wireless/rt2x00/rt2x00pci.h +++ b/drivers/net/wireless/rt2x00/rt2x00pci.h @@ -43,22 +43,11 @@ #define REGISTER_BUSY_COUNT 5 #define REGISTER_BUSY_DELAY 100 -/* - * Descriptor availability flags. - * All PCI device descriptors have these 2 flags - * with the exact same definition. - * By storing them here we can use them inside rt2x00pci - * for some simple entry availability checking. - */ -#define TXD_ENTRY_OWNER_NIC FIELD32(0x00000001) -#define TXD_ENTRY_VALID FIELD32(0x00000002) -#define RXD_ENTRY_OWNER_NIC FIELD32(0x00000001) - /* * Register access. */ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, u32 *value) { *value = readl(rt2x00dev->csr.base + offset); @@ -66,14 +55,14 @@ static inline void rt2x00pci_register_read(struct rt2x00_dev *rt2x00dev, static inline void rt2x00pci_register_multiread(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, void *value, const u16 length) { memcpy_fromio(value, rt2x00dev->csr.base + offset, length); } static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, u32 value) { writel(value, rt2x00dev->csr.base + offset); @@ -81,12 +70,30 @@ static inline void rt2x00pci_register_write(struct rt2x00_dev *rt2x00dev, static inline void rt2x00pci_register_multiwrite(struct rt2x00_dev *rt2x00dev, - const unsigned long offset, + const unsigned int offset, const void *value, const u16 length) { memcpy_toio(rt2x00dev->csr.base + offset, value, length); } +/** + * rt2x00pci_regbusy_read - Read from register with busy check + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @field: Field to check if register is busy + * @reg: Pointer to where register contents should be stored + * + * This function will read the given register, and checks if the + * register is busy. If it is, it will sleep for a couple of + * microseconds before reading the register again. If the register + * is not read after a certain timeout, this function will return + * FALSE. + */ +int rt2x00pci_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + const struct rt2x00_field32 field, + u32 *reg); + /** * rt2x00pci_write_tx_data - Initialize data for TX operation * @entry: The entry where the frame is located diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c index 451d410ecdae4fae126ab835bdadd5647a4f13b8..eaec6bd93ed5e0adc3f5a0911a8d9dac72356db1 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.c +++ b/drivers/net/wireless/rt2x00/rt2x00queue.c @@ -55,14 +55,12 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct rt2x00_dev *rt2x00dev, /* * For IV/EIV/ICV assembly we must make sure there is * at least 8 bytes bytes available in headroom for IV/EIV - * and 4 bytes for ICV data as tailroon. + * and 8 bytes for ICV data as tailroon. */ -#ifdef CONFIG_RT2X00_LIB_CRYPTO if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags)) { head_size += 8; - tail_size += 4; + tail_size += 8; } -#endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* * Allocate skbuffer. @@ -174,7 +172,7 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, txdesc->cw_max = entry->queue->cw_max; txdesc->aifs = entry->queue->aifs; - /* Data length + CRC + IV/EIV/ICV/MMIC (when using encryption) */ + /* Data length + CRC */ data_length = entry->skb->len + 4; /* @@ -183,34 +181,17 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK)) __set_bit(ENTRY_TXD_ACK, &txdesc->flags); -#ifdef CONFIG_RT2X00_LIB_CRYPTO if (test_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags) && !entry->skb->do_not_encrypt) { - struct ieee80211_key_conf *hw_key = tx_info->control.hw_key; - - __set_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags); - - txdesc->cipher = rt2x00crypto_key_to_cipher(hw_key); - - if (hw_key->flags & IEEE80211_KEY_FLAG_PAIRWISE) - __set_bit(ENTRY_TXD_ENCRYPT_PAIRWISE, &txdesc->flags); - - txdesc->key_idx = hw_key->hw_key_idx; - txdesc->iv_offset = ieee80211_get_hdrlen_from_skb(entry->skb); + /* Apply crypto specific descriptor information */ + rt2x00crypto_create_tx_descriptor(entry, txdesc); /* * Extend frame length to include all encryption overhead * that will be added by the hardware. */ data_length += rt2x00crypto_tx_overhead(tx_info); - - if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_IV)) - __set_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc->flags); - - if (!(hw_key->flags & IEEE80211_KEY_FLAG_GENERATE_MMIC)) - __set_bit(ENTRY_TXD_ENCRYPT_MMIC, &txdesc->flags); } -#endif /* CONFIG_RT2X00_LIB_CRYPTO */ /* * Check if this is a RTS/CTS frame @@ -230,8 +211,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Determine retry information. */ - txdesc->retry_limit = tx_info->control.retry_limit; - if (tx_info->flags & IEEE80211_TX_CTL_LONG_RETRY_LIMIT) + txdesc->retry_limit = tx_info->control.rates[0].count - 1; + if (txdesc->retry_limit >= rt2x00dev->long_retry) __set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags); /* @@ -312,8 +293,8 @@ static void rt2x00queue_create_tx_descriptor(struct queue_entry *entry, /* * Convert length to microseconds. */ - residual = get_duration_res(data_length, hwrate->bitrate); - duration = get_duration(data_length, hwrate->bitrate); + residual = GET_DURATION_RES(data_length, hwrate->bitrate); + duration = GET_DURATION(data_length, hwrate->bitrate); if (residual != 0) { duration++; @@ -371,13 +352,15 @@ static void rt2x00queue_write_tx_descriptor(struct queue_entry *entry, int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) { + struct ieee80211_tx_info *tx_info; struct queue_entry *entry = rt2x00queue_get_entry(queue, Q_INDEX); struct txentry_desc txdesc; struct skb_frame_desc *skbdesc; unsigned int iv_len = 0; + u8 rate_idx, rate_flags; if (unlikely(rt2x00queue_full(queue))) - return -EINVAL; + return -ENOBUFS; if (test_and_set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags)) { ERROR(queue->rt2x00dev, @@ -399,13 +382,18 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) iv_len = IEEE80211_SKB_CB(skb)->control.hw_key->iv_len; /* - * All information is retreived from the skb->cb array, + * All information is retrieved from the skb->cb array, * now we should claim ownership of the driver part of that - * array. + * array, preserving the bitrate index and flags. */ - skbdesc = get_skb_frame_desc(entry->skb); + tx_info = IEEE80211_SKB_CB(skb); + rate_idx = tx_info->control.rates[0].idx; + rate_flags = tx_info->control.rates[0].flags; + skbdesc = get_skb_frame_desc(skb); memset(skbdesc, 0, sizeof(*skbdesc)); skbdesc->entry = entry; + skbdesc->tx_rate_idx = rate_idx; + skbdesc->tx_rate_flags = rate_flags; /* * When hardware encryption is supported, and this frame @@ -414,19 +402,21 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb) */ if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) && !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) { - rt2x00crypto_tx_remove_iv(skb, iv_len); + if (test_bit(CONFIG_CRYPTO_COPY_IV, &queue->rt2x00dev->flags)) + rt2x00crypto_tx_copy_iv(skb, iv_len); + else + rt2x00crypto_tx_remove_iv(skb, iv_len); } /* * It could be possible that the queue was corrupted and this - * call failed. Just drop the frame, we cannot rollback and pass - * the frame to mac80211 because the skb->cb has now been tainted. + * call failed. Since we always return NETDEV_TX_OK to mac80211, + * this frame will simply be dropped. */ if (unlikely(queue->rt2x00dev->ops->lib->write_tx_data(entry))) { clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - dev_kfree_skb_any(entry->skb); entry->skb = NULL; - return 0; + return -EIO; } if (test_bit(DRIVER_REQUIRE_DMA, &queue->rt2x00dev->flags)) @@ -556,7 +546,7 @@ void rt2x00queue_index_inc(struct data_queue *queue, enum queue_index index) queue->length++; } else if (index == Q_INDEX_DONE) { queue->length--; - queue->count ++; + queue->count++; } spin_unlock_irqrestore(&queue->lock, irqflags); @@ -575,40 +565,18 @@ static void rt2x00queue_reset(struct data_queue *queue) 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++) { - queue->entries[i].flags = 0; - - rt2x00dev->ops->lib->init_rxentry(rt2x00dev, - &queue->entries[i]); - } -} - -void rt2x00queue_init_tx(struct rt2x00_dev *rt2x00dev) +void rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev) { struct data_queue *queue; unsigned int i; - txall_queue_for_each(rt2x00dev, queue) { + queue_for_each(rt2x00dev, queue) { rt2x00queue_reset(queue); - if (!rt2x00dev->ops->lib->init_txentry) - continue; - for (i = 0; i < queue->limit; i++) { queue->entries[i].flags = 0; - rt2x00dev->ops->lib->init_txentry(rt2x00dev, - &queue->entries[i]); + rt2x00dev->ops->lib->clear_entry(&queue->entries[i]); } } } diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.h b/drivers/net/wireless/rt2x00/rt2x00queue.h index 9dbf04f0f04c1ceeae6ac10f0789aec9eb649a95..28293715340849363aa98eeb480f18f593fae7ec 100644 --- a/drivers/net/wireless/rt2x00/rt2x00queue.h +++ b/drivers/net/wireless/rt2x00/rt2x00queue.h @@ -104,22 +104,25 @@ enum skb_frame_desc_flags { * * @flags: Frame flags, see &enum skb_frame_desc_flags. * @desc_len: Length of the frame descriptor. + * @tx_rate_idx: the index of the TX rate, used for TX status reporting + * @tx_rate_flags: the TX rate flags, used for TX status reporting * @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. - * @iv: IV data used during encryption/decryption. - * @eiv: EIV data used during encryption/decryption. + * @iv: IV/EIV data used during encryption/decryption. * @skb_dma: (PCI-only) the DMA address associated with the sk buffer. * @entry: The entry to which this sk buffer belongs. */ struct skb_frame_desc { - unsigned int flags; + u8 flags; + + u8 desc_len; + u8 tx_rate_idx; + u8 tx_rate_flags; - unsigned int desc_len; void *desc; - __le32 iv; - __le32 eiv; + __le32 iv[2]; dma_addr_t skb_dma; @@ -143,11 +146,15 @@ static inline struct skb_frame_desc* get_skb_frame_desc(struct sk_buff *skb) * @RXDONE_SIGNAL_PLCP: Signal field contains the plcp value. * @RXDONE_SIGNAL_BITRATE: Signal field contains the bitrate value. * @RXDONE_MY_BSS: Does this frame originate from device's BSS. + * @RXDONE_CRYPTO_IV: Driver provided IV/EIV data. + * @RXDONE_CRYPTO_ICV: Driver provided ICV data. */ enum rxdone_entry_desc_flags { RXDONE_SIGNAL_PLCP = 1 << 0, RXDONE_SIGNAL_BITRATE = 1 << 1, RXDONE_MY_BSS = 1 << 2, + RXDONE_CRYPTO_IV = 1 << 3, + RXDONE_CRYPTO_ICV = 1 << 4, }; /** @@ -163,8 +170,7 @@ enum rxdone_entry_desc_flags { * @dev_flags: Ralink receive flags (See &enum rxdone_entry_desc_flags). * @cipher: Cipher type used during decryption. * @cipher_status: Decryption status. - * @iv: IV data used during decryption. - * @eiv: EIV data used during decryption. + * @iv: IV/EIV data used during decryption. * @icv: ICV data used during decryption. */ struct rxdone_entry_desc { @@ -177,8 +183,7 @@ struct rxdone_entry_desc { u8 cipher; u8 cipher_status; - __le32 iv; - __le32 eiv; + __le32 iv[2]; __le32 icv; }; @@ -375,6 +380,8 @@ enum queue_index { * @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. + * @usb_endpoint: Device endpoint used for communication (USB only) + * @usb_maxpacket: Max packet size for given endpoint (USB only) */ struct data_queue { struct rt2x00_dev *rt2x00dev; @@ -396,6 +403,9 @@ struct data_queue { unsigned short data_size; unsigned short desc_size; + + unsigned short usb_endpoint; + unsigned short usb_maxpacket; }; /** @@ -438,6 +448,19 @@ struct data_queue_desc { #define tx_queue_end(__dev) \ &(__dev)->tx[(__dev)->ops->tx_queues] +/** + * queue_next - Return pointer to next queue in list (HELPER MACRO). + * @__queue: Current queue for which we need the next queue + * + * Using the current queue address we take the address directly + * after the queue to take the next queue. Note that this macro + * should be used carefully since it does not protect against + * moving past the end of the list. (See macros &queue_end and + * &tx_queue_end for determining the end of the queue). + */ +#define queue_next(__queue) \ + &(__queue)[1] + /** * queue_loop - Loop through the queues within a specific range (HELPER MACRO). * @__entry: Pointer where the current queue entry will be stored in. @@ -448,8 +471,8 @@ struct data_queue_desc { */ #define queue_loop(__entry, __start, __end) \ for ((__entry) = (__start); \ - prefetch(&(__entry)[1]), (__entry) != (__end); \ - (__entry) = &(__entry)[1]) + prefetch(queue_next(__entry)), (__entry) != (__end);\ + (__entry) = queue_next(__entry)) /** * queue_for_each - Loop through all queues diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c index b73a7e0aeed4c54221435bbb3050326450dc093a..83df312ac56fe02b3b833022c8f432d674e0215e 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.c +++ b/drivers/net/wireless/rt2x00/rt2x00usb.c @@ -79,7 +79,7 @@ int rt2x00usb_vendor_req_buff_lock(struct rt2x00_dev *rt2x00dev, { int status; - BUG_ON(!mutex_is_locked(&rt2x00dev->usb_cache_mutex)); + BUG_ON(!mutex_is_locked(&rt2x00dev->csr_mutex)); /* * Check for Cache availability. @@ -110,13 +110,13 @@ int rt2x00usb_vendor_request_buff(struct rt2x00_dev *rt2x00dev, { int status; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); status = rt2x00usb_vendor_req_buff_lock(rt2x00dev, request, requesttype, offset, buffer, buffer_length, timeout); - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); return status; } @@ -132,7 +132,7 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, unsigned char *tb; u16 off, len, bsize; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); tb = (char *)buffer; off = offset; @@ -148,12 +148,34 @@ int rt2x00usb_vendor_request_large_buff(struct rt2x00_dev *rt2x00dev, off += bsize; } - mutex_unlock(&rt2x00dev->usb_cache_mutex); + mutex_unlock(&rt2x00dev->csr_mutex); return status; } EXPORT_SYMBOL_GPL(rt2x00usb_vendor_request_large_buff); +int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field32 field, + u32 *reg) +{ + unsigned int i; + + for (i = 0; i < REGISTER_BUSY_COUNT; i++) { + rt2x00usb_register_read_lock(rt2x00dev, offset, reg); + if (!rt2x00_get_field32(*reg, field)) + return 1; + udelay(REGISTER_BUSY_DELAY); + } + + ERROR(rt2x00dev, "Indirect register access failed: " + "offset=0x%.08x, value=0x%.08x\n", offset, *reg); + *reg = ~0; + + return 0; +} +EXPORT_SYMBOL_GPL(rt2x00usb_regbusy_read); + /* * TX data handlers. */ @@ -212,10 +234,10 @@ int rt2x00usb_write_tx_data(struct queue_entry *entry) * length of the data to usb_fill_bulk_urb. Pass the skb * to the driver to determine what the length should be. */ - length = rt2x00dev->ops->lib->get_tx_data_len(rt2x00dev, entry->skb); + length = rt2x00dev->ops->lib->get_tx_data_len(entry); usb_fill_bulk_urb(entry_priv->urb, usb_dev, - usb_sndbulkpipe(usb_dev, 1), + usb_sndbulkpipe(usb_dev, entry->queue->usb_endpoint), entry->skb->data, length, rt2x00usb_interrupt_txdone, entry); @@ -351,28 +373,96 @@ EXPORT_SYMBOL_GPL(rt2x00usb_disable_radio); /* * Device initialization handlers. */ -void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +void rt2x00usb_clear_entry(struct queue_entry *entry) { - struct usb_device *usb_dev = to_usb_device_intf(rt2x00dev->dev); + struct usb_device *usb_dev = + to_usb_device_intf(entry->queue->rt2x00dev->dev); struct queue_entry_priv_usb *entry_priv = entry->priv_data; + int pipe; - usb_fill_bulk_urb(entry_priv->urb, usb_dev, - usb_rcvbulkpipe(usb_dev, 1), - entry->skb->data, entry->skb->len, - rt2x00usb_interrupt_rxdone, entry); + if (entry->queue->qid == QID_RX) { + pipe = usb_rcvbulkpipe(usb_dev, entry->queue->usb_endpoint); + usb_fill_bulk_urb(entry_priv->urb, usb_dev, pipe, + entry->skb->data, entry->skb->len, + rt2x00usb_interrupt_rxdone, entry); - set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); - usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + set_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags); + usb_submit_urb(entry_priv->urb, GFP_ATOMIC); + } else { + entry->flags = 0; + } } -EXPORT_SYMBOL_GPL(rt2x00usb_init_rxentry); +EXPORT_SYMBOL_GPL(rt2x00usb_clear_entry); -void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt2x00usb_assign_endpoint(struct data_queue *queue, + struct usb_endpoint_descriptor *ep_desc) { - entry->flags = 0; + struct usb_device *usb_dev = to_usb_device_intf(queue->rt2x00dev->dev); + int pipe; + + queue->usb_endpoint = usb_endpoint_num(ep_desc); + + if (queue->qid == QID_RX) { + pipe = usb_rcvbulkpipe(usb_dev, queue->usb_endpoint); + queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 0); + } else { + pipe = usb_sndbulkpipe(usb_dev, queue->usb_endpoint); + queue->usb_maxpacket = usb_maxpacket(usb_dev, pipe, 1); + } + + if (!queue->usb_maxpacket) + queue->usb_maxpacket = 1; +} + +static int rt2x00usb_find_endpoints(struct rt2x00_dev *rt2x00dev) +{ + struct usb_interface *intf = to_usb_interface(rt2x00dev->dev); + struct usb_host_interface *intf_desc = intf->cur_altsetting; + struct usb_endpoint_descriptor *ep_desc; + struct data_queue *queue = rt2x00dev->tx; + struct usb_endpoint_descriptor *tx_ep_desc = NULL; + unsigned int i; + + /* + * Walk through all available endpoints to search for "bulk in" + * and "bulk out" endpoints. When we find such endpoints collect + * the information we need from the descriptor and assign it + * to the queue. + */ + for (i = 0; i < intf_desc->desc.bNumEndpoints; i++) { + ep_desc = &intf_desc->endpoint[i].desc; + + if (usb_endpoint_is_bulk_in(ep_desc)) { + rt2x00usb_assign_endpoint(rt2x00dev->rx, ep_desc); + } else if (usb_endpoint_is_bulk_out(ep_desc)) { + rt2x00usb_assign_endpoint(queue, ep_desc); + + if (queue != queue_end(rt2x00dev)) + queue = queue_next(queue); + tx_ep_desc = ep_desc; + } + } + + /* + * At least 1 endpoint for RX and 1 endpoint for TX must be available. + */ + if (!rt2x00dev->rx->usb_endpoint || !rt2x00dev->tx->usb_endpoint) { + ERROR(rt2x00dev, "Bulk-in/Bulk-out endpoints not found\n"); + return -EPIPE; + } + + /* + * It might be possible not all queues have a dedicated endpoint. + * Loop through all TX queues and copy the endpoint information + * which we have gathered from already assigned endpoints. + */ + txall_queue_for_each(rt2x00dev, queue) { + if (!queue->usb_endpoint) + rt2x00usb_assign_endpoint(queue, tx_ep_desc); + } + + return 0; } -EXPORT_SYMBOL_GPL(rt2x00usb_init_txentry); static int rt2x00usb_alloc_urb(struct rt2x00_dev *rt2x00dev, struct data_queue *queue) @@ -444,6 +534,13 @@ int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev) struct data_queue *queue; int status; + /* + * Find endpoints for each queue + */ + status = rt2x00usb_find_endpoints(rt2x00dev); + if (status) + goto exit; + /* * Allocate DMA */ @@ -534,12 +631,6 @@ int rt2x00usb_probe(struct usb_interface *usb_intf, rt2x00dev->dev = &usb_intf->dev; rt2x00dev->ops = ops; rt2x00dev->hw = hw; - mutex_init(&rt2x00dev->usb_cache_mutex); - - rt2x00dev->usb_maxpacket = - usb_maxpacket(usb_dev, usb_sndbulkpipe(usb_dev, 1), 1); - if (!rt2x00dev->usb_maxpacket) - rt2x00dev->usb_maxpacket = 1; retval = rt2x00usb_alloc_reg(rt2x00dev); if (retval) diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.h b/drivers/net/wireless/rt2x00/rt2x00usb.h index 3b4a67417f956625c55da3b88568ed08f140e3e5..2bd4ac855f528db67f60879ee2166a7b280b037f 100644 --- a/drivers/net/wireless/rt2x00/rt2x00usb.h +++ b/drivers/net/wireless/rt2x00/rt2x00usb.h @@ -231,6 +231,142 @@ static inline int rt2x00usb_eeprom_read(struct rt2x00_dev *rt2x00dev, REGISTER_TIMEOUT16(length)); } +/** + * rt2x00usb_regbusy_read - Read 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Pointer to where register contents should be stored + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) +{ + __le32 reg; + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); + *value = le32_to_cpu(reg); +} + +/** + * rt2x00usb_register_read_lock - Read 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Pointer to where register contents should be stored + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_req_buff_lock(). + */ +static inline void rt2x00usb_register_read_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 *value) +{ + __le32 reg; + rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); + *value = le32_to_cpu(reg); +} + +/** + * rt2x00usb_register_multiread - Read 32bit register words + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Pointer to where register contents should be stored + * @length: Length of the data + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_multiread(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, + USB_VENDOR_REQUEST_IN, offset, + value, length, + REGISTER_TIMEOUT32(length)); +} + +/** + * rt2x00usb_register_write - Write 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Data which should be written + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_write(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + __le32 reg = cpu_to_le32(value); + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); +} + +/** + * rt2x00usb_register_write_lock - Write 32bit register word + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Data which should be written + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_req_buff_lock(). + */ +static inline void rt2x00usb_register_write_lock(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + u32 value) +{ + __le32 reg = cpu_to_le32(value); + rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + ®, sizeof(reg), REGISTER_TIMEOUT); +} + +/** + * rt2x00usb_register_multiwrite - Write 32bit register words + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @value: Data which should be written + * @length: Length of the data + * + * This function is a simple wrapper for 32bit register access + * through rt2x00usb_vendor_request_buff(). + */ +static inline void rt2x00usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + void *value, const u32 length) +{ + rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, + USB_VENDOR_REQUEST_OUT, offset, + value, length, + REGISTER_TIMEOUT32(length)); +} + +/** + * rt2x00usb_regbusy_read - Read from register with busy check + * @rt2x00dev: Device pointer, see &struct rt2x00_dev. + * @offset: Register offset + * @field: Field to check if register is busy + * @reg: Pointer to where register contents should be stored + * + * This function will read the given register, and checks if the + * register is busy. If it is, it will sleep for a couple of + * microseconds before reading the register again. If the register + * is not read after a certain timeout, this function will return + * FALSE. + */ +int rt2x00usb_regbusy_read(struct rt2x00_dev *rt2x00dev, + const unsigned int offset, + struct rt2x00_field32 field, + u32 *reg); + /* * Radio handlers */ @@ -286,10 +422,7 @@ void rt2x00usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, /* * Device initialization handlers. */ -void rt2x00usb_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); -void rt2x00usb_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry); +void rt2x00usb_clear_entry(struct queue_entry *entry); int rt2x00usb_initialize(struct rt2x00_dev *rt2x00dev); void rt2x00usb_uninitialize(struct rt2x00_dev *rt2x00dev); diff --git a/drivers/net/wireless/rt2x00/rt61pci.c b/drivers/net/wireless/rt2x00/rt61pci.c index a461620b489f0350536bb06148e2813c609ea77f..987e89009f74ed36debc32498783d57812b68916 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.c +++ b/drivers/net/wireless/rt2x00/rt61pci.c @@ -55,45 +55,36 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * the access attempt is considered to have failed, * and we will print an error. */ -static u32 rt61pci_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, PHY_CSR3, ®); - if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - break; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg)) +#define WAIT_FOR_MCU(__dev, __reg) \ + rt2x00pci_regbusy_read((__dev), H2M_MAILBOX_CSR, \ + H2M_MAILBOX_CSR_OWNER, (__reg)) static void rt61pci_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { - ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the data into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_VALUE, value); - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_VALUE, value); + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); + + rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + } - rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -101,66 +92,58 @@ static void rt61pci_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - /* - * Wait until the BBP becomes ready. - */ - reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - return; - } + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the request into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); - rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); + rt2x00pci_register_write(rt2x00dev, PHY_CSR3, reg); - /* - * Wait until the BBP becomes ready. - */ - reg = rt61pci_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) { - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - *value = 0xff; - return; + WAIT_FOR_BBP(rt2x00dev, ®); } *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); + + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt2x00pci_register_read(rt2x00dev, PHY_CSR4, ®); - if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } + mutex_lock(&rt2x00dev->csr_mutex); - ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); - return; + /* + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); + rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); + rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); -rf_write: - reg = 0; - rt2x00_set_field32(®, PHY_CSR4_VALUE, value); - rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, 21); - rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); - rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); + rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } - rt2x00pci_register_write(rt2x00dev, PHY_CSR4, reg); - rt2x00_rf_write(rt2x00dev, word, value); + mutex_unlock(&rt2x00dev->csr_mutex); } #ifdef CONFIG_RT2X00_LIB_LEDS @@ -175,25 +158,27 @@ static void rt61pci_mcu_request(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt2x00pci_register_read(rt2x00dev, H2M_MAILBOX_CSR, ®); + mutex_lock(&rt2x00dev->csr_mutex); - if (rt2x00_get_field32(reg, H2M_MAILBOX_CSR_OWNER)) { - ERROR(rt2x00dev, "mcu request error. " - "Request 0x%02x failed for token 0x%02x.\n", - command, token); - return; + /* + * Wait until the MCU becomes available, afterwards we + * can safely write the new data into the register. + */ + if (WAIT_FOR_MCU(rt2x00dev, ®)) { + rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); + rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); + rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); + + rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, ®); + rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); + rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); + rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); } - rt2x00_set_field32(®, H2M_MAILBOX_CSR_OWNER, 1); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_CMD_TOKEN, token); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG0, arg0); - rt2x00_set_field32(®, H2M_MAILBOX_CSR_ARG1, arg1); - rt2x00pci_register_write(rt2x00dev, H2M_MAILBOX_CSR, reg); + mutex_unlock(&rt2x00dev->csr_mutex); - rt2x00pci_register_read(rt2x00dev, HOST_CMD_CSR, ®); - rt2x00_set_field32(®, HOST_CMD_CSR_HOST_COMMAND, command); - rt2x00_set_field32(®, HOST_CMD_CSR_INTERRUPT_MCU, 1); - rt2x00pci_register_write(rt2x00dev, HOST_CMD_CSR, reg); } #endif /* CONFIG_RT2X00_LIB_LEDS */ @@ -228,43 +213,34 @@ static void rt61pci_eepromregister_write(struct eeprom_93cx6 *eeprom) } #ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt61pci_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt2x00pci_register_read(rt2x00dev, CSR_OFFSET(word), data); -} - -static void rt61pci_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt2x00pci_register_write(rt2x00dev, CSR_OFFSET(word), data); -} - static const struct rt2x00debug rt61pci_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt61pci_read_csr, - .write = rt61pci_write_csr, + .read = rt2x00pci_register_read, + .write = rt2x00pci_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt61pci_bbp_read, .write = rt61pci_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt61pci_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, @@ -643,95 +619,18 @@ static void rt61pci_config_erp(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); -} - - -static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u16 eeprom; - short lna_gain = 0; - - if (libconf->band == IEEE80211_BAND_2GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) - lna_gain += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); - } else { - if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) - lna_gain += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); - } - - rt2x00dev->lna_gain = lna_gain; -} - -static void rt61pci_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) -{ - rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask); -} - -static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, const int txpower) -{ - u8 r3; - u8 r94; - u8 smart; - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - - smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527)); - - rt61pci_bbp_read(rt2x00dev, 3, &r3); - rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); - rt61pci_bbp_write(rt2x00dev, 3, r3); - - r94 = 6; - if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) - r94 += txpower - MAX_TXPOWER; - else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) - r94 += txpower; - rt61pci_bbp_write(rt2x00dev, 94, r94); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); - rt61pci_rf_write(rt2x00dev, 1, rf->rf1); - rt61pci_rf_write(rt2x00dev, 2, rf->rf2); - rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt61pci_rf_write(rt2x00dev, 4, rf->rf4); - - udelay(200); - - rt61pci_rf_write(rt2x00dev, 1, rf->rf1); - rt61pci_rf_write(rt2x00dev, 2, rf->rf2); - rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); - rt61pci_rf_write(rt2x00dev, 4, rf->rf4); - - udelay(200); - - rt61pci_rf_write(rt2x00dev, 1, rf->rf1); - rt61pci_rf_write(rt2x00dev, 2, rf->rf2); - rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt61pci_rf_write(rt2x00dev, 4, rf->rf4); - - msleep(1); -} - -static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, - const int txpower) -{ - struct rf_channel rf; - - rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); - rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); - rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); - rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); + rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); - rt61pci_config_channel(rt2x00dev, &rf, txpower); + rt2x00pci_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); + rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); + rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); + rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg); } static void rt61pci_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -906,8 +805,8 @@ static const struct antenna_sel antenna_sel_bg[] = { { 98, { 0x48, 0x48 } }, }; -static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt61pci_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { const struct antenna_sel *sel; unsigned int lna; @@ -954,20 +853,105 @@ static void rt61pci_config_antenna(struct rt2x00_dev *rt2x00dev, } } -static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, +static void rt61pci_config_lna_gain(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain = 0; + + if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } else { + if (test_bit(CONFIG_EXTERNAL_LNA_A, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } + + rt2x00dev->lna_gain = lna_gain; +} + +static void rt61pci_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) +{ + u8 r3; + u8 r94; + u8 smart; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); + + rt61pci_bbp_read(rt2x00dev, 3, &r3); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); + rt61pci_bbp_write(rt2x00dev, 3, r3); + + r94 = 6; + if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) + r94 += txpower - MAX_TXPOWER; + else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) + r94 += txpower; + rt61pci_bbp_write(rt2x00dev, 94, r94); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(200); + + rt61pci_rf_write(rt2x00dev, 1, rf->rf1); + rt61pci_rf_write(rt2x00dev, 2, rf->rf2); + rt61pci_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt61pci_rf_write(rt2x00dev, 4, rf->rf4); + + msleep(1); +} + +static void rt61pci_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + struct rf_channel rf; + + rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); + rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); + rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); + rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + + rt61pci_config_channel(rt2x00dev, &rf, txpower); +} + +static void rt61pci_config_retry_limit(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) { u32 reg; - rt2x00pci_register_read(rt2x00dev, MAC_CSR9, ®); - rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, libconf->slot_time); - rt2x00pci_register_write(rt2x00dev, MAC_CSR9, reg); + rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, + libconf->conf->short_frame_max_tx_count); + rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); +} - rt2x00pci_register_read(rt2x00dev, MAC_CSR8, ®); - rt2x00_set_field32(®, MAC_CSR8_SIFS, libconf->sifs); - rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); - rt2x00_set_field32(®, MAC_CSR8_EIFS, libconf->eifs); - rt2x00pci_register_write(rt2x00dev, MAC_CSR8, reg); +static void rt61pci_config_duration(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u32 reg; rt2x00pci_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); @@ -990,16 +974,15 @@ static void rt61pci_config(struct rt2x00_dev *rt2x00dev, /* Always recalculate LNA gain before changing configuration */ rt61pci_config_lna_gain(rt2x00dev, libconf); - if (flags & CONFIG_UPDATE_PHYMODE) - rt61pci_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt61pci_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt61pci_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt61pci_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt61pci_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt61pci_config_duration(rt2x00dev, libconf); } @@ -1263,33 +1246,44 @@ static int rt61pci_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, /* * Initialization functions. */ -static void rt61pci_init_rxentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static bool rt61pci_get_entry_state(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; - struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 5, &word); - rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, - skbdesc->skb_dma); - rt2x00_desc_write(entry_priv->desc, 5, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 0, &word); + + return rt2x00_get_field32(word, RXD_W0_OWNER_NIC); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); - rt2x00_desc_write(entry_priv->desc, 0, word); + return (rt2x00_get_field32(word, TXD_W0_OWNER_NIC) || + rt2x00_get_field32(word, TXD_W0_VALID)); + } } -static void rt61pci_init_txentry(struct rt2x00_dev *rt2x00dev, - struct queue_entry *entry) +static void rt61pci_clear_entry(struct queue_entry *entry) { struct queue_entry_priv_pci *entry_priv = entry->priv_data; + struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); u32 word; - rt2x00_desc_read(entry_priv->desc, 0, &word); - rt2x00_set_field32(&word, TXD_W0_VALID, 0); - rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); - rt2x00_desc_write(entry_priv->desc, 0, word); + if (entry->queue->qid == QID_RX) { + rt2x00_desc_read(entry_priv->desc, 5, &word); + rt2x00_set_field32(&word, RXD_W5_BUFFER_PHYSICAL_ADDRESS, + skbdesc->skb_dma); + rt2x00_desc_write(entry_priv->desc, 5, word); + + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, RXD_W0_OWNER_NIC, 1); + rt2x00_desc_write(entry_priv->desc, 0, word); + } else { + rt2x00_desc_read(entry_priv->desc, 0, &word); + rt2x00_set_field32(&word, TXD_W0_VALID, 0); + rt2x00_set_field32(&word, TXD_W0_OWNER_NIC, 0); + rt2x00_desc_write(entry_priv->desc, 0, word); + } } static int rt61pci_init_queues(struct rt2x00_dev *rt2x00dev) @@ -1784,8 +1778,8 @@ static void rt61pci_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { - _rt2x00_desc_write(txd, 3, skbdesc->iv); - _rt2x00_desc_write(txd, 4, skbdesc->eiv); + _rt2x00_desc_write(txd, 3, skbdesc->iv[0]); + _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); } rt2x00_desc_read(txd, 5, &word); @@ -1934,7 +1928,7 @@ static int rt61pci_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) } static void rt61pci_fill_rxdone(struct queue_entry *entry, - struct rxdone_entry_desc *rxdesc) + struct rxdone_entry_desc *rxdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct queue_entry_priv_pci *entry_priv = entry->priv_data; @@ -1955,9 +1949,12 @@ static void rt61pci_fill_rxdone(struct queue_entry *entry, } if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv); - _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->eiv); + _rt2x00_desc_read(entry_priv->desc, 2, &rxdesc->iv[0]); + _rt2x00_desc_read(entry_priv->desc, 3, &rxdesc->iv[1]); + rxdesc->dev_flags |= RXDONE_CRYPTO_IV; + _rt2x00_desc_read(entry_priv->desc, 4, &rxdesc->icv); + rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; /* * Hardware has stripped IV/EIV data from 802.11 frame during @@ -2175,10 +2172,8 @@ static int rt61pci_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); @@ -2630,20 +2625,6 @@ static int rt61pci_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt61pci_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt2x00pci_register_read(rt2x00dev, TXRX_CSR4, ®); - rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry); - rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry); - rt2x00pci_register_write(rt2x00dev, TXRX_CSR4, reg); - - return 0; -} - static int rt61pci_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { @@ -2726,7 +2707,6 @@ static const struct ieee80211_ops rt61pci_mac80211_ops = { .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt61pci_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt61pci_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -2741,8 +2721,8 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .load_firmware = rt61pci_load_firmware, .initialize = rt2x00pci_initialize, .uninitialize = rt2x00pci_uninitialize, - .init_rxentry = rt61pci_init_rxentry, - .init_txentry = rt61pci_init_txentry, + .get_entry_state = rt61pci_get_entry_state, + .clear_entry = rt61pci_clear_entry, .set_device_state = rt61pci_set_device_state, .rfkill_poll = rt61pci_rfkill_poll, .link_stats = rt61pci_link_stats, @@ -2758,6 +2738,7 @@ static const struct rt2x00lib_ops rt61pci_rt2x00_ops = { .config_filter = rt61pci_config_filter, .config_intf = rt61pci_config_intf, .config_erp = rt61pci_config_erp, + .config_ant = rt61pci_config_ant, .config = rt61pci_config, }; diff --git a/drivers/net/wireless/rt2x00/rt61pci.h b/drivers/net/wireless/rt2x00/rt61pci.h index 8ec1451308ccea2700ce05e03f0be2229a3c2779..65fe3332364aa8cb414793ec0f0a057e40038252 100644 --- a/drivers/net/wireless/rt2x00/rt61pci.h +++ b/drivers/net/wireless/rt2x00/rt61pci.h @@ -48,7 +48,9 @@ #define CSR_REG_SIZE 0x04b0 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0100 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0080 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* diff --git a/drivers/net/wireless/rt2x00/rt73usb.c b/drivers/net/wireless/rt2x00/rt73usb.c index 934f8e03c5aae99fa9f6175d0c509d48fc245a48..d638a8a593705384f58a2cbf6a6e95fd4dd7d0db 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.c +++ b/drivers/net/wireless/rt2x00/rt73usb.c @@ -46,7 +46,7 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); /* * Register access. * All access to the CSR registers will go through the methods - * rt73usb_register_read and rt73usb_register_write. + * rt2x00usb_register_read and rt2x00usb_register_write. * BBP and RF register require indirect register access, * and use the CSR registers BBPCSR and RFCSR to achieve this. * These indirect registers work with busy bits, @@ -55,113 +55,35 @@ MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption."); * between each attampt. When the busy bit is still set at that time, * the access attempt is considered to have failed, * and we will print an error. - * The _lock versions must be used if you already hold the usb_cache_mutex + * The _lock versions must be used if you already hold the csr_mutex */ -static inline void rt73usb_register_read(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value) -{ - __le32 reg; - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); - *value = le32_to_cpu(reg); -} - -static inline void rt73usb_register_read_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 *value) -{ - __le32 reg; - rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); - *value = le32_to_cpu(reg); -} - -static inline void rt73usb_register_multiread(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length) -{ - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_READ, - USB_VENDOR_REQUEST_IN, offset, - value, length, - REGISTER_TIMEOUT32(length)); -} - -static inline void rt73usb_register_write(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 value) -{ - __le32 reg = cpu_to_le32(value); - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); -} - -static inline void rt73usb_register_write_lock(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, u32 value) -{ - __le32 reg = cpu_to_le32(value); - rt2x00usb_vendor_req_buff_lock(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, offset, - ®, sizeof(u32), REGISTER_TIMEOUT); -} - -static inline void rt73usb_register_multiwrite(struct rt2x00_dev *rt2x00dev, - const unsigned int offset, - void *value, const u32 length) -{ - rt2x00usb_vendor_request_buff(rt2x00dev, USB_MULTI_WRITE, - USB_VENDOR_REQUEST_OUT, offset, - value, length, - REGISTER_TIMEOUT32(length)); -} - -static u32 rt73usb_bbp_check(struct rt2x00_dev *rt2x00dev) -{ - u32 reg; - unsigned int i; - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read_lock(rt2x00dev, PHY_CSR3, ®); - if (!rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - break; - udelay(REGISTER_BUSY_DELAY); - } - - return reg; -} +#define WAIT_FOR_BBP(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), PHY_CSR3, PHY_CSR3_BUSY, (__reg)) +#define WAIT_FOR_RF(__dev, __reg) \ + rt2x00usb_regbusy_read((__dev), PHY_CSR4, PHY_CSR4_BUSY, (__reg)) static void rt73usb_bbp_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u8 value) { u32 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); + mutex_lock(&rt2x00dev->csr_mutex); /* - * Wait until the BBP becomes ready. + * Wait until the BBP becomes available, afterwards we + * can safely write the new data into the register. */ - reg = rt73usb_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; - - /* - * Write the data into the BBP. - */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_VALUE, value); - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); - - rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); - mutex_unlock(&rt2x00dev->usb_cache_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_VALUE, value); + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 0); + + rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); + } - ERROR(rt2x00dev, "PHY_CSR3 register busy. Write failed.\n"); + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, @@ -169,123 +91,95 @@ static void rt73usb_bbp_read(struct rt2x00_dev *rt2x00dev, { u32 reg; - mutex_lock(&rt2x00dev->usb_cache_mutex); - - /* - * Wait until the BBP becomes ready. - */ - reg = rt73usb_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; + mutex_lock(&rt2x00dev->csr_mutex); /* - * Write the request into the BBP. + * Wait until the BBP becomes available, afterwards we + * can safely write the read request into the register. + * After the data has been written, we wait until hardware + * returns the correct value, if at any time the register + * doesn't become available in time, reg will be 0xffffffff + * which means we return 0xff to the caller. */ - reg = 0; - rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); - rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); - rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); + if (WAIT_FOR_BBP(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR3_REGNUM, word); + rt2x00_set_field32(®, PHY_CSR3_BUSY, 1); + rt2x00_set_field32(®, PHY_CSR3_READ_CONTROL, 1); - rt73usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); + rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR3, reg); - /* - * Wait until the BBP becomes ready. - */ - reg = rt73usb_bbp_check(rt2x00dev); - if (rt2x00_get_field32(reg, PHY_CSR3_BUSY)) - goto exit_fail; + WAIT_FOR_BBP(rt2x00dev, ®); + } *value = rt2x00_get_field32(reg, PHY_CSR3_VALUE); - mutex_unlock(&rt2x00dev->usb_cache_mutex); - - return; - -exit_fail: - mutex_unlock(&rt2x00dev->usb_cache_mutex); - ERROR(rt2x00dev, "PHY_CSR3 register busy. Read failed.\n"); - *value = 0xff; + mutex_unlock(&rt2x00dev->csr_mutex); } static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev, const unsigned int word, const u32 value) { u32 reg; - unsigned int i; if (!word) return; - mutex_lock(&rt2x00dev->usb_cache_mutex); - - for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read_lock(rt2x00dev, PHY_CSR4, ®); - if (!rt2x00_get_field32(reg, PHY_CSR4_BUSY)) - goto rf_write; - udelay(REGISTER_BUSY_DELAY); - } - - mutex_unlock(&rt2x00dev->usb_cache_mutex); - ERROR(rt2x00dev, "PHY_CSR4 register busy. Write failed.\n"); - return; - -rf_write: - reg = 0; - rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + mutex_lock(&rt2x00dev->csr_mutex); /* - * RF5225 and RF2527 contain 21 bits per RF register value, - * all others contain 20 bits. + * Wait until the RF becomes available, afterwards we + * can safely write the new data into the register. */ - rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, - 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527))); - rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); - rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); - - rt73usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); - rt2x00_rf_write(rt2x00dev, word, value); - mutex_unlock(&rt2x00dev->usb_cache_mutex); -} - -#ifdef CONFIG_RT2X00_LIB_DEBUGFS -#define CSR_OFFSET(__word) ( CSR_REG_BASE + ((__word) * sizeof(u32)) ) - -static void rt73usb_read_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 *data) -{ - rt73usb_register_read(rt2x00dev, CSR_OFFSET(word), data); -} + if (WAIT_FOR_RF(rt2x00dev, ®)) { + reg = 0; + rt2x00_set_field32(®, PHY_CSR4_VALUE, value); + /* + * RF5225 and RF2527 contain 21 bits per RF register value, + * all others contain 20 bits. + */ + rt2x00_set_field32(®, PHY_CSR4_NUMBER_OF_BITS, + 20 + (rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527))); + rt2x00_set_field32(®, PHY_CSR4_IF_SELECT, 0); + rt2x00_set_field32(®, PHY_CSR4_BUSY, 1); + + rt2x00usb_register_write_lock(rt2x00dev, PHY_CSR4, reg); + rt2x00_rf_write(rt2x00dev, word, value); + } -static void rt73usb_write_csr(struct rt2x00_dev *rt2x00dev, - const unsigned int word, u32 data) -{ - rt73usb_register_write(rt2x00dev, CSR_OFFSET(word), data); + mutex_unlock(&rt2x00dev->csr_mutex); } +#ifdef CONFIG_RT2X00_LIB_DEBUGFS static const struct rt2x00debug rt73usb_rt2x00debug = { .owner = THIS_MODULE, .csr = { - .read = rt73usb_read_csr, - .write = rt73usb_write_csr, + .read = rt2x00usb_register_read, + .write = rt2x00usb_register_write, + .flags = RT2X00DEBUGFS_OFFSET, + .word_base = CSR_REG_BASE, .word_size = sizeof(u32), .word_count = CSR_REG_SIZE / sizeof(u32), }, .eeprom = { .read = rt2x00_eeprom_read, .write = rt2x00_eeprom_write, + .word_base = EEPROM_BASE, .word_size = sizeof(u16), .word_count = EEPROM_SIZE / sizeof(u16), }, .bbp = { .read = rt73usb_bbp_read, .write = rt73usb_bbp_write, + .word_base = BBP_BASE, .word_size = sizeof(u8), .word_count = BBP_SIZE / sizeof(u8), }, .rf = { .read = rt2x00_rf_read, .write = rt73usb_rf_write, + .word_base = RF_BASE, .word_size = sizeof(u32), .word_count = RF_SIZE / sizeof(u32), }, @@ -341,10 +235,10 @@ static int rt73usb_blink_set(struct led_classdev *led_cdev, container_of(led_cdev, struct rt2x00_led, led_dev); u32 reg; - rt73usb_register_read(led->rt2x00dev, MAC_CSR14, ®); + rt2x00usb_register_read(led->rt2x00dev, MAC_CSR14, ®); rt2x00_set_field32(®, MAC_CSR14_ON_PERIOD, *delay_on); rt2x00_set_field32(®, MAC_CSR14_OFF_PERIOD, *delay_off); - rt73usb_register_write(led->rt2x00dev, MAC_CSR14, reg); + rt2x00usb_register_write(led->rt2x00dev, MAC_CSR14, reg); return 0; } @@ -387,7 +281,7 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = (0xf << crypto->bssidx); - rt73usb_register_read(rt2x00dev, SEC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR0, ®); reg &= mask; if (reg && reg == mask) @@ -424,16 +318,16 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, field.bit_offset = (3 * key->hw_key_idx); field.bit_mask = 0x7 << field.bit_offset; - rt73usb_register_read(rt2x00dev, SEC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR1, ®); rt2x00_set_field32(®, field, crypto->cipher); - rt73usb_register_write(rt2x00dev, SEC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR1, reg); } else { field.bit_offset = (3 * (key->hw_key_idx - 8)); field.bit_mask = 0x7 << field.bit_offset; - rt73usb_register_read(rt2x00dev, SEC_CSR5, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR5, ®); rt2x00_set_field32(®, field, crypto->cipher); - rt73usb_register_write(rt2x00dev, SEC_CSR5, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR5, reg); } /* @@ -456,12 +350,12 @@ static int rt73usb_config_shared_key(struct rt2x00_dev *rt2x00dev, */ mask = 1 << key->hw_key_idx; - rt73usb_register_read(rt2x00dev, SEC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR0, ®); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) reg &= ~mask; - rt73usb_register_write(rt2x00dev, SEC_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR0, reg); return 0; } @@ -486,10 +380,10 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * When both registers are full, we drop the key, * otherwise we use the first invalid entry. */ - rt73usb_register_read(rt2x00dev, SEC_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR2, ®); if (reg && reg == ~0) { key->hw_key_idx = 32; - rt73usb_register_read(rt2x00dev, SEC_CSR3, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR3, ®); if (reg && reg == ~0) return -ENOSPC; } @@ -517,14 +411,14 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, /* * Send the address and cipher type to the hardware register. * This data fits within the CSR cache size, so we can use - * rt73usb_register_multiwrite() directly. + * rt2x00usb_register_multiwrite() directly. */ memset(&addr_entry, 0, sizeof(addr_entry)); memcpy(&addr_entry, crypto->address, ETH_ALEN); addr_entry.cipher = crypto->cipher; reg = PAIRWISE_TA_ENTRY(key->hw_key_idx); - rt73usb_register_multiwrite(rt2x00dev, reg, + rt2x00usb_register_multiwrite(rt2x00dev, reg, &addr_entry, sizeof(addr_entry)); /* @@ -532,9 +426,9 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, * without this received frames will not be decrypted * by the hardware. */ - rt73usb_register_read(rt2x00dev, SEC_CSR4, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR4, ®); reg |= (1 << crypto->bssidx); - rt73usb_register_write(rt2x00dev, SEC_CSR4, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR4, reg); /* * The driver does not support the IV/EIV generation @@ -557,21 +451,21 @@ static int rt73usb_config_pairwise_key(struct rt2x00_dev *rt2x00dev, if (key->hw_key_idx < 32) { mask = 1 << key->hw_key_idx; - rt73usb_register_read(rt2x00dev, SEC_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR2, ®); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) reg &= ~mask; - rt73usb_register_write(rt2x00dev, SEC_CSR2, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR2, reg); } else { mask = 1 << (key->hw_key_idx - 32); - rt73usb_register_read(rt2x00dev, SEC_CSR3, ®); + rt2x00usb_register_read(rt2x00dev, SEC_CSR3, ®); if (crypto->cmd == SET_KEY) reg |= mask; else if (crypto->cmd == DISABLE_KEY) reg &= ~mask; - rt73usb_register_write(rt2x00dev, SEC_CSR3, reg); + rt2x00usb_register_write(rt2x00dev, SEC_CSR3, reg); } return 0; @@ -588,7 +482,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, * and broadcast frames will always be accepted since * there is no filter for it at this time. */ - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_DROP_CRC, !(filter_flags & FIF_FCSFAIL)); rt2x00_set_field32(®, TXRX_CSR0_DROP_PHYSICAL, @@ -606,7 +500,7 @@ static void rt73usb_config_filter(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, TXRX_CSR0_DROP_BROADCAST, 0); rt2x00_set_field32(®, TXRX_CSR0_DROP_ACK_CTS, !(filter_flags & FIF_CONTROL)); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); } static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, @@ -625,16 +519,16 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, * 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); + rt2x00usb_register_write(rt2x00dev, beacon_base, 0); /* * Enable synchronisation. */ - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_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); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } if (flags & CONFIG_UPDATE_MAC) { @@ -642,7 +536,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_CSR3_UNICAST_TO_ME_MASK, 0xff); conf->mac[1] = cpu_to_le32(reg); - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR2, + rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR2, conf->mac, sizeof(conf->mac)); } @@ -651,7 +545,7 @@ static void rt73usb_config_intf(struct rt2x00_dev *rt2x00dev, rt2x00_set_field32(®, MAC_CSR5_BSS_ID_MASK, 3); conf->bssid[1] = cpu_to_le32(reg); - rt73usb_register_multiwrite(rt2x00dev, MAC_CSR4, + rt2x00usb_register_multiwrite(rt2x00dev, MAC_CSR4, conf->bssid, sizeof(conf->bssid)); } } @@ -661,95 +555,26 @@ static void rt73usb_config_erp(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_RX_ACK_TIMEOUT, erp->ack_timeout); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_PREAMBLE, !!erp->short_preamble); - rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); -} - -static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, - struct rt2x00lib_conf *libconf) -{ - u16 eeprom; - short lna_gain = 0; - - if (libconf->band == IEEE80211_BAND_2GHZ) { - if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) - lna_gain += 14; - - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); - } else { - rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); - lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); - } - - rt2x00dev->lna_gain = lna_gain; -} - -static void rt73usb_config_phymode(struct rt2x00_dev *rt2x00dev, - const int basic_rate_mask) -{ - rt73usb_register_write(rt2x00dev, TXRX_CSR5, basic_rate_mask); -} - -static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, - struct rf_channel *rf, const int txpower) -{ - u8 r3; - u8 r94; - u8 smart; - - rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); - rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); - - smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || - rt2x00_rf(&rt2x00dev->chip, RF2527)); - - rt73usb_bbp_read(rt2x00dev, 3, &r3); - rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); - rt73usb_bbp_write(rt2x00dev, 3, r3); - - r94 = 6; - if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) - r94 += txpower - MAX_TXPOWER; - else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) - r94 += txpower; - rt73usb_bbp_write(rt2x00dev, 94, r94); - - rt73usb_rf_write(rt2x00dev, 1, rf->rf1); - rt73usb_rf_write(rt2x00dev, 2, rf->rf2); - rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); - rt73usb_rf_write(rt2x00dev, 1, rf->rf1); - rt73usb_rf_write(rt2x00dev, 2, rf->rf2); - rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); - rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR5, erp->basic_rates); - rt73usb_rf_write(rt2x00dev, 1, rf->rf1); - rt73usb_rf_write(rt2x00dev, 2, rf->rf2); - rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); - rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, erp->slot_time); + rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); - udelay(10); -} - -static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, - const int txpower) -{ - struct rf_channel rf; - - rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); - rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); - rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); - rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); - - rt73usb_config_channel(rt2x00dev, &rf, txpower); + rt2x00usb_register_read(rt2x00dev, MAC_CSR8, ®); + rt2x00_set_field32(®, MAC_CSR8_SIFS, erp->sifs); + rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); + rt2x00_set_field32(®, MAC_CSR8_EIFS, erp->eifs); + rt2x00usb_register_write(rt2x00dev, MAC_CSR8, reg); } static void rt73usb_config_antenna_5x(struct rt2x00_dev *rt2x00dev, @@ -869,8 +694,8 @@ static const struct antenna_sel antenna_sel_bg[] = { { 98, { 0x48, 0x48 } }, }; -static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, - struct antenna_setup *ant) +static void rt73usb_config_ant(struct rt2x00_dev *rt2x00dev, + struct antenna_setup *ant) { const struct antenna_sel *sel; unsigned int lna; @@ -895,14 +720,14 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, for (i = 0; i < ARRAY_SIZE(antenna_sel_a); i++) rt73usb_bbp_write(rt2x00dev, sel[i].word, sel[i].value[lna]); - rt73usb_register_read(rt2x00dev, PHY_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, PHY_CSR0, ®); rt2x00_set_field32(®, PHY_CSR0_PA_PE_BG, (rt2x00dev->curr_band == IEEE80211_BAND_2GHZ)); rt2x00_set_field32(®, PHY_CSR0_PA_PE_A, (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ)); - rt73usb_register_write(rt2x00dev, PHY_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, PHY_CSR0, reg); if (rt2x00_rf(&rt2x00dev->chip, RF5226) || rt2x00_rf(&rt2x00dev->chip, RF5225)) @@ -912,33 +737,111 @@ static void rt73usb_config_antenna(struct rt2x00_dev *rt2x00dev, rt73usb_config_antenna_2x(rt2x00dev, ant); } -static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, +static void rt73usb_config_lna_gain(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_conf *libconf) +{ + u16 eeprom; + short lna_gain = 0; + + if (libconf->conf->channel->band == IEEE80211_BAND_2GHZ) { + if (test_bit(CONFIG_EXTERNAL_LNA_BG, &rt2x00dev->flags)) + lna_gain += 14; + + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_BG, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_BG_1); + } else { + rt2x00_eeprom_read(rt2x00dev, EEPROM_RSSI_OFFSET_A, &eeprom); + lna_gain -= rt2x00_get_field16(eeprom, EEPROM_RSSI_OFFSET_A_1); + } + + rt2x00dev->lna_gain = lna_gain; +} + +static void rt73usb_config_channel(struct rt2x00_dev *rt2x00dev, + struct rf_channel *rf, const int txpower) +{ + u8 r3; + u8 r94; + u8 smart; + + rt2x00_set_field32(&rf->rf3, RF3_TXPOWER, TXPOWER_TO_DEV(txpower)); + rt2x00_set_field32(&rf->rf4, RF4_FREQ_OFFSET, rt2x00dev->freq_offset); + + smart = !(rt2x00_rf(&rt2x00dev->chip, RF5225) || + rt2x00_rf(&rt2x00dev->chip, RF2527)); + + rt73usb_bbp_read(rt2x00dev, 3, &r3); + rt2x00_set_field8(&r3, BBP_R3_SMART_MODE, smart); + rt73usb_bbp_write(rt2x00dev, 3, r3); + + r94 = 6; + if (txpower > MAX_TXPOWER && txpower <= (MAX_TXPOWER + r94)) + r94 += txpower - MAX_TXPOWER; + else if (txpower < MIN_TXPOWER && txpower >= (MIN_TXPOWER - r94)) + r94 += txpower; + rt73usb_bbp_write(rt2x00dev, 94, r94); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 | 0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + rt73usb_rf_write(rt2x00dev, 1, rf->rf1); + rt73usb_rf_write(rt2x00dev, 2, rf->rf2); + rt73usb_rf_write(rt2x00dev, 3, rf->rf3 & ~0x00000004); + rt73usb_rf_write(rt2x00dev, 4, rf->rf4); + + udelay(10); +} + +static void rt73usb_config_txpower(struct rt2x00_dev *rt2x00dev, + const int txpower) +{ + struct rf_channel rf; + + rt2x00_rf_read(rt2x00dev, 1, &rf.rf1); + rt2x00_rf_read(rt2x00dev, 2, &rf.rf2); + rt2x00_rf_read(rt2x00dev, 3, &rf.rf3); + rt2x00_rf_read(rt2x00dev, 4, &rf.rf4); + + rt73usb_config_channel(rt2x00dev, &rf, txpower); +} + +static void rt73usb_config_retry_limit(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) { u32 reg; - rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); - rt2x00_set_field32(®, MAC_CSR9_SLOT_TIME, libconf->slot_time); - rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, + libconf->conf->long_frame_max_tx_count); + rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, + libconf->conf->short_frame_max_tx_count); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); +} - rt73usb_register_read(rt2x00dev, MAC_CSR8, ®); - rt2x00_set_field32(®, MAC_CSR8_SIFS, libconf->sifs); - rt2x00_set_field32(®, MAC_CSR8_SIFS_AFTER_RX_OFDM, 3); - rt2x00_set_field32(®, MAC_CSR8_EIFS, libconf->eifs); - rt73usb_register_write(rt2x00dev, MAC_CSR8, reg); +static void rt73usb_config_duration(struct rt2x00_dev *rt2x00dev, + struct rt2x00lib_conf *libconf) +{ + u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_TSF_OFFSET, IEEE80211_HEADER); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR4, ®); rt2x00_set_field32(®, TXRX_CSR4_AUTORESPOND_ENABLE, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR4, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, libconf->conf->beacon_int * 16); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } static void rt73usb_config(struct rt2x00_dev *rt2x00dev, @@ -948,16 +851,15 @@ static void rt73usb_config(struct rt2x00_dev *rt2x00dev, /* Always recalculate LNA gain before changing configuration */ rt73usb_config_lna_gain(rt2x00dev, libconf); - if (flags & CONFIG_UPDATE_PHYMODE) - rt73usb_config_phymode(rt2x00dev, libconf->basic_rates); - if (flags & CONFIG_UPDATE_CHANNEL) + if (flags & IEEE80211_CONF_CHANGE_CHANNEL) rt73usb_config_channel(rt2x00dev, &libconf->rf, libconf->conf->power_level); - if ((flags & CONFIG_UPDATE_TXPOWER) && !(flags & CONFIG_UPDATE_CHANNEL)) + if ((flags & IEEE80211_CONF_CHANGE_POWER) && + !(flags & IEEE80211_CONF_CHANGE_CHANNEL)) rt73usb_config_txpower(rt2x00dev, libconf->conf->power_level); - if (flags & CONFIG_UPDATE_ANTENNA) - rt73usb_config_antenna(rt2x00dev, &libconf->ant); - if (flags & (CONFIG_UPDATE_SLOT_TIME | CONFIG_UPDATE_BEACON_INT)) + if (flags & IEEE80211_CONF_CHANGE_RETRY_LIMITS) + rt73usb_config_retry_limit(rt2x00dev, libconf); + if (flags & IEEE80211_CONF_CHANGE_BEACON_INTERVAL) rt73usb_config_duration(rt2x00dev, libconf); } @@ -972,13 +874,13 @@ static void rt73usb_link_stats(struct rt2x00_dev *rt2x00dev, /* * Update FCS error count from register. */ - rt73usb_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR0, ®); qual->rx_failed = rt2x00_get_field32(reg, STA_CSR0_FCS_ERROR); /* * Update False CCA count from register. */ - rt73usb_register_read(rt2x00dev, STA_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR1, ®); qual->false_cca = rt2x00_get_field32(reg, STA_CSR1_FALSE_CCA_ERROR); } @@ -1138,7 +1040,7 @@ static int rt73usb_load_firmware(struct rt2x00_dev *rt2x00dev, const void *data, * Wait for stable hardware. */ for (i = 0; i < 100; i++) { - rt73usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); if (reg) break; msleep(1); @@ -1180,13 +1082,13 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) { u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_AUTO_TX_SEQ, 1); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, 0); rt2x00_set_field32(®, TXRX_CSR0_TX_WITHOUT_WAITING, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR1, ®); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0, 47); /* CCK Signal */ rt2x00_set_field32(®, TXRX_CSR1_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID1, 30); /* Rssi */ @@ -1195,12 +1097,12 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXRX_CSR1_BBP_ID2_VALID, 1); rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3, 30); /* Rssi */ rt2x00_set_field32(®, TXRX_CSR1_BBP_ID3_VALID, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR1, reg); /* * CCK TXD BBP registers */ - rt73usb_register_read(rt2x00dev, TXRX_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR2, ®); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0, 13); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID1, 12); @@ -1209,77 +1111,77 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) rt2x00_set_field32(®, TXRX_CSR2_BBP_ID2_VALID, 1); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3, 10); rt2x00_set_field32(®, TXRX_CSR2_BBP_ID3_VALID, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR2, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR2, reg); /* * OFDM TXD BBP registers */ - rt73usb_register_read(rt2x00dev, TXRX_CSR3, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR3, ®); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0, 7); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID0_VALID, 1); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1, 6); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID1_VALID, 1); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2, 5); rt2x00_set_field32(®, TXRX_CSR3_BBP_ID2_VALID, 1); - rt73usb_register_write(rt2x00dev, TXRX_CSR3, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR3, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR7, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR7, ®); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_6MBS, 59); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_9MBS, 53); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_12MBS, 49); rt2x00_set_field32(®, TXRX_CSR7_ACK_CTS_18MBS, 46); - rt73usb_register_write(rt2x00dev, TXRX_CSR7, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR7, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR8, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR8, ®); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_24MBS, 44); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_36MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_48MBS, 42); rt2x00_set_field32(®, TXRX_CSR8_ACK_CTS_54MBS, 42); - rt73usb_register_write(rt2x00dev, TXRX_CSR8, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR8, reg); - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR9, ®); rt2x00_set_field32(®, TXRX_CSR9_BEACON_INTERVAL, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_TICKING, 0); rt2x00_set_field32(®, TXRX_CSR9_TSF_SYNC, 0); rt2x00_set_field32(®, TXRX_CSR9_TBTT_ENABLE, 0); rt2x00_set_field32(®, TXRX_CSR9_BEACON_GEN, 0); rt2x00_set_field32(®, TXRX_CSR9_TIMESTAMP_COMPENSATE, 0); - rt73usb_register_write(rt2x00dev, TXRX_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); - rt73usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR15, 0x0000000f); - rt73usb_register_read(rt2x00dev, MAC_CSR6, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR6, ®); rt2x00_set_field32(®, MAC_CSR6_MAX_FRAME_UNIT, 0xfff); - rt73usb_register_write(rt2x00dev, MAC_CSR6, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR6, reg); - rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718); + rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00000718); if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE)) return -EBUSY; - rt73usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00); + rt2x00usb_register_write(rt2x00dev, MAC_CSR13, 0x00007f00); /* * Invalidate all Shared Keys (SEC_CSR0), * and clear the Shared key Cipher algorithms (SEC_CSR1 & SEC_CSR5) */ - rt73usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000); - rt73usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000); - rt73usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); + rt2x00usb_register_write(rt2x00dev, SEC_CSR0, 0x00000000); + rt2x00usb_register_write(rt2x00dev, SEC_CSR1, 0x00000000); + rt2x00usb_register_write(rt2x00dev, SEC_CSR5, 0x00000000); reg = 0x000023b0; if (rt2x00_rf(&rt2x00dev->chip, RF5225) || rt2x00_rf(&rt2x00dev->chip, RF2527)) rt2x00_set_field32(®, PHY_CSR1_RF_RPI, 1); - rt73usb_register_write(rt2x00dev, PHY_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, PHY_CSR1, reg); - rt73usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06); - rt73usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); - rt73usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); + rt2x00usb_register_write(rt2x00dev, PHY_CSR5, 0x00040a06); + rt2x00usb_register_write(rt2x00dev, PHY_CSR6, 0x00080606); + rt2x00usb_register_write(rt2x00dev, PHY_CSR7, 0x00000408); - rt73usb_register_read(rt2x00dev, MAC_CSR9, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR9, ®); rt2x00_set_field32(®, MAC_CSR9_CW_SELECT, 0); - rt73usb_register_write(rt2x00dev, MAC_CSR9, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR9, reg); /* * Clear all beacons @@ -1287,36 +1189,36 @@ static int rt73usb_init_registers(struct rt2x00_dev *rt2x00dev) * 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); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE0, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE1, 0); + rt2x00usb_register_write(rt2x00dev, HW_BEACON_BASE2, 0); + rt2x00usb_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_register_read(rt2x00dev, STA_CSR0, ®); - rt73usb_register_read(rt2x00dev, STA_CSR1, ®); - rt73usb_register_read(rt2x00dev, STA_CSR2, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, STA_CSR2, ®); /* * Reset MAC and BBP registers. */ - rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 1); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 1); - rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); rt2x00_set_field32(®, MAC_CSR1_SOFT_RESET, 0); rt2x00_set_field32(®, MAC_CSR1_BBP_RESET, 0); - rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); - rt73usb_register_read(rt2x00dev, MAC_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR1, ®); rt2x00_set_field32(®, MAC_CSR1_HOST_READY, 1); - rt73usb_register_write(rt2x00dev, MAC_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR1, reg); return 0; } @@ -1394,11 +1296,11 @@ static void rt73usb_toggle_rx(struct rt2x00_dev *rt2x00dev, { u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR0, ®); rt2x00_set_field32(®, TXRX_CSR0_DISABLE_RX, (state == STATE_RADIO_RX_OFF) || (state == STATE_RADIO_RX_OFF_LINK)); - rt73usb_register_write(rt2x00dev, TXRX_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR0, reg); } static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) @@ -1415,12 +1317,12 @@ static int rt73usb_enable_radio(struct rt2x00_dev *rt2x00dev) static void rt73usb_disable_radio(struct rt2x00_dev *rt2x00dev) { - rt73usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818); + rt2x00usb_register_write(rt2x00dev, MAC_CSR10, 0x00001818); /* * Disable synchronisation. */ - rt73usb_register_write(rt2x00dev, TXRX_CSR9, 0); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, 0); rt2x00usb_disable_radio(rt2x00dev); } @@ -1433,10 +1335,10 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) put_to_sleep = (state != STATE_AWAKE); - rt73usb_register_read(rt2x00dev, MAC_CSR12, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®); rt2x00_set_field32(®, MAC_CSR12_FORCE_WAKEUP, !put_to_sleep); rt2x00_set_field32(®, MAC_CSR12_PUT_TO_SLEEP, put_to_sleep); - rt73usb_register_write(rt2x00dev, MAC_CSR12, reg); + rt2x00usb_register_write(rt2x00dev, MAC_CSR12, reg); /* * Device is not guaranteed to be in the requested state yet. @@ -1444,7 +1346,7 @@ static int rt73usb_set_state(struct rt2x00_dev *rt2x00dev, enum dev_state state) * device has entered the correct state. */ for (i = 0; i < REGISTER_BUSY_COUNT; i++) { - rt73usb_register_read(rt2x00dev, MAC_CSR12, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR12, ®); state = rt2x00_get_field32(reg, MAC_CSR12_BBP_CURRENT_STATE); if (state == !put_to_sleep) return 0; @@ -1526,8 +1428,8 @@ static void rt73usb_write_tx_desc(struct rt2x00_dev *rt2x00dev, rt2x00_desc_write(txd, 2, word); if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc->flags)) { - _rt2x00_desc_write(txd, 3, skbdesc->iv); - _rt2x00_desc_write(txd, 4, skbdesc->eiv); + _rt2x00_desc_write(txd, 3, skbdesc->iv[0]); + _rt2x00_desc_write(txd, 4, skbdesc->iv[1]); } rt2x00_desc_read(txd, 5, &word); @@ -1584,11 +1486,11 @@ static void rt73usb_write_beacon(struct queue_entry *entry) * Disable beaconing while we are reloading the beacon data, * otherwise we might be sending out invalid data. */ - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_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); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); /* * Write entire beacon with descriptor to register. @@ -1606,8 +1508,7 @@ static void rt73usb_write_beacon(struct queue_entry *entry) entry->skb = NULL; } -static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, - struct sk_buff *skb) +static int rt73usb_get_tx_data_len(struct queue_entry *entry) { int length; @@ -1615,8 +1516,8 @@ static int rt73usb_get_tx_data_len(struct rt2x00_dev *rt2x00dev, * The length _must_ be a multiple of 4, * but it must _not_ be a multiple of the USB packet size. */ - length = roundup(skb->len, 4); - length += (4 * !(length % rt2x00dev->usb_maxpacket)); + length = roundup(entry->skb->len, 4); + length += (4 * !(length % entry->queue->usb_maxpacket)); return length; } @@ -1635,14 +1536,14 @@ static void rt73usb_kick_tx_queue(struct rt2x00_dev *rt2x00dev, * For Wi-Fi faily generated beacons between participating stations. * Set TBTT phase adaptive adjustment step to 8us (default 16us) */ - rt73usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR10, 0x00001008); - rt73usb_register_read(rt2x00dev, TXRX_CSR9, ®); + rt2x00usb_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); + rt2x00usb_register_write(rt2x00dev, TXRX_CSR9, reg); } } @@ -1685,7 +1586,7 @@ static int rt73usb_agc_to_rssi(struct rt2x00_dev *rt2x00dev, int rxd_w1) } static void rt73usb_fill_rxdone(struct queue_entry *entry, - struct rxdone_entry_desc *rxdesc) + struct rxdone_entry_desc *rxdesc) { struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev; struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb); @@ -1717,9 +1618,12 @@ static void rt73usb_fill_rxdone(struct queue_entry *entry, } if (rxdesc->cipher != CIPHER_NONE) { - _rt2x00_desc_read(rxd, 2, &rxdesc->iv); - _rt2x00_desc_read(rxd, 3, &rxdesc->eiv); + _rt2x00_desc_read(rxd, 2, &rxdesc->iv[0]); + _rt2x00_desc_read(rxd, 3, &rxdesc->iv[1]); + rxdesc->dev_flags |= RXDONE_CRYPTO_IV; + _rt2x00_desc_read(rxd, 4, &rxdesc->icv); + rxdesc->dev_flags |= RXDONE_CRYPTO_ICV; /* * Hardware has stripped IV/EIV data from 802.11 frame during @@ -1781,10 +1685,8 @@ static int rt73usb_validate_eeprom(struct rt2x00_dev *rt2x00dev) */ mac = rt2x00_eeprom_addr(rt2x00dev, EEPROM_MAC_ADDR_0); if (!is_valid_ether_addr(mac)) { - DECLARE_MAC_BUF(macbuf); - random_ether_addr(mac); - EEPROM(rt2x00dev, "MAC: %s\n", print_mac(macbuf, mac)); + EEPROM(rt2x00dev, "MAC: %pM\n", mac); } rt2x00_eeprom_read(rt2x00dev, EEPROM_ANTENNA, &word); @@ -1883,7 +1785,7 @@ static int rt73usb_init_eeprom(struct rt2x00_dev *rt2x00dev) * Identify RF chipset. */ value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_RF_TYPE); - rt73usb_register_read(rt2x00dev, MAC_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, MAC_CSR0, ®); rt2x00_set_chip(rt2x00dev, RT2571, value, reg); if (!rt2x00_check_rev(&rt2x00dev->chip, 0x25730)) { @@ -2211,20 +2113,6 @@ static int rt73usb_probe_hw(struct rt2x00_dev *rt2x00dev) /* * IEEE80211 stack callback functions. */ -static int rt73usb_set_retry_limit(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retry) -{ - struct rt2x00_dev *rt2x00dev = hw->priv; - u32 reg; - - rt73usb_register_read(rt2x00dev, TXRX_CSR4, ®); - rt2x00_set_field32(®, TXRX_CSR4_LONG_RETRY_LIMIT, long_retry); - rt2x00_set_field32(®, TXRX_CSR4_SHORT_RETRY_LIMIT, short_retry); - rt73usb_register_write(rt2x00dev, TXRX_CSR4, reg); - - return 0; -} - static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, const struct ieee80211_tx_queue_params *params) { @@ -2251,33 +2139,33 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx, field.bit_offset = queue_idx * 16; field.bit_mask = 0xffff << field.bit_offset; - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); + rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR0, ®); rt2x00_set_field32(®, field, queue->txop); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); + rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR0, reg); } else if (queue_idx < 4) { field.bit_offset = (queue_idx - 2) * 16; field.bit_mask = 0xffff << field.bit_offset; - rt73usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); + rt2x00usb_register_read(rt2x00dev, AC_TXOP_CSR1, ®); rt2x00_set_field32(®, field, queue->txop); - rt73usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); + rt2x00usb_register_write(rt2x00dev, AC_TXOP_CSR1, reg); } /* Update WMM registers */ field.bit_offset = queue_idx * 4; field.bit_mask = 0xf << field.bit_offset; - rt73usb_register_read(rt2x00dev, AIFSN_CSR, ®); + rt2x00usb_register_read(rt2x00dev, AIFSN_CSR, ®); rt2x00_set_field32(®, field, queue->aifs); - rt73usb_register_write(rt2x00dev, AIFSN_CSR, reg); + rt2x00usb_register_write(rt2x00dev, AIFSN_CSR, reg); - rt73usb_register_read(rt2x00dev, CWMIN_CSR, ®); + rt2x00usb_register_read(rt2x00dev, CWMIN_CSR, ®); rt2x00_set_field32(®, field, queue->cw_min); - rt73usb_register_write(rt2x00dev, CWMIN_CSR, reg); + rt2x00usb_register_write(rt2x00dev, CWMIN_CSR, reg); - rt73usb_register_read(rt2x00dev, CWMAX_CSR, ®); + rt2x00usb_register_read(rt2x00dev, CWMAX_CSR, ®); rt2x00_set_field32(®, field, queue->cw_max); - rt73usb_register_write(rt2x00dev, CWMAX_CSR, reg); + rt2x00usb_register_write(rt2x00dev, CWMAX_CSR, reg); return 0; } @@ -2295,9 +2183,9 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw) u64 tsf; u32 reg; - rt73usb_register_read(rt2x00dev, TXRX_CSR13, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR13, ®); tsf = (u64) rt2x00_get_field32(reg, TXRX_CSR13_HIGH_TSFTIMER) << 32; - rt73usb_register_read(rt2x00dev, TXRX_CSR12, ®); + rt2x00usb_register_read(rt2x00dev, TXRX_CSR12, ®); tsf |= rt2x00_get_field32(reg, TXRX_CSR12_LOW_TSFTIMER); return tsf; @@ -2317,7 +2205,6 @@ static const struct ieee80211_ops rt73usb_mac80211_ops = { .configure_filter = rt2x00mac_configure_filter, .set_key = rt2x00mac_set_key, .get_stats = rt2x00mac_get_stats, - .set_retry_limit = rt73usb_set_retry_limit, .bss_info_changed = rt2x00mac_bss_info_changed, .conf_tx = rt73usb_conf_tx, .get_tx_stats = rt2x00mac_get_tx_stats, @@ -2331,8 +2218,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .load_firmware = rt73usb_load_firmware, .initialize = rt2x00usb_initialize, .uninitialize = rt2x00usb_uninitialize, - .init_rxentry = rt2x00usb_init_rxentry, - .init_txentry = rt2x00usb_init_txentry, + .clear_entry = rt2x00usb_clear_entry, .set_device_state = rt73usb_set_device_state, .link_stats = rt73usb_link_stats, .reset_tuner = rt73usb_reset_tuner, @@ -2348,6 +2234,7 @@ static const struct rt2x00lib_ops rt73usb_rt2x00_ops = { .config_filter = rt73usb_config_filter, .config_intf = rt73usb_config_intf, .config_erp = rt73usb_config_erp, + .config_ant = rt73usb_config_ant, .config = rt73usb_config, }; diff --git a/drivers/net/wireless/rt2x00/rt73usb.h b/drivers/net/wireless/rt2x00/rt73usb.h index 868386c457f65c39c4e15d11ef92cefbebb534a4..46e1405eb0e21ae7d643e5b6d17a011101199d30 100644 --- a/drivers/net/wireless/rt2x00/rt73usb.h +++ b/drivers/net/wireless/rt2x00/rt73usb.h @@ -48,7 +48,9 @@ #define CSR_REG_SIZE 0x04b0 #define EEPROM_BASE 0x0000 #define EEPROM_SIZE 0x0100 +#define BBP_BASE 0x0000 #define BBP_SIZE 0x0080 +#define RF_BASE 0x0000 #define RF_SIZE 0x0014 /* diff --git a/drivers/net/wireless/rtl818x/Makefile b/drivers/net/wireless/rtl818x/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..c113b3e690467fccfa266f92ab42da8a0e3275fb --- /dev/null +++ b/drivers/net/wireless/rtl818x/Makefile @@ -0,0 +1,7 @@ +rtl8180-objs := rtl8180_dev.o rtl8180_rtl8225.o rtl8180_sa2400.o rtl8180_max2820.o rtl8180_grf5101.o +rtl8187-objs := rtl8187_dev.o rtl8187_rtl8225.o + +obj-$(CONFIG_RTL8180) += rtl8180.o +obj-$(CONFIG_RTL8187) += rtl8187.o + + diff --git a/drivers/net/wireless/rtl8180.h b/drivers/net/wireless/rtl818x/rtl8180.h similarity index 100% rename from drivers/net/wireless/rtl8180.h rename to drivers/net/wireless/rtl818x/rtl8180.h diff --git a/drivers/net/wireless/rtl8180_dev.c b/drivers/net/wireless/rtl818x/rtl8180_dev.c similarity index 96% rename from drivers/net/wireless/rtl8180_dev.c rename to drivers/net/wireless/rtl818x/rtl8180_dev.c index df7e78ee8a88451cfe6a00111e93327bcd8f996c..5f887fb137a9c0d4e95b2fd926e517fb479b4dae 100644 --- a/drivers/net/wireless/rtl8180_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8180_dev.c @@ -182,15 +182,13 @@ static void rtl8180_handle_tx(struct ieee80211_hw *dev, unsigned int prio) skb->len, PCI_DMA_TODEVICE); info = IEEE80211_SKB_CB(skb); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); - if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) { - if (flags & RTL818X_TX_DESC_FLAG_TX_OK) - info->flags |= IEEE80211_TX_STAT_ACK; - else - info->status.excessive_retries = 1; - } - info->status.retry_count = flags & 0xFF; + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && + (flags & RTL818X_TX_DESC_FLAG_TX_OK)) + info->flags |= IEEE80211_TX_STAT_ACK; + + info->status.rates[0].count = (flags & 0xFF) + 1; ieee80211_tx_status_irqsafe(dev, skb); if (ring->entries - skb_queue_len(&ring->queue) == 2) @@ -243,6 +241,7 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) unsigned int idx, prio; dma_addr_t mapping; u32 tx_flags; + u8 rc_flags; u16 plcp_len = 0; __le16 rts_duration = 0; @@ -261,15 +260,16 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) tx_flags |= RTL818X_TX_DESC_FLAG_DMA | RTL818X_TX_DESC_FLAG_NO_ENC; - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + rc_flags = info->control.rates[0].flags; + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) { tx_flags |= RTL818X_TX_DESC_FLAG_RTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (rc_flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { tx_flags |= RTL818X_TX_DESC_FLAG_CTS; tx_flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) rts_duration = ieee80211_rts_duration(dev, priv->vif, skb->len, info); @@ -292,9 +292,9 @@ static int rtl8180_tx(struct ieee80211_hw *dev, struct sk_buff *skb) 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 = info->control.retries[0].rate_idx >= 0 ? + entry->flags2 = info->control.rates[1].idx >= 0 ? ieee80211_get_alt_retry_rate(dev, info, 0)->bitrate << 4 : 0; - entry->retry_limit = info->control.retry_limit; + entry->retry_limit = info->control.rates[0].count; entry->flags = cpu_to_le32(tx_flags); __skb_queue_tail(&ring->queue, skb); if (ring->entries - skb_queue_len(&ring->queue) < 2) @@ -692,9 +692,10 @@ static void rtl8180_remove_interface(struct ieee80211_hw *dev, priv->vif = NULL; } -static int rtl8180_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int rtl8180_config(struct ieee80211_hw *dev, u32 changed) { struct rtl8180_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; priv->rf->set_chan(dev, conf); @@ -719,6 +720,17 @@ static int rtl8180_config_interface(struct ieee80211_hw *dev, return 0; } +static void rtl8180_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct rtl8180_priv *priv = dev->priv; + + if (changed & BSS_CHANGED_ERP_SLOT && priv->rf->conf_erp) + priv->rf->conf_erp(dev, info); +} + static void rtl8180_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -759,6 +771,7 @@ static const struct ieee80211_ops rtl8180_ops = { .remove_interface = rtl8180_remove_interface, .config = rtl8180_config, .config_interface = rtl8180_config_interface, + .bss_info_changed = rtl8180_bss_info_changed, .configure_filter = rtl8180_configure_filter, }; @@ -806,7 +819,6 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, const char *chip_name, *rf_name = NULL; u32 reg; u16 eeprom_val; - DECLARE_MAC_BUF(mac); err = pci_enable_device(pdev); if (err) { @@ -855,7 +867,7 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, priv = dev->priv; priv->pdev = pdev; - dev->max_altrates = 1; + dev->max_rates = 2; SET_IEEE80211_DEV(dev, &pdev->dev); pci_set_drvdata(pdev, dev); @@ -1002,8 +1014,8 @@ static int __devinit rtl8180_probe(struct pci_dev *pdev, goto err_iounmap; } - printk(KERN_INFO "%s: hwaddr %s, %s + %s\n", - wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %pM, %s + %s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, chip_name, priv->rf->name); return 0; diff --git a/drivers/net/wireless/rtl8180_grf5101.c b/drivers/net/wireless/rtl818x/rtl8180_grf5101.c similarity index 100% rename from drivers/net/wireless/rtl8180_grf5101.c rename to drivers/net/wireless/rtl818x/rtl8180_grf5101.c diff --git a/drivers/net/wireless/rtl8180_grf5101.h b/drivers/net/wireless/rtl818x/rtl8180_grf5101.h similarity index 100% rename from drivers/net/wireless/rtl8180_grf5101.h rename to drivers/net/wireless/rtl818x/rtl8180_grf5101.h diff --git a/drivers/net/wireless/rtl8180_max2820.c b/drivers/net/wireless/rtl818x/rtl8180_max2820.c similarity index 100% rename from drivers/net/wireless/rtl8180_max2820.c rename to drivers/net/wireless/rtl818x/rtl8180_max2820.c diff --git a/drivers/net/wireless/rtl8180_max2820.h b/drivers/net/wireless/rtl818x/rtl8180_max2820.h similarity index 100% rename from drivers/net/wireless/rtl8180_max2820.h rename to drivers/net/wireless/rtl818x/rtl8180_max2820.h diff --git a/drivers/net/wireless/rtl8180_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c similarity index 98% rename from drivers/net/wireless/rtl8180_rtl8225.c rename to drivers/net/wireless/rtl818x/rtl8180_rtl8225.c index cd22781728a945713a86c70488bbcb2197a9a4ab..4d2be0d9672b58b529ab6570f5c940a6bb78c9ad 100644 --- a/drivers/net/wireless/rtl8180_rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.c @@ -725,8 +725,14 @@ static void rtl8225_rf_set_channel(struct ieee80211_hw *dev, rtl8225_write(dev, 0x7, rtl8225_chan[chan - 1]); msleep(10); +} + +static void rtl8225_rf_conf_erp(struct ieee80211_hw *dev, + struct ieee80211_bss_conf *info) +{ + struct rtl8180_priv *priv = dev->priv; - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { + if (info->use_short_slot) { rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); @@ -745,14 +751,16 @@ static const struct rtl818x_rf_ops rtl8225_ops = { .name = "rtl8225", .init = rtl8225_rf_init, .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel + .set_chan = rtl8225_rf_set_channel, + .conf_erp = rtl8225_rf_conf_erp, }; static const struct rtl818x_rf_ops rtl8225z2_ops = { .name = "rtl8225z2", .init = rtl8225z2_rf_init, .stop = rtl8225_rf_stop, - .set_chan = rtl8225_rf_set_channel + .set_chan = rtl8225_rf_set_channel, + .conf_erp = rtl8225_rf_conf_erp, }; const struct rtl818x_rf_ops * rtl8180_detect_rf(struct ieee80211_hw *dev) diff --git a/drivers/net/wireless/rtl8180_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8180_rtl8225.h similarity index 100% rename from drivers/net/wireless/rtl8180_rtl8225.h rename to drivers/net/wireless/rtl818x/rtl8180_rtl8225.h diff --git a/drivers/net/wireless/rtl8180_sa2400.c b/drivers/net/wireless/rtl818x/rtl8180_sa2400.c similarity index 100% rename from drivers/net/wireless/rtl8180_sa2400.c rename to drivers/net/wireless/rtl818x/rtl8180_sa2400.c diff --git a/drivers/net/wireless/rtl8180_sa2400.h b/drivers/net/wireless/rtl818x/rtl8180_sa2400.h similarity index 100% rename from drivers/net/wireless/rtl8180_sa2400.h rename to drivers/net/wireless/rtl818x/rtl8180_sa2400.h diff --git a/drivers/net/wireless/rtl8187.h b/drivers/net/wireless/rtl818x/rtl8187.h similarity index 97% rename from drivers/net/wireless/rtl8187.h rename to drivers/net/wireless/rtl818x/rtl8187.h index e82bb4d289e834e2a2117a463d1a96697534a47d..3b1e1c2aad26cb35e18167eb7da16e5e354b98b4 100644 --- a/drivers/net/wireless/rtl8187.h +++ b/drivers/net/wireless/rtl818x/rtl8187.h @@ -99,8 +99,8 @@ struct rtl8187_priv { struct ieee80211_supported_band band; struct usb_device *udev; u32 rx_conf; + struct usb_anchor anchored; u16 txpwr_base; - u16 seqno; u8 asic_rev; u8 is_rtl8187b; enum { @@ -112,6 +112,12 @@ struct rtl8187_priv { u8 signal; u8 quality; u8 noise; + u8 slot_time; + u8 aifsn[4]; + struct { + __le64 buf; + struct sk_buff_head queue; + } b_tx_status; }; void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data); diff --git a/drivers/net/wireless/rtl8187_dev.c b/drivers/net/wireless/rtl818x/rtl8187_dev.c similarity index 79% rename from drivers/net/wireless/rtl8187_dev.c rename to drivers/net/wireless/rtl818x/rtl8187_dev.c index 69eb0132593b72cc2a5d995788a28d2744fcecce..00ce3ef39abe6e496de43fa10edaf3e3dd97858a 100644 --- a/drivers/net/wireless/rtl8187_dev.c +++ b/drivers/net/wireless/rtl818x/rtl8187_dev.c @@ -7,6 +7,11 @@ * Based on the r8187 driver, which is: * Copyright 2005 Andrea Merello , et al. * + * The driver was extended to the RTL8187B in 2008 by: + * Herton Ronaldo Krzesinski + * Hin-Tak Leung + * Larry Finger + * * Magic delays and register offsets below are taken from the original * r8187 driver sources. Thanks to Realtek for their support! * @@ -27,6 +32,9 @@ MODULE_AUTHOR("Michael Wu "); MODULE_AUTHOR("Andrea Merello "); +MODULE_AUTHOR("Herton Ronaldo Krzesinski "); +MODULE_AUTHOR("Hin-Tak Leung "); +MODULE_AUTHOR("Larry Finger "); MODULE_DESCRIPTION("RTL8187/RTL8187B USB wireless driver"); MODULE_LICENSE("GPL"); @@ -91,7 +99,6 @@ static const struct ieee80211_channel rtl818x_channels[] = { static void rtl8187_iowrite_async_cb(struct urb *urb) { kfree(urb->context); - usb_free_urb(urb); } static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, @@ -128,11 +135,13 @@ static void rtl8187_iowrite_async(struct rtl8187_priv *priv, __le16 addr, usb_fill_control_urb(urb, priv->udev, usb_sndctrlpipe(priv->udev, 0), (unsigned char *)dr, buf, len, rtl8187_iowrite_async_cb, buf); + usb_anchor_urb(urb, &priv->anchored); rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc < 0) { kfree(buf); - usb_free_urb(urb); + usb_unanchor_urb(urb); } + usb_free_urb(urb); } static inline void rtl818x_iowrite32_async(struct rtl8187_priv *priv, @@ -155,30 +164,45 @@ void rtl8187_write_phy(struct ieee80211_hw *dev, u8 addr, u32 data) rtl818x_iowrite8(priv, &priv->map->PHY[2], (data >> 16) & 0xFF); rtl818x_iowrite8(priv, &priv->map->PHY[1], (data >> 8) & 0xFF); rtl818x_iowrite8(priv, &priv->map->PHY[0], data & 0xFF); - - msleep(1); } static void rtl8187_tx_cb(struct urb *urb) { struct sk_buff *skb = (struct sk_buff *)urb->context; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = info->driver_data[0]; + struct ieee80211_hw *hw = info->rate_driver_data[0]; struct rtl8187_priv *priv = hw->priv; - usb_free_urb(info->driver_data[1]); skb_pull(skb, priv->is_rtl8187b ? sizeof(struct rtl8187b_tx_hdr) : sizeof(struct rtl8187_tx_hdr)); - memset(&info->status, 0, sizeof(info->status)); - info->flags |= IEEE80211_TX_STAT_ACK; - ieee80211_tx_status_irqsafe(hw, skb); + ieee80211_tx_info_clear_status(info); + + if (!urb->status && + !(info->flags & IEEE80211_TX_CTL_NO_ACK) && + priv->is_rtl8187b) { + skb_queue_tail(&priv->b_tx_status.queue, skb); + + /* queue is "full", discard last items */ + while (skb_queue_len(&priv->b_tx_status.queue) > 5) { + struct sk_buff *old_skb; + + dev_dbg(&priv->udev->dev, + "transmit status queue full\n"); + + old_skb = skb_dequeue(&priv->b_tx_status.queue); + ieee80211_tx_status_irqsafe(hw, old_skb); + } + } else { + if (!(info->flags & IEEE80211_TX_CTL_NO_ACK) && !urb->status) + info->flags |= IEEE80211_TX_STAT_ACK; + ieee80211_tx_status_irqsafe(hw, skb); + } } static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) { struct rtl8187_priv *priv = dev->priv; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *ieee80211hdr = (struct ieee80211_hdr *)skb->data; unsigned int ep; void *buf; struct urb *urb; @@ -189,7 +213,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) urb = usb_alloc_urb(0, GFP_ATOMIC); if (!urb) { kfree_skb(skb); - return 0; + return -ENOMEM; } flags = skb->len; @@ -198,12 +222,12 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) flags |= ieee80211_get_tx_rate(dev, info)->hw_value << 24; if (ieee80211_has_morefrags(((struct ieee80211_hdr *)skb->data)->frame_control)) flags |= RTL818X_TX_DESC_FLAG_MOREFRAG; - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) { + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) { flags |= RTL818X_TX_DESC_FLAG_RTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; rts_dur = ieee80211_rts_duration(dev, priv->vif, skb->len, info); - } else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) { + } else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) { flags |= RTL818X_TX_DESC_FLAG_CTS; flags |= ieee80211_get_rts_cts_rate(dev, info)->hw_value << 19; } @@ -214,7 +238,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) hdr->flags = cpu_to_le32(flags); hdr->len = 0; hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(info->control.retry_limit << 8); + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); buf = hdr; ep = 2; @@ -232,7 +256,7 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) memset(hdr, 0, sizeof(*hdr)); hdr->flags = cpu_to_le32(flags); hdr->rts_duration = rts_dur; - hdr->retry = cpu_to_le32(info->control.retry_limit << 8); + hdr->retry = cpu_to_le32((info->control.rates[0].count - 1) << 8); hdr->tx_duration = ieee80211_generic_frame_duration(dev, priv->vif, skb->len, txrate); @@ -244,32 +268,20 @@ static int rtl8187_tx(struct ieee80211_hw *dev, struct sk_buff *skb) ep = epmap[skb_get_queue_mapping(skb)]; } - /* FIXME: The sequence that follows is needed for this driver to - * work with mac80211 since "mac80211: fix TX sequence numbers". - * As with the temporary code in rt2x00, changes will be needed - * to get proper sequence numbers on beacons. In addition, this - * patch places the sequence number in the hardware state, which - * limits us to a single virtual state. - */ - if (info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) { - if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) - priv->seqno += 0x10; - ieee80211hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG); - ieee80211hdr->seq_ctrl |= cpu_to_le16(priv->seqno); - } - - info->driver_data[0] = dev; - info->driver_data[1] = urb; + info->rate_driver_data[0] = dev; + info->rate_driver_data[1] = urb; usb_fill_bulk_urb(urb, priv->udev, usb_sndbulkpipe(priv->udev, ep), buf, skb->len, rtl8187_tx_cb, skb); + usb_anchor_urb(urb, &priv->anchored); rc = usb_submit_urb(urb, GFP_ATOMIC); if (rc < 0) { - usb_free_urb(urb); + usb_unanchor_urb(urb); kfree_skb(skb); } + usb_free_urb(urb); - return 0; + return rc; } static void rtl8187_rx_cb(struct urb *urb) @@ -282,50 +294,35 @@ static void rtl8187_rx_cb(struct urb *urb) int rate, signal; u32 flags; u32 quality; + unsigned long f; - spin_lock(&priv->rx_queue.lock); + spin_lock_irqsave(&priv->rx_queue.lock, f); if (skb->next) __skb_unlink(skb, &priv->rx_queue); else { - spin_unlock(&priv->rx_queue.lock); + spin_unlock_irqrestore(&priv->rx_queue.lock, f); return; } - spin_unlock(&priv->rx_queue.lock); + spin_unlock_irqrestore(&priv->rx_queue.lock, f); + skb_put(skb, urb->actual_length); if (unlikely(urb->status)) { - usb_free_urb(urb); dev_kfree_skb_irq(skb); return; } - skb_put(skb, urb->actual_length); if (!priv->is_rtl8187b) { struct rtl8187_rx_hdr *hdr = (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); flags = le32_to_cpu(hdr->flags); - signal = hdr->signal & 0x7f; + /* As with the RTL8187B below, the AGC is used to calculate + * signal strength and quality. In this case, the scaling + * constants are derived from the output of p54usb. + */ + quality = 130 - ((41 * hdr->agc) >> 6); + signal = -4 - ((27 * hdr->agc) >> 6); rx_status.antenna = (hdr->signal >> 7) & 1; - rx_status.noise = hdr->noise; rx_status.mactime = le64_to_cpu(hdr->mac_time); - priv->quality = signal; - rx_status.qual = priv->quality; - priv->noise = hdr->noise; - rate = (flags >> 20) & 0xF; - if (rate > 3) { /* OFDM rate */ - if (signal > 90) - signal = 90; - else if (signal < 25) - signal = 25; - signal = 90 - signal; - } else { /* CCK rate */ - if (signal > 95) - signal = 95; - else if (signal < 30) - signal = 30; - signal = 95 - signal; - } - rx_status.signal = signal; - priv->signal = signal; } else { struct rtl8187b_rx_hdr *hdr = (typeof(hdr))(skb_tail_pointer(skb) - sizeof(*hdr)); @@ -343,18 +340,18 @@ static void rtl8187_rx_cb(struct urb *urb) */ flags = le32_to_cpu(hdr->flags); quality = 170 - hdr->agc; - if (quality > 100) - quality = 100; signal = 14 - hdr->agc / 2; - rx_status.qual = quality; - priv->quality = quality; - rx_status.signal = signal; - priv->signal = signal; rx_status.antenna = (hdr->rssi >> 7) & 1; rx_status.mactime = le64_to_cpu(hdr->mac_time); - rate = (flags >> 20) & 0xF; } + if (quality > 100) + quality = 100; + rx_status.qual = quality; + priv->quality = quality; + rx_status.signal = signal; + priv->signal = signal; + rate = (flags >> 20) & 0xF; skb_trim(skb, flags & 0x0FFF); rx_status.rate_idx = rate; rx_status.freq = dev->conf.channel->center_freq; @@ -366,7 +363,6 @@ static void rtl8187_rx_cb(struct urb *urb) skb = dev_alloc_skb(RTL8187_MAX_RX); if (unlikely(!skb)) { - usb_free_urb(urb); /* TODO check rx queue length and refill *somewhere* */ return; } @@ -378,24 +374,32 @@ static void rtl8187_rx_cb(struct urb *urb) urb->context = skb; skb_queue_tail(&priv->rx_queue, skb); - usb_submit_urb(urb, GFP_ATOMIC); + usb_anchor_urb(urb, &priv->anchored); + if (usb_submit_urb(urb, GFP_ATOMIC)) { + usb_unanchor_urb(urb); + skb_unlink(skb, &priv->rx_queue); + dev_kfree_skb_irq(skb); + } } static int rtl8187_init_urbs(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; - struct urb *entry; + struct urb *entry = NULL; struct sk_buff *skb; struct rtl8187_rx_info *info; + int ret = 0; while (skb_queue_len(&priv->rx_queue) < 8) { skb = __dev_alloc_skb(RTL8187_MAX_RX, GFP_KERNEL); - if (!skb) - break; + if (!skb) { + ret = -ENOMEM; + goto err; + } entry = usb_alloc_urb(0, GFP_KERNEL); if (!entry) { - kfree_skb(skb); - break; + ret = -ENOMEM; + goto err; } usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, @@ -406,10 +410,129 @@ static int rtl8187_init_urbs(struct ieee80211_hw *dev) info->urb = entry; info->dev = dev; skb_queue_tail(&priv->rx_queue, skb); - usb_submit_urb(entry, GFP_KERNEL); + usb_anchor_urb(entry, &priv->anchored); + ret = usb_submit_urb(entry, GFP_KERNEL); + if (ret) { + skb_unlink(skb, &priv->rx_queue); + usb_unanchor_urb(entry); + goto err; + } + usb_free_urb(entry); } + return ret; - return 0; +err: + usb_free_urb(entry); + kfree_skb(skb); + usb_kill_anchored_urbs(&priv->anchored); + return ret; +} + +static void rtl8187b_status_cb(struct urb *urb) +{ + struct ieee80211_hw *hw = (struct ieee80211_hw *)urb->context; + struct rtl8187_priv *priv = hw->priv; + u64 val; + unsigned int cmd_type; + + if (unlikely(urb->status)) + return; + + /* + * Read from status buffer: + * + * bits [30:31] = cmd type: + * - 0 indicates tx beacon interrupt + * - 1 indicates tx close descriptor + * + * In the case of tx beacon interrupt: + * [0:9] = Last Beacon CW + * [10:29] = reserved + * [30:31] = 00b + * [32:63] = Last Beacon TSF + * + * If it's tx close descriptor: + * [0:7] = Packet Retry Count + * [8:14] = RTS Retry Count + * [15] = TOK + * [16:27] = Sequence No + * [28] = LS + * [29] = FS + * [30:31] = 01b + * [32:47] = unused (reserved?) + * [48:63] = MAC Used Time + */ + val = le64_to_cpu(priv->b_tx_status.buf); + + cmd_type = (val >> 30) & 0x3; + if (cmd_type == 1) { + unsigned int pkt_rc, seq_no; + bool tok; + struct sk_buff *skb; + struct ieee80211_hdr *ieee80211hdr; + unsigned long flags; + + pkt_rc = val & 0xFF; + tok = val & (1 << 15); + seq_no = (val >> 16) & 0xFFF; + + spin_lock_irqsave(&priv->b_tx_status.queue.lock, flags); + skb_queue_reverse_walk(&priv->b_tx_status.queue, skb) { + ieee80211hdr = (struct ieee80211_hdr *)skb->data; + + /* + * While testing, it was discovered that the seq_no + * doesn't actually contains the sequence number. + * Instead of returning just the 12 bits of sequence + * number, hardware is returning entire sequence control + * (fragment number plus sequence number) in a 12 bit + * only field overflowing after some time. As a + * workaround, just consider the lower bits, and expect + * it's unlikely we wrongly ack some sent data + */ + if ((le16_to_cpu(ieee80211hdr->seq_ctrl) + & 0xFFF) == seq_no) + break; + } + if (skb != (struct sk_buff *) &priv->b_tx_status.queue) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); + + __skb_unlink(skb, &priv->b_tx_status.queue); + if (tok) + info->flags |= IEEE80211_TX_STAT_ACK; + info->status.rates[0].count = pkt_rc + 1; + + ieee80211_tx_status_irqsafe(hw, skb); + } + spin_unlock_irqrestore(&priv->b_tx_status.queue.lock, flags); + } + + usb_anchor_urb(urb, &priv->anchored); + if (usb_submit_urb(urb, GFP_ATOMIC)) + usb_unanchor_urb(urb); +} + +static int rtl8187b_init_status_urb(struct ieee80211_hw *dev) +{ + struct rtl8187_priv *priv = dev->priv; + struct urb *entry; + int ret = 0; + + entry = usb_alloc_urb(0, GFP_KERNEL); + if (!entry) + return -ENOMEM; + + usb_fill_bulk_urb(entry, priv->udev, usb_rcvbulkpipe(priv->udev, 9), + &priv->b_tx_status.buf, sizeof(priv->b_tx_status.buf), + rtl8187b_status_cb, dev); + + usb_anchor_urb(entry, &priv->anchored); + ret = usb_submit_urb(entry, GFP_KERNEL); + if (ret) + usb_unanchor_urb(entry); + usb_free_urb(entry); + + return ret; } static int rtl8187_cmd_reset(struct ieee80211_hw *dev) @@ -687,7 +810,7 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, 0x0480); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, 0x2488); rtl818x_iowrite16(priv, &priv->map->RFPinsEnable, 0x1FFF); - msleep(1100); + msleep(100); priv->rf->init(dev); @@ -721,6 +844,13 @@ static int rtl8187b_init_hw(struct ieee80211_hw *dev) rtl818x_iowrite16_idx(priv, (__le16 *)0xFFEC, 0x0800, 1); + priv->slot_time = 0x9; + priv->aifsn[0] = 2; /* AIFSN[AC_VO] */ + priv->aifsn[1] = 2; /* AIFSN[AC_VI] */ + priv->aifsn[2] = 7; /* AIFSN[AC_BK] */ + priv->aifsn[3] = 3; /* AIFSN[AC_BE] */ + rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0); + return 0; } @@ -736,6 +866,9 @@ static int rtl8187_start(struct ieee80211_hw *dev) return ret; mutex_lock(&priv->conf_mutex); + + init_usb_anchor(&priv->anchored); + if (priv->is_rtl8187b) { reg = RTL818X_RX_CONF_MGMT | RTL818X_RX_CONF_DATA | @@ -757,6 +890,7 @@ static int rtl8187_start(struct ieee80211_hw *dev) (7 << 0 /* long retry limit */) | (7 << 21 /* MAX TX DMA */)); rtl8187_init_urbs(dev); + rtl8187b_init_status_urb(dev); mutex_unlock(&priv->conf_mutex); return 0; } @@ -809,7 +943,6 @@ static int rtl8187_start(struct ieee80211_hw *dev) static void rtl8187_stop(struct ieee80211_hw *dev) { struct rtl8187_priv *priv = dev->priv; - struct rtl8187_rx_info *info; struct sk_buff *skb; u32 reg; @@ -828,11 +961,10 @@ static void rtl8187_stop(struct ieee80211_hw *dev) rtl818x_iowrite8(priv, &priv->map->CONFIG4, reg | RTL818X_CONFIG4_VCOOFF); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_NORMAL); - while ((skb = skb_dequeue(&priv->rx_queue))) { - info = (struct rtl8187_rx_info *)skb->cb; - usb_kill_urb(info->urb); - kfree_skb(skb); - } + while ((skb = skb_dequeue(&priv->b_tx_status.queue))) + dev_kfree_skb_any(skb); + + usb_kill_anchored_urbs(&priv->anchored); mutex_unlock(&priv->conf_mutex); } @@ -876,9 +1008,10 @@ static void rtl8187_remove_interface(struct ieee80211_hw *dev, mutex_unlock(&priv->conf_mutex); } -static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) +static int rtl8187_config(struct ieee80211_hw *dev, u32 changed) { struct rtl8187_priv *priv = dev->priv; + struct ieee80211_conf *conf = &dev->conf; u32 reg; mutex_lock(&priv->conf_mutex); @@ -889,27 +1022,10 @@ static int rtl8187_config(struct ieee80211_hw *dev, struct ieee80211_conf *conf) */ rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg | RTL818X_TX_CONF_LOOPBACK_MAC); - msleep(10); priv->rf->set_chan(dev, conf); msleep(10); rtl818x_iowrite32(priv, &priv->map->TX_CONF, reg); - if (!priv->is_rtl8187b) { - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - - if (conf->flags & IEEE80211_CONF_SHORT_SLOT_TIME) { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0x73); - } else { - rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); - rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); - rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); - rtl818x_iowrite8(priv, &priv->map->CW_VAL, 0xa5); - } - } - rtl818x_iowrite16(priv, &priv->map->ATIM_WND, 2); rtl818x_iowrite16(priv, &priv->map->ATIMTR_INTERVAL, 100); rtl818x_iowrite16(priv, &priv->map->BEACON_INTERVAL, 100); @@ -944,6 +1060,89 @@ static int rtl8187_config_interface(struct ieee80211_hw *dev, return 0; } +/* + * With 8187B, AC_*_PARAM clashes with FEMR definition in struct rtl818x_csr for + * example. Thus we have to use raw values for AC_*_PARAM register addresses. + */ +static __le32 *rtl8187b_ac_addr[4] = { + (__le32 *) 0xFFF0, /* AC_VO */ + (__le32 *) 0xFFF4, /* AC_VI */ + (__le32 *) 0xFFFC, /* AC_BK */ + (__le32 *) 0xFFF8, /* AC_BE */ +}; + +#define SIFS_TIME 0xa + +static void rtl8187_conf_erp(struct rtl8187_priv *priv, bool use_short_slot, + bool use_short_preamble) +{ + if (priv->is_rtl8187b) { + u8 difs, eifs; + u16 ack_timeout; + int queue; + + if (use_short_slot) { + priv->slot_time = 0x9; + difs = 0x1c; + eifs = 0x53; + } else { + priv->slot_time = 0x14; + difs = 0x32; + eifs = 0x5b; + } + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + rtl818x_iowrite8(priv, &priv->map->SLOT, priv->slot_time); + rtl818x_iowrite8(priv, &priv->map->DIFS, difs); + + /* + * BRSR+1 on 8187B is in fact EIFS register + * Value in units of 4 us + */ + rtl818x_iowrite8(priv, (u8 *)&priv->map->BRSR + 1, eifs); + + /* + * For 8187B, CARRIER_SENSE_COUNTER is in fact ack timeout + * register. In units of 4 us like eifs register + * ack_timeout = ack duration + plcp + difs + preamble + */ + ack_timeout = 112 + 48 + difs; + if (use_short_preamble) + ack_timeout += 72; + else + ack_timeout += 144; + rtl818x_iowrite8(priv, &priv->map->CARRIER_SENSE_COUNTER, + DIV_ROUND_UP(ack_timeout, 4)); + + for (queue = 0; queue < 4; queue++) + rtl818x_iowrite8(priv, (u8 *) rtl8187b_ac_addr[queue], + priv->aifsn[queue] * priv->slot_time + + SIFS_TIME); + } else { + rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); + if (use_short_slot) { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x9); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x14); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x14); + } else { + rtl818x_iowrite8(priv, &priv->map->SLOT, 0x14); + rtl818x_iowrite8(priv, &priv->map->DIFS, 0x24); + rtl818x_iowrite8(priv, &priv->map->EIFS, 91 - 0x24); + } + } +} + +static void rtl8187_bss_info_changed(struct ieee80211_hw *dev, + struct ieee80211_vif *vif, + struct ieee80211_bss_conf *info, + u32 changed) +{ + struct rtl8187_priv *priv = dev->priv; + + if (changed & (BSS_CHANGED_ERP_SLOT | BSS_CHANGED_ERP_PREAMBLE)) + rtl8187_conf_erp(priv, info->use_short_slot, + info->use_short_preamble); +} + static void rtl8187_configure_filter(struct ieee80211_hw *dev, unsigned int changed_flags, unsigned int *total_flags, @@ -976,6 +1175,42 @@ static void rtl8187_configure_filter(struct ieee80211_hw *dev, rtl818x_iowrite32_async(priv, &priv->map->RX_CONF, priv->rx_conf); } +static int rtl8187_conf_tx(struct ieee80211_hw *dev, u16 queue, + const struct ieee80211_tx_queue_params *params) +{ + struct rtl8187_priv *priv = dev->priv; + u8 cw_min, cw_max; + + if (queue > 3) + return -EINVAL; + + cw_min = fls(params->cw_min); + cw_max = fls(params->cw_max); + + if (priv->is_rtl8187b) { + priv->aifsn[queue] = params->aifs; + + /* + * This is the structure of AC_*_PARAM registers in 8187B: + * - TXOP limit field, bit offset = 16 + * - ECWmax, bit offset = 12 + * - ECWmin, bit offset = 8 + * - AIFS, bit offset = 0 + */ + rtl818x_iowrite32(priv, rtl8187b_ac_addr[queue], + (params->txop << 16) | (cw_max << 12) | + (cw_min << 8) | (params->aifs * + priv->slot_time + SIFS_TIME)); + } else { + if (queue != 0) + return -EINVAL; + + rtl818x_iowrite8(priv, &priv->map->CW_VAL, + cw_min | (cw_max << 4)); + } + return 0; +} + static const struct ieee80211_ops rtl8187_ops = { .tx = rtl8187_tx, .start = rtl8187_start, @@ -984,7 +1219,9 @@ static const struct ieee80211_ops rtl8187_ops = { .remove_interface = rtl8187_remove_interface, .config = rtl8187_config, .config_interface = rtl8187_config_interface, + .bss_info_changed = rtl8187_bss_info_changed, .configure_filter = rtl8187_configure_filter, + .conf_tx = rtl8187_conf_tx }; static void rtl8187_eeprom_register_read(struct eeprom_93cx6 *eeprom) @@ -1029,7 +1266,6 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, const char *chip_name; u16 txpwr, reg; int err, i; - DECLARE_MAC_BUF(mac); dev = ieee80211_alloc_hw(sizeof(*priv), &rtl8187_ops); if (!dev) { @@ -1065,6 +1301,7 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, priv->mode = NL80211_IFTYPE_MONITOR; dev->flags = IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING | + IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_RX_INCLUDES_FCS; eeprom.data = dev; @@ -1180,16 +1417,13 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, (*channel++).hw_value = txpwr >> 8; } - if (priv->is_rtl8187b) { - printk(KERN_WARNING "rtl8187: 8187B chip detected. Support " - "is EXPERIMENTAL, and could damage your\n" - " hardware, use at your own risk\n"); - dev->flags |= IEEE80211_HW_SIGNAL_DBM; - } else { - dev->flags |= IEEE80211_HW_SIGNAL_UNSPEC; - dev->max_signal = 65; - } + if (priv->is_rtl8187b) + printk(KERN_WARNING "rtl8187: 8187B chip detected.\n"); + /* + * XXX: Once this driver supports anything that requires + * beacons it must implement IEEE80211_TX_CTL_ASSIGN_SEQ. + */ dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION); if ((id->driver_info == DEVICE_RTL8187) && priv->is_rtl8187b) @@ -1211,9 +1445,10 @@ static int __devinit rtl8187_probe(struct usb_interface *intf, goto err_free_dev; } mutex_init(&priv->conf_mutex); + skb_queue_head_init(&priv->b_tx_status.queue); - printk(KERN_INFO "%s: hwaddr %s, %s V%d + %s\n", - wiphy_name(dev->wiphy), print_mac(mac, dev->wiphy->perm_addr), + printk(KERN_INFO "%s: hwaddr %pM, %s V%d + %s\n", + wiphy_name(dev->wiphy), dev->wiphy->perm_addr, chip_name, priv->asic_rev, priv->rf->name); return 0; diff --git a/drivers/net/wireless/rtl8187_rtl8225.c b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c similarity index 69% rename from drivers/net/wireless/rtl8187_rtl8225.c rename to drivers/net/wireless/rtl818x/rtl8187_rtl8225.c index 1bae8990341096913c6800c19df076ac4f7e208a..4e75e8e7fa909036e89fca107f8acbad06e4d70c 100644 --- a/drivers/net/wireless/rtl8187_rtl8225.c +++ b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.c @@ -64,7 +64,6 @@ static void rtl8225_write_bitbang(struct ieee80211_hw *dev, u8 addr, u16 data) rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); - msleep(2); } static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) @@ -98,7 +97,6 @@ static void rtl8225_write_8051(struct ieee80211_hw *dev, u8 addr, __le16 data) rtl818x_iowrite16(priv, &priv->map->RFPinsOutput, reg80 | (1 << 2)); rtl818x_iowrite16(priv, &priv->map->RFPinsSelect, reg84); - msleep(2); } static void rtl8225_write(struct ieee80211_hw *dev, u8 addr, u16 data) @@ -333,21 +331,21 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev) struct rtl8187_priv *priv = dev->priv; int i; - rtl8225_write(dev, 0x0, 0x067); msleep(1); - rtl8225_write(dev, 0x1, 0xFE0); msleep(1); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x3, 0x441); msleep(1); - rtl8225_write(dev, 0x4, 0x486); msleep(1); - rtl8225_write(dev, 0x5, 0xBC0); msleep(1); - rtl8225_write(dev, 0x6, 0xAE6); msleep(1); - rtl8225_write(dev, 0x7, 0x82A); msleep(1); - rtl8225_write(dev, 0x8, 0x01F); msleep(1); - rtl8225_write(dev, 0x9, 0x334); msleep(1); - rtl8225_write(dev, 0xA, 0xFD4); msleep(1); - rtl8225_write(dev, 0xB, 0x391); msleep(1); - rtl8225_write(dev, 0xC, 0x050); msleep(1); - rtl8225_write(dev, 0xD, 0x6DB); msleep(1); - rtl8225_write(dev, 0xE, 0x029); msleep(1); + rtl8225_write(dev, 0x0, 0x067); + rtl8225_write(dev, 0x1, 0xFE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x486); + rtl8225_write(dev, 0x5, 0xBC0); + rtl8225_write(dev, 0x6, 0xAE6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x01F); + rtl8225_write(dev, 0x9, 0x334); + rtl8225_write(dev, 0xA, 0xFD4); + rtl8225_write(dev, 0xB, 0x391); + rtl8225_write(dev, 0xC, 0x050); + rtl8225_write(dev, 0xD, 0x6DB); + rtl8225_write(dev, 0xE, 0x029); rtl8225_write(dev, 0xF, 0x914); msleep(100); rtl8225_write(dev, 0x2, 0xC4D); msleep(200); @@ -375,91 +373,89 @@ static void rtl8225_rf_init(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - msleep(1); rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - msleep(1); } msleep(1); - rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x11, 0x06); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x21, 0x27); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x25, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); + rtl8225_write_phy_ofdm(dev, 0x02, 0x42); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x09); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); + rtl8225_write_phy_ofdm(dev, 0x11, 0x06); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x76); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); + rtl8225_write_phy_ofdm(dev, 0x21, 0x27); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); + rtl8225_write_phy_ofdm(dev, 0x25, 0x20); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); rtl8225_write_phy_ofdm(dev, 0x0d, rtl8225_gain[2 * 4]); rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225_gain[2 * 4 + 2]); rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225_gain[2 * 4 + 3]); rtl8225_write_phy_ofdm(dev, 0x23, rtl8225_gain[2 * 4 + 1]); - rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); - rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); - rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); - rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); - rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); - rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); - rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); - rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x00, 0x98); + rtl8225_write_phy_cck(dev, 0x03, 0x20); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); + rtl8225_write_phy_cck(dev, 0x05, 0x12); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); + rtl8225_write_phy_cck(dev, 0x07, 0x78); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); + rtl8225_write_phy_cck(dev, 0x10, 0x9b); + rtl8225_write_phy_cck(dev, 0x11, 0x88); + rtl8225_write_phy_cck(dev, 0x12, 0x47); rtl8225_write_phy_cck(dev, 0x13, 0xd0); rtl8225_write_phy_cck(dev, 0x19, 0x00); rtl8225_write_phy_cck(dev, 0x1a, 0xa0); rtl8225_write_phy_cck(dev, 0x1b, 0x08); rtl8225_write_phy_cck(dev, 0x40, 0x86); - rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1); - rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); - rtl8225_write_phy_cck(dev, 0x44, 0x1f); msleep(1); - rtl8225_write_phy_cck(dev, 0x45, 0x1e); msleep(1); - rtl8225_write_phy_cck(dev, 0x46, 0x1a); msleep(1); - rtl8225_write_phy_cck(dev, 0x47, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x48, 0x10); msleep(1); - rtl8225_write_phy_cck(dev, 0x49, 0x0a); msleep(1); - rtl8225_write_phy_cck(dev, 0x4a, 0x05); msleep(1); - rtl8225_write_phy_cck(dev, 0x4b, 0x02); msleep(1); - rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); + rtl8225_write_phy_cck(dev, 0x42, 0x15); + rtl8225_write_phy_cck(dev, 0x43, 0x18); + rtl8225_write_phy_cck(dev, 0x44, 0x1f); + rtl8225_write_phy_cck(dev, 0x45, 0x1e); + rtl8225_write_phy_cck(dev, 0x46, 0x1a); + rtl8225_write_phy_cck(dev, 0x47, 0x15); + rtl8225_write_phy_cck(dev, 0x48, 0x10); + rtl8225_write_phy_cck(dev, 0x49, 0x0a); + rtl8225_write_phy_cck(dev, 0x4a, 0x05); + rtl8225_write_phy_cck(dev, 0x4b, 0x02); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); rtl818x_iowrite8(priv, &priv->map->TESTR, 0x0D); rtl8225_rf_set_tx_power(dev, 1); /* RX antenna default to A */ - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ msleep(1); @@ -629,7 +625,7 @@ static void rtl8225z2_b_rf_set_tx_power(struct ieee80211_hw *dev, int channel) rtl8225_write_phy_cck(dev, 0x44 + i, *tmp++); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, - rtl8225z2_tx_gain_cck_ofdm[cck_power]); + rtl8225z2_tx_gain_cck_ofdm[cck_power] << 1); msleep(1); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, @@ -687,22 +683,23 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev) struct rtl8187_priv *priv = dev->priv; int i; - rtl8225_write(dev, 0x0, 0x2BF); msleep(1); - rtl8225_write(dev, 0x1, 0xEE0); msleep(1); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x3, 0x441); msleep(1); - rtl8225_write(dev, 0x4, 0x8C3); msleep(1); - rtl8225_write(dev, 0x5, 0xC72); msleep(1); - rtl8225_write(dev, 0x6, 0x0E6); msleep(1); - rtl8225_write(dev, 0x7, 0x82A); msleep(1); - rtl8225_write(dev, 0x8, 0x03F); msleep(1); - rtl8225_write(dev, 0x9, 0x335); msleep(1); - rtl8225_write(dev, 0xa, 0x9D4); msleep(1); - rtl8225_write(dev, 0xb, 0x7BB); msleep(1); - rtl8225_write(dev, 0xc, 0x850); msleep(1); - rtl8225_write(dev, 0xd, 0xCDF); msleep(1); - rtl8225_write(dev, 0xe, 0x02B); msleep(1); - rtl8225_write(dev, 0xf, 0x114); msleep(100); + rtl8225_write(dev, 0x0, 0x2BF); + rtl8225_write(dev, 0x1, 0xEE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x8C3); + rtl8225_write(dev, 0x5, 0xC72); + rtl8225_write(dev, 0x6, 0x0E6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x03F); + rtl8225_write(dev, 0x9, 0x335); + rtl8225_write(dev, 0xa, 0x9D4); + rtl8225_write(dev, 0xb, 0x7BB); + rtl8225_write(dev, 0xc, 0x850); + rtl8225_write(dev, 0xd, 0xCDF); + rtl8225_write(dev, 0xe, 0x02B); + rtl8225_write(dev, 0xf, 0x114); + msleep(100); rtl8225_write(dev, 0x0, 0x1B7); @@ -736,94 +733,92 @@ static void rtl8225z2_rf_init(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(rtl8225_agc); i++) { rtl8225_write_phy_ofdm(dev, 0xB, rtl8225_agc[i]); - msleep(1); rtl8225_write_phy_ofdm(dev, 0xA, 0x80 + i); - msleep(1); } msleep(1); - rtl8225_write_phy_ofdm(dev, 0x00, 0x01); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x01, 0x02); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x02, 0x42); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x03, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x04, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x05, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x06, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x07, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x08, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x00, 0x01); + rtl8225_write_phy_ofdm(dev, 0x01, 0x02); + rtl8225_write_phy_ofdm(dev, 0x02, 0x42); + rtl8225_write_phy_ofdm(dev, 0x03, 0x00); + rtl8225_write_phy_ofdm(dev, 0x04, 0x00); + rtl8225_write_phy_ofdm(dev, 0x05, 0x00); + rtl8225_write_phy_ofdm(dev, 0x06, 0x40); + rtl8225_write_phy_ofdm(dev, 0x07, 0x00); + rtl8225_write_phy_ofdm(dev, 0x08, 0x40); + rtl8225_write_phy_ofdm(dev, 0x09, 0xfe); + rtl8225_write_phy_ofdm(dev, 0x0a, 0x08); + rtl8225_write_phy_ofdm(dev, 0x0b, 0x80); + rtl8225_write_phy_ofdm(dev, 0x0c, 0x01); rtl8225_write_phy_ofdm(dev, 0x0d, 0x43); - rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x10, 0x84); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x11, 0x07); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x12, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x13, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x14, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x15, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x16, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x17, 0x40); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x18, 0xef); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x19, 0x19); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x21, 0x17); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x22, 0x16); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x23, 0x80); msleep(1); //FIXME: not needed? - rtl8225_write_phy_ofdm(dev, 0x24, 0x46); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x25, 0x00); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x27, 0x88); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x0e, 0xd3); + rtl8225_write_phy_ofdm(dev, 0x0f, 0x38); + rtl8225_write_phy_ofdm(dev, 0x10, 0x84); + rtl8225_write_phy_ofdm(dev, 0x11, 0x07); + rtl8225_write_phy_ofdm(dev, 0x12, 0x20); + rtl8225_write_phy_ofdm(dev, 0x13, 0x20); + rtl8225_write_phy_ofdm(dev, 0x14, 0x00); + rtl8225_write_phy_ofdm(dev, 0x15, 0x40); + rtl8225_write_phy_ofdm(dev, 0x16, 0x00); + rtl8225_write_phy_ofdm(dev, 0x17, 0x40); + rtl8225_write_phy_ofdm(dev, 0x18, 0xef); + rtl8225_write_phy_ofdm(dev, 0x19, 0x19); + rtl8225_write_phy_ofdm(dev, 0x1a, 0x20); + rtl8225_write_phy_ofdm(dev, 0x1b, 0x15); + rtl8225_write_phy_ofdm(dev, 0x1c, 0x04); + rtl8225_write_phy_ofdm(dev, 0x1d, 0xc5); + rtl8225_write_phy_ofdm(dev, 0x1e, 0x95); + rtl8225_write_phy_ofdm(dev, 0x1f, 0x75); + rtl8225_write_phy_ofdm(dev, 0x20, 0x1f); + rtl8225_write_phy_ofdm(dev, 0x21, 0x17); + rtl8225_write_phy_ofdm(dev, 0x22, 0x16); + rtl8225_write_phy_ofdm(dev, 0x23, 0x80); + rtl8225_write_phy_ofdm(dev, 0x24, 0x46); + rtl8225_write_phy_ofdm(dev, 0x25, 0x00); + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); + rtl8225_write_phy_ofdm(dev, 0x27, 0x88); rtl8225_write_phy_ofdm(dev, 0x0b, rtl8225z2_gain_bg[4 * 3]); rtl8225_write_phy_ofdm(dev, 0x1b, rtl8225z2_gain_bg[4 * 3 + 1]); rtl8225_write_phy_ofdm(dev, 0x1d, rtl8225z2_gain_bg[4 * 3 + 2]); rtl8225_write_phy_ofdm(dev, 0x21, 0x37); - rtl8225_write_phy_cck(dev, 0x00, 0x98); msleep(1); - rtl8225_write_phy_cck(dev, 0x03, 0x20); msleep(1); - rtl8225_write_phy_cck(dev, 0x04, 0x7e); msleep(1); - rtl8225_write_phy_cck(dev, 0x05, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x06, 0xfc); msleep(1); - rtl8225_write_phy_cck(dev, 0x07, 0x78); msleep(1); - rtl8225_write_phy_cck(dev, 0x08, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); - rtl8225_write_phy_cck(dev, 0x11, 0x88); msleep(1); - rtl8225_write_phy_cck(dev, 0x12, 0x47); msleep(1); + rtl8225_write_phy_cck(dev, 0x00, 0x98); + rtl8225_write_phy_cck(dev, 0x03, 0x20); + rtl8225_write_phy_cck(dev, 0x04, 0x7e); + rtl8225_write_phy_cck(dev, 0x05, 0x12); + rtl8225_write_phy_cck(dev, 0x06, 0xfc); + rtl8225_write_phy_cck(dev, 0x07, 0x78); + rtl8225_write_phy_cck(dev, 0x08, 0x2e); + rtl8225_write_phy_cck(dev, 0x10, 0x9b); + rtl8225_write_phy_cck(dev, 0x11, 0x88); + rtl8225_write_phy_cck(dev, 0x12, 0x47); rtl8225_write_phy_cck(dev, 0x13, 0xd0); rtl8225_write_phy_cck(dev, 0x19, 0x00); rtl8225_write_phy_cck(dev, 0x1a, 0xa0); rtl8225_write_phy_cck(dev, 0x1b, 0x08); rtl8225_write_phy_cck(dev, 0x40, 0x86); - rtl8225_write_phy_cck(dev, 0x41, 0x8d); msleep(1); - rtl8225_write_phy_cck(dev, 0x42, 0x15); msleep(1); - rtl8225_write_phy_cck(dev, 0x43, 0x18); msleep(1); - rtl8225_write_phy_cck(dev, 0x44, 0x36); msleep(1); - rtl8225_write_phy_cck(dev, 0x45, 0x35); msleep(1); - rtl8225_write_phy_cck(dev, 0x46, 0x2e); msleep(1); - rtl8225_write_phy_cck(dev, 0x47, 0x25); msleep(1); - rtl8225_write_phy_cck(dev, 0x48, 0x1c); msleep(1); - rtl8225_write_phy_cck(dev, 0x49, 0x12); msleep(1); - rtl8225_write_phy_cck(dev, 0x4a, 0x09); msleep(1); - rtl8225_write_phy_cck(dev, 0x4b, 0x04); msleep(1); - rtl8225_write_phy_cck(dev, 0x4c, 0x05); msleep(1); + rtl8225_write_phy_cck(dev, 0x41, 0x8d); + rtl8225_write_phy_cck(dev, 0x42, 0x15); + rtl8225_write_phy_cck(dev, 0x43, 0x18); + rtl8225_write_phy_cck(dev, 0x44, 0x36); + rtl8225_write_phy_cck(dev, 0x45, 0x35); + rtl8225_write_phy_cck(dev, 0x46, 0x2e); + rtl8225_write_phy_cck(dev, 0x47, 0x25); + rtl8225_write_phy_cck(dev, 0x48, 0x1c); + rtl8225_write_phy_cck(dev, 0x49, 0x12); + rtl8225_write_phy_cck(dev, 0x4a, 0x09); + rtl8225_write_phy_cck(dev, 0x4b, 0x04); + rtl8225_write_phy_cck(dev, 0x4c, 0x05); rtl818x_iowrite8(priv, (u8 *)0xFF5B, 0x0D); msleep(1); rtl8225z2_rf_set_tx_power(dev, 1); /* RX antenna default to A */ - rtl8225_write_phy_cck(dev, 0x10, 0x9b); msleep(1); /* B: 0xDB */ - rtl8225_write_phy_ofdm(dev, 0x26, 0x90); msleep(1); /* B: 0x10 */ + rtl8225_write_phy_cck(dev, 0x10, 0x9b); /* B: 0xDB */ + rtl8225_write_phy_ofdm(dev, 0x26, 0x90); /* B: 0x10 */ rtl818x_iowrite8(priv, &priv->map->TX_ANTENNA, 0x03); /* B: 0x00 */ msleep(1); @@ -835,40 +830,38 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) struct rtl8187_priv *priv = dev->priv; int i; - rtl8225_write(dev, 0x0, 0x0B7); msleep(1); - rtl8225_write(dev, 0x1, 0xEE0); msleep(1); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x3, 0x441); msleep(1); - rtl8225_write(dev, 0x4, 0x8C3); msleep(1); - rtl8225_write(dev, 0x5, 0xC72); msleep(1); - rtl8225_write(dev, 0x6, 0x0E6); msleep(1); - rtl8225_write(dev, 0x7, 0x82A); msleep(1); - rtl8225_write(dev, 0x8, 0x03F); msleep(1); - rtl8225_write(dev, 0x9, 0x335); msleep(1); - rtl8225_write(dev, 0xa, 0x9D4); msleep(1); - rtl8225_write(dev, 0xb, 0x7BB); msleep(1); - rtl8225_write(dev, 0xc, 0x850); msleep(1); - rtl8225_write(dev, 0xd, 0xCDF); msleep(1); - rtl8225_write(dev, 0xe, 0x02B); msleep(1); - rtl8225_write(dev, 0xf, 0x114); msleep(1); - - rtl8225_write(dev, 0x0, 0x1B7); msleep(1); + rtl8225_write(dev, 0x0, 0x0B7); + rtl8225_write(dev, 0x1, 0xEE0); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x3, 0x441); + rtl8225_write(dev, 0x4, 0x8C3); + rtl8225_write(dev, 0x5, 0xC72); + rtl8225_write(dev, 0x6, 0x0E6); + rtl8225_write(dev, 0x7, 0x82A); + rtl8225_write(dev, 0x8, 0x03F); + rtl8225_write(dev, 0x9, 0x335); + rtl8225_write(dev, 0xa, 0x9D4); + rtl8225_write(dev, 0xb, 0x7BB); + rtl8225_write(dev, 0xc, 0x850); + rtl8225_write(dev, 0xd, 0xCDF); + rtl8225_write(dev, 0xe, 0x02B); + rtl8225_write(dev, 0xf, 0x114); + + rtl8225_write(dev, 0x0, 0x1B7); for (i = 0; i < ARRAY_SIZE(rtl8225z2_rxgain); i++) { - rtl8225_write(dev, 0x1, i + 1); msleep(1); - rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); msleep(1); + rtl8225_write(dev, 0x1, i + 1); + rtl8225_write(dev, 0x2, rtl8225z2_rxgain[i]); } - rtl8225_write(dev, 0x3, 0x080); msleep(1); - rtl8225_write(dev, 0x5, 0x004); msleep(1); - rtl8225_write(dev, 0x0, 0x0B7); msleep(1); - msleep(3000); + rtl8225_write(dev, 0x3, 0x080); + rtl8225_write(dev, 0x5, 0x004); + rtl8225_write(dev, 0x0, 0x0B7); - rtl8225_write(dev, 0x2, 0xC4D); msleep(1); - msleep(2000); + rtl8225_write(dev, 0x2, 0xC4D); - rtl8225_write(dev, 0x2, 0x44D); msleep(1); - rtl8225_write(dev, 0x0, 0x2BF); msleep(1); + rtl8225_write(dev, 0x2, 0x44D); + rtl8225_write(dev, 0x0, 0x2BF); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_CCK, 0x03); rtl818x_iowrite8(priv, &priv->map->TX_GAIN_OFDM, 0x07); @@ -885,24 +878,10 @@ static void rtl8225z2_b_rf_init(struct ieee80211_hw *dev) for (i = 0; i < ARRAY_SIZE(rtl8225z2_ofdm); i++) rtl8225_write_phy_ofdm(dev, i, rtl8225z2_ofdm[i]); - rtl818x_iowrite8(priv, &priv->map->SIFS, 0x22); - rtl818x_iowrite8(priv, &priv->map->SLOT, 9); - rtl818x_iowrite8(priv, (u8 *)0xFFF0, 28); - rtl818x_iowrite8(priv, (u8 *)0xFFF4, 28); - rtl818x_iowrite8(priv, (u8 *)0xFFF8, 28); - rtl818x_iowrite8(priv, (u8 *)0xFFFC, 28); - rtl818x_iowrite8(priv, (u8 *)0xFF2D, 0x5B); - rtl818x_iowrite8(priv, (u8 *)0xFF79, 0x5B); - rtl818x_iowrite32(priv, (__le32 *)0xFFF0, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFF4, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFF8, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite32(priv, (__le32 *)0xFFFC, (7 << 12) | (3 << 8) | 28); - rtl818x_iowrite8(priv, &priv->map->ACM_CONTROL, 0); - - rtl8225_write_phy_ofdm(dev, 0x97, 0x46); msleep(1); - rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); msleep(1); - rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); msleep(1); - rtl8225_write_phy_cck(dev, 0xc1, 0x88); msleep(1); + rtl8225_write_phy_ofdm(dev, 0x97, 0x46); + rtl8225_write_phy_ofdm(dev, 0xa4, 0xb6); + rtl8225_write_phy_ofdm(dev, 0x85, 0xfc); + rtl8225_write_phy_cck(dev, 0xc1, 0x88); } static void rtl8225_rf_stop(struct ieee80211_hw *dev) @@ -910,7 +889,7 @@ static void rtl8225_rf_stop(struct ieee80211_hw *dev) u8 reg; struct rtl8187_priv *priv = dev->priv; - rtl8225_write(dev, 0x4, 0x1f); msleep(1); + rtl8225_write(dev, 0x4, 0x1f); rtl818x_iowrite8(priv, &priv->map->EEPROM_CMD, RTL818X_EEPROM_CMD_CONFIG); reg = rtl818x_ioread8(priv, &priv->map->CONFIG3); diff --git a/drivers/net/wireless/rtl8187_rtl8225.h b/drivers/net/wireless/rtl818x/rtl8187_rtl8225.h similarity index 100% rename from drivers/net/wireless/rtl8187_rtl8225.h rename to drivers/net/wireless/rtl818x/rtl8187_rtl8225.h diff --git a/drivers/net/wireless/rtl818x.h b/drivers/net/wireless/rtl818x/rtl818x.h similarity index 98% rename from drivers/net/wireless/rtl818x.h rename to drivers/net/wireless/rtl818x/rtl818x.h index 3538b15211b190bd2cf07d96ecd6caf79c527232..34a5555cc19c04fe3162f634e34c7937ac570018 100644 --- a/drivers/net/wireless/rtl818x.h +++ b/drivers/net/wireless/rtl818x/rtl818x.h @@ -191,6 +191,7 @@ struct rtl818x_rf_ops { void (*init)(struct ieee80211_hw *); void (*stop)(struct ieee80211_hw *); void (*set_chan)(struct ieee80211_hw *, struct ieee80211_conf *); + void (*conf_erp)(struct ieee80211_hw *, struct ieee80211_bss_conf *); }; /* Tx/Rx flags are common between RTL818X chips */ diff --git a/drivers/net/wireless/strip.c b/drivers/net/wireless/strip.c index 417e9e675facceab098ca13f594419572a0a0d6d..dd0de3a9ed4eef2f479b5a36aead3d580ba50d81 100644 --- a/drivers/net/wireless/strip.c +++ b/drivers/net/wireless/strip.c @@ -1234,7 +1234,7 @@ static void ResetRadio(struct strip *strip_info) static void strip_write_some_more(struct tty_struct *tty) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* First make sure we're connected. */ if (!strip_info || strip_info->magic != STRIP_MAGIC || @@ -1252,7 +1252,7 @@ static void strip_write_some_more(struct tty_struct *tty) #endif } else { /* Else start transmission of another packet */ - tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); + clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); strip_unlock(strip_info); } } @@ -1455,8 +1455,7 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) */ strip_info->tx_head = strip_info->tx_buff; strip_info->tx_left = ptr - strip_info->tx_buff; - strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - + set_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags); /* * 4. Debugging check to make sure we're not overflowing the buffer. */ @@ -1997,7 +1996,6 @@ static void deliver_packet(struct strip *strip_info, STRIP_Header * header, #ifdef EXT_COUNTERS strip_info->rx_bytes += packetlen; #endif - skb->dev->last_rx = jiffies; netif_rx(skb); } } @@ -2261,7 +2259,7 @@ static void process_message(struct strip *strip_info) static void strip_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; const unsigned char *end = cp + count; if (!strip_info || strip_info->magic != STRIP_MAGIC @@ -2455,8 +2453,7 @@ static int strip_close_low(struct net_device *dev) if (strip_info->tty == NULL) return -EBUSY; - strip_info->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP); - + clear_bit(TTY_DO_WRITE_WAKEUP, &strip_info->tty->flags); netif_stop_queue(dev); /* @@ -2490,7 +2487,6 @@ static void strip_dev_setup(struct net_device *dev) */ dev->trans_start = 0; - dev->last_rx = 0; dev->tx_queue_len = 30; /* Drop after 30 frames queued */ dev->flags = 0; @@ -2498,7 +2494,7 @@ static void strip_dev_setup(struct net_device *dev) dev->type = ARPHRD_METRICOM; /* dtang */ dev->hard_header_len = sizeof(STRIP_Header); /* - * dev->priv Already holds a pointer to our struct strip + * netdev_priv(dev) Already holds a pointer to our struct strip */ *(MetricomAddress *) & dev->broadcast = broadcast_address; @@ -2598,7 +2594,7 @@ static struct strip *strip_alloc(void) static int strip_open(struct tty_struct *tty) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* * First make sure we're not already connected. @@ -2669,7 +2665,7 @@ static int strip_open(struct tty_struct *tty) static void strip_close(struct tty_struct *tty) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* * First make sure we're connected. @@ -2695,7 +2691,7 @@ static void strip_close(struct tty_struct *tty) static int strip_ioctl(struct tty_struct *tty, struct file *file, unsigned int cmd, unsigned long arg) { - struct strip *strip_info = (struct strip *) tty->disc_data; + struct strip *strip_info = tty->disc_data; /* * First make sure we're connected. diff --git a/drivers/net/wireless/wavelan.c b/drivers/net/wireless/wavelan.c index e939a73ff794a731583292d5e41e7e8a23f64d8e..832679396b6cbc14a23124d35abd2ae389de83b6 100644 --- a/drivers/net/wireless/wavelan.c +++ b/drivers/net/wireless/wavelan.c @@ -134,7 +134,7 @@ static inline void wv_16_on(unsigned long ioaddr, u16 hacr) */ static inline void wv_ints_off(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; lp->hacr &= ~HACR_INTRON; @@ -148,7 +148,7 @@ static inline void wv_ints_off(struct net_device * dev) */ static inline void wv_ints_on(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; lp->hacr |= HACR_INTRON; @@ -526,7 +526,7 @@ static inline void obram_write(unsigned long ioaddr, u16 o, u8 * b, int n) */ static void wv_ack(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cs; int i; @@ -568,7 +568,7 @@ static void wv_ack(struct net_device * dev) */ static int wv_synchronous_cmd(struct net_device * dev, const char *str) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cmd; ach_t cb; @@ -824,7 +824,7 @@ if (lp->tx_n_in_use > 0) */ static void wv_82586_reconfig(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; /* Arm the flag, will be cleard in wv_82586_config() */ @@ -859,8 +859,6 @@ static void wv_82586_reconfig(struct net_device * dev) */ static void wv_psa_show(psa_t * p) { - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "##### WaveLAN PSA contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, @@ -872,13 +870,10 @@ static void wv_psa_show(psa_t * p) printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_unused0[]: %s\n", - print_mac(mac, p->psa_unused0)); + printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); #endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n", - print_mac(mac, p->psa_univ_mac_addr)); - printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n", - print_mac(mac, p->psa_local_mac_addr)); + printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); + printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); printk("psa_comp_number: %d, ", p->psa_comp_number); @@ -927,7 +922,7 @@ static void wv_psa_show(psa_t * p) static void wv_mmc_show(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); mmr_t m; /* Basic check */ @@ -1107,8 +1102,6 @@ static void wv_scb_show(unsigned long ioaddr) */ static void wv_ru_show(struct net_device * dev) { - /* net_local *lp = (net_local *) dev->priv; */ - printk(KERN_DEBUG "##### WaveLAN i82586 receiver unit status: #####\n"); printk(KERN_DEBUG "ru:"); @@ -1153,7 +1146,7 @@ static void wv_cu_show_one(struct net_device * dev, net_local * lp, int i, u16 p */ static void wv_cu_show(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned int i; u16 p; @@ -1195,7 +1188,7 @@ static void wv_local_show(struct net_device * dev) { net_local *lp; - lp = (net_local *) dev->priv; + lp = netdev_priv(dev); printk(KERN_DEBUG "local:"); printk(" tx_n_in_use=%d,", lp->tx_n_in_use); @@ -1220,14 +1213,13 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */ { /* Name of the function */ int i; int maxi; - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG - "%s: %s(): dest %s, length %d\n", - msg1, msg2, print_mac(mac, p), length); + "%s: %s(): dest %pM, length %d\n", + msg1, msg2, p, length); printk(KERN_DEBUG - "%s: %s(): src %s, type 0x%02X%02X\n", - msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]); + "%s: %s(): src %pM, type 0x%02X%02X\n", + msg1, msg2, &p[6], p[12], p[13]); #ifdef DEBUG_PACKET_DUMP @@ -1256,11 +1248,8 @@ static inline void wv_packet_info(u8 * p, /* Packet to dump */ static void wv_init_info(struct net_device * dev) { short ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); psa_t psa; -#ifdef DEBUG_BASIC_SHOW - DECLARE_MAC_BUF(mac); -#endif /* Read the parameter storage area */ psa_read(ioaddr, lp->hacr, 0, (unsigned char *) &psa, sizeof(psa)); @@ -1277,8 +1266,8 @@ static void wv_init_info(struct net_device * dev) #ifdef DEBUG_BASIC_SHOW /* Now, let's go for the basic stuff. */ - printk(KERN_NOTICE "%s: WaveLAN at %#x, %s, IRQ %d", - dev->name, ioaddr, print_mac(mac, dev->dev_addr), dev->irq); + printk(KERN_NOTICE "%s: WaveLAN at %#x, %pM, IRQ %d", + dev->name, ioaddr, dev->dev_addr, dev->irq); /* Print current network ID. */ if (psa.psa_nwid_select) @@ -1369,7 +1358,7 @@ static en_stats *wavelan_get_stats(struct net_device * dev) printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name); #endif - return (&((net_local *) dev->priv)->stats); + return &((net_local *)netdev_priv(dev))->stats; } /*------------------------------------------------------------------*/ @@ -1382,7 +1371,7 @@ static en_stats *wavelan_get_stats(struct net_device * dev) */ static void wavelan_set_multicast_list(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); #ifdef DEBUG_IOCTL_TRACE printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", @@ -1716,7 +1705,7 @@ static inline void wl_spy_gather(struct net_device * dev, */ static inline void wl_his_gather(struct net_device * dev, u8 * stats) { /* Statistics to gather */ - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); u8 level = stats[0] & MMR_SIGNAL_LVL; int i; @@ -1753,7 +1742,7 @@ static int wavelan_set_nwid(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; mm_t m; unsigned long flags; @@ -1812,7 +1801,7 @@ static int wavelan_get_nwid(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1844,7 +1833,7 @@ static int wavelan_set_freq(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ unsigned long flags; int ret; @@ -1874,7 +1863,7 @@ static int wavelan_get_freq(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1920,7 +1909,7 @@ static int wavelan_set_sens(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1956,7 +1945,7 @@ static int wavelan_get_sens(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -1987,7 +1976,7 @@ static int wavelan_set_encode(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ unsigned long flags; psa_t psa; int ret = 0; @@ -2057,7 +2046,7 @@ static int wavelan_get_encode(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; int ret = 0; @@ -2104,7 +2093,7 @@ static int wavelan_get_range(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ struct iw_range *range = (struct iw_range *) extra; unsigned long flags; int ret = 0; @@ -2179,7 +2168,7 @@ static int wavelan_set_qthr(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; @@ -2211,7 +2200,7 @@ static int wavelan_get_qthr(struct net_device *dev, char *extra) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ psa_t psa; unsigned long flags; @@ -2239,7 +2228,7 @@ static int wavelan_set_histo(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ /* Check the number of intervals. */ if (wrqu->data.length > 16) { @@ -2282,7 +2271,7 @@ static int wavelan_get_histo(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - net_local *lp = (net_local *) dev->priv; /* lp is not unused */ + net_local *lp = netdev_priv(dev); /* lp is not unused */ /* Set the number of intervals. */ wrqu->data.length = lp->his_number; @@ -2386,7 +2375,7 @@ static const struct iw_handler_def wavelan_handler_def = static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); mmr_t m; iw_stats *wstats; unsigned long flags; @@ -2461,7 +2450,7 @@ static iw_stats *wavelan_get_wireless_stats(struct net_device * dev) static void wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; struct sk_buff *skb; @@ -2537,7 +2526,6 @@ wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) netif_rx(skb); /* Keep statistics up to date */ - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += sksize; @@ -2556,7 +2544,7 @@ wv_packet_read(struct net_device * dev, u16 buf_off, int sksize) static void wv_receive(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); fd_t fd; rbd_t rbd; int nreaped = 0; @@ -2738,7 +2726,7 @@ static void wv_receive(struct net_device * dev) */ static int wv_packet_write(struct net_device * dev, void *buf, short length) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned short txblock; unsigned short txpred; @@ -2869,7 +2857,7 @@ static int wv_packet_write(struct net_device * dev, void *buf, short length) */ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; char data[ETH_ZLEN]; @@ -2937,7 +2925,7 @@ static int wavelan_packet_xmit(struct sk_buff *skb, struct net_device * dev) static int wv_mmc_init(struct net_device * dev) { unsigned long ioaddr = dev->base_addr; - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); psa_t psa; mmw_t m; int configured; @@ -3108,7 +3096,7 @@ static int wv_mmc_init(struct net_device * dev) */ static int wv_ru_start(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cs; fd_t fd; @@ -3200,7 +3188,7 @@ static int wv_ru_start(struct net_device * dev) */ static int wv_cu_start(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; int i; u16 txblock; @@ -3301,7 +3289,7 @@ static int wv_cu_start(struct net_device * dev) */ static int wv_82586_start(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; scp_t scp; /* system configuration pointer */ iscp_t iscp; /* intermediate scp */ @@ -3433,7 +3421,7 @@ static int wv_82586_start(struct net_device * dev) */ static void wv_82586_config(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; unsigned short txblock; unsigned short txpred; @@ -3565,15 +3553,11 @@ static void wv_82586_config(struct net_device * dev) WAVELAN_ADDR_SIZE >> 1); #ifdef DEBUG_CONFIG_INFO - { - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: wv_82586_config(): set %d multicast addresses:\n", dev->name, lp->mc_count); for (dmi = dev->mc_list; dmi; dmi = dmi->next) - printk(KERN_DEBUG " %s\n", - print_mac(mac, dmi->dmi_addr)); - } + printk(KERN_DEBUG " %pM\n", dmi->dmi_addr); #endif } @@ -3613,7 +3597,7 @@ static void wv_82586_config(struct net_device * dev) */ static void wv_82586_stop(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; u16 scb_cmd; @@ -3650,7 +3634,7 @@ static void wv_82586_stop(struct net_device * dev) */ static int wv_hw_reset(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long ioaddr = dev->base_addr; #ifdef DEBUG_CONFIG_TRACE @@ -3751,7 +3735,7 @@ static irqreturn_t wavelan_interrupt(int irq, void *dev_id) printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name); #endif - lp = (net_local *) dev->priv; + lp = netdev_priv(dev); ioaddr = dev->base_addr; #ifdef DEBUG_INTERRUPT_INFO @@ -3894,7 +3878,7 @@ static irqreturn_t wavelan_interrupt(int irq, void *dev_id) */ static void wavelan_watchdog(struct net_device * dev) { - net_local * lp = (net_local *)dev->priv; + net_local *lp = netdev_priv(dev); u_long ioaddr = dev->base_addr; unsigned long flags; unsigned int nreaped; @@ -3974,7 +3958,7 @@ static void wavelan_watchdog(struct net_device * dev) */ static int wavelan_open(struct net_device * dev) { - net_local * lp = (net_local *)dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; #ifdef DEBUG_CALLBACK_TRACE @@ -4029,7 +4013,7 @@ static int wavelan_open(struct net_device * dev) */ static int wavelan_close(struct net_device * dev) { - net_local *lp = (net_local *) dev->priv; + net_local *lp = netdev_priv(dev); unsigned long flags; #ifdef DEBUG_CALLBACK_TRACE @@ -4128,8 +4112,8 @@ static int __init wavelan_config(struct net_device *dev, unsigned short ioaddr) dev->if_port = 0; /* Initialize device structures */ - memset(dev->priv, 0, sizeof(net_local)); - lp = (net_local *) dev->priv; + memset(netdev_priv(dev), 0, sizeof(net_local)); + lp = netdev_priv(dev); /* Back link to the device structure. */ lp->dev = dev; diff --git a/drivers/net/wireless/wavelan_cs.c b/drivers/net/wireless/wavelan_cs.c index e124b1d6267afa03cc5e3c149d8ab77080159b2c..de717f8ffd61061a5caccfa92cb62d70403b1087 100644 --- a/drivers/net/wireless/wavelan_cs.c +++ b/drivers/net/wireless/wavelan_cs.c @@ -1020,7 +1020,6 @@ wv_82593_reconfig(struct net_device * dev) static void wv_psa_show(psa_t * p) { - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "##### wavelan psa contents: #####\n"); printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n", p->psa_io_base_addr_1, @@ -1034,13 +1033,10 @@ wv_psa_show(psa_t * p) printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params); printk("psa_int_req_no: %d\n", p->psa_int_req_no); #ifdef DEBUG_SHOW_UNUSED - printk(KERN_DEBUG "psa_unused0[]: %s\n", - print_mac(mac, p->psa_unused0)); + printk(KERN_DEBUG "psa_unused0[]: %pM\n", p->psa_unused0); #endif /* DEBUG_SHOW_UNUSED */ - printk(KERN_DEBUG "psa_univ_mac_addr[]: %s\n", - print_mac(mac, p->psa_univ_mac_addr)); - printk(KERN_DEBUG "psa_local_mac_addr[]: %s\n", - print_mac(mac, p->psa_local_mac_addr)); + printk(KERN_DEBUG "psa_univ_mac_addr[]: %pM\n", p->psa_univ_mac_addr); + printk(KERN_DEBUG "psa_local_mac_addr[]: %pM\n", p->psa_local_mac_addr); printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel); printk("psa_comp_number: %d, ", p->psa_comp_number); printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set); @@ -1238,12 +1234,11 @@ wv_packet_info(u_char * p, /* Packet to dump */ { int i; int maxi; - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "%s: %s(): dest %s, length %d\n", - msg1, msg2, print_mac(mac, p), length); - printk(KERN_DEBUG "%s: %s(): src %s, type 0x%02X%02X\n", - msg1, msg2, print_mac(mac, &p[6]), p[12], p[13]); + printk(KERN_DEBUG "%s: %s(): dest %pM, length %d\n", + msg1, msg2, p, length); + printk(KERN_DEBUG "%s: %s(): src %pM, type 0x%02X%02X\n", + msg1, msg2, &p[6], p[12], p[13]); #ifdef DEBUG_PACKET_DUMP @@ -1274,7 +1269,6 @@ wv_init_info(struct net_device * dev) { unsigned int base = dev->base_addr; psa_t psa; - DECLARE_MAC_BUF(mac); /* Read the parameter storage area */ psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa)); @@ -1291,10 +1285,8 @@ wv_init_info(struct net_device * dev) #ifdef DEBUG_BASIC_SHOW /* Now, let's go for the basic stuff */ - printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, " - "hw_addr %s", - dev->name, base, dev->irq, - print_mac(mac, dev->dev_addr)); + printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr %pM", + dev->name, base, dev->irq, dev->dev_addr); /* Print current network id */ if(psa.psa_nwid_select) @@ -2243,13 +2235,7 @@ static int wavelan_set_wap(struct net_device *dev, char *extra) { #ifdef DEBUG_IOCTL_INFO - printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", - wrqu->ap_addr.sa_data[0], - wrqu->ap_addr.sa_data[1], - wrqu->ap_addr.sa_data[2], - wrqu->ap_addr.sa_data[3], - wrqu->ap_addr.sa_data[4], - wrqu->ap_addr.sa_data[5]); + printk(KERN_DEBUG "Set AP to : %pM\n", wrqu->ap_addr.sa_data); #endif /* DEBUG_IOCTL_INFO */ return -EOPNOTSUPP; @@ -2892,7 +2878,6 @@ wv_packet_read(struct net_device * dev, netif_rx(skb); /* Keep stats up to date */ - dev->last_rx = jiffies; lp->stats.rx_packets++; lp->stats.rx_bytes += sksize; @@ -3647,12 +3632,10 @@ wv_82593_config(struct net_device * dev) int addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count; #ifdef DEBUG_CONFIG_INFO - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n", dev->name, lp->mc_count); for(dmi=dev->mc_list; dmi; dmi=dmi->next) - printk(KERN_DEBUG " %s\n", - print_mac(mac, dmi->dmi_addr)); + printk(KERN_DEBUG " %pM\n", dmi->dmi_addr); #endif /* Initialize adapter's ethernet multicast addresses */ diff --git a/drivers/net/wireless/wl3501.h b/drivers/net/wireless/wl3501.h index 65ceb088f7000c9e06b371605857302d59beeeff..59bb3a55ab48c82838da43c1545d9863560bf572 100644 --- a/drivers/net/wireless/wl3501.h +++ b/drivers/net/wireless/wl3501.h @@ -2,7 +2,7 @@ #define __WL3501_H__ #include -#include +#include /* define for WLA 2.0 */ #define WL3501_BLKSZ 256 @@ -548,7 +548,7 @@ struct wl3501_80211_tx_plcp_hdr { struct wl3501_80211_tx_hdr { struct wl3501_80211_tx_plcp_hdr pclp_hdr; - struct ieee80211_hdr_4addr mac_hdr; + struct ieee80211_hdr mac_hdr; } __attribute__ ((packed)); /* diff --git a/drivers/net/wireless/wl3501_cs.c b/drivers/net/wireless/wl3501_cs.c index 68789c6e1ce9ac96cb180b7c8a6d798719764294..c99a1b6b948fca668dfbf31b82ace895bb005de7 100644 --- a/drivers/net/wireless/wl3501_cs.c +++ b/drivers/net/wireless/wl3501_cs.c @@ -860,10 +860,9 @@ static int wl3501_esbq_confirm(struct wl3501_card *this) static void wl3501_online(struct net_device *dev) { struct wl3501_card *this = netdev_priv(dev); - DECLARE_MAC_BUF(mac); - printk(KERN_INFO "%s: Wireless LAN online. BSSID: %s\n", - dev->name, print_mac(mac, this->bssid)); + printk(KERN_INFO "%s: Wireless LAN online. BSSID: %pM\n", + dev->name, this->bssid); netif_wake_queue(dev); } @@ -1014,7 +1013,6 @@ static inline void wl3501_md_ind_interrupt(struct net_device *dev, wl3501_receive(this, skb->data, pkt_len); skb_put(skb, pkt_len); skb->protocol = eth_type_trans(skb, dev); - dev->last_rx = jiffies; this->stats.rx_packets++; this->stats.rx_bytes += skb->len; netif_rx(skb); @@ -1965,7 +1963,6 @@ static int wl3501_config(struct pcmcia_device *link) struct net_device *dev = link->priv; int i = 0, j, last_fn, last_ret; struct wl3501_card *this; - DECLARE_MAC_BUF(mac); /* Try allocating IO ports. This tries a few fixed addresses. If you * want, you can also read the card's config table to pick addresses -- @@ -2024,9 +2021,9 @@ static int wl3501_config(struct pcmcia_device *link) /* print probe information */ printk(KERN_INFO "%s: wl3501 @ 0x%3.3x, IRQ %d, " - "MAC addr in flash ROM:%s\n", + "MAC addr in flash ROM:%pM\n", dev->name, this->base_addr, (int)dev->irq, - print_mac(mac, dev->dev_addr)); + dev->dev_addr); /* * Initialize card parameters - added by jss */ diff --git a/drivers/net/wireless/zd1201.c b/drivers/net/wireless/zd1201.c index b16ec6e5f0e3913115fe6a40b15ae9a9e0bde4ca..b45c27d42fd83f98ac6a5f3479b0251f40443e7b 100644 --- a/drivers/net/wireless/zd1201.c +++ b/drivers/net/wireless/zd1201.c @@ -17,11 +17,11 @@ #include #include #include +#include #include #include #include #include -#include #include "zd1201.h" static struct usb_device_id zd1201_table[] = { @@ -328,7 +328,6 @@ static void zd1201_usbrx(struct urb *urb) memcpy(skb_put(skb, 2), &data[datalen-24], 2); memcpy(skb_put(skb, len), data, len); skb->protocol = eth_type_trans(skb, zd->dev); - skb->dev->last_rx = jiffies; zd->stats.rx_packets++; zd->stats.rx_bytes += skb->len; netif_rx(skb); @@ -346,7 +345,7 @@ static void zd1201_usbrx(struct urb *urb) frag = kmalloc(sizeof(*frag), GFP_ATOMIC); if (!frag) goto resubmit; - skb = dev_alloc_skb(IEEE80211_DATA_LEN +14+2); + skb = dev_alloc_skb(IEEE80211_MAX_DATA_LEN +14+2); if (!skb) { kfree(frag); goto resubmit; @@ -385,7 +384,6 @@ static void zd1201_usbrx(struct urb *urb) memcpy(skb_put(skb, len), data+8, len); } skb->protocol = eth_type_trans(skb, zd->dev); - skb->dev->last_rx = jiffies; zd->stats.rx_packets++; zd->stats.rx_bytes += skb->len; netif_rx(skb); @@ -745,7 +743,7 @@ static int zd1201_join(struct zd1201 *zd, char *essid, int essidlen) static int zd1201_net_open(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); /* Start MAC with wildcard if no essid set */ if (!zd->mac_enabled) @@ -783,7 +781,7 @@ static int zd1201_net_stop(struct net_device *dev) */ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); unsigned char *txbuf = zd->txdata; int txbuflen, pad = 0, err; struct urb *urb = zd->tx_urb; @@ -833,7 +831,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) static void zd1201_tx_timeout(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); if (!zd) return; @@ -848,7 +846,7 @@ static void zd1201_tx_timeout(struct net_device *dev) static int zd1201_set_mac_address(struct net_device *dev, void *p) { struct sockaddr *addr = p; - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; if (!zd) @@ -865,21 +863,21 @@ static int zd1201_set_mac_address(struct net_device *dev, void *p) static struct net_device_stats *zd1201_get_stats(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); return &zd->stats; } static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); return &zd->iwstats; } static void zd1201_set_multicast(struct net_device *dev) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); struct dev_mc_list *mc = dev->mc_list; unsigned char reqbuf[ETH_ALEN*ZD1201_MAXMULTI]; int i; @@ -899,7 +897,7 @@ static void zd1201_set_multicast(struct net_device *dev) static int zd1201_config_commit(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); return zd1201_mac_reset(zd); } @@ -914,7 +912,7 @@ static int zd1201_get_name(struct net_device *dev, static int zd1201_set_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short channel = 0; int err; @@ -939,7 +937,7 @@ static int zd1201_set_freq(struct net_device *dev, static int zd1201_get_freq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short channel; int err; @@ -955,7 +953,7 @@ static int zd1201_get_freq(struct net_device *dev, static int zd1201_set_mode(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short porttype, monitor = 0; unsigned char buffer[IW_ESSID_MAX_SIZE+2]; int err; @@ -1017,7 +1015,7 @@ static int zd1201_set_mode(struct net_device *dev, static int zd1201_get_mode(struct net_device *dev, struct iw_request_info *info, __u32 *mode, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short porttype; int err; @@ -1093,7 +1091,7 @@ static int zd1201_get_range(struct net_device *dev, static int zd1201_get_wap(struct net_device *dev, struct iw_request_info *info, struct sockaddr *ap_addr, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); unsigned char buffer[6]; if (!zd1201_getconfig(zd, ZD1201_RID_COMMSQUALITY, buffer, 6)) { @@ -1121,7 +1119,7 @@ static int zd1201_set_scan(struct net_device *dev, static int zd1201_get_scan(struct net_device *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err, i, j, enabled_save; struct iw_event iwe; char *cev = extra; @@ -1213,7 +1211,7 @@ static int zd1201_get_scan(struct net_device *dev, static int zd1201_set_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); if (data->length > IW_ESSID_MAX_SIZE) return -EINVAL; @@ -1228,7 +1226,7 @@ static int zd1201_set_essid(struct net_device *dev, static int zd1201_get_essid(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); memcpy(essid, zd->essid, zd->essidlen); data->flags = 1; @@ -1249,7 +1247,7 @@ static int zd1201_get_nick(struct net_device *dev, struct iw_request_info *info, static int zd1201_set_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short rate; int err; @@ -1282,7 +1280,7 @@ static int zd1201_set_rate(struct net_device *dev, static int zd1201_get_rate(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short rate; int err; @@ -1315,7 +1313,7 @@ static int zd1201_get_rate(struct net_device *dev, static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; short val = rts->value; @@ -1335,7 +1333,7 @@ static int zd1201_set_rts(struct net_device *dev, struct iw_request_info *info, static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short rtst; int err; @@ -1352,7 +1350,7 @@ static int zd1201_get_rts(struct net_device *dev, struct iw_request_info *info, static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; short val = frag->value; @@ -1373,7 +1371,7 @@ static int zd1201_set_frag(struct net_device *dev, struct iw_request_info *info, static int zd1201_get_frag(struct net_device *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short fragt; int err; @@ -1402,7 +1400,7 @@ static int zd1201_get_retry(struct net_device *dev, static int zd1201_set_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short i; int err, rid; @@ -1459,7 +1457,7 @@ static int zd1201_set_encode(struct net_device *dev, static int zd1201_get_encode(struct net_device *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short i; int err; @@ -1492,7 +1490,7 @@ static int zd1201_get_encode(struct net_device *dev, static int zd1201_set_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short enabled, duration, level; int err; @@ -1531,7 +1529,7 @@ out: static int zd1201_get_power(struct net_device *dev, struct iw_request_info *info, struct iw_param *vwrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short enabled, level, duration; int err; @@ -1618,7 +1616,7 @@ static const iw_handler zd1201_iw_handler[] = static int zd1201_set_hostauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); if (!zd->ap) return -EOPNOTSUPP; @@ -1629,7 +1627,7 @@ static int zd1201_set_hostauth(struct net_device *dev, static int zd1201_get_hostauth(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short hostauth; int err; @@ -1648,7 +1646,7 @@ static int zd1201_get_hostauth(struct net_device *dev, static int zd1201_auth_sta(struct net_device *dev, struct iw_request_info *info, struct sockaddr *sta, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); unsigned char buffer[10]; if (!zd->ap) @@ -1664,7 +1662,7 @@ static int zd1201_auth_sta(struct net_device *dev, static int zd1201_set_maxassoc(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); int err; if (!zd->ap) @@ -1679,7 +1677,7 @@ static int zd1201_set_maxassoc(struct net_device *dev, static int zd1201_get_maxassoc(struct net_device *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - struct zd1201 *zd = (struct zd1201 *)dev->priv; + struct zd1201 *zd = netdev_priv(dev); short maxassoc; int err; @@ -1731,6 +1729,7 @@ static int zd1201_probe(struct usb_interface *interface, const struct usb_device_id *id) { struct zd1201 *zd; + struct net_device *dev; struct usb_device *usb; int err; short porttype; @@ -1738,9 +1737,12 @@ static int zd1201_probe(struct usb_interface *interface, usb = interface_to_usbdev(interface); - zd = kzalloc(sizeof(struct zd1201), GFP_KERNEL); - if (!zd) + dev = alloc_etherdev(sizeof(*zd)); + if (!dev) return -ENOMEM; + zd = netdev_priv(dev); + zd->dev = dev; + zd->ap = ap; zd->usb = usb; zd->removed = 0; @@ -1775,34 +1777,29 @@ static int zd1201_probe(struct usb_interface *interface, if (err) goto err_start; - zd->dev = alloc_etherdev(0); - if (!zd->dev) - goto err_start; - - zd->dev->priv = zd; - zd->dev->open = zd1201_net_open; - zd->dev->stop = zd1201_net_stop; - zd->dev->get_stats = zd1201_get_stats; - zd->dev->wireless_handlers = + dev->open = zd1201_net_open; + dev->stop = zd1201_net_stop; + dev->get_stats = zd1201_get_stats; + dev->wireless_handlers = (struct iw_handler_def *)&zd1201_iw_handlers; - zd->dev->hard_start_xmit = zd1201_hard_start_xmit; - zd->dev->watchdog_timeo = ZD1201_TX_TIMEOUT; - zd->dev->tx_timeout = zd1201_tx_timeout; - zd->dev->set_multicast_list = zd1201_set_multicast; - zd->dev->set_mac_address = zd1201_set_mac_address; - strcpy(zd->dev->name, "wlan%d"); + dev->hard_start_xmit = zd1201_hard_start_xmit; + dev->watchdog_timeo = ZD1201_TX_TIMEOUT; + dev->tx_timeout = zd1201_tx_timeout; + dev->set_multicast_list = zd1201_set_multicast; + dev->set_mac_address = zd1201_set_mac_address; + strcpy(dev->name, "wlan%d"); err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, - zd->dev->dev_addr, zd->dev->addr_len); + dev->dev_addr, dev->addr_len); if (err) - goto err_net; + goto err_start; /* Set wildcard essid to match zd->essid */ *(__le16 *)buf = cpu_to_le16(0); err = zd1201_setconfig(zd, ZD1201_RID_CNFDESIREDSSID, buf, IW_ESSID_MAX_SIZE+2, 1); if (err) - goto err_net; + goto err_start; if (zd->ap) porttype = ZD1201_PORTTYPE_AP; @@ -1810,30 +1807,28 @@ static int zd1201_probe(struct usb_interface *interface, porttype = ZD1201_PORTTYPE_BSS; err = zd1201_setconfig16(zd, ZD1201_RID_CNFPORTTYPE, porttype); if (err) - goto err_net; + goto err_start; - SET_NETDEV_DEV(zd->dev, &usb->dev); + SET_NETDEV_DEV(dev, &usb->dev); - err = register_netdev(zd->dev); + err = register_netdev(dev); if (err) - goto err_net; + goto err_start; dev_info(&usb->dev, "%s: ZD1201 USB Wireless interface\n", - zd->dev->name); + dev->name); usb_set_intfdata(interface, zd); zd1201_enable(zd); /* zd1201 likes to startup enabled, */ zd1201_disable(zd); /* interfering with all the wifis in range */ return 0; -err_net: - free_netdev(zd->dev); err_start: /* Leave the device in reset state */ zd1201_docmd(zd, ZD1201_CMDCODE_INIT, 0, 0, 0); err_zd: usb_free_urb(zd->tx_urb); usb_free_urb(zd->rx_urb); - kfree(zd); + free_netdev(dev); return err; } @@ -1846,10 +1841,6 @@ static void zd1201_disconnect(struct usb_interface *interface) if (!zd) return; usb_set_intfdata(interface, NULL); - if (zd->dev) { - unregister_netdev(zd->dev); - free_netdev(zd->dev); - } hlist_for_each_entry_safe(frag, node, node2, &zd->fraglist, fnode) { hlist_del_init(&frag->fnode); @@ -1865,7 +1856,11 @@ static void zd1201_disconnect(struct usb_interface *interface) usb_kill_urb(zd->rx_urb); usb_free_urb(zd->rx_urb); } - kfree(zd); + + if (zd->dev) { + unregister_netdev(zd->dev); + free_netdev(zd->dev); + } } #ifdef CONFIG_PM diff --git a/drivers/net/wireless/zd1211rw/zd_chip.c b/drivers/net/wireless/zd1211rw/zd_chip.c index e0ac58b8ff1fafe3e57a042f8e2a2ddfafeacc30..f1519143f8a65e80fca00501be81e5fd456cec73 100644 --- a/drivers/net/wireless/zd1211rw/zd_chip.c +++ b/drivers/net/wireless/zd1211rw/zd_chip.c @@ -378,7 +378,6 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) [0] = { .addr = CR_MAC_ADDR_P1 }, [1] = { .addr = CR_MAC_ADDR_P2 }, }; - DECLARE_MAC_BUF(mac); if (mac_addr) { reqs[0].value = (mac_addr[3] << 24) @@ -387,8 +386,7 @@ int zd_write_mac_addr(struct zd_chip *chip, const u8 *mac_addr) | mac_addr[0]; reqs[1].value = (mac_addr[5] << 8) | mac_addr[4]; - dev_dbg_f(zd_chip_dev(chip), - "mac addr %s\n", print_mac(mac, mac_addr)); + dev_dbg_f(zd_chip_dev(chip), "mac addr %pM\n", mac_addr); } else { dev_dbg_f(zd_chip_dev(chip), "set NULL mac\n"); } diff --git a/drivers/net/wireless/zd1211rw/zd_mac.c b/drivers/net/wireless/zd1211rw/zd_mac.c index cac732f4047f524b3b575a1e86dbee1d7fd68644..9caa96a135866c8c79cbc240d63ebfadc9c5e699 100644 --- a/drivers/net/wireless/zd1211rw/zd_mac.c +++ b/drivers/net/wireless/zd1211rw/zd_mac.c @@ -171,7 +171,7 @@ int zd_mac_init_hw(struct ieee80211_hw *hw) r = zd_reg2alpha2(mac->regdomain, alpha2); if (!r) - regulatory_hint(hw->wiphy, alpha2, NULL); + regulatory_hint(hw->wiphy, alpha2); r = 0; disable_int: @@ -296,15 +296,14 @@ static void zd_op_stop(struct ieee80211_hw *hw) * If no status information has been requested, the skb is freed. */ static void tx_status(struct ieee80211_hw *hw, struct sk_buff *skb, - u32 flags, int ackssi, bool success) + int ackssi, bool success) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - memset(&info->status, 0, sizeof(info->status)); + ieee80211_tx_info_clear_status(info); - if (!success) - info->status.excessive_retries = 1; - info->flags |= flags; + if (success) + info->flags |= IEEE80211_TX_STAT_ACK; info->status.ack_signal = ackssi; ieee80211_tx_status_irqsafe(hw, skb); } @@ -326,7 +325,7 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) if (skb == NULL) return; - tx_status(hw, skb, 0, 0, 0); + tx_status(hw, skb, 0, 0); } /** @@ -342,12 +341,12 @@ void zd_mac_tx_failed(struct ieee80211_hw *hw) void zd_mac_tx_to_dev(struct sk_buff *skb, int error) { struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hw *hw = info->driver_data[0]; + struct ieee80211_hw *hw = info->rate_driver_data[0]; skb_pull(skb, sizeof(struct zd_ctrlset)); if (unlikely(error || (info->flags & IEEE80211_TX_CTL_NO_ACK))) { - tx_status(hw, skb, 0, 0, !error); + tx_status(hw, skb, 0, !error); } else { struct sk_buff_head *q = &zd_hw_mac(hw)->ack_wait_queue; @@ -406,7 +405,8 @@ static int zd_calc_tx_length_us(u8 *service, u8 zd_rate, u16 tx_length) } static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, - struct ieee80211_hdr *header, u32 flags) + struct ieee80211_hdr *header, + struct ieee80211_tx_info *info) { /* * CONTROL TODO: @@ -417,7 +417,7 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, cs->control = 0; /* First fragment */ - if (flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) + if (info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) cs->control |= ZD_CS_NEED_RANDOM_BACKOFF; /* Multicast */ @@ -428,10 +428,10 @@ static void cs_set_control(struct zd_mac *mac, struct zd_ctrlset *cs, if (ieee80211_is_pspoll(header->frame_control)) cs->control |= ZD_CS_PS_POLL_FRAME; - if (flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) cs->control |= ZD_CS_RTS; - if (flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) cs->control |= ZD_CS_SELF_CTS; /* FIXME: Management frame? */ @@ -517,12 +517,12 @@ static int fill_ctrlset(struct zd_mac *mac, txrate = ieee80211_get_tx_rate(mac->hw, info); cs->modulation = txrate->hw_value; - if (info->flags & IEEE80211_TX_CTL_SHORT_PREAMBLE) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) cs->modulation = txrate->hw_value_short; cs->tx_length = cpu_to_le16(frag_len); - cs_set_control(mac, cs, hdr, info->flags); + cs_set_control(mac, cs, hdr, info); packet_length = frag_len + sizeof(struct zd_ctrlset) + 10; ZD_ASSERT(packet_length <= 0xffff); @@ -577,7 +577,7 @@ static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb) if (r) return r; - info->driver_data[0] = hw; + info->rate_driver_data[0] = hw; r = zd_usb_tx(&mac->chip.usb, skb); if (r) @@ -618,7 +618,7 @@ static int filter_ack(struct ieee80211_hw *hw, struct ieee80211_hdr *rx_hdr, if (likely(!memcmp(tx_hdr->addr2, rx_hdr->addr1, ETH_ALEN))) { __skb_unlink(skb, q); - tx_status(hw, skb, IEEE80211_TX_STAT_ACK, stats->signal, 1); + tx_status(hw, skb, stats->signal, 1); goto out; } } @@ -743,9 +743,11 @@ static void zd_op_remove_interface(struct ieee80211_hw *hw, zd_write_mac_addr(&mac->chip, NULL); } -static int zd_op_config(struct ieee80211_hw *hw, struct ieee80211_conf *conf) +static int zd_op_config(struct ieee80211_hw *hw, u32 changed) { struct zd_mac *mac = zd_hw_mac(hw); + struct ieee80211_conf *conf = &hw->conf; + return zd_chip_set_channel(&mac->chip, conf->channel->hw_value); } @@ -852,14 +854,12 @@ static void zd_op_configure_filter(struct ieee80211_hw *hw, if (*new_flags & (FIF_PROMISC_IN_BSS | FIF_ALLMULTI)) { zd_mc_add_all(&hash); } else { - DECLARE_MAC_BUF(macbuf); - zd_mc_clear(&hash); for (i = 0; i < mc_count; i++) { if (!mclist) break; - dev_dbg_f(zd_mac_dev(mac), "mc addr %s\n", - print_mac(macbuf, mclist->dmi_addr)); + dev_dbg_f(zd_mac_dev(mac), "mc addr %pM\n", + mclist->dmi_addr); zd_mc_add_addr(&hash, mclist->dmi_addr); mclist = mclist->next; } diff --git a/drivers/net/wireless/zd1211rw/zd_usb.c b/drivers/net/wireless/zd1211rw/zd_usb.c index a3ccd8c1c716957bd669ec678681bc2fcfe1f806..04c1396669656261d87cf6dbc53a6bc1c4b748ff 100644 --- a/drivers/net/wireless/zd1211rw/zd_usb.c +++ b/drivers/net/wireless/zd1211rw/zd_usb.c @@ -909,7 +909,7 @@ free_urb: * it might be freed by zd_mac_tx_to_dev or mac80211) */ info = IEEE80211_SKB_CB(skb); - usb = &zd_hw_mac(info->driver_data[0])->chip.usb; + usb = &zd_hw_mac(info->rate_driver_data[0])->chip.usb; zd_mac_tx_to_dev(skb, urb->status); free_tx_urb(usb, urb); tx_dec_submitted_urbs(usb); diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c index 6d017adc914ac18c5389fb550b53ed5aa09b3246..761635be9104f155af6978a72a8283ebec2cde9e 100644 --- a/drivers/net/xen-netfront.c +++ b/drivers/net/xen-netfront.c @@ -196,7 +196,7 @@ static void rx_refill_timeout(unsigned long data) { struct net_device *dev = (struct net_device *)data; struct netfront_info *np = netdev_priv(dev); - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); } static int netfront_tx_slot_available(struct netfront_info *np) @@ -328,7 +328,7 @@ static int xennet_open(struct net_device *dev) xennet_alloc_rx_buffers(dev); np->rx.sring->rsp_event = np->rx.rsp_cons + 1; if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); } spin_unlock_bh(&np->rx_lock); @@ -841,7 +841,6 @@ static int handle_incoming_queue(struct net_device *dev, /* Pass it up. */ netif_receive_skb(skb); - dev->last_rx = jiffies; } return packets_dropped; @@ -980,7 +979,7 @@ err: RING_FINAL_CHECK_FOR_RESPONSES(&np->rx, more_to_do); if (!more_to_do) - __netif_rx_complete(dev, napi); + __netif_rx_complete(napi); local_irq_restore(flags); } @@ -1311,7 +1310,7 @@ static irqreturn_t xennet_interrupt(int irq, void *dev_id) xennet_tx_buf_gc(dev); /* Under tx_lock: protects access to rx shared-ring indexes. */ if (RING_HAS_UNCONSUMED_RESPONSES(&np->rx)) - netif_rx_schedule(dev, &np->napi); + netif_rx_schedule(&np->napi); } spin_unlock_irqrestore(&np->tx_lock, flags); diff --git a/drivers/net/xtsonic.c b/drivers/net/xtsonic.c index da42aa06a3babc7982b37f820ebd9172cab0ffd6..03a3f34e90393c43202db9731caac53cd25ed40a 100644 --- a/drivers/net/xtsonic.c +++ b/drivers/net/xtsonic.c @@ -239,8 +239,6 @@ int __init xtsonic_probe(struct platform_device *pdev) struct resource *resmem, *resirq; int err = 0; - DECLARE_MAC_BUF(mac); - if ((resmem = platform_get_resource(pdev, IORESOURCE_MEM, 0)) == NULL) return -ENODEV; @@ -263,8 +261,8 @@ int __init xtsonic_probe(struct platform_device *pdev) if ((err = register_netdev(dev))) goto out1; - printk("%s: SONIC ethernet @%08lx, MAC %s, IRQ %d\n", dev->name, - dev->base_addr, print_mac(mac, dev->dev_addr), dev->irq); + printk("%s: SONIC ethernet @%08lx, MAC %pM, IRQ %d\n", dev->name, + dev->base_addr, dev->dev_addr, dev->irq); return 0; diff --git a/drivers/net/yellowfin.c b/drivers/net/yellowfin.c index 57e1f495b9fc0456db009a9540ec0f7111295b51..cf97129227780ee2f8d2427f687c6e5c1f4128ca 100644 --- a/drivers/net/yellowfin.c +++ b/drivers/net/yellowfin.c @@ -355,6 +355,16 @@ static int yellowfin_close(struct net_device *dev); static void set_rx_mode(struct net_device *dev); static const struct ethtool_ops ethtool_ops; +static const struct net_device_ops netdev_ops = { + .ndo_open = yellowfin_open, + .ndo_stop = yellowfin_close, + .ndo_start_xmit = yellowfin_start_xmit, + .ndo_set_multicast_list = set_rx_mode, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_do_ioctl = netdev_ioctl, + .ndo_tx_timeout = yellowfin_tx_timeout, +}; static int __devinit yellowfin_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -374,7 +384,6 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, #else int bar = 1; #endif - DECLARE_MAC_BUF(mac); /* when built into the kernel, we only print version if device is found */ #ifndef MODULE @@ -465,13 +474,8 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, np->duplex_lock = 1; /* The Yellowfin-specific entries in the device structure. */ - dev->open = &yellowfin_open; - dev->hard_start_xmit = &yellowfin_start_xmit; - dev->stop = &yellowfin_close; - dev->set_multicast_list = &set_rx_mode; - dev->do_ioctl = &netdev_ioctl; + dev->netdev_ops = &netdev_ops; SET_ETHTOOL_OPS(dev, ðtool_ops); - dev->tx_timeout = yellowfin_tx_timeout; dev->watchdog_timeo = TX_TIMEOUT; if (mtu) @@ -481,10 +485,10 @@ static int __devinit yellowfin_init_one(struct pci_dev *pdev, if (i) goto err_out_unmap_status; - printk(KERN_INFO "%s: %s type %8x at %p, %s, IRQ %d.\n", + printk(KERN_INFO "%s: %s type %8x at %p, %pM, IRQ %d.\n", dev->name, pci_id_tbl[chip_idx].name, ioread32(ioaddr + ChipRev), ioaddr, - print_mac(mac, dev->dev_addr), irq); + dev->dev_addr, irq); if (np->drv_flags & HasMII) { int phy, phy_idx = 0; @@ -1100,11 +1104,9 @@ static int yellowfin_rx(struct net_device *dev) memcmp(le32_to_cpu(yp->rx_ring_dma + entry*sizeof(struct yellowfin_desc)), "\377\377\377\377\377\377", 6) != 0) { - if (bogus_rx++ == 0) { - DECLARE_MAC_BUF(mac); - printk(KERN_WARNING "%s: Bad frame to %s\n", - dev->name, print_mac(mac, buf_addr)); - } + if (bogus_rx++ == 0) + printk(KERN_WARNING "%s: Bad frame to %pM\n", + dev->name, buf_addr); #endif } else { struct sk_buff *skb; @@ -1141,7 +1143,6 @@ static int yellowfin_rx(struct net_device *dev) } skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -1423,14 +1424,3 @@ static void __exit yellowfin_cleanup (void) module_init(yellowfin_init); module_exit(yellowfin_cleanup); - -/* - * Local variables: - * compile-command: "gcc -DMODULE -Wall -Wstrict-prototypes -O6 -c yellowfin.c" - * compile-command-alphaLX: "gcc -DMODULE -Wall -Wstrict-prototypes -O2 -c yellowfin.c -fomit-frame-pointer -fno-strength-reduce -mno-fp-regs -Wa,-m21164a -DBWX_USABLE -DBWIO_ENABLED" - * simple-compile-command: "gcc -DMODULE -O6 -c yellowfin.c" - * c-indent-level: 4 - * c-basic-offset: 4 - * tab-width: 4 - * End: - */ diff --git a/drivers/net/znet.c b/drivers/net/znet.c index a86c022d6a9494e4f96822095b06366d7531054b..f0b15c9347d0dae517497544ef629b9e0f8d80c1 100644 --- a/drivers/net/znet.c +++ b/drivers/net/znet.c @@ -167,7 +167,7 @@ static void znet_tx_timeout (struct net_device *dev); /* Request needed resources */ static int znet_request_resources (struct net_device *dev) { - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); unsigned long flags; if (request_irq (dev->irq, &znet_interrupt, 0, "ZNet", dev)) @@ -201,7 +201,7 @@ static int znet_request_resources (struct net_device *dev) static void znet_release_resources (struct net_device *dev) { - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); unsigned long flags; release_region (znet->sia_base, znet->sia_size); @@ -216,7 +216,7 @@ static void znet_release_resources (struct net_device *dev) /* Keep the magical SIA stuff in a single function... */ static void znet_transceiver_power (struct net_device *dev, int on) { - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); unsigned char v; /* Turn on/off the 82501 SIA, using zenith-specific magic. */ @@ -235,7 +235,7 @@ static void znet_transceiver_power (struct net_device *dev, int on) Also used from hardware_init. */ static void znet_set_multicast_list (struct net_device *dev) { - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); short ioaddr = dev->base_addr; struct i82593_conf_block *cfblk = &znet->i593_init; @@ -370,7 +370,6 @@ static int __init znet_probe (void) struct net_device *dev; char *p; int err = -ENOMEM; - DECLARE_MAC_BUF(mac); /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ for(p = (char *)phys_to_virt(0xf0000); p < (char *)phys_to_virt(0x100000); p++) @@ -387,7 +386,7 @@ static int __init znet_probe (void) if (!dev) return -ENOMEM; - znet = dev->priv; + znet = netdev_priv(dev); netinfo = (struct netidblk *)p; dev->base_addr = netinfo->iobase1; @@ -397,9 +396,9 @@ static int __init znet_probe (void) for (i = 0; i < 6; i++) dev->dev_addr[i] = netinfo->netid[i]; - printk(KERN_INFO "%s: ZNET at %#3lx, %s" + printk(KERN_INFO "%s: ZNET at %#3lx, %pM" ", using IRQ %d DMA %d and %d.\n", - dev->name, dev->base_addr, print_mac(mac, dev->dev_addr), + dev->name, dev->base_addr, dev->dev_addr, dev->irq, netinfo->dma1, netinfo->dma2); if (znet_debug > 1) { @@ -531,7 +530,7 @@ static void znet_tx_timeout (struct net_device *dev) static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) { int ioaddr = dev->base_addr; - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); unsigned long flags; short length = skb->len; @@ -601,7 +600,7 @@ static int znet_send_packet(struct sk_buff *skb, struct net_device *dev) static irqreturn_t znet_interrupt(int irq, void *dev_id) { struct net_device *dev = dev_id; - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); int ioaddr; int boguscnt = 20; int handled = 0; @@ -679,7 +678,7 @@ static irqreturn_t znet_interrupt(int irq, void *dev_id) static void znet_rx(struct net_device *dev) { - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); int ioaddr = dev->base_addr; int boguscount = 1; short next_frame_end_offset = 0; /* Offset of next frame start. */ @@ -786,7 +785,6 @@ static void znet_rx(struct net_device *dev) } skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); - dev->last_rx = jiffies; dev->stats.rx_packets++; dev->stats.rx_bytes += pkt_len; } @@ -829,7 +827,7 @@ static void show_dma(struct net_device *dev) { short ioaddr = dev->base_addr; unsigned char stat = inb (ioaddr); - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); unsigned long flags; short dma_port = ((znet->tx_dma&3)<<2) + IO_DMA2_BASE; unsigned addr = inb(dma_port); @@ -852,7 +850,7 @@ static void hardware_init(struct net_device *dev) { unsigned long flags; short ioaddr = dev->base_addr; - struct znet_private *znet = dev->priv; + struct znet_private *znet = netdev_priv(dev); znet->rx_cur = znet->rx_start; znet->tx_cur = znet->tx_start; @@ -914,7 +912,7 @@ static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset) static __exit void znet_cleanup (void) { if (znet_dev) { - struct znet_private *znet = znet_dev->priv; + struct znet_private *znet = netdev_priv(znet_dev); unregister_netdev (znet_dev); kfree (znet->rx_start); diff --git a/drivers/net/zorro8390.c b/drivers/net/zorro8390.c index 3926b2aa9cca4c7aaa761fbc486e65d727bf762b..affd904deafc6c885f3a4e5c0908561ffa654f23 100644 --- a/drivers/net/zorro8390.c +++ b/drivers/net/zorro8390.c @@ -122,7 +122,7 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, break; board = z->resource.start; ioaddr = board+cards[i].offset; - dev = ____alloc_ei_netdev(0); + dev = alloc_ei_netdev(); if (!dev) return -ENOMEM; if (!request_mem_region(ioaddr, NE_IO_EXTENT*2, DRV_NAME)) { @@ -139,6 +139,20 @@ static int __devinit zorro8390_init_one(struct zorro_dev *z, return 0; } +static const struct net_device_ops zorro8390_netdev_ops = { + .ndo_open = zorro8390_open, + .ndo_stop = zorro8390_close, + .ndo_start_xmit = ei_start_xmit, + .ndo_tx_timeout = ei_tx_timeout, + .ndo_get_stats = ei_get_stats, + .ndo_set_multicast_list = ei_set_multicast_list, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = ei_poll, +#endif +}; + static int __devinit zorro8390_init(struct net_device *dev, unsigned long board, const char *name, unsigned long ioaddr) @@ -151,7 +165,6 @@ static int __devinit zorro8390_init(struct net_device *dev, 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e, }; - DECLARE_MAC_BUF(mac); /* Reset card. Who knows what dain-bramaged state it was left in. */ { @@ -216,7 +229,7 @@ static int __devinit zorro8390_init(struct net_device *dev, dev->dev_addr[i] = SA_prom[i]; #ifdef DEBUG - printk("%s", print_mac(mac, dev->dev_addr)); + printk("%pM", dev->dev_addr); #endif ei_status.name = name; @@ -231,12 +244,8 @@ static int __devinit zorro8390_init(struct net_device *dev, ei_status.block_output = &zorro8390_block_output; ei_status.get_8390_hdr = &zorro8390_get_8390_hdr; ei_status.reg_offset = zorro8390_offsets; - dev->open = &zorro8390_open; - dev->stop = &zorro8390_close; -#ifdef CONFIG_NET_POLL_CONTROLLER - dev->poll_controller = __ei_poll; -#endif + dev->netdev_ops = &zorro8390_netdev_ops; __NS8390_init(dev, 0); err = register_netdev(dev); if (err) { @@ -244,8 +253,8 @@ static int __devinit zorro8390_init(struct net_device *dev, return err; } - printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address %s\n", - dev->name, name, board, print_mac(mac, dev->dev_addr)); + printk(KERN_INFO "%s: %s at 0x%08lx, Ethernet Address %pM\n", + dev->name, name, board, dev->dev_addr); return 0; } diff --git a/drivers/parisc/led.c b/drivers/parisc/led.c index f9b12664f9fb90c24e07ce2cc6f49cd8769a81cd..454b6532e40998cce76aa3eeb7ed8fdaa901748a 100644 --- a/drivers/parisc/led.c +++ b/drivers/parisc/led.c @@ -360,13 +360,13 @@ static __inline__ int led_get_net_activity(void) read_lock(&dev_base_lock); rcu_read_lock(); for_each_netdev(&init_net, dev) { - struct net_device_stats *stats; + const struct net_device_stats *stats; struct in_device *in_dev = __in_dev_get_rcu(dev); if (!in_dev || !in_dev->ifa_list) continue; if (ipv4_is_loopback(in_dev->ifa_list->ifa_local)) continue; - stats = dev->get_stats(dev); + stats = dev_get_stats(dev); rx_total += stats->rx_packets; tx_total += stats->tx_packets; } diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c index fb6c70cec253f078393749af069aa506c4a5ad94..acca6678cb2bb721c6a433c311fd099779e0dc6d 100644 --- a/drivers/s390/net/lcs.c +++ b/drivers/s390/net/lcs.c @@ -1295,7 +1295,7 @@ lcs_set_multicast_list(struct net_device *dev) struct lcs_card *card; LCS_DBF_TEXT(4, trace, "setmulti"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; if (!lcs_set_thread_start_bit(card, LCS_SET_MC_THREAD)) schedule_work(&card->kernel_thread_starter); @@ -1617,7 +1617,7 @@ lcs_start_xmit(struct sk_buff *skb, struct net_device *dev) int rc; LCS_DBF_TEXT(5, trace, "pktxmit"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; rc = __lcs_start_xmit(card, skb, dev); return rc; } @@ -1874,7 +1874,7 @@ lcs_getstats(struct net_device *dev) struct lcs_card *card; LCS_DBF_TEXT(4, trace, "netstats"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; return &card->stats; } @@ -1889,7 +1889,7 @@ lcs_stop_device(struct net_device *dev) int rc; LCS_DBF_TEXT(2, trace, "stopdev"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; netif_carrier_off(dev); netif_tx_disable(dev); dev->flags &= ~IFF_UP; @@ -1913,7 +1913,7 @@ lcs_open_device(struct net_device *dev) int rc; LCS_DBF_TEXT(2, trace, "opendev"); - card = (struct lcs_card *) dev->priv; + card = (struct lcs_card *) dev->ml_priv; /* initialize statistics */ rc = lcs_detect(card); if (rc) { @@ -2163,7 +2163,7 @@ lcs_new_device(struct ccwgroup_device *ccwgdev) if (!dev) goto out; card->dev = dev; - card->dev->priv = card; + card->dev->ml_priv = card; card->dev->open = lcs_open_device; card->dev->stop = lcs_stop_device; card->dev->hard_start_xmit = lcs_start_xmit; diff --git a/drivers/s390/net/qeth_core_offl.c b/drivers/s390/net/qeth_core_offl.c index 452874e897400fbf340c57bfdd46ab30b0dbd173..4080126ca48c916352e8a44e94932b6586528cc7 100644 --- a/drivers/s390/net/qeth_core_offl.c +++ b/drivers/s390/net/qeth_core_offl.c @@ -350,7 +350,7 @@ static __wsum qeth_eddp_check_tcp4_hdr(struct qeth_eddp_data *eddp, phcsum = csum_tcpudp_nofold(eddp->nh.ip4.h.saddr, eddp->nh.ip4.h.daddr, eddp->thl + data_len, IPPROTO_TCP, 0); /* compute checksum of tcp header */ - return csum_partial((u8 *)&eddp->th, eddp->thl, phcsum); + return csum_partial(&eddp->th, eddp->thl, phcsum); } static __wsum qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, @@ -362,12 +362,12 @@ static __wsum qeth_eddp_check_tcp6_hdr(struct qeth_eddp_data *eddp, QETH_DBF_TEXT(TRACE, 5, "eddpckt6"); eddp->th.tcp.h.check = 0; /* compute pseudo header checksum */ - phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.saddr, + phcsum = csum_partial(&eddp->nh.ip6.h.saddr, sizeof(struct in6_addr), 0); - phcsum = csum_partial((u8 *)&eddp->nh.ip6.h.daddr, + phcsum = csum_partial(&eddp->nh.ip6.h.daddr, sizeof(struct in6_addr), phcsum); proto = htonl(IPPROTO_TCP); - phcsum = csum_partial((u8 *)&proto, sizeof(u32), phcsum); + phcsum = csum_partial(&proto, sizeof(u32), phcsum); return phcsum; } diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c index af15bc648ba178d1699f28261a6a2ed48cfd2e80..2c48591ced444530448b01c1881109da4acc34d5 100644 --- a/drivers/s390/net/qeth_l2_main.c +++ b/drivers/s390/net/qeth_l2_main.c @@ -134,17 +134,13 @@ static int qeth_l2_send_setgroupmac_cb(struct qeth_card *card, mac = &cmd->data.setdelmac.mac[0]; /* MAC already registered, needed in couple/uncouple case */ if (cmd->hdr.return_code == 0x2005) { - QETH_DBF_MESSAGE(2, "Group MAC %02x:%02x:%02x:%02x:%02x:%02x " - "already existing on %s \n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - QETH_CARD_IFNAME(card)); + QETH_DBF_MESSAGE(2, "Group MAC %pM already existing on %s \n", + mac, QETH_CARD_IFNAME(card)); cmd->hdr.return_code = 0; } if (cmd->hdr.return_code) - QETH_DBF_MESSAGE(2, "Could not set group MAC " - "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - QETH_CARD_IFNAME(card), cmd->hdr.return_code); + QETH_DBF_MESSAGE(2, "Could not set group MAC %pM on %s: %x\n", + mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code); return 0; } @@ -166,10 +162,8 @@ static int qeth_l2_send_delgroupmac_cb(struct qeth_card *card, cmd = (struct qeth_ipa_cmd *) data; mac = &cmd->data.setdelmac.mac[0]; if (cmd->hdr.return_code) - QETH_DBF_MESSAGE(2, "Could not delete group MAC " - "%02x:%02x:%02x:%02x:%02x:%02x on %s: %x\n", - mac[0], mac[1], mac[2], mac[3], mac[4], mac[5], - QETH_CARD_IFNAME(card), cmd->hdr.return_code); + QETH_DBF_MESSAGE(2, "Could not delete group MAC %pM on %s: %x\n", + mac, QETH_CARD_IFNAME(card), cmd->hdr.return_code); return 0; } diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c index ed6c54cae7b14a132c19241859470559c4a6b7aa..e11bce6ab63c7bd5290883d517f556979cedaf2a 100644 --- a/drivers/scsi/iscsi_tcp.c +++ b/drivers/scsi/iscsi_tcp.c @@ -1601,14 +1601,14 @@ static int iscsi_tcp_get_addr(struct iscsi_conn *conn, struct socket *sock, case AF_INET: sin = (struct sockaddr_in *)addr; spin_lock_bh(&conn->session->lock); - sprintf(buf, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr)); + sprintf(buf, "%pI4", &sin->sin_addr.s_addr); *port = be16_to_cpu(sin->sin_port); spin_unlock_bh(&conn->session->lock); break; case AF_INET6: sin6 = (struct sockaddr_in6 *)addr; spin_lock_bh(&conn->session->lock); - sprintf(buf, NIP6_FMT, NIP6(sin6->sin6_addr)); + sprintf(buf, "%pI6", &sin6->sin6_addr); *port = be16_to_cpu(sin6->sin6_port); spin_unlock_bh(&conn->session->lock); break; diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c index db7ea3bb4e833afb50884b92c74f1b98c4b5d6ec..eb3a414b189a111f8110385440c0911300085210 100644 --- a/drivers/scsi/qla4xxx/ql4_os.c +++ b/drivers/scsi/qla4xxx/ql4_os.c @@ -206,8 +206,7 @@ static int qla4xxx_conn_get_param(struct iscsi_cls_conn *conn, break; case ISCSI_PARAM_CONN_ADDRESS: /* TODO: what are the ipv6 bits */ - len = sprintf(buf, "%u.%u.%u.%u\n", - NIPQUAD(ddb_entry->ip_addr)); + len = sprintf(buf, "%pI4\n", &ddb_entry->ip_addr); break; default: return -ENOSYS; diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 0ffabf5c0b60dd9892b5b9c45e2a1d8881129108..65a1ed951a1daa80abe1c9ac2b091af8664b38ad 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c @@ -226,7 +226,7 @@ int ssb_devices_freeze(struct ssb_bus *bus) err = drv->suspend(dev, state); if (err) { ssb_printk(KERN_ERR PFX "Failed to freeze device %s\n", - dev->dev->bus_id); + dev_name(dev->dev)); goto err_unwind; } } @@ -269,7 +269,7 @@ int ssb_devices_thaw(struct ssb_bus *bus) err = drv->resume(dev); if (err) { ssb_printk(KERN_ERR PFX "Failed to thaw device %s\n", - dev->dev->bus_id); + dev_name(dev->dev)); } } @@ -454,8 +454,7 @@ static int ssb_devices_register(struct ssb_bus *bus) dev->release = ssb_release_dev; dev->bus = &ssb_bustype; - snprintf(dev->bus_id, sizeof(dev->bus_id), - "ssb%u:%d", bus->busnumber, dev_idx); + dev_set_name(dev, "ssb%u:%d", bus->busnumber, dev_idx); switch (bus->bustype) { case SSB_BUSTYPE_PCI: @@ -480,7 +479,7 @@ static int ssb_devices_register(struct ssb_bus *bus) if (err) { ssb_printk(KERN_ERR PFX "Could not register %s\n", - dev->bus_id); + dev_name(dev)); /* Set dev to NULL to not unregister * dev on error unwinding. */ sdev->dev = NULL; @@ -796,7 +795,7 @@ int ssb_bus_pcibus_register(struct ssb_bus *bus, err = ssb_bus_register(bus, ssb_pci_get_invariants, 0); if (!err) { ssb_printk(KERN_INFO PFX "Sonics Silicon Backplane found on " - "PCI device %s\n", host_pci->dev.bus_id); + "PCI device %s\n", dev_name(&host_pci->dev)); } return err; diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c index e82db4aaa050ad5902f04de679c04b0bc6261013..26737a010c6d03080f345955ecfa97c30cc8fa27 100644 --- a/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c @@ -65,7 +65,7 @@ static int ssb_pcihost_probe(struct pci_dev *dev, err = pci_enable_device(dev); if (err) goto err_kfree_ssb; - name = dev->dev.bus_id; + name = dev_name(&dev->dev); if (dev->driver && dev->driver->name) name = dev->driver->name; err = pci_request_regions(dev, name); diff --git a/drivers/staging/slicoss/slicoss.c b/drivers/staging/slicoss/slicoss.c index 8fa9490b3e2ca707320e3ccafc28d21089a07b26..00390362f10ff9c8f71981bc4eb267881f573380 100644 --- a/drivers/staging/slicoss/slicoss.c +++ b/drivers/staging/slicoss/slicoss.c @@ -765,8 +765,7 @@ static int slic_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) #ifdef SLIC_USER_REQUEST_DUMP_ENABLED case SIOCSLICDUMPCARD: { - struct adapter *adapter = (struct adapter *) - dev->priv; + struct adapter *adapter = netdev_priv(dev); struct sliccard *card; ASSERT(adapter); @@ -1685,7 +1684,7 @@ static void slic_timer_ping(ulong dev) struct sliccard *card; ASSERT(dev); - adapter = (struct adapter *)((struct net_device *) dev)->priv; + adapter = netdev_priv((struct net_device *)dev); ASSERT(adapter); card = adapter->card; ASSERT(card); @@ -3136,7 +3135,7 @@ static void slic_timer_get_stats(ulong dev) struct slic_shmem *pshmem; ASSERT(dev); - adapter = (struct adapter *)((struct net_device *)dev)->priv; + adapter = netdev_priv((struct net_device *)dev); ASSERT(adapter); card = adapter->card; ASSERT(card); diff --git a/drivers/staging/winbond/linux/wbusb.c b/drivers/staging/winbond/linux/wbusb.c index f4a7875f2389673d146c7d840be4383156eb6a9c..39ca9b9878f8111765b7936e9a045f72c3694720 100644 --- a/drivers/staging/winbond/linux/wbusb.c +++ b/drivers/staging/winbond/linux/wbusb.c @@ -336,7 +336,11 @@ WbUsb_destroy(phw_data_t pHwData) int wb35_open(struct net_device *netdev) { - PADAPTER Adapter = (PADAPTER)netdev->priv; + /* netdev_priv() or netdev->ml_priv should reference to the address of + * private data(PADAPTER). It depends on whether private data memory is + * allocated when alloc_netdev(). + */ + PADAPTER Adapter = (PADAPTER)netdev_priv(netdev); phw_data_t pHwData = &Adapter->sHwData; netif_start_queue(netdev); diff --git a/drivers/staging/wlan-ng/p80211netdev.c b/drivers/staging/wlan-ng/p80211netdev.c index 11f84a829e14a4d4595259c6184963b0a0e00cd7..2b705eaa50e8d40d3c545bf882a6e75369a39306 100644 --- a/drivers/staging/wlan-ng/p80211netdev.c +++ b/drivers/staging/wlan-ng/p80211netdev.c @@ -244,7 +244,7 @@ static int p80211knetdev_init( netdevice_t *netdev) static struct net_device_stats* p80211knetdev_get_stats(netdevice_t *netdev) { - wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; + wlandevice_t *wlandev = netdev->ml_priv; DBFENTER; /* TODO: review the MIB stats for items that correspond to @@ -272,7 +272,7 @@ p80211knetdev_get_stats(netdevice_t *netdev) static int p80211knetdev_open( netdevice_t *netdev ) { int result = 0; /* success */ - wlandevice_t *wlandev = (wlandevice_t*)(netdev->priv); + wlandevice_t *wlandev = netdev->ml_priv; DBFENTER; @@ -315,7 +315,7 @@ static int p80211knetdev_open( netdevice_t *netdev ) static int p80211knetdev_stop( netdevice_t *netdev ) { int result = 0; - wlandevice_t *wlandev = (wlandevice_t*)(netdev->priv); + wlandevice_t *wlandev = netdev->ml_priv; DBFENTER; @@ -460,7 +460,7 @@ static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netd { int result = 0; int txresult = -1; - wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; + wlandevice_t *wlandev = netdev->ml_priv; p80211_hdr_t p80211_hdr; p80211_metawep_t p80211_wep; @@ -603,7 +603,7 @@ static int p80211knetdev_hard_start_xmit( struct sk_buff *skb, netdevice_t *netd ----------------------------------------------------------------*/ static void p80211knetdev_set_multicast_list(netdevice_t *dev) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; DBFENTER; @@ -696,7 +696,7 @@ static int p80211knetdev_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) { int result = 0; p80211ioctl_req_t *req = (p80211ioctl_req_t*)ifr; - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; UINT8 *msgbuf; DBFENTER; @@ -812,7 +812,7 @@ static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) dot11req.msgcode = DIDmsg_dot11req_mibset; dot11req.msglen = sizeof(p80211msg_dot11req_mibset_t); memcpy(dot11req.devname, - ((wlandevice_t*)(dev->priv))->name, + ((wlandevice_t *)dev->ml_priv)->name, WLAN_DEVNAMELEN_MAX - 1); /* Set up the mibattribute argument */ @@ -833,7 +833,7 @@ static int p80211knetdev_set_mac_address(netdevice_t *dev, void *addr) resultcode->data = 0; /* now fire the request */ - result = p80211req_dorequest(dev->priv, (UINT8*)&dot11req); + result = p80211req_dorequest(dev->ml_priv, (UINT8 *)&dot11req); /* If the request wasn't successful, report an error and don't * change the netdev address @@ -917,7 +917,7 @@ int wlan_setup(wlandevice_t *wlandev) memset( dev, 0, sizeof(netdevice_t)); ether_setup(dev); wlandev->netdev = dev; - dev->priv = wlandev; + dev->ml_priv = wlandev; dev->hard_start_xmit = p80211knetdev_hard_start_xmit; dev->get_stats = p80211knetdev_get_stats; #ifdef HAVE_PRIVATE_IOCTL @@ -1487,7 +1487,7 @@ void p80211_resume(wlandevice_t *wlandev) static void p80211knetdev_tx_timeout( netdevice_t *netdev) { - wlandevice_t *wlandev = (wlandevice_t*)netdev->priv; + wlandevice_t *wlandev = netdev->ml_priv; DBFENTER; if (wlandev->tx_timeout) { diff --git a/drivers/staging/wlan-ng/p80211wext.c b/drivers/staging/wlan-ng/p80211wext.c index 906ba439237669b0150f12fb0f57cd42afd36ea4..b2c9ea25fa425a3558bff9ab5b1c96da01de841c 100644 --- a/drivers/staging/wlan-ng/p80211wext.c +++ b/drivers/staging/wlan-ng/p80211wext.c @@ -218,7 +218,7 @@ exit: struct iw_statistics* p80211wext_get_wireless_stats (netdevice_t *dev) { p80211msg_lnxreq_commsquality_t quality; - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct iw_statistics* wstats = &wlandev->wstats; int retval; @@ -301,7 +301,7 @@ static int p80211wext_giwfreq(netdevice_t *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -339,7 +339,7 @@ static int p80211wext_siwfreq(netdevice_t *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -380,7 +380,7 @@ static int p80211wext_giwmode(netdevice_t *dev, struct iw_request_info *info, __u32 *mode, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; DBFENTER; @@ -407,7 +407,7 @@ static int p80211wext_siwmode(netdevice_t *dev, struct iw_request_info *info, __u32 *mode, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -550,7 +550,7 @@ static int p80211wext_giwap(netdevice_t *dev, struct sockaddr *ap_addr, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; DBFENTER; @@ -566,7 +566,7 @@ static int p80211wext_giwencode(netdevice_t *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; int err = 0; int i; @@ -607,7 +607,7 @@ static int p80211wext_siwencode(netdevice_t *dev, struct iw_request_info *info, struct iw_point *erq, char *key) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211msg_dot11req_mibset_t msg; p80211item_pstr32_t pstr; @@ -736,7 +736,7 @@ static int p80211wext_giwessid(netdevice_t *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; DBFENTER; @@ -762,7 +762,7 @@ static int p80211wext_siwessid(netdevice_t *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211msg_lnxreq_autojoin_t msg; int result; @@ -816,7 +816,7 @@ static int p80211wext_siwcommit(netdevice_t *dev, struct iw_request_info *info, struct iw_point *data, char *essid) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; int err = 0; DBFENTER; @@ -839,7 +839,7 @@ static int p80211wext_giwrate(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -893,7 +893,7 @@ static int p80211wext_giwrts(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -927,7 +927,7 @@ static int p80211wext_siwrts(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rts, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -964,7 +964,7 @@ static int p80211wext_giwfrag(netdevice_t *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -997,7 +997,7 @@ static int p80211wext_siwfrag(netdevice_t *dev, struct iw_request_info *info, struct iw_param *frag, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -1047,7 +1047,7 @@ static int p80211wext_giwretry(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -1126,7 +1126,7 @@ static int p80211wext_siwretry(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -1198,7 +1198,7 @@ static int p80211wext_siwtxpow(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -1243,7 +1243,7 @@ static int p80211wext_giwtxpow(netdevice_t *dev, struct iw_request_info *info, struct iw_param *rrq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211item_uint32_t mibitem; p80211msg_dot11req_mibset_t msg; int result; @@ -1281,7 +1281,7 @@ static int p80211wext_siwspy(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct sockaddr address[IW_MAX_SPY]; int number = srq->length; int i; @@ -1317,7 +1317,7 @@ static int p80211wext_giwspy(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct sockaddr address[IW_MAX_SPY]; struct iw_quality spy_stat[IW_MAX_SPY]; @@ -1378,7 +1378,7 @@ static int p80211wext_siwscan(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211msg_dot11req_scan_t msg; int result; int err = 0; @@ -1501,7 +1501,7 @@ static int p80211wext_giwscan(netdevice_t *dev, struct iw_request_info *info, struct iw_point *srq, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; p80211msg_dot11req_scan_results_t msg; int result = 0; int err = 0; @@ -1551,7 +1551,7 @@ static int p80211wext_set_encodeext(struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; p80211msg_dot11req_mibset_t msg; p80211item_pstr32_t *pstr; @@ -1627,7 +1627,7 @@ static int p80211wext_get_encodeext(struct net_device *dev, union iwreq_data *wrqu, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; struct iw_point *encoding = &wrqu->encoding; @@ -1682,7 +1682,7 @@ static int p80211_wext_set_iwauth (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct iw_param *param = &wrqu->param; int result =0; @@ -1734,7 +1734,7 @@ static int p80211_wext_get_iwauth (struct net_device *dev, struct iw_request_info *info, union iwreq_data *wrqu, char *extra) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; struct iw_param *param = &wrqu->param; int result =0; @@ -1868,7 +1868,7 @@ struct iw_handler_def p80211wext_handler_def = { /* wireless extensions' ioctls */ int p80211wext_support_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd) { - wlandevice_t *wlandev = (wlandevice_t*)dev->priv; + wlandevice_t *wlandev = dev->ml_priv; #if WIRELESS_EXT < 13 struct iwreq *iwr = (struct iwreq*)ifr; diff --git a/drivers/usb/atm/cxacru.c b/drivers/usb/atm/cxacru.c index 9aea43a8c4adce959b3aafcc1b171f807b2fc1a7..5ed4ae07bac108cd5f3f3999676c7031e6d5f2a5 100644 --- a/drivers/usb/atm/cxacru.c +++ b/drivers/usb/atm/cxacru.c @@ -286,9 +286,7 @@ static ssize_t cxacru_sysfs_show_mac_address(struct device *dev, struct usbatm_data *usbatm_instance = usb_get_intfdata(intf); struct atm_dev *atm_dev = usbatm_instance->atm_dev; - return snprintf(buf, PAGE_SIZE, "%02x:%02x:%02x:%02x:%02x:%02x\n", - atm_dev->esi[0], atm_dev->esi[1], atm_dev->esi[2], - atm_dev->esi[3], atm_dev->esi[4], atm_dev->esi[5]); + return snprintf(buf, PAGE_SIZE, "%pM\n", atm_dev->esi); } static ssize_t cxacru_sysfs_show_adsl_state(struct device *dev, diff --git a/drivers/usb/atm/usbatm.c b/drivers/usb/atm/usbatm.c index 06dd114910d45ac4cda3a080c375459329cada0d..fbea8563df1ede695f0ccf7b5dc8d367c6f623dc 100644 --- a/drivers/usb/atm/usbatm.c +++ b/drivers/usb/atm/usbatm.c @@ -770,10 +770,7 @@ static int usbatm_atm_proc_read(struct atm_dev *atm_dev, loff_t * pos, char *pag return sprintf(page, "%s\n", instance->description); if (!left--) - return sprintf(page, "MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", - atm_dev->esi[0], atm_dev->esi[1], - atm_dev->esi[2], atm_dev->esi[3], - atm_dev->esi[4], atm_dev->esi[5]); + return sprintf(page, "MAC: %pM\n", atm_dev->esi); if (!left--) return sprintf(page, diff --git a/drivers/usb/gadget/f_phonet.c b/drivers/usb/gadget/f_phonet.c new file mode 100644 index 0000000000000000000000000000000000000000..d8fc9b32fe3682c52b9ad060fa3862a6ab557143 --- /dev/null +++ b/drivers/usb/gadget/f_phonet.c @@ -0,0 +1,621 @@ +/* + * f_phonet.c -- USB CDC Phonet function + * + * Copyright (C) 2007-2008 Nokia Corporation. All rights reserved. + * + * Author: Rémi Denis-Courmont + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include "u_phonet.h" + +#define PN_MEDIA_USB 0x1B + +/*-------------------------------------------------------------------------*/ + +struct phonet_port { + struct f_phonet *usb; + spinlock_t lock; +}; + +struct f_phonet { + struct usb_function function; + struct net_device *dev; + struct usb_ep *in_ep, *out_ep; + + struct usb_request *in_req; + struct usb_request *out_reqv[0]; +}; + +static int phonet_rxq_size = 2; + +static inline struct f_phonet *func_to_pn(struct usb_function *f) +{ + return container_of(f, struct f_phonet, function); +} + +/*-------------------------------------------------------------------------*/ + +#define USB_CDC_SUBCLASS_PHONET 0xfe +#define USB_CDC_PHONET_TYPE 0xab + +static struct usb_interface_descriptor +pn_control_intf_desc = { + .bLength = sizeof pn_control_intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + + /* .bInterfaceNumber = DYNAMIC, */ + .bInterfaceClass = USB_CLASS_COMM, + .bInterfaceSubClass = USB_CDC_SUBCLASS_PHONET, +}; + +static const struct usb_cdc_header_desc +pn_header_desc = { + .bLength = sizeof pn_header_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_HEADER_TYPE, + .bcdCDC = __constant_cpu_to_le16(0x0110), +}; + +static const struct usb_cdc_header_desc +pn_phonet_desc = { + .bLength = sizeof pn_phonet_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_PHONET_TYPE, + .bcdCDC = __constant_cpu_to_le16(0x1505), /* ??? */ +}; + +static struct usb_cdc_union_desc +pn_union_desc = { + .bLength = sizeof pn_union_desc, + .bDescriptorType = USB_DT_CS_INTERFACE, + .bDescriptorSubType = USB_CDC_UNION_TYPE, + + /* .bMasterInterface0 = DYNAMIC, */ + /* .bSlaveInterface0 = DYNAMIC, */ +}; + +static struct usb_interface_descriptor +pn_data_nop_intf_desc = { + .bLength = sizeof pn_data_nop_intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + + /* .bInterfaceNumber = DYNAMIC, */ + .bAlternateSetting = 0, + .bNumEndpoints = 0, + .bInterfaceClass = USB_CLASS_CDC_DATA, +}; + +static struct usb_interface_descriptor +pn_data_intf_desc = { + .bLength = sizeof pn_data_intf_desc, + .bDescriptorType = USB_DT_INTERFACE, + + /* .bInterfaceNumber = DYNAMIC, */ + .bAlternateSetting = 1, + .bNumEndpoints = 2, + .bInterfaceClass = USB_CLASS_CDC_DATA, +}; + +static struct usb_endpoint_descriptor +pn_fs_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_endpoint_descriptor +pn_hs_sink_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_OUT, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), +}; + +static struct usb_endpoint_descriptor +pn_fs_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, +}; + +static struct usb_endpoint_descriptor +pn_hs_source_desc = { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + + .bEndpointAddress = USB_DIR_IN, + .bmAttributes = USB_ENDPOINT_XFER_BULK, + .wMaxPacketSize = __constant_cpu_to_le16(512), +}; + +static struct usb_descriptor_header *fs_pn_function[] = { + (struct usb_descriptor_header *) &pn_control_intf_desc, + (struct usb_descriptor_header *) &pn_header_desc, + (struct usb_descriptor_header *) &pn_phonet_desc, + (struct usb_descriptor_header *) &pn_union_desc, + (struct usb_descriptor_header *) &pn_data_nop_intf_desc, + (struct usb_descriptor_header *) &pn_data_intf_desc, + (struct usb_descriptor_header *) &pn_fs_sink_desc, + (struct usb_descriptor_header *) &pn_fs_source_desc, + NULL, +}; + +static struct usb_descriptor_header *hs_pn_function[] = { + (struct usb_descriptor_header *) &pn_control_intf_desc, + (struct usb_descriptor_header *) &pn_header_desc, + (struct usb_descriptor_header *) &pn_phonet_desc, + (struct usb_descriptor_header *) &pn_union_desc, + (struct usb_descriptor_header *) &pn_data_nop_intf_desc, + (struct usb_descriptor_header *) &pn_data_intf_desc, + (struct usb_descriptor_header *) &pn_hs_sink_desc, + (struct usb_descriptor_header *) &pn_hs_source_desc, + NULL, +}; + +/*-------------------------------------------------------------------------*/ + +static int pn_net_open(struct net_device *dev) +{ + if (netif_carrier_ok(dev)) + netif_wake_queue(dev); + return 0; +} + +static int pn_net_close(struct net_device *dev) +{ + netif_stop_queue(dev); + return 0; +} + +static void pn_tx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_phonet *fp = ep->driver_data; + struct net_device *dev = fp->dev; + struct sk_buff *skb = req->context; + + switch (req->status) { + case 0: + dev->stats.tx_packets++; + dev->stats.tx_bytes += skb->len; + break; + + case -ESHUTDOWN: /* disconnected */ + case -ECONNRESET: /* disabled */ + dev->stats.tx_aborted_errors++; + default: + dev->stats.tx_errors++; + } + + dev_kfree_skb_any(skb); + if (netif_carrier_ok(dev)) + netif_wake_queue(dev); +} + +static int pn_net_xmit(struct sk_buff *skb, struct net_device *dev) +{ + struct phonet_port *port = netdev_priv(dev); + struct f_phonet *fp; + struct usb_request *req; + unsigned long flags; + + if (skb->protocol != htons(ETH_P_PHONET)) + goto out; + + spin_lock_irqsave(&port->lock, flags); + fp = port->usb; + if (unlikely(!fp)) /* race with carrier loss */ + goto out_unlock; + + req = fp->in_req; + req->buf = skb->data; + req->length = skb->len; + req->complete = pn_tx_complete; + req->zero = 1; + req->context = skb; + + if (unlikely(usb_ep_queue(fp->in_ep, req, GFP_ATOMIC))) + goto out_unlock; + + netif_stop_queue(dev); + skb = NULL; + +out_unlock: + spin_unlock_irqrestore(&port->lock, flags); +out: + if (unlikely(skb)) { + dev_kfree_skb_any(skb); + dev->stats.tx_dropped++; + } + return 0; +} + +static int pn_net_mtu(struct net_device *dev, int new_mtu) +{ + struct phonet_port *port = netdev_priv(dev); + unsigned long flags; + int err = -EBUSY; + + if ((new_mtu < PHONET_MIN_MTU) || (new_mtu > PHONET_MAX_MTU)) + return -EINVAL; + + spin_lock_irqsave(&port->lock, flags); + if (!netif_carrier_ok(dev)) { + dev->mtu = new_mtu; + err = 0; + } + spin_unlock_irqrestore(&port->lock, flags); + return err; +} + +static void pn_net_setup(struct net_device *dev) +{ + dev->features = 0; + dev->type = ARPHRD_PHONET; + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + dev->mtu = PHONET_DEV_MTU; + dev->hard_header_len = 1; + dev->dev_addr[0] = PN_MEDIA_USB; + dev->addr_len = 1; + dev->tx_queue_len = 1; + + dev->destructor = free_netdev; + dev->header_ops = &phonet_header_ops; + dev->open = pn_net_open; + dev->stop = pn_net_close; + dev->hard_start_xmit = pn_net_xmit; /* mandatory */ + dev->change_mtu = pn_net_mtu; +} + +/*-------------------------------------------------------------------------*/ + +/* + * Queue buffer for data from the host + */ +static int +pn_rx_submit(struct f_phonet *fp, struct usb_request *req, gfp_t gfp_flags) +{ + struct sk_buff *skb; + const size_t size = fp->dev->mtu; + int err; + + skb = alloc_skb(size, gfp_flags); + if (!skb) + return -ENOMEM; + + req->buf = skb->data; + req->length = size; + req->context = skb; + + err = usb_ep_queue(fp->out_ep, req, gfp_flags); + if (unlikely(err)) + dev_kfree_skb_any(skb); + return err; +} + +static void pn_rx_complete(struct usb_ep *ep, struct usb_request *req) +{ + struct f_phonet *fp = ep->driver_data; + struct net_device *dev = fp->dev; + struct sk_buff *skb = req->context; + int status = req->status; + + switch (status) { + case 0: + if (unlikely(!netif_running(dev))) + break; + if (unlikely(req->actual < 1)) + break; + skb_put(skb, req->actual); + skb->protocol = htons(ETH_P_PHONET); + skb_reset_mac_header(skb); + __skb_pull(skb, 1); + skb->dev = dev; + dev->stats.rx_packets++; + dev->stats.rx_bytes += skb->len; + + netif_rx(skb); + skb = NULL; + break; + + /* Do not resubmit in these cases: */ + case -ESHUTDOWN: /* disconnect */ + case -ECONNABORTED: /* hw reset */ + case -ECONNRESET: /* dequeued (unlink or netif down) */ + req = NULL; + break; + + /* Do resubmit in these cases: */ + case -EOVERFLOW: /* request buffer overflow */ + dev->stats.rx_over_errors++; + default: + dev->stats.rx_errors++; + break; + } + + if (skb) + dev_kfree_skb_any(skb); + if (req) + pn_rx_submit(fp, req, GFP_ATOMIC); +} + +/*-------------------------------------------------------------------------*/ + +static void __pn_reset(struct usb_function *f) +{ + struct f_phonet *fp = func_to_pn(f); + struct net_device *dev = fp->dev; + struct phonet_port *port = netdev_priv(dev); + + netif_carrier_off(dev); + netif_stop_queue(dev); + port->usb = NULL; + + usb_ep_disable(fp->out_ep); + usb_ep_disable(fp->in_ep); +} + +static int pn_set_alt(struct usb_function *f, unsigned intf, unsigned alt) +{ + struct f_phonet *fp = func_to_pn(f); + struct usb_gadget *gadget = fp->function.config->cdev->gadget; + + if (intf == pn_control_intf_desc.bInterfaceNumber) + /* control interface, no altsetting */ + return (alt > 0) ? -EINVAL : 0; + + if (intf == pn_data_intf_desc.bInterfaceNumber) { + struct net_device *dev = fp->dev; + struct phonet_port *port = netdev_priv(dev); + + /* data intf (0: inactive, 1: active) */ + if (alt > 1) + return -EINVAL; + + spin_lock(&port->lock); + __pn_reset(f); + if (alt == 1) { + struct usb_endpoint_descriptor *out, *in; + int i; + + out = ep_choose(gadget, + &pn_hs_sink_desc, + &pn_fs_sink_desc); + in = ep_choose(gadget, + &pn_hs_source_desc, + &pn_fs_source_desc); + usb_ep_enable(fp->out_ep, out); + usb_ep_enable(fp->in_ep, in); + + port->usb = fp; + fp->out_ep->driver_data = fp; + fp->in_ep->driver_data = fp; + + netif_carrier_on(dev); + if (netif_running(dev)) + netif_wake_queue(dev); + for (i = 0; i < phonet_rxq_size; i++) + pn_rx_submit(fp, fp->out_reqv[i], GFP_ATOMIC); + } + spin_unlock(&port->lock); + return 0; + } + + return -EINVAL; +} + +static int pn_get_alt(struct usb_function *f, unsigned intf) +{ + struct f_phonet *fp = func_to_pn(f); + + if (intf == pn_control_intf_desc.bInterfaceNumber) + return 0; + + if (intf == pn_data_intf_desc.bInterfaceNumber) { + struct phonet_port *port = netdev_priv(fp->dev); + u8 alt; + + spin_lock(&port->lock); + alt = port->usb != NULL; + spin_unlock(&port->lock); + return alt; + } + + return -EINVAL; +} + +static void pn_disconnect(struct usb_function *f) +{ + struct f_phonet *fp = func_to_pn(f); + struct phonet_port *port = netdev_priv(fp->dev); + unsigned long flags; + + /* remain disabled until set_alt */ + spin_lock_irqsave(&port->lock, flags); + __pn_reset(f); + spin_unlock_irqrestore(&port->lock, flags); +} + +/*-------------------------------------------------------------------------*/ + +static __init +int pn_bind(struct usb_configuration *c, struct usb_function *f) +{ + struct usb_composite_dev *cdev = c->cdev; + struct usb_gadget *gadget = cdev->gadget; + struct f_phonet *fp = func_to_pn(f); + struct usb_ep *ep; + int status, i; + + /* Reserve interface IDs */ + status = usb_interface_id(c, f); + if (status < 0) + goto err; + pn_control_intf_desc.bInterfaceNumber = status; + pn_union_desc.bMasterInterface0 = status; + + status = usb_interface_id(c, f); + if (status < 0) + goto err; + pn_data_nop_intf_desc.bInterfaceNumber = status; + pn_data_intf_desc.bInterfaceNumber = status; + pn_union_desc.bSlaveInterface0 = status; + + /* Reserve endpoints */ + status = -ENODEV; + ep = usb_ep_autoconfig(gadget, &pn_fs_sink_desc); + if (!ep) + goto err; + fp->out_ep = ep; + ep->driver_data = fp; /* Claim */ + + ep = usb_ep_autoconfig(gadget, &pn_fs_source_desc); + if (!ep) + goto err; + fp->in_ep = ep; + ep->driver_data = fp; /* Claim */ + + pn_hs_sink_desc.bEndpointAddress = + pn_fs_sink_desc.bEndpointAddress; + pn_hs_source_desc.bEndpointAddress = + pn_fs_source_desc.bEndpointAddress; + + /* Do not try to bind Phonet twice... */ + fp->function.descriptors = fs_pn_function; + fp->function.hs_descriptors = hs_pn_function; + + /* Incoming USB requests */ + status = -ENOMEM; + for (i = 0; i < phonet_rxq_size; i++) { + struct usb_request *req; + + req = usb_ep_alloc_request(fp->out_ep, GFP_KERNEL); + if (!req) + goto err; + + req->complete = pn_rx_complete; + fp->out_reqv[i] = req; + } + + /* Outgoing USB requests */ + fp->in_req = usb_ep_alloc_request(fp->in_ep, GFP_KERNEL); + if (!fp->in_req) + goto err; + + INFO(cdev, "USB CDC Phonet function\n"); + INFO(cdev, "using %s, OUT %s, IN %s\n", cdev->gadget->name, + fp->out_ep->name, fp->in_ep->name); + return 0; + +err: + if (fp->out_ep) + fp->out_ep->driver_data = NULL; + if (fp->in_ep) + fp->in_ep->driver_data = NULL; + ERROR(cdev, "USB CDC Phonet: cannot autoconfigure\n"); + return status; +} + +static void +pn_unbind(struct usb_configuration *c, struct usb_function *f) +{ + struct f_phonet *fp = func_to_pn(f); + int i; + + /* We are already disconnected */ + if (fp->in_req) + usb_ep_free_request(fp->in_ep, fp->in_req); + for (i = 0; i < phonet_rxq_size; i++) + if (fp->out_reqv[i]) + usb_ep_free_request(fp->out_ep, fp->out_reqv[i]); + + kfree(fp); +} + +/*-------------------------------------------------------------------------*/ + +static struct net_device *dev; + +int __init phonet_bind_config(struct usb_configuration *c) +{ + struct f_phonet *fp; + int err; + + fp = kzalloc(sizeof(*fp), GFP_KERNEL); + if (!fp) + return -ENOMEM; + + fp->dev = dev; + fp->function.name = "phonet"; + fp->function.bind = pn_bind; + fp->function.unbind = pn_unbind; + fp->function.set_alt = pn_set_alt; + fp->function.get_alt = pn_get_alt; + fp->function.disable = pn_disconnect; + + err = usb_add_function(c, &fp->function); + if (err) + kfree(fp); + return err; +} + +int __init gphonet_setup(struct usb_gadget *gadget) +{ + struct phonet_port *port; + int err; + + /* Create net device */ + BUG_ON(dev); + dev = alloc_netdev(sizeof(*port) + + (phonet_rxq_size * sizeof(struct usb_request *)), + "upnlink%d", pn_net_setup); + if (!dev) + return -ENOMEM; + + port = netdev_priv(dev); + spin_lock_init(&port->lock); + netif_carrier_off(dev); + netif_stop_queue(dev); + SET_NETDEV_DEV(dev, &gadget->dev); + + err = register_netdev(dev); + if (err) + free_netdev(dev); + return err; +} + +void gphonet_cleanup(void) +{ + unregister_netdev(dev); +} diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c index 66948b72bb9b06e5c73345322b800af69a9618db..d9739d52f8f55ad6f2106037c1805b3aadc41ab4 100644 --- a/drivers/usb/gadget/u_ether.c +++ b/drivers/usb/gadget/u_ether.c @@ -146,7 +146,7 @@ static inline int qlen(struct usb_gadget *gadget) /* NETWORK DRIVER HOOKUP (to the layer above this driver) */ -static int eth_change_mtu(struct net_device *net, int new_mtu) +static int ueth_change_mtu(struct net_device *net, int new_mtu) { struct eth_dev *dev = netdev_priv(net); unsigned long flags; @@ -764,7 +764,7 @@ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) if (ethaddr) memcpy(ethaddr, dev->host_mac, ETH_ALEN); - net->change_mtu = eth_change_mtu; + net->change_mtu = ueth_change_mtu; net->hard_start_xmit = eth_start_xmit; net->open = eth_open; net->stop = eth_stop; @@ -787,10 +787,8 @@ int __init gether_setup(struct usb_gadget *g, u8 ethaddr[ETH_ALEN]) dev_dbg(&g->dev, "register_netdev failed, %d\n", status); free_netdev(net); } else { - DECLARE_MAC_BUF(tmp); - - INFO(dev, "MAC %s\n", print_mac(tmp, net->dev_addr)); - INFO(dev, "HOST MAC %s\n", print_mac(tmp, dev->host_mac)); + INFO(dev, "MAC %pM\n", net->dev_addr); + INFO(dev, "HOST MAC %pM\n", dev->host_mac); the_dev = dev; } diff --git a/drivers/usb/gadget/u_phonet.h b/drivers/usb/gadget/u_phonet.h new file mode 100644 index 0000000000000000000000000000000000000000..09a75259b6cd4f790bb62954f34880bb180050be --- /dev/null +++ b/drivers/usb/gadget/u_phonet.h @@ -0,0 +1,21 @@ +/* + * u_phonet.h - interface to Phonet + * + * Copyright (C) 2007-2008 by Nokia Corporation + * + * This software is distributed under the terms of the GNU General + * Public License ("GPL") as published by the Free Software Foundation, + * either version 2 of that License or (at your option) any later version. + */ + +#ifndef __U_PHONET_H +#define __U_PHONET_H + +#include +#include + +int gphonet_setup(struct usb_gadget *gadget); +int phonet_bind_config(struct usb_configuration *c); +void gphonet_cleanup(void); + +#endif /* __U_PHONET_H */ diff --git a/drivers/uwb/wlp/eda.c b/drivers/uwb/wlp/eda.c index cdfe8dfc4340a7317272737ca5c254602ff9d27f..10985fa233ccfc038e66abc5e5fad9cbe8362e4e 100644 --- a/drivers/uwb/wlp/eda.c +++ b/drivers/uwb/wlp/eda.c @@ -313,12 +313,9 @@ int wlp_eda_for_virtual(struct wlp_eda *eda, list_for_each_entry(itr, &eda->cache, list_node) { if (!memcmp(itr->virt_addr, virt_addr, sizeof(itr->virt_addr))) { - d_printf(6, dev, "EDA: looking for " - "%02x:%02x:%02x:%02x:%02x:%02x hit %02x:%02x " + d_printf(6, dev, "EDA: looking for %pM hit %02x:%02x " "wss %p tag 0x%02x state %u\n", - virt_addr[0], virt_addr[1], - virt_addr[2], virt_addr[3], - virt_addr[4], virt_addr[5], + virt_addr, itr->dev_addr.data[1], itr->dev_addr.data[0], itr->wss, itr->tag, itr->state); @@ -327,24 +324,13 @@ int wlp_eda_for_virtual(struct wlp_eda *eda, found = 1; break; } else - d_printf(6, dev, "EDA: looking for " - "%02x:%02x:%02x:%02x:%02x:%02x " - "against " - "%02x:%02x:%02x:%02x:%02x:%02x miss\n", - virt_addr[0], virt_addr[1], - virt_addr[2], virt_addr[3], - virt_addr[4], virt_addr[5], - itr->virt_addr[0], itr->virt_addr[1], - itr->virt_addr[2], itr->virt_addr[3], - itr->virt_addr[4], itr->virt_addr[5]); + d_printf(6, dev, "EDA: looking for %pM against %pM miss\n", + virt_addr, itr->virt_addr); } if (!found) { if (printk_ratelimit()) - dev_err(dev, "EDA: Eth addr %02x:%02x:%02x" - ":%02x:%02x:%02x not found.\n", - virt_addr[0], virt_addr[1], - virt_addr[2], virt_addr[3], - virt_addr[4], virt_addr[5]); + dev_err(dev, "EDA: Eth addr %pM not found.\n", + virt_addr); result = -ENODEV; } spin_unlock_irqrestore(&eda->lock, flags); @@ -380,19 +366,13 @@ ssize_t wlp_eda_show(struct wlp *wlp, char *buf) "tag state virt_addr\n"); list_for_each_entry(entry, &eda->cache, list_node) { result += scnprintf(buf + result, PAGE_SIZE - result, - "%02x:%02x:%02x:%02x:%02x:%02x %02x:%02x " - "%p 0x%02x %s " - "%02x:%02x:%02x:%02x:%02x:%02x\n", - entry->eth_addr[0], entry->eth_addr[1], - entry->eth_addr[2], entry->eth_addr[3], - entry->eth_addr[4], entry->eth_addr[5], + "%pM %02x:%02x %p 0x%02x %s %pM\n", + entry->eth_addr, entry->dev_addr.data[1], entry->dev_addr.data[0], entry->wss, entry->tag, wlp_wss_connect_state_str(entry->state), - entry->virt_addr[0], entry->virt_addr[1], - entry->virt_addr[2], entry->virt_addr[3], - entry->virt_addr[4], entry->virt_addr[5]); + entry->virt_addr); if (result >= PAGE_SIZE) break; } diff --git a/firmware/Makefile b/firmware/Makefile index ca8cd305ff934be128ac7bdacef662c947812989..4993a4b3d8ab5d68c2277f8eb580740deee85b50 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -24,6 +24,9 @@ fw-shipped-$(CONFIG_ATARI_DSP56K) += dsp56k/bootstrap.bin fw-shipped-$(CONFIG_ATM_AMBASSADOR) += atmsar11.fw fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin +fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \ + cxgb3/t3c_psram-1.1.0.bin \ + cxgb3/t3fw-7.0.0.bin fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin fw-shipped-$(CONFIG_SMCTR) += tr_smctr.bin fw-shipped-$(CONFIG_SND_KORG1212) += korg/k1212.dsp diff --git a/firmware/WHENCE b/firmware/WHENCE index 57002cdecd42dae9d6d2bdd5b7f94e438a63b756..8f06639ba3e76923deae1255d65402016452ef31 100644 --- a/firmware/WHENCE +++ b/firmware/WHENCE @@ -349,3 +349,14 @@ Licence: Unknown Found in hex form in kernel source. -------------------------------------------------------------------------- + +Driver: cxgb3 - Chelsio Terminator 3 1G/10G Ethernet adapter + +File: cxgb3/t3b_psram-1.1.0.bin.ihex +File: cxgb3/t3c_psram-1.1.0.bin.ihex +file: cxgb3/t3fw-7.0.0.bin.ihex + +License: GPLv2 or OpenIB.org BSD license, no source visible + +-------------------------------------------------------------------------- + diff --git a/firmware/cxgb3/t3b_psram-1.1.0.bin.ihex b/firmware/cxgb3/t3b_psram-1.1.0.bin.ihex new file mode 100644 index 0000000000000000000000000000000000000000..140893005171120eb7a59c30882b54121993a021 --- /dev/null +++ b/firmware/cxgb3/t3b_psram-1.1.0.bin.ihex @@ -0,0 +1,162 @@ +:10000000FFFFFFFC000000000000000300000000F4 +:1000100000010100FFFFFFFC0000000000000003E2 +:100020000000000000000000FFFFFFFC00000000D7 +:10003000000000030000000000000000FFFFFFFCC4 +:1000400000000000000000030000000000000000AD +:10005000FFFFFFFC000000000000000300000000A4 +:1000600000000000FFFFFFFC000000000000000394 +:100070000000000000000000FFFFFFFC0000000087 +:10008000000000030000000000000000FFFFFFFC74 +:10009000000000000000000300000000000000005D +:1000A000FFFFFFFC00000000000000030000000054 +:1000B00000000000FFFFFFFC000000000000000344 +:1000C0000000000000000000FFFFFFFC0000000037 +:1000D000000000030000000000000000FFFFFFFC24 +:1000E000000000000000000300000000000000000D +:1000F000FFFFFFFC00000000000000030000000004 +:1001000000000000FFFFFFFC0000000000000003F3 +:100110000000000000000000FFFFFFFBD03403E6FA +:1001200080262A430000000000000000FFFFFFF8C7 +:10013000007000000000000200000081C604000002 +:10014000FFFFFFFC000000000000000300000000B3 +:1001500000000000FFFFFFFC0000000000000003A3 +:100160000000000000000000FFFFFFFC0000000096 +:10017000000000030000000000000000FFFFFFFC83 +:10018000000000000000000300000000000000006C +:10019000FFFFFFFC00000000000000030000000063 +:1001A00000000000FFFFFFFC000000000000000353 +:1001B0000000000000000000FFFFFFFBD03403E25E +:1001C000802829230000000000000000FFFFFFF846 +:1001D0000600023701C5C00013940481C6057000F3 +:1001E000FFFFFFF88200020637030803000000004B +:1001F00000000000FFFFFFFC000000000000000204 +:10020000208000818DF40000FFFFFFFC0000000053 +:10021000000000030000000000000000FFFFFFFCE2 +:1002200000000000000000030000000000000000CB +:10023000FFFFFFFC000000000000000300000000C2 +:1002400000000000FFFFFFFC0000000000000003B2 +:100250000000000000000000FFFFFFF9C4310000B3 +:1002600000282C830000000000000000FFFFFFF0CA +:100270004E70021D00C5C00000000001C118000042 +:10028000FFFFFFFC00000000000000030000000072 +:1002900000000000FFFFFFFC000000000000000362 +:1002A0000000000000000000FFFFFFFC0000000055 +:1002B000000000030000000000000000FFFFFFFC42 +:1002C000000000000000000300000000000000002B +:1002D000FFFFFFFC00000000000000030000000022 +:1002E00000000000FFFFFFFC000000000000000312 +:1002F0000000000000000000FFFFFFF1C00003E667 +:10030000802828230000000000000000FFFFFFFC01 +:1003100000000000000000021394040000017000BF +:10032000FFFFFFFC000000000000000300000000D1 +:1003300000000000FFFFFFFC0000000000000003C1 +:100340000000000000000000FFFFFFFC00000000B4 +:10035000000000030000000000000000FFFFFFFCA1 +:10036000000000000000000300000000000000008A +:10037000FFFFFFFC00000000000000030000000081 +:1003800000000000FFFFFFFC000000000000000371 +:100390000000000000000000FFFFFFFA103400041E +:1003A000000001030000000000000000FFFFFFF05C +:1003B0006000000620030802700000F080259A907B +:1003C000FFFFFFFC00000000000000030000000031 +:1003D00000000000FFFFFFFC000000000000000321 +:1003E0000000000000000000FFFFFFFC0000000014 +:1003F000000000030000000000000000FFFFFFFC01 +:1004000000000000000000030000000000000000E9 +:10041000FFFFFFF1C83102060A000242000000811E +:1004200080000000FFFFFFF9C83103C60A962A4288 +:100430000000008180000000FFFFFFF00431000495 +:10044000000004030000000000000000FFFFFFF0B8 +:1004500020B000000000000213940401C1197000D4 +:10046000FFFFFFFC00000000000000000000000192 +:1004700000001000FFFFFFFC000000000000000370 +:100480000000000000000000FFFFFFFC0000000073 +:10049000000000030000000000000000FFFFFFFC60 +:1004A0000000000000000003000000000000000049 +:1004B000FFFFFFF00000000400004000680C200176 +:1004C00000001090FFFFFFF9C031C3E600266A402C +:1004D0000000000100001000FFFFFFFA10F4000010 +:1004E000000002430000000000000000FFFFFFF8D2 +:1004F0006050080000000000700C20F080259A90E9 +:10050000FFFFFFF0060000000100400000000001B6 +:1005100000001000FFFFFFFC0000000000000002D0 +:10052000288C108085C01000FFFFFFFC0000000039 +:10053000000000030000000000000000FFFFFFFCBF +:1005400000000000000000030000000000000000A8 +:10055000FFFFFFFC0000000000000003000000009F +:1005600000000000FFFFFFFC00000000000000038F +:100570000000000000000000FFFFFFF04E00000040 +:10058000000000030000000000000000FFFFFFF17A +:10059000C00002DE00061A40000000829035C00054 +:1005A000FFFFFFFC0000000000000003000000004F +:1005B00000000000FFFFFFFC00000000000000033F +:1005C0000000000000000000FFFFFFFC0000000032 +:1005D000000000030000000000000000FFFFFFFC1F +:1005E0000000000000000003000000000000000008 +:1005F000FFFFFFFC000000000000000300000000FF +:1006000000000000FFFFFFF1CA31C3C20A966A432F +:100610000000000000000000FFFFFFF84E501439FA +:100620001CC5C0030000000000000000FFFFFFF039 +:100630000000000000000002288C108085C010001F +:10064000FFFFFFFC000000000000000300000000AE +:1006500000000000FFFFFFFC00000000000000039E +:100660000000000000000000FFFFFFFC0000000091 +:10067000000000030000000000000000FFFFFFFC7E +:100680000000000000000003000000000000000067 +:10069000FFFFFFFC0000000000000003000000005E +:1006A00000000000FFFFFFF3CA3323D60E966A4313 +:1006B0000000000000000000FFFFFFF8000004063B +:1006C00020D002430000000000000000FFFFFFF800 +:1006D00000D0000000000000000000839031C00046 +:1006E000FFFFFFFC0000000000000003000000000E +:1006F00000000000FFFFFFFC0000000000000003FE +:100700000000000000000000FFFFFFFC00000000F0 +:10071000000000030000000000000000FFFFFFFCDD +:1007200000000000000000030000000000000000C6 +:10073000FFFFFFFC000000000000000300000000BD +:1007400000000000FFFFFFF3CA33E3D60E966A43B2 +:100750000000000000000000FFFFFFF000501A1032 +:10076000003002430000000000000000FFFFFFF81F +:100770000000020620030800700000F990118A9022 +:10078000FFFFFFFC0000000000000003000000006D +:1007900000000000FFFFFFFC00000000000000035D +:1007A0000000000000000000FFFFFFFC0000000050 +:1007B000000000030000000000000000FFFFFFFC3D +:1007C0000000000000000003000000000000000026 +:1007D000FFFFFFFC0000000000000003000000001D +:1007E00000000000FFFFFFFC00000000000000030D +:1007F0000000000000000000FFFFFFF9C0501BA632 +:1008000000D202430000000000000000FFFFFFF0E4 +:100810004000020700100002700000E890344A9087 +:10082000FFFFFFFC000000000000000300000000CC +:1008300000000000FFFFFFFC0000000000000003BC +:100840000000000000000000FFFFFFFC00000000AF +:10085000000000030000000000000000FFFFFFFC9C +:100860000000000000000003000000000000000085 +:10087000FFFFFFFC0000000000000003000000007C +:1008800000000000FFFFFFFC00000000000000036C +:100890000000000000000000FFFFFFFA10F4020853 +:1008A00000C002430000000000000000FFFFFFF056 +:1008B0000000000000000000728CC8D893891090DE +:1008C000FFFFFFF082900000030000030000000023 +:1008D00000000000FFFFFFFC00000000000000031C +:1008E0000000000000000000FFFFFFFC000000000F +:1008F000000000030000000000000000FFFFFFFCFC +:1009000000000000000000030000000000000000E4 +:10091000FFFFFFFC000000000000000300000000DB +:1009200000000000FFFFFFFC0000000000000003CB +:100930000000000000000000FFFFFFF000000000CA +:10094000000000030000000000000000FFFFFFF2B5 +:1009500000000320002612430000000000000000F9 +:10096000FFFFFFF040000203101000030000000032 +:1009700000000000FFFFFFFC00000000000000037B +:100980000000000000000000FFFFFFFC000000006E +:10099000000000030000000000000000FFFFFFFC5B +:1009A0000000000000000003000000000000000044 +:1009B000FFFFFFFC0000000000000003000000003B +:1009C00000000000FFFFFFFC00000000000000032B +:1009D0000000000000000000FFFFFFF1D03403E63C +:1009E00080262A430000000000000000FFFFFFF205 +:1009F0000834023000C005030000000000000000C1 +:040A000070EAA57F74 +:00000001FF diff --git a/firmware/cxgb3/t3c_psram-1.1.0.bin.ihex b/firmware/cxgb3/t3c_psram-1.1.0.bin.ihex new file mode 100644 index 0000000000000000000000000000000000000000..c6504803852ff824429ee21632e1733f6e8b27f7 --- /dev/null +++ b/firmware/cxgb3/t3c_psram-1.1.0.bin.ihex @@ -0,0 +1,162 @@ +:10000000FFFFFFF4000000040000000100000001F9 +:1000100000010100FFFFFFF40000000400000001E8 +:100020000000000100000000FFFFFFF400000004DA +:10003000000000010000000100000000FFFFFFF4CD +:1000400000000004000000010000000100000000AA +:10005000FFFFFFF4000000040000000100000001A9 +:1000600000000000FFFFFFF400000004000000019A +:100070000000000100000000FFFFFFF4000000048A +:10008000000000010000000100000000FFFFFFF47D +:10009000000000040000000100000001000000005A +:1000A000FFFFFFF400000004000000010000000159 +:1000B00000000000FFFFFFF400000004000000014A +:1000C0000000000100000000FFFFFFF4000000043A +:1000D000000000010000000100000000FFFFFFF42D +:1000E000000000040000000100000001000000000A +:1000F000FFFFFFF400000004000000010000000109 +:1001000000000000FFFFFFF40000000400000001F9 +:100110000000000100000000FFFFFFF3D03403E205 +:1001200080262A410000000100000000FFFFFFF8C8 +:10013000007000000000000000000080C604000005 +:10014000FFFFFFF4000000040000000100000001B8 +:1001500000000000FFFFFFF40000000400000001A9 +:100160000000000100000000FFFFFFF40000000499 +:10017000000000010000000100000000FFFFFFF48C +:100180000000000400000001000000010000000069 +:10019000FFFFFFF400000004000000010000000168 +:1001A00000000000FFFFFFF4000000040000000159 +:1001B0000000000100000000FFFFFFFBD03403E25D +:1001C000802829210000000100000000FFFFFFF847 +:1001D0000600023701C5C00213940480C6057000F2 +:1001E000FFFFFFF88200020637030801000000014C +:1001F00000000000FFFFFFF400000004000000000A +:10020000208000808DF40000FFFFFFF40000000458 +:10021000000000010000000100000000FFFFFFF4EB +:1002200000000004000000010000000100000000C8 +:10023000FFFFFFF4000000040000000100000001C7 +:1002400000000000FFFFFFF40000000400000001B8 +:100250000000000100000000FFFFFFF9C4310000B2 +:1002600000282C810000000100000000FFFFFFF0CB +:100270004E70021D00C5C00200000000C118000041 +:10028000FFFFFFF400000004000000010000000177 +:1002900000000000FFFFFFF4000000040000000168 +:1002A0000000000100000000FFFFFFF40000000458 +:1002B000000000010000000100000000FFFFFFF44B +:1002C0000000000400000001000000010000000028 +:1002D000FFFFFFF400000004000000010000000127 +:1002E00000000000FFFFFFF4000000040000000118 +:1002F0000000000100000000FFFFFFF1C00003E666 +:10030000802828210000000100000000FFFFFFF40A +:1003100000000004000000021394040000017000BB +:10032000FFFFFFF4000000040000000100000001D6 +:1003300000000000FFFFFFF40000000400000001C7 +:100340000000000100000000FFFFFFF400000004B7 +:10035000000000010000000100000000FFFFFFF4AA +:100360000000000400000001000000010000000087 +:10037000FFFFFFF400000004000000010000000186 +:1003800000000000FFFFFFF4000000040000000177 +:100390000000000100000000FFFFFFFA103400041D +:1003A000000001010000000100000000FFFFFFF05D +:1003B0006000000620030802700000F080259A907B +:1003C000FFFFFFF400000004000000010000000136 +:1003D00000000000FFFFFFF4000000040000000127 +:1003E0000000000100000000FFFFFFF40000000417 +:1003F000000000010000000100000000FFFFFFF40A +:1004000000000004000000010000000100000000E6 +:10041000FFFFFFF9C83102020A000242000000811A +:1004200080000000FFFFFFF1C83103C20A962A4294 +:100430000000008180000000FFFFFFF00431000495 +:10044000000004010000000100000000FFFFFFF8B1 +:1004500020B000040000000013940400C1197000D3 +:10046000FFFFFFF400000004000000020000000095 +:1004700000001000FFFFFFF4000000040000000176 +:100480000000000100000000FFFFFFF40000000476 +:10049000000000010000000100000000FFFFFFF469 +:1004A0000000000400000001000000010000000046 +:1004B000FFFFFFF80000000000004000680C200172 +:1004C00000001090FFFFFFF9C031C3E600266A422A +:1004D0000000000000001000FFFFFFF210F4000415 +:1004E000000002410000000100000000FFFFFFF0DB +:1004F0006050080400000002700C20F180259A90E2 +:10050000FFFFFFF8060000040100400200000000A9 +:1005100000001000FFFFFFF40000000400000002D4 +:10052000288C108085C01000FFFFFFF4000000043D +:10053000000000010000000100000000FFFFFFF4C8 +:1005400000000004000000010000000100000000A5 +:10055000FFFFFFF4000000040000000100000001A4 +:1005600000000000FFFFFFF4000000040000000195 +:100570000000000100000000FFFFFFF04E0000003F +:10058000000000010000000100000000FFFFFFF973 +:10059000C00002DA00061A42000000839035C00055 +:1005A000FFFFFFF400000004000000010000000154 +:1005B00000000000FFFFFFF4000000040000000145 +:1005C0000000000100000000FFFFFFF40000000435 +:1005D000000000010000000100000000FFFFFFF428 +:1005E0000000000400000001000000010000000005 +:1005F000FFFFFFF400000004000000010000000104 +:1006000000000000FFFFFFF9CA31C3C60A966A4125 +:100610000000000100000000FFFFFFF84E501439F9 +:100620001CC5C0010000000100000000FFFFFFF03A +:100630000000000000000002288C108085C010001F +:10064000FFFFFFF4000000040000000100000001B3 +:1006500000000000FFFFFFF40000000400000001A4 +:100660000000000100000000FFFFFFF40000000494 +:10067000000000010000000100000000FFFFFFF487 +:100680000000000400000001000000010000000064 +:10069000FFFFFFF400000004000000010000000163 +:1006A00000000000FFFFFFF3CA3323D60E966A4115 +:1006B0000000000100000000FFFFFFF8000004063A +:1006C00020D002410000000100000000FFFFFFF801 +:1006D00000D0000000000000000000839031C00046 +:1006E000FFFFFFF400000004000000010000000113 +:1006F00000000000FFFFFFF4000000040000000104 +:100700000000000100000000FFFFFFF400000004F3 +:10071000000000010000000100000000FFFFFFF4E6 +:1007200000000004000000010000000100000000C3 +:10073000FFFFFFF4000000040000000100000001C2 +:1007400000000000FFFFFFFBCA33E3D20E966A41B0 +:100750000000000100000000FFFFFFF000501A1031 +:10076000003002410000000100000000FFFFFFF028 +:100770000000020220030800700000F990118A9026 +:10078000FFFFFFF400000004000000010000000172 +:1007900000000000FFFFFFF4000000040000000163 +:1007A0000000000100000000FFFFFFF40000000453 +:1007B000000000010000000100000000FFFFFFF446 +:1007C0000000000400000001000000010000000023 +:1007D000FFFFFFF400000004000000010000000122 +:1007E00000000000FFFFFFF4000000040000000113 +:1007F0000000000100000000FFFFFFF1C0501BA23D +:1008000000D202410000000100000000FFFFFFF8DD +:100810004000020300100002700000E890344A908B +:10082000FFFFFFF4000000040000000100000001D1 +:1008300000000000FFFFFFF40000000400000001C2 +:100840000000000100000000FFFFFFF400000004B2 +:10085000000000010000000100000000FFFFFFF4A5 +:100860000000000400000001000000010000000082 +:10087000FFFFFFF400000004000000010000000181 +:1008800000000000FFFFFFF4000000040000000172 +:100890000000000100000000FFFFFFFA10F4020852 +:1008A00000C002410000000100000000FFFFFFF057 +:1008B0000000000000000002728CC8D993891090DB +:1008C000FFFFFFF082900000030000010000000124 +:1008D00000000000FFFFFFF4000000040000000122 +:1008E0000000000100000000FFFFFFF40000000412 +:1008F000000000010000000100000000FFFFFFF405 +:1009000000000004000000010000000100000000E1 +:10091000FFFFFFF4000000040000000100000001E0 +:1009200000000000FFFFFFF40000000400000001D1 +:100930000000000100000000FFFFFFF000000000C9 +:10094000000000010000000100000000FFFFFFF2B6 +:1009500000000320002612410000000100000000FA +:10096000FFFFFFF040000203101000010000000133 +:1009700000000000FFFFFFF4000000040000000181 +:100980000000000100000000FFFFFFF40000000471 +:10099000000000010000000100000000FFFFFFF464 +:1009A0000000000400000001000000010000000041 +:1009B000FFFFFFF400000004000000010000000140 +:1009C00000000000FFFFFFF4000000040000000131 +:1009D0000000000100000000FFFFFFF9D03403E237 +:1009E00080262A410000000100000000FFFFFFF206 +:1009F0000834023000C005010000000100000000C2 +:040A000070EAA741B0 +:00000001FF diff --git a/firmware/cxgb3/t3fw-7.0.0.bin.ihex b/firmware/cxgb3/t3fw-7.0.0.bin.ihex new file mode 100644 index 0000000000000000000000000000000000000000..e66117938e88517f546a2580d10818114e3af939 --- /dev/null +++ b/firmware/cxgb3/t3fw-7.0.0.bin.ihex @@ -0,0 +1,1881 @@ +:1000000060007400200380002003700000001000D6 +:1000100000002000E100028400070000E1000288E7 +:1000200000010000E0000000E00000A0010000006E +:1000300044444440E3000183200200002001E0002A +:100040002001FF101FFFD0001FFFC000E300043C91 +:1000500002000000200069541FFFC5802000699C39 +:100060001FFFC584200069DC1FFFC58820006A507F +:100070001FFFC58C200003C0C00000E43100EA313E +:1000800000A13100A03103020002ED306E2A05000C +:10009000ED3100020002160012FFDBC03014FFDA5F +:1000A000D30FD30FD30F03431F244C107249F0D347 +:1000B0000FD30FD30F12FFD5230A00240A00D30F4A +:1000C000D30FD30F03431F244C107249F0D30FD327 +:1000D0000FD30F14FFCE03421F14FFCB03421F1296 +:1000E000FFCCC0302D37302D37342D37382D373CED +:1000F000233D017233ED00020012FFC4C0302F37E0 +:10010000002F37102F37202F3730233D017233ED6A +:1001100000020012FFBEC0302737002737102737F4 +:1001200020273730233D017233ED03020012FFB95F +:1001300013FFBA0C0200932012FFB913FFB90C028F +:1001400000932012FFB8C0319320822012FFB71312 +:10015000FFB7932012FFB715FFB316FFB6C030D715 +:100160002005660160001B00000000000000000088 +:10017000043605000200D30FD30F7531140747145E +:1001800005330C0704437631E60436057539ED0076 +:10019000020012FFA715FFA3C030D72060000600A1 +:1001A00007471405330C070443043E057539F00373 +:1001B000020012FFA1C03014FFA1D30FD30FD30F41 +:1001C0009340B4447249F2D30FD30FD30F14FF9B63 +:1001D000834014FF9B834012FF9B230A0014FF9A65 +:1001E000D30FD30FD30F9340B4447249F2D30FD33C +:1001F0000FD30F14FF95834012FF95CA20832084EC +:10020000218522BC22743B108650B4559630B433FD +:100210007433F463FFE6000000653FE0655FDD12C4 +:10022000FF7CC03028374028374428374828374CCF +:10023000233D017233ED03020000020012FF7AC079 +:1002400032032E0503020012FF7813FF819320C0B2 +:1002500011014931004831010200C00014FF7E0441 +:10026000D23115FF7D945014FF7D04D33115FF7CEE +:10027000945014FF7C04D43115FF7C24560014FFE5 +:100280007B04D53115FF7B24560010FF7A03000054 +:10029000000000000000000000000000000000005E +:1002A000000000000000000000000000000000004E +:1002B000000000000000000000000000000000003E +:1002C000000000000000000000000000000000002E +:1002D000000000000000000000000000000000001E +:1002E000000000000000000000000000000000000E +:1002F00000000000000000000000000000000000FE +:1003000000000000000000000000000000000000ED +:1003100000000000000000000000000000000000DD +:1003200000000000000000000000000000000000CD +:1003300000000000000000000000000000000000BD +:1003400000000000000000000000000000000000AD +:10035000000000000000000000000000000000009D +:10036000000000000000000000000000000000008D +:10037000000000000000000000000000000000007D +:10038000000000000000000000000000000000006D +:10039000000000000000000000000000000000005D +:1003A000000000000000000000000000000000004D +:1003B000000000000000000000000000000000003D +:1003C000000000000000000000000000000000002D +:1003D000000000000000000000000000000000001D +:1003E000000000000000000000000000000000000D +:1003F00000000000000000000000000000000000FD +:1004000000000000000000000000000000000000EC +:1004100000000000000000000000000000000000DC +:1004200063FFFC000000000000000000000000006E +:100430000000000000000000000000001FFC0000A1 +:100440001FFC0000E30005C81FFC00001FFC0000AB +:10045000E30005C81FFC00001FFC0000E30005C806 +:100460001FFFC0001FFFC000E30005C81FFFC00042 +:100470001FFFC018E30005C81FFFC0181FFFC018EA +:10048000E30005E01FFFC0181FFFC288E30005E07E +:100490001FFFC2881FFFC288E30008501FFFC290E1 +:1004A0001FFFC57CE3000850200000002000016A07 +:1004B000E3000B3C2000018020000180E3000CA839 +:1004C0002000020020000203E3000CA82000021C10 +:1004D00020000220E3000CAC2000022020000226B5 +:1004E000E3000CB02000023C20000240E3000CB806 +:1004F0002000024020000249E3000CBC2000024C16 +:1005000020000250E3000CC82000025020000259D5 +:10051000E3000CCC2000025C20000260E3000CD859 +:100520002000026020000269E3000CDC2000026C65 +:1005300020000270E3000CE8200002702000027925 +:10054000E3000CEC2000028C2000028CE3000CF88D +:100550002000029020000293E3000CF8200002AC7F +:10056000200002B0E3000CFC200002D0200002F2C8 +:10057000E3000D00200003B0200003B0E3000D24D1 +:10058000200003B0200003B0E3000D24200003B0DE +:10059000200003B0E3000D24200003B0200003B0CE +:1005A000E3000D24200003B020006B74E3000D2451 +:1005B00020006B7420006B74E30074E800000000FE +:1005C00000000000000000001FFC00001FFC0000F5 +:1005D0001FFFC5801FFFC67020006B7820006B785E +:1005E000DEFFFE000000080CDEADBEEF1FFFC29074 +:1005F0001FFCFE001FFFC0841FFFC5C030000000AD +:10060000003FFFFF8040000010000000080FFFFFC8 +:100610001FFFC25D000FFFFF804FFFFF8000000043 +:1006200000000880B000000560500000600000007D +:1006300040000011350000004100000010000001E2 +:1006400020000000000010007FFFFFFF40000000BE +:1006500005000000800000190400000000000800F0 +:1006600010000005806000007000000020000009FC +:10067000001FF8008000001EA0000000F80000002D +:100680000800000007FFFFFF1800000001008001C4 +:10069000420000001FFFC20D1FFFC0CC0001008000 +:1006A000604000001A0000000C0000000000300054 +:1006B000600008008000001C000100008000001A9B +:1006C00080000018FC0000008000000100004000D5 +:1006D000800004000300000050000003FFFFBFFF84 +:1006E00000000FFF1FFFC390FFFFF000000016D0B7 +:1006F0000000FFF7A50000001FFFC4A01FFFC451AA +:100700000001000800000B20202FFF801FFFC445C0 +:1007100000002C00FFFEFFF800FFFFFF1FFFC56871 +:1007200000002000FFFFDFFF0000FFEF01001100CD +:100730001FFFC4611FFFC3C21FFFC4101FFFC5906E +:10074000FFFFEFFF0000FFFB1FFFBE90FFFFF7FF63 +:100750001FFFC0540000FFFD0001FBD01FFFC5B00C +:100760001FFFC6601FFFC591E0FFFE000000800074 +:100770001FFFC52C1FFFC5B41FFFC0581FFFC4D0EB +:100780001FFCFFD800010081E100060000002710D7 +:100790001FFCFE301FFCFE70E10002001FFFC52899 +:1007A0001FFFC5400003D0901FFFC5542B5063802E +:1007B0002B5079802B5090802B50A6801FFFC4595E +:1007C0000100110F202FFE0020300080202FFF009D +:1007D0000000FFFF0001FFF82B50B2002B50B208C1 +:1007E000000100102B50B1802B50B2802B50BA006A +:1007F000000100112B50BD282B50BC802B50BDA0F8 +:1008000020300000DFFFFE005000000200C00000AA +:1008100002000000FFFFF7F41FFFC05C000FF800AC +:1008200004400000001000000C4000001C400000CC +:10083000E00000A01FFFC5301FFD00081FFFC544DA +:100840001FFFC5581FFFC56CE1000690E10006ECD4 +:100850000100000000000000000000000000000097 +:100860002010004020100040201000402014008084 +:10087000200C0000200C0000200C00002010004084 +:10088000201400802014008020140080201800C054 +:10089000201C0100201C0100201C01002020014020 +:1008A000201800C0201800C0201800C0201C010023 +:1008B000201800C0201800C0201800C0201C010013 +:1008C000202001402020014020200140202009401C +:1008D00020200940202009402020094020240980B0 +:1008E000FFFFFFFFFFFFFFFFFFFFFFFF0000000014 +:1008F00000000000000000000000000000000000F8 +:100900002000525420005124200052542000525400 +:1009100020005060200050602000506020004E9465 +:1009200020004E9420004E8C20004DFC20004CA056 +:1009300020004A88200048880000000000000000D5 +:1009400020005224200050F02000519420005194A7 +:1009500020004F3820004F3820004F3820004F38FB +:1009600020004F3820004E8420004F3820004BC418 +:1009700020004A3C20004838000000000000000031 +:1009800020000B702000384C200004C02000442CB4 +:1009900020000B6820003F40200003F0200043ECC3 +:1009A0002000481420003C5020003B6C200037C839 +:1009B00020003654200033CC20002EF8200039CC03 +:1009C00020002B5C200027942000648C2000232032 +:1009D0002000200420001FB820001CA4200017B015 +:1009E000200014F020000D8C20000BB4200010BC5F +:1009F000200012A02000413020003C0420000B7891 +:100A0000200004C000000000000000000000000002 +:100A100000000000000000000000000000000000D6 +:100A200000000000000000000000000000000000C6 +:100A300000000000000000000000000000000000B6 +:100A400000000000000000000000000000000000A6 +:100A50000000000000000000000000000000000096 +:100A60000000000000000000000000000000000086 +:100A70000000000000000000000000000000000076 +:100A8000000000003264000000000000326400003A +:100A90006400640064006400640064006400640036 +:100AA0000000000000000000000000000000000046 +:100AB0000000000000000000000000000000000036 +:100AC0000000000000000000000000000000000026 +:100AD0000000000000000000000000000000000016 +:100AE00000000000000000000000100000000000F6 +:100AF00000000000000000000000000000000000F6 +:100B000000001000000000000000000000000000D5 +:100B100000000000004323800000000000000000EF +:100B200000000000000000000000000000000000C5 +:100B3000000000000000000000000000005C9401C4 +:100B40005D94025E94035F94004300000000000087 +:100B50000000000000000000000000000000000095 +:100B60000000000000000000000000000000000085 +:100B7000000000000000000000000000005C900188 +:100B80005D90025E90035F90005300000000000043 +:100B90000000000000000000000000000000000055 +:100BA0000000000000000000000000000000000045 +:100BB000000000000000000000000000009C940005 +:100BC0001D90019D94029E94039F9404089405092E +:100BD00094060A94070B94004300000000000000F4 +:100BE0000000000000000000000000000000000005 +:100BF000000000000000000000000000009C9001C8 +:100C00009D90029E90071D90039F90047890057917 +:100C100090067A90077B90005300000000000000CF +:100C200000000000000000000000000000000000C4 +:100C300000000000000000000000000000DC940044 +:100C40001D9001DD9402DE9403DF940404940505F5 +:100C5000940606940707940808940909940A0A94CC +:100C60000B0B940043000000000000000000000097 +:100C700000000000000000000000000000DC900107 +:100C8000DD9002DE900B1D9003DF9004B49005B55B +:100C90009006B69007B79008B89009B9900ABA9034 +:100CA0000BBB90005300000063FFFC002000693084 +:100CB00010FFFF0A000000002000695400D231102C +:100CC000FFFE0A00000000002000699C00D33110E4 +:100CD000FFFE0A0000000000200069DC00D4311093 +:100CE000FFFE0A000000000020006A5000D531100D +:100CF000FFFE0A000000000063FFFC00E00000A00F +:100D000012FFF78220028257C82163FFFC12FFF313 +:100D100003E83004EE3005C030932094219522631F +:100D2000FFFC00001FFFD000000400201FFFC58053 +:100D30001FFFC670200A0011FFFB13FFFB03E63103 +:100D400001020016FFFA17FFFAD30F776B069060C7 +:100D5000B4667763F85415265419D90F140063FF4D +:100D6000F90000006C1004C020D10F006C1006C008 +:100D7000C71AEF060D4911D830D7201BEF05BC224A +:100D80008572AB76837105450B957209330C23761A +:100D900001723B05233D08237601A39D19EEFE7DDC +:100DA0006326C021C0E0032E380E0E42C8EE29A6ED +:100DB0007E6D4A0500808800308C8271D10FC0F0B2 +:100DC000082F387FC0EA63FFE49210037F0CABFF6B +:100DD0000F3D12DB802EDC100E4E36C021C05003BA +:100DE0002538221200050542CB5029A67E6DEA0562 +:100DF00000B08800308CBC76C050A8F3C081068556 +:100E000038050542CA5129A67E0D480CD30F6D8ABC +:100E10000500308800208C8271D10F00C061C05065 +:100E200008653875C0C663FFC0C0B0038B387BC08F +:100E3000D763FFD16C101216EED82A221E2E221D67 +:100E4000C0D07AE11B2CA000D7A028CCE96481484F +:100E500029CCE8649341C1B97BC12569CC1B6000F2 +:100E6000222CD000D7D028CCE964815429CCE86466 +:100E700093BAC1B97BC10968CC09C020D10F000069 +:100E8000002D25028C32C0900C6F5065F586292408 +:100E900067090847658582B44927200C18EEC00C05 +:100EA0007F11A8FF28F286DB707893026005541941 +:100EB000EEBC09790A2992A36890082822000988C3 +:100EC0000C65853F29F28564953929161A655563A5 +:100ED0007AE104DBA0600001C0B022161B8DB412C1 +:100EE000EEB10D881482240D0D47A82218EEAF092B +:100EF000DD10082202929018EEAD12EEAE08C80185 +:100F00000D88020242021DEEAA92910D880298926B +:100F100022B0232DB02204281006DD100242120850 +:100F2000DD0228B0210722100C88100288020D88EB +:100F30000212EEA18D3302DD0182340D88029893F6 +:100F400092B992948DB582399D9588B68D389896D0 +:100F500088B792999D989897C0D028F28512EE97FD +:100F600008480BA2722D24CF28F68522121B655447 +:100F7000DE7AE104DBA0600001C0B064BEFB2CB0EF +:100F80000728B000DA2006880A28824CC0D10B80DE +:100F900000DBA065AFE763FEE02EA0032B2067D93E +:100FA000E0D4E065B1AB8B320BFC5064C4B218EEF8 +:100FB000848F2A08B80108FF0C64F2CDC09260014A +:100FC0008A2AD003292067D4A06594C98B320BFCF0 +:100FD0005064C48C1FEE7B8E2A0FBF017FE9DC8C2E +:100FE000330CE8506484B4C0B00CA5118F592B1693 +:100FF000128A578E582A1611DBE0AAFA7FAB01B18C +:10100000EB75CE599E1F8937951CAF98981D798B2B +:101010000825160C29EC0129160F9A168A1D851F22 +:101020002A16192A0A007BE30A7BE9052B12067FA0 +:10103000BB01C0A165A4698B35C0A0C08078E30462 +:1010400064E3B5C0A165A458891C2916170C4A543D +:101050002A1616BCAA2A16186000AF0000008837AE +:10106000893628161429161508F80C09E90C2916D2 +:1010700013981E78FB07281213B088281613891EB0 +:101080009A189F172A1213C0F02916197BE30C7BBC +:10109000E9078E172B12087EBB01C0F165F406C06C +:1010A000B02F121988352E12129819281211AAEE93 +:1010B000AF8F78FB022EEC019F138F199F12C0F0A7 +:1010C0007BE30C7EB9078913281202798B01C0F1EA +:1010D00065F3D22516172912150C4F54C0E12F16AF +:1010E00016BCFF2F161800F10400EE1A2F1214B0D0 +:1010F000EE0EF8130988010FEE012F1219A8AAAEFF +:10110000FE7FEB01B1AAD5A02E16192B1219DA50C9 +:101110002C12185818D3C0D0C0902E121907480AA4 +:101120002C1218DAB08F34C0B1AAFF00C1042A1201 +:10113000162F86162C121700BB1AB0BB0EBE019ECE +:10114000C90BFB1305BB019BC82A7410292467290E +:1011500070038E75B19F2F7403B0EE0E4E0C65EDCB +:10116000182820672D25026583132A221E29221D97 +:101170007A9104DBA0600001C0B064BCFC2CB00715 +:1011800028B000DA2006880A28824CC0D10B8000E3 +:10119000DBA065AFE763FCE189AAB199659094890A +:1011A000341BEE0899AA88331FEE0208485428A47D +:1011B0002C8E2A8C320FEE020BCB017EB9640C4BC5 +:1011C000516FB25E8B3375B6592CA0130BEE510ED6 +:1011D000CE010E0E410C0C417EC9472FA012B0FF6C +:1011E00065F2DD8E378CA88B368FA97CB3077BC95F +:1011F000027EFB01C0D1CED98835DDB00E8E0878D5 +:10120000EB01B1BD89A7DAC00F9B0879BB022ACCDC +:1012100001DCB0C0B07DA3077AD9027CEB01C0B17C +:1012200064B163C091292467C020D10F008BDAB16B +:10123000BB64B0C02C20672D250265C2281DEDDCE3 +:101240008C321FEDE10DCD010FDD0C65D1C10C4FCE +:10125000516FF2026001B8C0902924670908476500 +:10126000820F7AE104DBA0600001C0B064BC0A2CEC +:10127000B00728B000DA2006880A28824CC0D10BBB +:101280008000DBA065AFE763FBEF8C330CE95064B3 +:1012900092090CEF11AFAF2F16178EF885F7DBE030 +:1012A0008FF9251610A5F57F5B022BEC010CA850D9 +:1012B0006580DD8837DAE0AF8929160A789B022A33 +:1012C000EC019514891AD5A02916192A0A007BE386 +:1012D0000A7BE9052B12047FBB01C0A165A1C18B6C +:1012E00035C0A0C08078E30464E104C0A164AD5CB3 +:1012F0006001AD00008E3419EDB39EDA8C331BED26 +:10130000AC0C4C542CD42C8A2A8C320BAA0209C95E +:10131000010A990C659F0B0C4F516EF20263FF029C +:101320008B330BA850648EFA29D0130BEA510A9A1A +:10133000010A0A410909410A990C659EE52BD01260 +:10134000B0BB65B188C0A08E378CD82B32062FD2A7 +:10135000097CB3077BC9027EFB01C0A165AEC388CF +:1013600035D3B0AE8E78EB01B1B389D7DAC0AF9B7D +:1013700079BB01B1CADCB0C0B073A3077A39027C73 +:10138000EB01C0B165BE9BC090292467C020D10F7E +:10139000008A3688372A16152816140AEA0C08F827 +:1013A0000C981B78FB01B0AA9F158F1B2F16192FC5 +:1013B0000A007BE30A7BE905281205785B01C0F18E +:1013C00065F0E2AADE8B352F1219291210C050AF3A +:1013D0009F79FB01B1EE9F11C0F075E30A7E5905BC +:1013E00028120178BB01C0F164FCEA6000B700007C +:1013F0007FB30263FEF663FEF17FB30263FC4563D5 +:10140000FC4000006450A4DA205815C8C020D10F59 +:10141000C09163FE43C09163FA73DA20DB70C0D1E0 +:101420002E0A80C09A2924682C70075814B8D2A0BC +:10143000D10F000019ED6603480B9810088B0209C4 +:1014400029087983022B8DF829121A63FA8B000080 +:101450002A2C74DB40580E442E221D2A221E63FBC8 +:101460000FC09163FCE5022A0258024C0AA2020650 +:101470000000022A025802490AA202060000DB709C +:10148000DA20C0D12E0A80C0CE2C24682C700758D8 +:10149000149FC020D10FD9A063FCB600C09463FC98 +:1014A000AAC09663FCA5C09663FCA0002A2C74DB3E +:1014B00030DC405BFE2EC2D02DA4002B200C63FF3D +:1014C000458F358EA77FEB0263FEBB63FD548935E4 +:1014D00088D7798B0263FEAE63FD47006C1004C0B1 +:1014E00020D10F006C1004C020D10F006C10042B11 +:1014F000221E28221DC0A0C0942924062A25027B72 +:101500008901DBA0C9B913ED24DA2028B0002CB082 +:101510000703880A28824CC0D10B8000DBA065AF8E +:10152000E7C020D10F0000006C100602260229201F +:1015300006C0E0689805289CF96581202A61021799 +:10154000ED170A0A4C65A0F02B729E1AED136FB8C6 +:10155000026000F42AA22668A0098B60D30F0ABBA0 +:101560000C65B0E42A729D64A0DE2B600C0CBC11EB +:1015700007CC082DC2866FD9026000D71DED090D7A +:10158000BD0A2DD2A368D0078F600DFF0C65F0C394 +:1015900022C285C0F06420BB1DED0E68434D18EDDE +:1015A0000D8C6B08CC029C208A6008AA110DAA023F +:1015B0009A21896A9924883298252C610408CC11D3 +:1015C0009C271CECFE0CBA11A7AA29A285ACBC2F43 +:1015D000C4CF299C2829A685C85A2A6C74DB405898 +:1015E0000DE2D2A0D10FD2E0D10F0000289CF96407 +:1015F00080912C60668931B1CC0C0C472C64666FED +:10160000C669709E661AECF48C30896B0C8C400BAA +:10161000CC100C99020A9902992088600888110D53 +:10162000880298218C339C238A329A22896A9924D1 +:101630008834982563FF820000CC57DA60DB30DC09 +:10164000405814A7C020D10F00DA60C0B658153733 +:1016500063FFE500DA6058153563FFDC00DA20DB54 +:1016600030DC40DD505815B7D2A0D10F9E102B6151 +:10167000045813C81DECD78E102B600CC0F02F64DB +:101680006663FF80296123C08879830263FF752E1A +:1016900016002C60662B61042CCC010C0C472C64CA +:1016A000665813BC1DECCB8E102B600CC0F02F6461 +:1016B0006663FF506C1004C0B7C0A116ECC815ECEF +:1016C000BAD720D840B822C040053502967195702F +:1016D00002A438040442C94B1AECAD19ECAE29A699 +:1016E0007EC140D30F6D4A0500808800208C220AFD +:1016F00088A272D10FC05008A53875B0E363FFD738 +:101700006C100893149412292006655270C07168F9 +:1017100098052A9CF965A28016ECA12921028A1459 +:1017200009094C6590C78AA00A6A512AACFD65A0D8 +:10173000BCCC5FDB30DA208C12581469C0519A148B +:10174000C7BF9BA98E142EE20968E0602F629E1D20 +:10175000EC926FF8026000812DD22668D0052F220E +:10176000007DF9752C629DC79064C06D9C118A1430 +:101770002B200C2AA0200CBD11A6DD0A4F14BFA8F7 +:1017800009880129D286AF88288C09798B551FECEE +:10179000840FBF0A2FF2A368F0052822007F894337 +:1017A00029D285D49065907760003D00002B200CF5 +:1017B0001FEC7C0CBD11A6DD29D2860FBF0A6E96E8 +:1017C000102FF2A368F00488207F890529D285654F +:1017D0009155DA205814D5600013DA20C0B6581499 +:1017E000D3600009C09063FFB9DA205814D089147F +:1017F000899109FE506551CC8C128D14DA20DBD012 +:101800008DD09E100D6D515813419A1464A1F0C7EC +:101810005F8FA195A9C0510F0F479F1263FEFB0078 +:10182000C091C0F12820062C2066288CF9A7CC0C8A +:101830000C472C24666FC6088D148DD170DE01C054 +:1018400090DD90648141C9D28A112B210458135133 +:101850008A14C0B02B24668EA92AA020C1701CEC6B +:101860005B0E281415EC508E148556AC2C9C132E50 +:10187000EC28A855DDE07CE3022DEDF8D3D00A7703 +:1018800036DA40DB50DC305BFF8BD4A02E200CB46A +:1018900055290A88C0C01BEC490CEF11A6FF28F29D +:1018A00085ABEE2CE4CFA98828F685290A80881319 +:1018B000A933DD3089147833022D3DF8289020D3E8 +:1018C000D007880CC170080847289420087736652F +:1018D0007FAE891413EC438990C0D477973D18EC00 +:1018E00041C1BA2721048514099C4006CC118653B6 +:1018F00004771185520C77020B7702C0C098A09D27 +:10190000A18D2B9CA597A496A795A603DD029DA269 +:101910002BF2852CE4CF2BBC202BF6852A2C748B44 +:1019200012580D11D2A0D10F28203DC0E07C87773E +:101930002E24670E0A4765A07318EC2B8F201CEC31 +:10194000198E148CC48EE408FF1108FF020E8E1449 +:10195000AECC1EEC269F910ECC029C90C0801EEC5B +:10196000242C21021AEC162FD285AABAB8FF2FD642 +:10197000850ECC0228A4CF2C2502C020D10F8714BD +:10198000877007074763FD86282123C099798B025A +:1019900063FEB2DDF063FEAD00DA20DB308C12DDD9 +:1019A000505814E8D2A0D10FC0E163FF828B148C91 +:1019B00012DD50C0AA2E0A802A2468DA2058135358 +:1019C000D2A0D10F007096552B629E6EB8531DEBBE +:1019D000F22DD22668D0048E207DE9452A629DCB67 +:1019E000AF2B21042C20665812EBC090292466826C +:1019F0001418EC008F2108FF019F21C020D10F0097 +:101A00008B10C9B88CA00C6C51CCCC8E241FEBEE83 +:101A10008DE19E140FDD029DE18810658FA9C02025 +:101A2000D10FDA20C0B6581441C020D10F000000F9 +:101A30006C1006C0D02A2102941175A70E89347F3C +:101A400097098B357FBF042D2502DAD00A0C4C652F +:101A5000C17B16EBD21FEBD028629EC0EA78E3026E +:101A600060018129F2266890078A2009AA0C65A1E5 +:101A7000732A629DDEA064A1702B200CC0700CBC88 +:101A80001106CC0829C286280A0C79830260014C11 +:101A900019EBC409B90A2992A3689007882009881C +:101AA0000C65813824C2851CEBC664412F8931093D +:101AB0008B140CBB016FB11D2C20669E10B1CC0C99 +:101AC0000C472C24666EC60260013409FE5065E1A5 +:101AD0002E8A102AAC188934C0E47F973617EBC7DA +:101AE000C0821BEBC58C359E419B408B2098459D49 +:101AF0004418EBC307BB029B420C07400F771198B9 +:101B0000439747D7E07FC70B2C2102284A0008CC17 +:101B1000022C25027E97048B362B25227D97048C80 +:101B2000372C25217C973A0AAB022C0A01C0800A87 +:101B3000C8382A3C200808426480821CEB9419EBC8 +:101B40009529C67E00A08800B08C00A08800B08CCB +:101B500000A08800B08C28629D2DF4A2288C182843 +:101B6000669D89307797351FEB9F8C338832047BD5 +:101B70000B2A2104B47704AA119EB19FB08F2B9D2C +:101B8000B598B69CB718EB96099C4006CC110CAAE8 +:101B90000208FF029FB2C1CC0CAA029AB4C9772AEC +:101BA000200C1BEB860CA911A699289285ABAA2DB7 +:101BB000A4CF08780B289685CF58C020D10FC087B6 +:101BC000C0900AC93879880263FF7863FF6CCC57EC +:101BD000DA20DB308C11581342C020D10FDA2058A4 +:101BE00013D363FFE8C0A063FE89DA20C0B65813A0 +:101BF000CF63FFD92A2C748B11580C5BD2A0D10F64 +:101C00008A102B21045812631FEB64C0D02D246668 +:101C100063FEBD006C1006D62019EB5F1EEB612839 +:101C2000610217EB5E08084C65805F8A300A6A51D2 +:101C300069A3572B729E6EB83F2A922668A0048C27 +:101C4000607AC9342A729D2C4CFECAAB2B600CB64C +:101C50004F0CBD11A7DD28D2860EBE0A78FB269C4C +:101C6000112EE2A32C160068E0052F62007EF91504 +:101C700022D285CF2560000D00DA60C0B65813ABC4 +:101C8000C85A60010F00DA605813A8655106DC409D +:101C9000DB308D30DA600D6D5158121CD3A064A07A +:101CA000F384A1C05104044763FF6D00C0B02C60F1 +:101CB000668931B1CC0C0C472C64666FC6027096F5 +:101CC0000A2B6104581233C0B02B64666550B42AE5 +:101CD0003C10C0E7DC20C0D1C0F002DF380F0F425B +:101CE00064F09019EB2A18EB2B28967E8D106DDA94 +:101CF0000500A08800C08CC0A089301DEB3A779702 +:101D00005388328C108F3302CE0BC02492E12261B3 +:101D1000049DE00422118D6B9BE59FE798E61FEB85 +:101D2000300998400688110822020FDD02C18D9DFE +:101D3000E208220292E4B4C22E600C1FEB200CE8F1 +:101D400011A7882C8285AFEE0C220B2BE4CF2286C4 +:101D500085D2A0D10F28600CD2A08C1119EB180CE1 +:101D60008D11A7DD2ED285A9882B84CF0ECC0B2C0C +:101D7000D685D10FC0F00ADF387FE80263FF6C63BD +:101D8000FF6000002A6C74C0B2DC20DD40581211E4 +:101D9000C0B063FF63C020D10F0000006C10042CA2 +:101DA000221D2A221EC049D320293006243468C0AF +:101DB000407AC105DDA060000200C0D06E9738C037 +:101DC0008F2E0A802B3014C0962934060EBB022EAB +:101DD00031022B34147E8004243502DE407AC10E99 +:101DE000C8ABDBD0DA302C0A00580A792E31020E4B +:101DF0000F4CC8FEC020D10F6895F82831020808A2 +:101E00004C658FEF1AEAE61CEAE42BA29EC09A7B8F +:101E10009B462BC22668B0048D307BD93B29A29DFE +:101E2000C0E3CB9394901BEAF72D31049B9608DD19 +:101E3000110EDD029D979D9124C4A212EAF32F3169 +:101E40000228A29DC0E52E3406288C3028A69D02CB +:101E5000FF022F3502C020D10FDA30C0B65813333D +:101E6000C020D10F6C10062A2006941168A80528FE +:101E7000ACF965824F29210209094C659206CC5FB5 +:101E8000DB30DA208C11581296C051D3A0C7AF9A1C +:101E90003AC0E019EAC31DEAC91AEAC28F3A16EA43 +:101EA000BFB1FB64B1352C629E6FC8026001E927A7 +:101EB000DC33277226687007882007880C6581D874 +:101EC00024629DC0766441D02B200C0CBC11A6CCA2 +:101ED00028C286C09E7893026001C819EAB109B988 +:101EE0000A2992A39410689007882009880C6581BC +:101EF000B224C2856441AC292006299CF96491DF93 +:101F00002C20668931B1CC0C0C472C24666EC6029D +:101F100060019809F8506581921AEAA38C3619EA93 +:101F2000A10C881489940C0C4709CC10A8990A9923 +:101F30000218EAB62A210499409841882A19EAB47D +:101F40000C8802098802984228302C2C3013293042 +:101F50001204CC100699100C88109F4408A8020C9B +:101F6000990209880298438F379F458C389C46898F +:101F700039C0F1994719EAA788359F4B98480888D6 +:101F800014098802984A8F3018EA9777F732C0749C +:101F900089328C33984C974D0F9740882B2E4611E1 +:101FA0000677112C461329461204AC1119EA8D0745 +:101FB000CC02C179098802984E07CC022C4610C089 +:101FC0007AADBC0CBA11A6AA29A2852EC4CF097974 +:101FD0000B29A6856550FCC020D10F002B200C0CCE +:101FE000BC1106CC082FC28609B90A6FF90260013C +:101FF0001E2992A36890082F220009FF0C65F10F9B +:102000002FC28564F10928203D082840648084841B +:102010003504841464407C85A57453778436048425 +:102020001464406F74536C293013C08C798864C079 +:10203000902924670908476580DD882089A48435B4 +:102040001AEA6B048414A4940A440294F014EA6615 +:1020500008881104880298F1843698F3048414A443 +:10206000990A990299F21AEA6229210224C285ADDD +:10207000B82E84CF244C1024C6850A990229250243 +:10208000C020D10F00CC57DA20DB308C115812144D +:10209000C020D10FC09163FF97DA20C0B65812A3B9 +:1020A00063FFE100DA205812A163FFD88A102B21C8 +:1020B000045811381DEA422B200CC0E02E24668FF4 +:1020C0003A63FE5400DA20DB30DC40DD5058131D4B +:1020D000D2A0D10F2A2C748B11580B23D2A0D10F70 +:1020E000292123C08879830263FE2D2A12002C2027 +:1020F000662B21042CCC010C0C472C24665811258E +:102100001DEA2F2B200CC0E02E24668F3A63FE08B8 +:10211000DA2058128663FF6CDA205BFF20D2A0D150 +:102120000F0000006C100A9516C061C1B0D9402A9A +:10213000203DC0400BAA010A64382A200629160750 +:1021400068A8052CACF965C33B1DEA16C8442F12DC +:102150000664F29B2621021EEA12961406064C65BE +:1021600062DE15EA0E6440CF8A352930039A150ADB +:10217000990C6490C22C200C8B159C120CCC11A5D0 +:10218000CC9C132CC286B4BB7CB3026002CE8F12EF +:102190000EFE0A2EE2A368E0082622000E660C65F9 +:1021A00062BA88132882856482B2891564905EDAE7 +:1021B00080D9308C201EEA0C1FEA0D1DE9FA8B1520 +:1021C0008DD4D4B07FB718B88A293C10853608C69C +:1021D000110E66029681058514A5D50F55029580CE +:1021E0000418146D8927889608CB110888140EBB33 +:1021F00002A8D8299C200F88029BA198A088929BB6 +:10220000A3088814A8D80F880298A22AAC10C0D0BE +:102210008A151FE9EA8E1219E9F68B1388142CB27D +:1022200085098802AFEE0CAA0B2DE4CF2AB68528CB +:102230002502C020D10F000026529E18E9D76F68F2 +:102240000260020D2882266880098920D30F089930 +:102250000C6591FD2A529DC0FD9A1164A1F32B20BB +:102260000CC1CA0CB8110588082D82860EBE0A7DE5 +:10227000C30260020A2EE2A368E0082622000E666E +:102280000C6561FB288285DE806482072920069820 +:1022900010299CF96492042C20668831B1CC0C0C76 +:1022A000472C24666EC6026001BD08FD5065D1B79B +:1022B00017E9DA1CE9BD19E9C42A21048B2D28305D +:1022C000102D211D0C88100BDB090A8802098802D9 +:1022D0000CBB0264415589109B909791989284356C +:1022E000D9E064406FD730DB40D8307F4715273CBA +:1022F00010BCE92632168C3996E69CE78A37283CD2 +:10230000042AE6080B131464304A2A821686799A46 +:102310009696978C778A7D9C982B82172C7C209A96 +:102320009A2A9C189B99867BB03B298C086DB92111 +:102330008BC996A52692162AAC18B8999BA196A08F +:102340008BC786CD9BA22B921596A49BA386CB2CE4 +:10235000CC2026A605C0346B4420043B0C0448095D +:102360000E880A7FB705C0909988BC88C0900B1A68 +:10237000126DAA069988998B288C181CE9A81BE96C +:10238000A816E99DB1DD2A211C23E6130D0D4F2669 +:10239000E6122D251DC06087207DA907C0D0280A20 +:1023A0000028251D26E6172CE6162BE61505D81164 +:1023B0001AE99328E6180A7A022AE614292006293F +:1023C0009CF96491062A200CC0901BE97C0CAD118D +:1023D000A5DD2CD285ABAAC0B029A4CF0CFC0B2C58 +:1023E000D685DA208C172D120658110DD2A0D10FE8 +:1023F0008A356FA546D8308BD56DA90C8A860A8A96 +:1024000014CBA77AB335288C10C080282467080B1A +:102410004765B11CDA20DB308C17581131D3A0C0CE +:10242000C1C0D02DA4039C1663FD280086366461CC +:102430001689109B909791989263FEA1C08163FFCB +:10244000C98A16CCA7DA20DB308C17581125C0209A +:10245000D10FDA20C0B65811B563FFE400DA208B43 +:10246000125811B263FFD9009F189E198A112B21AF +:10247000045810488E198F18C0B02B246663FE2FA5 +:10248000C08063FE01DA20DB308C17DD5058122D3E +:10249000D2A0D10FDA205811A563FFA42D2123C0AB +:1024A000C87DC30263FE089F188A112B21042C20CB +:1024B000669819B1CC0C0C472C24665810368E192E +:1024C0008F18C0D02D246663FDE50000262123B0BF +:1024D0006606064F262523656EEA28206A7F870553 +:1024E0000829416490FDC0D01BE93F19E94E262020 +:1024F0000723E61BB166097A022BE61A28200A2D6B +:10250000E61D2AE61E09880228E61C8826060647DC +:1025100028E6208B2826E53E2BE6212D24072C20BB +:10252000062A20642CCCFD64C09DB4FF63FE950098 +:1025300000DB30DA208D16C0CE2E0A802C24688C69 +:1025400017581072D2A0D10F8E102632161FE9151F +:102550000626148FF62BE61297E127E61328E614D9 +:10256000A6FF0CFF029FE0C1F62EEC4826ECC064EB +:102570006D6B8435C080644DDBD9E0DC30DBE0DDA1 +:1025800030B18814E92986C98AC8279DFF2CCC1050 +:10259000299C102A76322A76300464011AE9242410 +:1025A0007631AA442476332AD21617E9219AB6073F +:1025B000660196B784C3BCBB94B58435B4DD74831F +:1025C000BF2D211D63FD8D0064AF5E1DE8F62C203C +:1025D000168DD20ACC0C00D10400CC1AACBC9C29BC +:1025E00063FF46002B21046EB8222C2066B8CC0C69 +:1025F0000C472C2466C9C49F189E198A11580FE5F0 +:102600008E198F18C0348720C0D02D2466C068264C +:10261000240663FED00000006C1008292006289CC8 +:10262000F86582C3292102C0AA09094C6590E62BEE +:10263000200C16E8DA0CBC11A6CC2EC286C1D27EC4 +:10264000D30260028E19E8D609B90A2992A32A1684 +:10265000026890078A2009AA0C65A27729C28564BE +:1026600092712B629E1AE8CC6FB80260026E2AA2A9 +:102670002629160168A0082B22000ABB0C65B25C53 +:1026800029629DC18C6492542A21200A806099108D +:102690002C203CC7EF000F3E010B3EB1BD0FDB39D4 +:1026A0000BBB098F260DBD112DDC1C0D0D410EDD60 +:1026B000038E27B1DD0D0D410FEE0C0DBB0B2BBCB6 +:1026C0001C0BB7027EC71C2C21257BCB162D1AFCB8 +:1026D0000CBA0C0DA16000093E01073EB1780987D4 +:1026E000390B770A77EB026002062B212328212180 +:1026F000B1BB0B0B4F2B25237B8B29B0BD2D252385 +:10270000C855DA20DB30580FF0292102CC96C0E8FA +:102710000E9E022E2502CC57DA20DB30DC4058100A +:1027200070C020D10F2C20668931B1CC0C0C472C05 +:1027300024666EC6026001CF09FD5065D1C92F0A1B +:10274000012830112922146480112A221B090C440B +:1027500000C10400FB1A0BAA022A261B2D3010C050 +:10276000A0C0E088301BE88F94139514240A01253B +:10277000203C2BB022088C14778704C0F10BFA3868 +:10278000C0F2C0840858010F5F010F4E3805354074 +:1027900007EE10C0F0084F3808FF100FEE0228DCDB +:1027A000FEC0F0084F38842B0BA8100AFF102A2116 +:1027B000200F88020E880208440218E89E8F110834 +:1027C00044022821250A2A140828140488110A889A +:1027D000022A210494F08E2004D41008EE1104EE95 +:1027E00002C04A04EE029EF1842A08AE110EDE02F7 +:1027F00094F40A54110E44020555100C1E4094F72F +:1028000007EE100E5502085502C08195F68433C0BC +:102810005094F3B1948E3295F898F99EF2C080C12D +:10282000EC24261498FB9EF599FA853895FC843A99 +:1028300094FD8E3B9EFE883998FF853525F61084E1 +:1028400036851424F6118E3784132EF612C0E064F8 +:10285000B04989307797442B301088338C111FE8AA +:10286000618D322FC614C0F42FC6158F2B2EC619BA +:102870002DC61A28C61B04AD1109984006881108F8 +:10288000DD020DBB0218E856C1D00DBB0208FF02E5 +:102890002FC6162BC618280A0E2816022B200C88C5 +:1028A000121CE8460CB911A6992A9285ACBB2EB42D +:1028B000CF0A880B289685C9718B268A2907BB0801 +:1028C0002B26060BAA0C0A0A482A2525655048C063 +:1028D00020D10F00DA2058109563FE3900DA20C0AD +:1028E000B658109263FE2E00689738C020D10F00B2 +:1028F00000DA20DB7058104FC0C0C0D10ADA390AA4 +:10290000DC3865CDE463FE0D8A102B2104580F21BD +:10291000C0E02E246663FE25DB402A2C7458091281 +:10292000D2A0D10FDA20580F2663FCF76C1004C038 +:1029300020D10F006C1004270A801CE83F1DE83FDF +:102940001AE8170C2911AA992A2CFC2B92850DAA9A +:10295000029CB19AB0C05113E83C28928516E83821 +:1029600014E839A62604240AB888289685234691B7 +:10297000A76625649FD10F006C100AD6302830104E +:10298000292006288CF964829768980B2A9CF9659F +:10299000A1B2022A02580F0A89371BE802C89164C3 +:1029A000520E2A21020A0C4C65C2558D3019E7FBE4 +:1029B00074D7052E212365E29A2F929E1AE7F76FAE +:1029C000F8026002502AA22668A0082C22000ACC35 +:1029D0000C65C2412A929D64A23B9A151FE7F18DB6 +:1029E00067C1E6C8DD2B620618E7EF64B0052880F2 +:1029F000217B8B432B200C18E7E90CBC11A8CC29B8 +:102A0000C28679EB460FBE0A2EE2A368E0052F22AC +:102A1000007EF9372CC2859C1864C22F2B212F878A +:102A2000660B7B360B790C6F9D266ED2462C203DB3 +:102A30007BC740CE5560001E2A200CC1B28C2058A6 +:102A4000106F9A1864A2418D6763FFCFC0C063FF07 +:102A5000C5D7B063FFD300C0E06000022E60030E54 +:102A6000DB0C6EB20EDC700CEA11AA6A2AAC20589C +:102A70000198D7A0DA20DB70C1C82D21205810158D +:102A80008C268B279A160CBB0C7AB3348F1889636B +:102A900099F3886298F28E659EF82D60108A189DD1 +:102AA0001768D729C0D09DA92C22182B22139CABC4 +:102AB0009BAA97A58E667E7302600097CF58600030 +:102AC0001FDA208B16580FDB65A13563FFBDC0816F +:102AD000C0908F18C0A29AF999FB98FA97F563FFF6 +:102AE000D2DB30DA20DC40580F7EC051D6A0C0C007 +:102AF0002BA0102CA4039B172C1208022A02066B91 +:102B000002DF702D60038E179D149E100CDD11C026 +:102B1000E0AD6D2DDC205801178C148B16ACAC2C5D +:102B200064038A268929ABAA0A990C9A2688660921 +:102B3000094829252507880C98662F2218A7FF2FFA +:102B4000261863FE96DA20DB30DC40DD5058107D1D +:102B5000D2A0D10FC0302C20668961B1CC0C0C47BB +:102B60002C24666EC6026000CEC03009FD5065D0D0 +:102B7000C68E6764E069647066DB608C18DF70DAAB +:102B8000202D60038E170CDD119E10AD6D2DDC2005 +:102B90001EE7A75800F8232618DA208B16DC402FF2 +:102BA0002213DD50B1FF2F2613580F1DD2A0D10FD5 +:102BB0000028203D084840658DE76F953EDA308D4E +:102BC000B56D990C8CA80C8C14CACF7CD32D2AAC73 +:102BD00010C090292467090D4764DDC560008E0090 +:102BE0002C1208066B022D6C20077F028E17DA204C +:102BF0009E101EE78E58007C63FF9A00C09163FF11 +:102C0000D1655080DA20DB60DC40580F35C020C031 +:102C1000F02FA403D10FDA20C0B6580FC463FFE031 +:102C2000006F950263FD70DA20DB30DC40DD50C4BC +:102C3000E0580EB6D2A0D10F8A152B2104580E559C +:102C4000232466286010981763FF2500DA20580FA8 +:102C5000B763FFACC858DB30DA20580E9B2A21023C +:102C600065AF9DC09409A90229250263FF92DB305C +:102C7000DC40DD50C0A32E0A802A2468DA20580EDA +:102C8000A3D2A0D10FC020D10FDA202B200C580FD7 +:102C9000C063FF6C6C1004282006C062288CF865A5 +:102CA0008125C050C7DF2B221BC0E12A206B2921C0 +:102CB0002300A104B099292523B1AA00EC1A0BC462 +:102CC000010A0A442A246B04E4390DCC030CBB012D +:102CD0002B261B64406929200C1BE7300C9A110B32 +:102CE000AA082FA2861BE72E6FF9026000B60B9B85 +:102CF0000A2BB2A368B0082C22000BCC0C65C0A430 +:102D00002BA2851CE75264B09B882B2F21040C88D2 +:102D10000298B08420C08508441108440294B1840C +:102D20002A08FF1194B48E349FB79EB5C0401DE7AA +:102D3000232EA2850D9D082EEC282EA68525D4CF06 +:102D400029210209094C68941A689820C9402A214F +:102D50000265A00B2A221E2B221D7AB10265A079E2 +:102D6000C020D10F2C212365CFDE6000082E212149 +:102D70002D21237EDBD52B221E2F221D2525027B14 +:102D8000F901C0B064BFC413E7042CB00728B00039 +:102D9000DA2003880A28824CC0D10B8000DBA065B2 +:102DA000AFE763FFA62A2C74C0B02C0A02580D8D21 +:102DB0001CE7289CA08B2008BB1106BB029BA189A5 +:102DC0003499A263FF790000262468DA20DB30DC26 +:102DD00040DD50580FDCD2A0D10FDA202B200C5848 +:102DE0000F53C020D10F00006C1006073D14C080A7 +:102DF000DC30DB40DA20C047C02123BC3003283858 +:102E00000808427740022DDC016481571EE6E01974 +:102E1000E6E129E67E6DDA0500508800308CC0E0DE +:102E2000C02025A03C14E6DFB6D38FC0C0D00F87EA +:102E3000142440220F8940941077F704C081048243 +:102E400038C0F10B2810C044C02204540104FD38DE +:102E500002520102FE3808DD10821C07EE100E6ED1 +:102E6000020EDD02242CFEC0E004FE380AEE100E35 +:102E700088020D88028DAB1EE6CF08D8020E8802AC +:102E800098B0C0E80428100E5E0184A025A1250892 +:102E90004411084402052514045511043402C0816C +:102EA0000E8E3994B18FAA84109FB475660A26A13C +:102EB0001FC0F206261460000726A120C0F20626D5 +:102EC000140565020F770107873905E610077810AA +:102ED00008660206550295B625A1040AE6110858AF +:102EE0001108280208660296B7C0606440566490D4 +:102EF00053067E11C0F489C288C30B340B964598E3 +:102F000047994618E6B79F410459110E99021FE6EA +:102F1000B5020E4708D8029F4098420E9902B43875 +:102F2000C1E00E990299442FA00C0CF91114E6A3EC +:102F30001EE69BA4FFAE992E928526F4CF0E880B39 +:102F4000289685D10F2BA00C0CBE111CE69C1FE609 +:102F500093ACBBAFEE2DE28526B4CF0D3D0B2DE635 +:102F600085D10F00C08005283878480263FEA5632C +:102F7000FE9900006C1006C0B0C0A6C0C06570F01D +:102F80008830C0300887140888406580D3C0E0C00E +:102F900091C0D4C08225203C0B3F109712831CC0E7 +:102FA000700858010D5D01089738C0800B983807EC +:102FB0007710048810086802087702C0800D9838DE +:102FC0002D3CFE0888100D9E388D2B0AEE1008EE61 +:102FD0000207EE020CB8100FDD02053B400EDD02C9 +:102FE0009D408920043D100899110D99022D21045E +:102FF00009A90208DD119941872A05B9100D3D0282 +:103000000ABB110DBB0208770297442821258712BD +:10301000082814048811071E4007EE100E99027547 +:10302000660926211F0626146000060026212006B8 +:1030300026140868029B47098802984629200CD26A +:10304000C0C0800C9E111BE65D1FE654AB99AFEE2D +:103050002DE2852894CF0DAD0B2DE685D10F000014 +:10306000001FE6502FF022C03065FF20C03163FF03 +:103070001BDD408E51CAE00E7836981008770CB2EE +:10308000AAB1BB8F502DDC1098D99FD889538F528D +:10309000991199DB9FDA7E830AB1CC255C10C9783F +:1030A00063FFCF0088108D1108E70C9751AD8DD7C5 +:1030B000F078DB01B1F79D5397528830C030088714 +:1030C00014088840648EC565BFA163FF93000000AB +:1030D0006C1004D720B03A8820C0308221CAA17475 +:1030E0002B1F2972046D080FC981C9928575B133F0 +:1030F000A2527A3B0C742B0963FFE90000649FEB3A +:10310000D10FD240D10F00006C1008D630C070959E +:1031100015DA408E3914E6239A1464E0026451F8FB +:103120002920062A9CF865A25B2A21020A0B4C651D +:10313000B21B2C320015E61974C7052D212365D367 +:10314000202E529E1AE6156FE8026002172AA22668 +:1031500068A0082B22000ABB0C65B2082E529D1DE8 +:10316000E61064E1FF8B3864B2299E16C8BC8D69F5 +:103170001EE60D64D0052EE0217BEB492E200C18B5 +:10318000E6070CEF11A8FF29F286C186798B4A1752 +:10319000E60407E70A2772A3687004882077893954 +:1031A00025F28564529E27212E07B73607B90C6F8A +:1031B0009D01D7B089696E924228203D7B873C8A69 +:1031C00015CDAF600018C1B28C202A200C580E8B90 +:1031D000D5A064A2A88B6863FFCBC05063FFC3C0B7 +:1031E000E06000022E60030E9B0C6EB20EDC700CD1 +:1031F000EA11AA6A2AAC285BFFB6D7A0DA20DB70F6 +:10320000C1C42D211F580E338C268B27D4A00CBB94 +:103210000C7AB3258A63C0909A5388629958985261 +:103220008F659F598E679E5B8D6697559D5A8B68FB +:103230007B7B748B15CEB360000DDA20DB40580D1C +:10324000FD65A10963FFCC00DA20DB308C14580D3A +:10325000A4D6A0C0C0C0D19D152CA403DA20DB6089 +:10326000DF70DC50C0E02560039E101EE5E60C5DBB +:1032700011AD6D2DDC285BFF3F8E66A5A88F6728FA +:103280006403AF7F77FB01B1EE9E669F678D268C4E +:1032900029A4DD0DCC0C9D268B680C0C482C252513 +:1032A00007BB0C9B6863FEC32C20668961B1CC0C04 +:1032B0000C472C24666EC6026000B409FD5065D030 +:1032C000AECBBB8E69CBE7DB60DC50DF70DA201E53 +:1032D000E5E12D6003C08098100CDD11AD6D2DDC93 +:1032E000285BFF248B15C84F8A268929A4AA9A2611 +:1032F0000A990C09094829252565B13BC020D10F41 +:10330000DB602D6C28DF70DA20C0C01EE5D29C1077 +:10331000DC505BFEB563FFCB002D203D0D4D4065BD +:10332000DDFD6FE522DA308F456DE90C8EAA0E8E39 +:1033300014C9E37EF3112AAC10C090292467090F49 +:103340004764FDDB60014100C09163FFED0088151B +:1033500065814CDA20DB608C14580D61C020C09070 +:1033600029A403D10FDA20C0B6580DF063FFDE00A8 +:103370008A162B2104580C87C0A02A24668B686308 +:10338000FF3E0000002B9CF965B0C5DA20580C8C7C +:1033900063FD95002B200C0CBA11A5AA2FA286C1A3 +:1033A000C27FC3026000FC0DB90A2992A36890078E +:1033B0008C2009CC0C65C0EB26A2856460E52C202E +:1033C000668931B1CC0C0C472C24666FC60270960E +:1033D0000ADAE02B2104580C6F272466893077978E +:1033E0004B18E57F1DE5808A328B33C0F42C210415 +:1033F000099E4006EE1104CC110ECC029F61C1E083 +:103400000ECC029D608F2B9A669B679C6497650823 +:10341000FF029F622F200C18E5690CFE11A5EE2D0E +:10342000E285A8FF27F4CF2DDC202DE6858F1565DA +:10343000F091C020D10F00002A2C748B1458064A3A +:10344000D2A0D10F00DA20DBE0580DB863FEFE00F9 +:1034500000DA20DB308C148D15580E3AD2A0D10F33 +:1034600000008815C888DA20DB30580C972A210222 +:1034700065AEDAC09409A90229250263FECFDA20DD +:103480002B200C580DC363FEC4272468DA20DB30E0 +:103490002C12042D12052E0A80580C9C63FC80000F +:1034A000C020D10FDA20580DA18A15CDA1DA200352 +:1034B0003B022C1204580D0A27A403C020D10F0090 +:1034C000C020D10F2A2C748B14580627D2A0D10FFC +:1034D0006C100E282102941008084C65835E1FE5CD +:1034E0002F29F29E6F98026003621DE52B29D226D8 +:1034F0006890082A220009AA0C65A3502CF29D644A +:10350000C34A2B200C0CB611AF66286286C1EC783A +:10351000E30260034219E52209B90A2992A36890DF +:10352000078A2009AA0C65A32E246285644328C05B +:10353000E12A3109C07027246689359A12992A88B0 +:10354000369913982B89379814992C88389915082F +:1035500058149816982D89392A25042E251D2925B9 +:103560001C283028C09228243C2A30290808479873 +:10357000170989012A243D2A311599180A09410998 +:10358000A90C299CEC29251F7E87192D2A000DA046 +:103590006000083E010A3EB1AD08DA390EAA110AF0 +:1035A000990C29251F27211F18E52C078160010888 +:1035B0003E000D3EB18A0DA8392D9CFC2D2520C161 +:1035C0009009883608DD1C08771C893D8A3C2E2628 +:1035D000132E26142E26152E246B2925222A25216A +:1035E000282014C0A027252E2D252F0808432D2183 +:1035F0001C282414C07027252427252527252C279F +:10360000261827261B2724672724682932112725F7 +:103610002399196ED2156D080AB1AA00A10400E918 +:103620001A7D9B0563FFEE00000089191DE4FDC0B3 +:10363000E0C0729B1D8813951B9F1F9C1E961C1C2F +:10364000E50826203DC0F006054008DB14076601AA +:103650000D8810C071057E38067F3885120BFF106B +:1036600016E4E60AEE1096400FEE020D5511B0AFCB +:1036700009FF110FEE021FE4F90855020FEE02C018 +:10368000F49F418A209F4996489C4B9B4E9D439EA8 +:10369000468D161EE4DA8B15C7CF9C4D9C4C9C457D +:1036A0009C440BD8140EAE020DBB109E4A9E4208DD +:1036B0005502954F0D181415E4CD0D88110588029B +:1036C000984718E4E885262E46122E461A2E4622E2 +:1036D0002646102646182646202F46112F46192F1B +:1036E00046212846242846262C46142C461595119A +:1036F0008C1718E4DD0505488F1805551109064893 +:1037000028461389140E66110655020F7F390C3EA8 +:103710004002EE1017E4D60D99110C26400F6611E9 +:103720000B99020C0C408B1D01CC1006FF022746A2 +:103730001B294616C07029311616E4CD0ECC0205A1 +:10374000FF021EE49C15E4CB2F461726461CC0F052 +:10375000861C2F461D2F461F2F46272546230ECC9D +:1037600002851B2C461E1EE4C41CE48E8F1F8CC7D2 +:103770002E4625ADCC28200629246A2431179C2DFD +:103780002425238C1ECC81272407C0D77F97188E31 +:10379000110928419E2964808E644098C098094987 +:1037A000362D240660000B00644075C09809493628 +:1037B0002D240601C4042D0AA02E210428628508A8 +:1037C000EE11AD88286685863F843E2D321006486E +:1037D0001898C300C40406461818E47804C45300BB +:1037E000661106DD02A8B82784CF9DC409064E964F +:1037F000C51DE4A305A61106440216E4A09DC0065B +:10380000440294C2C04304EE029EC114E46326F253 +:103810009D2744A2266C1826F69D655042C020D1F3 +:103820000FC09063FF890000654F70C098C0E82EFC +:10383000240663FF7D2D2406C09063FF75CC57DA04 +:1038400020DB308C10580C26C020D10F00DA20C0AD +:10385000B6580CB663FFE500DA20580CB463FFDC01 +:103860002A2C748B10580540D2A0D10F6C1006285A +:1038700020068A336F8202600161C05013E4472939 +:10388000210216E446699204252502D9502C201500 +:103890009A2814E4448F2627200B0AFE0C0477098B +:1038A0002B711C64E1398E428D436FBC0260016F45 +:1038B00000E104B0C800881A08A80808D8029827B0 +:1038C0002B200668B32ECE972B221E2C221D011111 +:1038D000027BC901C0B064B0172CB00728B000DA71 +:1038E0002003880A28824CC0D10B8000DBA065AF82 +:1038F000E7C020D10F2D206464DFCA8B29C0F10BF3 +:10390000AB0C66BFC02B200C0CBC11A6CC28C28609 +:103910002E0A0878EB611EE4220EBE0A2EE2A3688E +:10392000E0052822007E894F29C2851EE42E64907E +:10393000461FE43C9E90C084989128200A95930FDE +:10394000880298928E200FEE029E942F20078826E0 +:103950002F950A98969A972E200625240768E34308 +:103960002921021AE4162DC285AABA2DDC202DC603 +:103970008525A4CF63FF4E002B2065CBBDC0C22C94 +:103980002465C9F605E4310002002E62821FE41EA0 +:103990002D41020FEE022E66820DE43129210263D1 +:1039A000FF23000064DFB889422820160091040D2F +:1039B000880C00881AA8A8982963FFA38C202D32B0 +:1039C00021B1CC9CD02B32212A3223B4BB2B3621FF +:1039D0007BA9A92D32222D362163FFA0C020D10F53 +:1039E0009F27252415ACB828751C2B2006C0C12E96 +:1039F000BCFE64E0AB68B7772DBCFD65DEC72D204B +:103A000064C0F064D0868E290EAE0C66E089C0F1E9 +:103A100028205A288CFE08CF3865FEE863FF58003E +:103A200000E0049310C0810AF30C038339C78F08A8 +:103A3000D80308A80108F80C080819A83303C80C13 +:103A4000A8B828751C030B472B24158310CBB7008F +:103A5000E104B0BC00CC1AACAC0CDC029C27659E27 +:103A60005EC0B20B990209094F29250263FE50007E +:103A70002D206A0D2D4165DF7EDA20C0B0580C7212 +:103A800064AF18C0F163FEEF9F2763FFD02E221FA3 +:103A900065EE3263FF79000028221F658E2763FFE1 +:103AA0006E252406252502C09063FE196C1006655C +:103AB00071332B4C18C0C7293C18C0A1C08009A87D +:103AC000380808426481101CE3B11AE3B22AC67EAA +:103AD0002A5CFDD30F6DAA0500B08800908C884049 +:103AE000C0A00889471FE3DB090B47084C50080DAD +:103AF0005304DD10B4CC04CC100D5D029D310CBB21 +:103B0000029B3088438E2098350FEE029E328D2620 +:103B1000D850A6DD9D268E40C0900E5E5064E09782 +:103B20001CE3C11EE3B0038B0BC0F49FB19EB02D0C +:103B3000200A99B30CDD029DB28F200CFF029FB4C6 +:103B40008E262D20079EB68C282DB50A9CB72924D9 +:103B5000072F20062B206469F339CBB61DE392238F +:103B600020168DD20B330C00D10400331AA3C3B43A +:103B70008D932922200C13E3911FE3880C2E11AFA3 +:103B8000EEA3222924CF2FE285D2A00FDD0B2DE654 +:103B900085D10F00B48C2E200C0CEB111FE3881D77 +:103BA000E37FAFEEADBB22B28529E4CF02C20B2288 +:103BB000B685D2A0D10F00002E200C0CEB111FE314 +:103BC0007F1CE376AFEEACBB22B28529E4CF028244 +:103BD0000B22B685D2A0D10FC0D00BAD387DC80264 +:103BE00063FEEC63FEE08E40272C747BEE12DA70ED +:103BF000C0B32C3C18DD50580A77C090884063FE53 +:103C0000E3066E02022A02033B02DC40DD5058004C +:103C1000049A10DB50DA70580454881063FEF600E2 +:103C20006C10082E3C18C0A092161FE3688C40AFA1 +:103C30002F0C8C47C02304CB0BDDB07FB3022DBD0E +:103C4000F8D9D0C0B075C30260008D9F146D084FC5 +:103C50008D900D6D36ADAA0D660C0EB70B0EBF0A1A +:103C60009DF0B877B89FD8F000808800708C9711CD +:103C700087909810971568B12AB22277D32D889132 +:103C8000C0D0CB8F9890279C10007088971200F0BE +:103C90008C9F139D916460A0C08108BB0375CB38D5 +:103CA00063FFA900B1222EEC1863FFCE85920D7739 +:103CB0000C86939790A6D67D6B01B15595929693FD +:103CC0008942600017B3CC299C188814DD90789342 +:103CD000022D9DF8D9D063FFBB8942DA9085160C7E +:103CE0000D472D44021BE36792319B3086437A9146 +:103CF000261BE3581EE36589500E660196350B9925 +:103D000002993288420A880C98428756A7A797568C +:103D10008F44AFAF9F44D10F1BE34F895096350BB3 +:103D20009902993288420A880C98428756A7A79729 +:103D3000568F44AFAF9F44D10F894263FF9E00006E +:103D40006C10061FE3529310D6308830C091086380 +:103D5000510808470598389811282102293CFD0888 +:103D6000084C6581576591542A62030A2B5065B14E +:103D70007E0A68142E0AFF7CA60A2C205ACCC42D79 +:103D80000A022D245A78E0026002088A288926183F +:103D9000E3400A990C6592032E200B1CE33F08EECA +:103DA0000B2EED012DE0322EE03308DD110EDD0289 +:103DB0001EE339AFDD0EDD010DCC372D200C8960FF +:103DC000C1E07B96231AE2F78B622AA0219C127B2A +:103DD000A316DAD0C1B00B4B37B4BB8C20580B877D +:103DE0008C12DBA0CEAB6001BF0E4E371BE2EC0C99 +:103DF000DA11ABAA28A286B8EE78EB351EE2E90EFE +:103E0000DE0A2EE2A368E00488207E89242BA285A6 +:103E100064B0A28762DE700C79369B1388268D27EA +:103E2000097A0C08DD0C6FAD0E77D3107E7B6960CC +:103E3000001FC0B063FFD800D79063FFEB9C12DA7D +:103E400020DB70580AFC8B138C1265A06F8E627E8B +:103E50007B469C129B13CC5FDA208B10044C0258DB +:103E60000AA0D6A08B13250A01DE70DA20DC60DD03 +:103E7000405BFF6B8C12D9A02D200CC0E01BE2C769 +:103E800017E2CF0CDA11A7D7ABAA2BA2852E74CFDD +:103E90000B990B29A68563FF24DA20DC60DD40DE68 +:103EA000708911282007DF50A9882824075BFEFFAE +:103EB000D2A0D10F0000DBD0DA20580B1C6550F3E4 +:103EC0002A20140A3A4065A0EEDB60DC40DD30DADF +:103ED0002058098E1FE2EED6A064A0D784A183A04B +:103EE0000404470305479511036351C05163FE68FD +:103EF0002C200628CCFD6480A868C704C093292420 +:103F000006C0C18E6419E2A79E269E299E2889922A +:103F10009E2700910400CC1A009004B0C88D65085B +:103F2000EE01AECC0D0E5E01EE11AECCB0CC2E0A81 +:103F3000FE0C0C190ECC36C0E20C0C470ECC372C04 +:103F40002416C0B02B24072C20061BE29F0A0E4526 +:103F50000D084228240B2E240AB48929240C7DB88C +:103F60005A2920160A5D52B09E0EDD362D24642B90 +:103F7000CCFD65BDFB0D0C4764CDF51DE28A88289C +:103F80008DD20C9B0C00D10400BB1AAB889829631E +:103F9000FDDE00001CE2B963FE2000001CE2AF63FE +:103FA000FE188D6563FFA20000DA202B200C580A52 +:103FB000F8645F0BC020D10FC020D10FC093C0E3C5 +:103FC0002E241663FF9D00006C1004C06017E2727F +:103FD0001DE275C3812931012A300829240A78A1FC +:103FE00008C3B27BA172D260D10FC0C16550512607 +:103FF00025022AD0202F200B290AFB2B20142E204B +:104000001526241509BB010DFF0928F11C2B2414CA +:10401000A8EE2EF51C64A0B52B221E28221D01112E +:10402000027B8901DB6064B0172CB00728B000DA8E +:104030002007880A28824CC0D10B8000DBA065AF26 +:10404000E7DB30DC40DD50DA205800D829210209B6 +:104050000B4CCAB2D2A0D10F00CC5A2C30087BC175 +:10406000372ED02064E02D022A02033B02DC40DD23 +:10407000505800CED2A0D10F2B2014B0BB2B24144B +:104080000B0F4164F0827CB7CAC0C10C9C022C2586 +:1040900002D2A0D10FC020D10F2E200669E2C12F7D +:1040A00021020F0F4C69F1B82624062625022B2287 +:1040B0001E28221D2A200B2920150DAA092CA11C1F +:1040C000262415AC9929A51C7B814A600049B0BB08 +:1040D0002B24140B0D41CBD67CB7022C25022B22AE +:1040E0001E2E221D7BE9022B0A0064B0172CB0079C +:1040F00028B000DA2007880A28824CC0D10B800043 +:10410000DBA065AFE7C020D10F262406D2A0D10FD7 +:1041100026240663FFC7DB601DE22364BF422CB088 +:104120000728B000DA2007880A28824CC0D10B800B +:1041300000DBA065AFE71DE21B63FF246C100428C1 +:104140002006C0646F8564CA5B2920147D9726DA37 +:1041500020DB30DC40055D02580019292102090AE4 +:104160004CC8A3C020D10F00C0B10B9B022B25026D +:10417000C020D10F0000022A02033B022C0A015882 +:1041800000C9C9AADA20DB30DC405809D529A011C2 +:10419000D3A07E97082C0AFD0C9C012CA411C051C1 +:1041A0002D201406DD022D241463FFA2DA20DB305B +:1041B000DC40DD50C0E0580955D2A0D10F0000000E +:1041C0006C100616E1F61CE1F665513BC0E117E103 +:1041D000F22821028B2008084C65807C29320009D6 +:1041E00069516993732A629E6EA8482A722668A054 +:1041F000027AB93F2A629DB44FCBA72B200C0CBD8D +:104200001106DD0828D28678FB150CBF0A2FF2A311 +:1042100068F00488207F89072DD285D30F65D06090 +:104220002A210419E21ED30F7A9B1DDA2058085365 +:10423000600025002C21041BE2197CBB14DA20C08D +:10424000B658084EC9546000EFDA20580A386000AA +:104250000700DA20C0B6580A356550DCDC40DB3098 +:104260008D30DA200D6D515808A9D3A064A0C91C67 +:10427000E1CCC05184A18EA00404470E0E4763FF19 +:104280004F2B2104C08C8931C070DF7009F95009AF +:104290008F386EB8172C2066AECC0C0C472C2466D9 +:1042A0007CFB099D105808BB8D1027246694D11EF5 +:1042B000E1D2B8DC9ED0655056C0D7B83AC0B1C084 +:1042C000F00CBF380F0F42CBF119E1B018E1B22862 +:1042D000967EB04BD30F6DBA0500A08800C08C2C21 +:1042E000200CC0201DE1B60CCF11A6FF2EF285AD2B +:1042F000CC27C4CF0E4E0B2EF685D10FC0800AB846 +:104300003878D0CD63FFC1008E300E0E4763FEBDFE +:104310002A2C742B0A01044D025808AE2F200C12CF +:10432000E1A70CF911A699289285A2FF27F4CFD214 +:10433000A008480B289685D10FC020D10F0000009F +:104340006C1004C060CB55DB30DC40055D02022AF6 +:10435000025BFF9B29210209084CC882D2A0D10F21 +:104360002B2014B0BB2B24140B0C41CBC57DB7EB19 +:10437000C0C10C9C022C2502D2A0D10F0000022A41 +:1043800002033B02066C02C0D0C7F72E201428316E +:104390000126250228240A0FEE012E241458010CB0 +:1043A00063FFA300262406D2A0D10F006C100628BC +:1043B0002102D62008084C6580992B200C12E17749 +:1043C0000CB811A2882A8286B5497A9302600093BC +:1043D00019E17409B90A2992A36890082A620009B0 +:1043E000AA0C65A07E2882851CE17F6480759C8074 +:1043F000B887B14B9B819B10655072C0A7D97028BC +:104400000A01C0D0078D380D0D42CBDB1FE1601EC5 +:10441000E1612EF67ED830D30F6D4A05008088000A +:10442000908CC0802F30082F740029600C1AE16333 +:104430000C9D11A2DD2CD285C020AA992294CF0C0C +:10444000BC0B2CD685D280D10FC0E0038E387EA065 +:10445000C363FFB7CC582A6C74DB30DC405807E1EB +:10446000C020D10FDA605809B163FFE70000DD40DA +:1044700085102A6C74C0B0DC705808562F30082F95 +:10448000740028600CC0F00C8B11A2BB29B28512FD +:10449000E14B09590BA2822F24CF29B685D2A0D196 +:1044A0000F0000006C1004292014282006B199295F +:1044B0002414688124C0AF2C0A012B21022C24066D +:1044C0007BA004C0D02D2502022A02033B02044C2B +:1044D00002C0D05800BFD2A0D10FC020D10F000021 +:1044E0006C1004293101C2B429240A2A3011C28374 +:1044F00078A16C7BA1696450472C2006C0686FC509 +:1045000062CA572D20147CD722DA20DB30DC40DD54 +:10451000505BFFA6292102090E4CC8E2C020D10F32 +:10452000C0F10F9F022F2502C020D10FDA20DB300F +:10453000C0C05BFFDC28201406880228241463FF17 +:10454000C72920151BE1182A200BC0C09C240BAAE8 +:10455000092BA11C2C2415AB9929A51C63FF9900DC +:10456000C020D10FDA20DB30DC40DD50C0E058083D +:1045700067D2A0D10F0000006C1004CB5513E113DB +:1045800025221F0D461106550CA32326221E252683 +:104590001F06440B24261E734B1DC852D240D10F58 +:1045A000280A80C04024261FA82828261E28261D49 +:1045B000D240D10FC020D10F244DF824261E63FF16 +:1045C000D80000006C1004282006D6206E850260FA +:1045D00000DE17E0F21DE0F919E0F2C0C1C0202AA8 +:1045E0008CFC64A1322B6102B44E0B0B4C65B0A85D +:1045F0002B600C2A62000CB8110788082F828609EC +:10460000B90A7FE30260009F2992A368900509AA76 +:104610000C65A09328828564808DB8891BE0F7948F +:10462000819B8065514DC0B7B838C0A1C0E009AECC +:10463000380E0E4264E0481AE0D51FE0D62FA67E61 +:10464000B04A6DAA0500808800908CC0A02E600C36 +:104650000CE811A7882F8285ADEE0F4F0B2F8685B2 +:104660002B600622E4CF68B12A296015C0B2C99A2E +:10467000D2A02D61022B64060CDD022D6502D10F44 +:10468000C0E008AE387EB0B763FFAB00226406D24C +:10469000A0D10F00D2A0D10F00CC57DA60DB30DC04 +:1046A0004058088FC020D10FDA6058092063FFE816 +:1046B0000028221E29221D789902280A00C176C1ED +:1046C000C1C1D21BE0C2C124AB6B6480437891406E +:1046D0002A80000CAF0C64F0AE0DAE0C64E0A802B2 +:1046E000AF0C64F0A207AE0C64E09C2FACE864F061 +:1046F000962EACE764E0902FACE664F08A2A80073F +:1047000008A80B088A027B83022A8DF8D8A065AF1F +:10471000BBC09060007300002B600C0CB811A78820 +:104720002E82866EE87909BA0A2AA2A368A0048EAE +:10473000607AE96B2A828564A0651FE0AAC0E32E37 +:1047400064069EA19FA01FE0D62E600A92A30FEEE2 +:10475000029EA28E600FEE029EA42F60147AFF4785 +:1047600022A4172F8285ADBE22E4CF2FFC182F86FE +:104770008563FE702A6C74C0B1DC90DD40580795EB +:104780001DE08FC0C163FEC4D9A0DA60DB30DC401D +:10479000DD50C2F0C1E009FE395807DCD2A0D10FCC +:1047A000DA605808E263FEF02CA4172982850DBE5A +:1047B0000822E4CF299C1829868564500C2A6C7441 +:1047C000044B02580169D2A0D10FC020D10F0000C4 +:1047D0006C10062B221E28221D93107B8901C0B06D +:1047E000C0C9C03BC1F20406401DE078C0E2C074FD +:1047F0000747010E4E01AD2D9E11C0402E0A1464D4 +:10480000B06E6D084428221D7B81652AB0007EA110 +:104810003B7FA1477B51207CA14968A91768AA1456 +:1048200073A111C09F79A10CC18B78A107C1AE29DA +:104830000A1E29B4007CA12B2AB0070BAB0BDAB0FF +:104840007DB3022ABDF8DBA0CAA563FFB428B0106F +:1048500089116987BB649FB863FFDC00647FB46320 +:10486000FFD50000646FD0C041C1AE2AB40063FF21 +:10487000C62B2102CEBE2A221D2B221E7AB12A8CE3 +:10488000107CB1217AB901C0B0C9B913E043DA2074 +:1048900028B0002CB00703880A28824CC0D10B80B6 +:1048A00000DBA065AFE7D240D10F8910659FD463CC +:1048B000FFF300006C1008C0706451718F30292123 +:1048C000020F0F4716E036090C4C65C08F8D300D76 +:1048D0006E5168E30260008428629E1AE02F6E88A1 +:1048E000522AA22668A0048B207AB9472A629DB07A +:1048F0004ECBAF9A102B200C9E110CBC11A6CC29CC +:10490000C286B748798B4117E02607B70A2772A3FA +:1049100068700488207789302CC2859C12D7C065C6 +:10492000C0622C21041AE05D7CAB22DA2058069389 +:10493000600029002E21041DE0597EDB18DA20C01A +:10494000B658068EC958600156C0C063FFCCDA2045 +:10495000580876600006DA20C0B658087465513FE2 +:10496000DC40DB308D30DA200D6D515806E8D3A0E5 +:1049700064A12CC05129210284A18FA00404470FF7 +:104980000F4763FF412B2104C08C8931C0A009F976 +:1049900050098A386EB81E2C2066AFCC0C0C472C00 +:1049A00024667CAB109E142A12005806FA8E14C09E +:1049B000D02D24668D30C0921BE010C1F87FD60C3C +:1049C00087129B702976012F7408277C106550B7D9 +:1049D000B83AC0D7DC70C051C080075838080842C8 +:1049E0006480791DDFEA19DFEB29D67E6A420AD39B +:1049F0000F6DE90500A08800C08CC0A08830C0926F +:104A00007F863807E80B2F84089B809981B4E82CB7 +:104A1000200CC0901DDFEA0CC311A633223285ADF5 +:104A2000CC02820B29C4CF223685D2A0D10F8A3086 +:104A3000C0F17EAE3229210263FE88002C200C8E4C +:104A400011C0B01DDFDE0CCF11A6FF22F285ADCC68 +:104A50002BC4CF02EE0B2EF685D2A0D10FC0800A58 +:104A6000583878D08663FF7A9F13DB30DA20C0C1D4 +:104A7000DD705BFF572921028F132A9CFE65AE4330 +:104A8000272502C09063FE3B9E142A2C74C0B1DC23 +:104A900070DD405806D08E141BDFD8C1F863FF5B71 +:104AA000C020D10F6C100628210216DFBC08084C6C +:104AB00065821529629E6F980260021C19DFB72972 +:104AC00092266890078A2009AA0C65A20B27629D8E +:104AD000C0CC6472032B21048E31C0A0DDA00EFE79 +:104AE000500ECD386EB8112C20662CCC010C0C4722 +:104AF0002C24667CDB026001EAC0C12930081BDF80 +:104B0000A96490972F0AFFC0D3B09E64E0FD68921D +:104B10000E6450832A2C74DB40580093D2A0D10F2E +:104B20002B200C2721040CBC11A6CC29C286280AF4 +:104B3000087983026001B919DF9A09B90A2992A399 +:104B40006890082E220009EE0C65E1A42EC285644F +:104B5000E19E26200713DFA36E7B0260019A17DF18 +:104B60009A1FDFA319DFD0C0D228200A93E09DE16D +:104B7000A9690F880298E22F90802A9480B1FF07DC +:104B8000FF029FE31EDF8E2FC285AEBE0FDF0B2F0D +:104B9000C6852AE4CF655F7BC020D10F2F30102956 +:104BA00030112E301300993200ED3264F0EE2A30CD +:104BB000141FDFBD00AA3278EF050F9E092DE47F98 +:104BC0001EDFBB66A0050F98092A8480B4A718DFF2 +:104BD000B8C76F009104AE9EDDE000AF1A00C31AA3 +:104BE0006EE1052DB2000DED0C1EDFB208D81C06DB +:104BF0003303AE882A848B2EB02E27848C03EE01DB +:104C00000FEE022EB42E58018F63FF0429310829BC +:104C100025042830142E3109B0886480A32E240A7C +:104C2000C0812E30162CB4232E240BB4EF2F240C6D +:104C30008C378B36292504DEB0DFC00F8F390E8EFE +:104C4000390FEE0264EEC9089F1101C4048D380CBF +:104C5000B81800C4040CBE1800EE110EDD02C0E34B +:104C60000EFF021EDF879F719E701EDF848F2098CB +:104C7000739D7405FF110BCD53C18098750FDD0234 +:104C80000EDD029D722A24661EDF442F629D2AE4F7 +:104C9000A22FFC182F669D63FE760000002F3012B5 +:104CA0001BDF8600FA3278FF050B980B2A847F669B +:104CB000D0050B9A0B2DA4802A301100AA3263FF75 +:104CC000442F240A9E2B63FF56CC57DA20DB30DCBE +:104CD00040580703C020D10F00DA20C0B658079310 +:104CE00063FFE500DA7058062BC0A02A246663FE35 +:104CF00007DA2058078E63FFCFB16928200A862083 +:104D0000090947991129240798107F812693E027E4 +:104D1000E50A9AE388109DE119DF628D11096F029F +:104D20009FE42DE416098802C0D398E22A24076381 +:104D3000FE5100001FDF2B08691188118D2B93E0B5 +:104D4000098802C09F98E50FDD020478119DE2C03A +:104D5000F49FE1C0D409880298E463FFCE0000000C +:104D60006C1004C020D10F006C100485210D381187 +:104D700014DF088622A42408660C962205330B93C0 +:104D800021743B13C862D230D10FC030BC299921A5 +:104D900099209322D230D10F233DF8932163FFE372 +:104DA0006C100AD620941817DEFDD930B83898193F +:104DB0009914655252C0E1D2E02E61021DDEFA0E56 +:104DC0000E4C65E1638F308E190F6F512FFCFD651E +:104DD000F1568EE129D0230E8F5077E66B8F181E87 +:104DE000DF37B0FF0FF4110F1F146590CE18DF34BA +:104DF0008C60A8CCC0B119DEE828600B09CC0B0D83 +:104E0000880929811C28811A2A0A0009880C08BAF5 +:104E1000381BDF2A0CA90A2992947B9B0260008C24 +:104E20002B600C94160CBD11A7DD29D286B84879E9 +:104E300083026000D219DEDA09B80A2882A3981723 +:104E40006880026000A36000A51ADF1E84180AEEC5 +:104E500001CA981BDED18C192BB0008CC06EB31325 +:104E60001DDECE0C1C520DCC0B2DC295C0A17EDBDD +:104E7000AE6000380C0C5360000900000018DF1011 +:104E80008C60A8CCC0B119DEC428600B09CC0B0D16 +:104E9000880929811C28811A2A0A0009880C08BA65 +:104EA000380CA90A2992947E930263FF72DA60C0DB +:104EB000BA58071E64507460026600001ADEB78C90 +:104EC000192AA0008CC06EA31A18DEB30C1C52085D +:104ED000CC0B18DEFA2BC295C0A178B30263FF3F5A +:104EE00063FFC9000C0C5363FF0989607899182986 +:104EF000D285C9922B729E1DDEA86EB8242DD226B3 +:104F0000991369D00C60000EDA6058070860001829 +:104F1000000088607D890A9A1A29729D9C12991551 +:104F2000CF94DA60C0B65807016551F48D148C181F +:104F3000DBD08DD0DA600D6D51580574D3A09A1472 +:104F400064A1DD82A085A1B8AF9F190505470202C3 +:104F5000479518C05163FE602B6104C08C8931C035 +:104F6000A009F950098A386EB81F2C6066A2CC0CD3 +:104F70000C472C64667CAB119F119E1B8A1558054B +:104F8000858E1B8F11C0A02A64669F1164F0E18991 +:104F9000138819DEF06DE9172F810300908DAEFEA6 +:104FA0000080889F9200908C008088B89900908C37 +:104FB00065514E8A10851A8B301FDE8A881229604F +:104FC0000708580A2C82942D61040ECC0C2C869470 +:104FD0006FDB3C1CDEB4AC9C29C0800B5D50A299F9 +:104FE00009094729C48065D0DA2E600CC0D01FDEC5 +:104FF000730CE811A788228285AFEE02420B2DE4E4 +:10500000CF228685D2A0D10F8E300E0E4763FDA62B +:10501000A29C0C0C472C64077AB6CD8B602E600ADC +:10502000280AFF08E80C64810E18DE9D831682139F +:10503000B33902330B2C34162D350AC02392319F1D +:1050400030C020923308B20208E80292349832C08D +:10505000802B600C286407D2A01CDE580CBE11A760 +:10506000EE2DE285ACBB28B4CF0D9D0B2DE685D18E +:105070000F8B1888138D30B88C0D8F470D4950B4A5 +:10508000990499100D0D5F04DD1009FF029F800D3A +:10509000BB029B8165508D851AB83AC0F1C0800C67 +:1050A000F83808084264806B1BDE3919DE3A29B6ED +:1050B0007E8D18B0DD6DDA0500A08800C08CC0A020 +:1050C00063FEF3001DDE4B28600A82138B16C0E0DE +:1050D0002EC48002B20B0D8802B2BB99239F20C060 +:1050E000D298229D2122600C0C2D11A7DD28D2859B +:1050F00008BB0B18DE322BD685A8222E24CFD2A0D7 +:10510000D10F9E1B851A2A6C748B185BFF178E1BA0 +:1051100063FEA300C087C0900AF93879809263FFCC +:1051200086C020D10F9E1B2A6C74C0B18D18580503 +:10513000298E1B851A63FE7E886B8213891608BE32 +:10514000110ECE0202920B9E25B4991EDE259F20E1 +:105150000E88029822C0EF04D8110E88029824C04D +:10516000E49E21C080D2A02B600C2864071CDE13B3 +:105170000CBE11A7EE2DE285ACBB28B4CF0D9D0B64 +:105180002DE685D10F0000006C1004C020D10F0067 +:105190006C10048633C071C030600001B13300313F +:1051A0000400741A0462017460F1D10F6C100402DF +:1051B0002A02033B025BFFF61DDDFB1BDE43C79F9C +:1051C00088B009A903098A019AB02BD10279801B02 +:1051D0001CDDF3C0E00EE4310002002AC2821DDEB5 +:1051E0003B0DAA022AC6820BE431D10FC1F00FBFDA +:1051F000020F0F4F2FD5020FE431D10F6C100412A4 +:10520000DDE91ADDE6C0C00CE43100020029A2820B +:1052100018DE311BDE2F2621020B990108660129B9 +:10522000A68226250206E43114DE2C15DE27236A29 +:10523000902326128550242611252613222C40D196 +:105240000F0000006C100816DE252B0A642C1AB41F +:1052500017DDD51DDDD118DE220F2E110D2A11B25A +:10526000E90EEE11A8A80E9911ADAAA799A7EE9E76 +:10527000169911ACAA9A152C80FF2A80FE288D0160 +:1052800029800108AA112880000CAA0208881109A7 +:10529000880208AA1CB88828160058085D297116CB +:1052A0009A122916038A158B122AA0800BAA288B22 +:1052B00010580857D4708C168B1315DE0A0BAB28C8 +:1052C000235C419B142BC6282C308072C9158C148A +:1052D0002A50C02B3A200CAA2858084DC0D10ADD0C +:1052E000372D4540B444B255B2337639DAB2778FB0 +:1052F000118E168815B4EEB18898159E167FE9A414 +:10530000D10F00006C1004C021D10F006C1006C03A +:10531000701ADDA21EDDAD1DDDB31CDDB51BDD9EEB +:1053200013DDE1220A0818DD9F14DDEF28802E240A +:1053300040002816006D2A70A349289080C0F164AF +:1053400080598510004104C06100661A06550105A8 +:10535000F5390C56110A66082F62966EF74D0B5FF1 +:105360000A2FF22468F00812DDD102420872F93BDC +:105370002362950C4202CB349232C0F29D309F31B1 +:105380000E8F029F33236295AB522F0A002F948019 +:105390002F24A0233C1023669513DDC2B17712DDC4 +:1053A000D2B144040442242400D10F00D10FD10F04 +:1053B0006C10041ADD792AA00058021B5BFFD3028F +:1053C0002A02033B025BFFCF1BDD77C0C429B10279 +:1053D000C8AC0C9C020C0C4F2CB5020CE431D10F64 +:1053E0001EDD6FC08008E4310002002DE2821FDD67 +:1053F000800FDD022DE68209E431D10F6C10041517 +:10540000DD6716DD68C02002E4310002002452820C +:10541000226102734F0602E431C020D10F18DDB4BF +:1054200019DDB308280109490129568228650208B7 +:10543000E43113DDA9226C7023661DD10F0000003A +:105440006C1004292006289CF96480A02A9CFD6524 +:10545000A0968A288D262F0A087AD9042B221FC8E5 +:10546000BD2C206464C0812E22090EAE0C66E0784B +:105470002B200C1EDD4A0CBC11AECC28C28619DDD7 +:105480004878F3026000A909B90A2992A368900834 +:105490002E220009EE0C65E09729C2851FDD5264BB +:1054A000908E9F90C0E41FDD5F9E9128200AC0E08F +:1054B0009E930F8802989288200F880298942F203C +:1054C000079A979D962F950A2E24072820062920B3 +:1054D0006468832F28C28512DD39288C20A2B22E61 +:1054E00024CF28C685C020D10FC020D10F2A206A22 +:1054F0000A2A4165AF55DA20C0B05805D364AFE839 +:10550000C021D10F649FCC1FDD272D20168FF209FB +:10551000DD0C00F10400DD1AADAD9D2928C2851215 +:10552000DD27288C20A2B22E24CF28C685C020D10A +:105530000FC021D10F0000006C1004260A001BDDF3 +:105540006D15DD1828206517DD15288CFE64809404 +:105550000C4D11ADBD2CD2F52BD2F42A51027CB1E9 +:10556000422A5102B4BB2ED2F72BD6F47BE9052B8D +:10557000D2F62BD6F47CB92B29D2F629D6F529D62A +:10558000F406E4310002002F7282C79F004104C07C +:105590008100881A09880308FF012F76820AE43106 +:1055A000600000002624652BD2F48E5A2CD2F5B070 +:1055B000EE9E5A7BCB1629D2F62FD2F70CB80C09E7 +:1055C000FF0C08FF0C0F2F14C8F960002F0BCD0C37 +:1055D0000D2D14CED6C0E20EAE020E0E4F2E550289 +:1055E0000EE431D10FDB30DA205BFF951BDD426426 +:1055F000AF5D2A51020C4D11ADBD63FFA906E43128 +:105600000002002E72821FDD000FEE022E76820A4B +:10561000E431D10F6C100416DCE115DCE2C030037C +:10562000E43100020024628274472118DD33875A76 +:10563000084801286682CD7319DD310C2A11AA9918 +:105640002292832992847291038220CC292B5102C9 +:105650000BE431C020D10F001FDD2A2E51020FEEC6 +:10566000012E55020EE431B02DB17C9C5A225C60B3 +:1056700008DD112D5619D10F6C100A1ADCC71DDC7C +:10568000C923A00019DD206F33791CDD07C0281560 +:10569000DD1F1EDD1D2B1C10D4B083E0005086954D +:1056A0001000408A94186D2A4F0F35110C340924CC +:1056B00040800A560A2862940D55092F51400F4424 +:1056C000110B440A08970C0F77368F400F7736225C +:1056D000514107FF0C9F40A8772F62952766940FD2 +:1056E000980C0288368741078836B13308770CAFAB +:1056F0008F2F66959741030342B13808084298E01E +:10570000D10F00001CDD0314DD03BFC52442B564C6 +:105710003055C091C0D016DD000488432BC000C0B6 +:10572000406D393E00410400971A7780162FA295EC +:105730008E50AFEE2EED2006EE369E502DA69560D3 +:10574000001A000077B00983509D5023A695600091 +:105750000223A295223D2006223622A695B144B40A +:1057600055B8AA28C400D10F04884328C400D10F1B +:105770006C100415DCEA13DCEAC04004E4310002DA +:10578000008850CB815BFFBC1CDCE70C2D11ADCC3D +:105790002BC2822AC28394507BAB142EC28429C2AE +:1057A000850ABD0C0E990C0D990C09291460000591 +:1057B0000BA90C092914993015DC7B2A51020AE443 +:1057C000312A2CFC5800492B32001EDC742BBCFF04 +:1057D0002B3600CCB5C8A3D2A0D10F00D2A004E4D0 +:1057E000310002002DE2822C51022FBAFF0FDD01A1 +:1057F0002DE6820CE431D10F6C1004D10F000000B3 +:105800006C1004C020D10F006C100413DCC7C0D191 +:1058100003230923318DC0A06F34026000891BDC93 +:1058200061C7CF18DCC00C2911A988268283258284 +:105830008219DC5A7651442752002E8285255C0459 +:1058400025868275E9052582842586827659542627 +:105850008284D5602686822686830AE4310002008F +:105860002392822FB10200210400D41A0C440304B5 +:1058700033012396820FE43160000200D7A07659ED +:10588000220AE4310002002E928200210428B10293 +:1058900000DF1A0CFF030FEE012E968208E431D2CE +:1058A00070D10F00D270D10FC020D10F6C1004DB6B +:1058B00030862015DC39280A00282502DA2028B095 +:1058C000002CB00705880A28824C2D0A010B8000A5 +:1058D000DBA065AFE61ADC320A4A0A29A2A3C7BFD9 +:1058E000769101D10F2BA6A3D10F00006C1004C03C +:1058F000D1C7CF1BDC2CC0A018DC280C2911A9882B +:105900008785858419DC2677517986508E87B45532 +:10591000958475E9038586958477596C8F869F8574 +:105920009F840AE431000200239282B42E00E10435 +:105930002FB10200D41A0C44030433012396820FC2 +:10594000E4310AE43100020023928200D41A0C44AC +:10595000030433012396820FE431D260D10F00009B +:105960000AE431000200239282B42800810422B1AB +:105970000200D41A0C440304330123968202E4315A +:10598000D2A0D10FD6A07751D6D260D10F0000009F +:105990006C1004270A801CDC281DDC281ADC000C93 +:1059A0002911AA992A2CFC2B92850DAA029CB19A46 +:1059B000B0C05113DC2528928516DC2114DC22A608 +:1059C0002604240AB888289685234691A76625646C +:1059D0009FD10F006C100419DC550C2A11A9A9895C +:1059E00090C484798B761BDC45ABAC2AC2832CC275 +:1059F000847AC1688AA02BBC30D3A064A05E0B2B34 +:105A00000A2CB2A319DC0F68C0071DDC49D30F7D37 +:105A1000C94AA929299D0129901F68913270A603BE +:105A2000D3A0CA9E689210C7AF2AB6A32A2CFC5BEB +:105A3000FFAFD230D10F000013DBEF03A3018C3195 +:105A40001DDBE00C8C140DCC012CB6A363FFDC0035 +:105A5000C020D10FDA205BFFCEC020D10FC020D1F3 +:105A60000F0000006C1004DB30C0D019DBCBDA2053 +:105A700028300022300708481209880A28824CDCA6 +:105A8000200B80001BDBC60C4A11ABAA29A284099B +:105A9000290B29A684D10F006C1004C04118DBBF6C +:105AA00017DBC10C2611A727277030A86625628650 +:105AB000007104A35500441A75414822628415DB25 +:105AC000E202320BC922882117DBBE088414074486 +:105AD00001754905C834C020D10FD10F1DDC15C098 +:105AE000B28E201FDBAD0E0E43AFEC0FEE0A2BC4BF +:105AF000A02DE624C0202A62840809470A990B29B0 +:105B00006684D10FC020D10F6C1004DB30C0D018D8 +:105B1000DBA2DA2025300022300708580A28824C00 +:105B2000DC200B80008931709E121BDB9C0C4A111B +:105B3000ABAA29A28409290B29A684D10F09C9522D +:105B400068532600910418DB97C0A12F811200AA88 +:105B50001A0AFF022F85121EDB910C4D11AEDD2CAF +:105B6000D2840C2C0B2CD684D10FC0811FDB8EB8B5 +:105B70009A0A0A4700A1042EF11200881A08EE02C0 +:105B80002EF5121DDB860C4C11ADCC2BC2840B2BD9 +:105B90000B2BC684D10F00006C1004DB30C0D01971 +:105BA000DB7EDA2028300022300709880A28824C60 +:105BB000DC200B80001CDB790C4B11ACBB2AB284BF +:105BC0000A2A0B2AB684D10F6C1004C04118DB736B +:105BD00016DB750C2711A626266030A872252286B2 +:105BE000006104A35500441A754108222284023240 +:105BF0000BD10F00C020D10F6C100415DBCE024971 +:105C000014295611245212C0730208430F88110040 +:105C1000810400361AC78F00771A087703074401FA +:105C2000064402245612D10F6C1006C0B06E230237 +:105C30006000A264209D851013DBAA16DBBEC04065 +:105C4000A6BA2BA2AE0B194164905E68915568927A +:105C50004A6893372930FF2830FE2AA2AA08881103 +:105C60000A0A4D2AACF20988027589442B3D0129A4 +:105C7000B0002BB0010899110B99027A9932B83310 +:105C80002B2A00B1447249B7600048007FBF051558 +:105C9000DBAA63FFBE253AE863FFB800253AE86354 +:105CA000FFB10000250A6463FFA9C05A63FFA40086 +:105CB00000705F082534FF058C142C34FE70AF0B88 +:105CC0000A8D142E3D012AE4012DE400DA405BFD2B +:105CD0005D63FFA9D10FD10F6C10041ADB3219DB01 +:105CE0002F1CDB961BDB97C080C07160000D00008D +:105CF0000022A430B1AA299C107B915F269286795C +:105D0000C215C0206E62E96D080AB12200210400AC +:105D1000741A764BDB63FFEE2292850D6311032527 +:105D200014645FCFD650032D436DD9039820B4225D +:105D30000644146D4922982098219822982398248B +:105D400098259826982798289829982A982B982C4F +:105D5000982D982E982F222C4063FF971EDB10273A +:105D6000E68027E681D10F006C1004C062C04112AA +:105D7000DB0D13DB7423322D1ADB0819DB6E2AA02E +:105D8000002992AE6EA30260009128ACFE090D407E +:105D90002C1AC2C2BD0DCB392B25166480895BFF3E +:105DA000A215DB691ADB142B3AE80A3A0158059868 +:105DB0002B21160ABB28D3A02B56005805AF8B50B9 +:105DC0000ABB082A0A005805AE15DB602D21022CFB +:105DD0003AE80C3C2804DD022D25029C505805A60B +:105DE0008B50AABBC0A15805A61CDB592D21020C63 +:105DF0003C2806DD0213DB572D25029C3058059EFA +:105E00008B30AABBC0A258059E2A2102C0B40BAA9F +:105E1000020A0A4F2A25025805B2D10F242423C3AF +:105E2000CC2C251663FF760018DB4F1CDB4B19DBEF +:105E30004C1BDB4A17DB1F85202E0AFD1FDB4B2D79 +:105E4000202E24F47A24F47E24F4820EDD0124F43E +:105E5000862E0AF707552806DD02C0750EDD0105FE +:105E60000506AB5BA959C0E8AC5C24C4AB0EDD02EF +:105E700027C4AC2E0ADFA85527B4EC0EDD0124B4EC +:105E8000EBC2E027942C0EDD0224942B2E0A800D09 +:105E90000D4627546C24546B0EDD022D242E63FE18 +:105EA000FC0000006C1004C3A0C0B35BFF53C04AE9 +:105EB00012DB21C380282616242617C3A1C0B35B9A +:105EC000FF4EC03CC3A12A261619DAB6299020231A +:105ED000261764908F2A0A322B0A015BFF47C3A260 +:105EE0002B0A015BFF45C3B22B2616232617C2AF30 +:105EF000C0B15BFF41C2FF2F2616C0EE2E2617C28F +:105F0000D22D2616C0C82C26172426112A2212C7E5 +:105F1000B30BAA01C0B40BAA022A2612290AA1298E +:105F20002616C182282617C0B32B26112E22121F37 +:105F3000DACA0FEE022E2612C3D62D26162A0AA280 +:105F4000C1C32C26175BFF2C2C0AA22C2616C1B528 +:105F50002B2617C2AB2A2616C09729261718DB0353 +:105F6000282610D10FC3A2C0B35BFF2363FF6E00CE +:105F70006C10041CDACE1BDABB18DAFD17DAFE1639 +:105F8000DAFE15DAFEC0E0C0D414DACA1FDA8622BF +:105F90000A082FF2006D2A36DAC0D9C07C5B020FE6 +:105FA000C90C1CDAC30C9C28A8C3A6C22A36802AB6 +:105FB0002584A4C2A7CC2D248C2B248A2B24872EA5 +:105FC000248BB1BB2E369F2C369E2C369DB1AC1C3B +:105FD000DAA51BDAEBC0286D2A33DAC0D9C07C5BA6 +:105FE000020FC90C1CDAB30C9C28A8C3A6C22A361F +:105FF000802B2584A4C2B1BBA7CC2D248C2E248B4E +:106000002A248A2E369F2C369E2C369DB1ACC07920 +:1060100019DAA31BDADE13DADB1ADADB18DADD149D +:10602000DAA416DADC04F42812DADC04660C0405BF +:1060300006A252A858AA5AA3539B3029A500278428 +:106040008AC091C0A52A848C29848B17DAD518DAE6 +:10605000D3A75726361D26361E2E361F16DAD21324 +:10606000DAD2A65504330C2826C82E75002D54AC60 +:106070002E54AB2E54AA2326E62326E52E26E7D15E +:106080000F0000006C100613DAAF17DAAA24723D75 +:106090002232937F2F0B6D08052832937F8F026386 +:1060A000FFF3C0C4C0B01EDA3FC061D940096939EE +:1060B00029E4206E4401D6B0C328DFB026E42206CE +:1060C0002F392FE421C0501FDAB919DAAA16DAAB3A +:1060D00018DA7994102A72458DE017DAA59D111D02 +:1060E000DAB46DA94BD450255C037A5B18DE507589 +:1060F0006B052E12010E5E0C12DA6E02E2280111FF +:1061000002AF2222D681D54013DA6A746B052512BC +:106110000105450C035328B145A83EA932A73322F7 +:10612000369D22369E2436802B369F2BE48B2CE422 +:106130008C14DA8424424DC030041414C84C6D0809 +:1061400006B133041414C84263FFF20016DA13C414 +:1061500040C1580031041ADA13C0B193A200BB1A2F +:10616000B0BB9BA318DA7829824D23824E28825334 +:106170007A871C2C64008C106FC4481EDA0A043D18 +:106180000C2DE51C2FE11D2DE51A2FE51BD10F006D +:10619000C07212DA6882207E27DB03034F27640077 +:1061A0008810C0616F8430C0A00319140A54391AD2 +:1061B000D9FD04990C29A51C29A51D29A51A29A5D5 +:1061C0001BD10F001CD9F8053B0C2BC51C2DC11D84 +:1061D0002BC51A2DC51BD10F065439031E1404EE0E +:1061E0000C2EA51C2EA51D2EA51A2EA51BD10F0009 +:1061F0006C10081AD9EC14DA4F13DA52C72FC050BA +:1062000016DA6C2566A82566A92566AA2566AB223E +:1062100036292B424519DA13D8101CDA66C0D49DF2 +:10622000119C100080890B990C99A02816025BFF25 +:10623000952A32E31FD9DC0A5A149AF42932E4B1C0 +:10624000990959140A990C99F52832E508581498B7 +:10625000F62E32CD0E5E142EF6075BFF455BFF1166 +:1062600022463B1CD9D02AC102C1B00BAA021BDABC +:106270002A0A0A4F2AC5022B463A5804995BFEBAED +:106280005BFE95C0B0861317D9C525362DC74EC005 +:10629000309414C05014D9CA60004300007F9F0F8F +:1062A000B155091914659FF4C0500AA9027FA7EFE0 +:1062B00018D9BADA5008580A28822C2B0A000B8009 +:1062C00000005104D2A0C091C7AF00991A0A9903E7 +:1062D000291604CE33642063D3202B2007D6508C9C +:1062E000142A72827CA85C18D9AC08580A28822C1F +:1062F000DA500B8000D2A0643FDA8A310A8A140493 +:10630000AA01C82A2B22010B8B1404BB017AB940C5 +:10631000DDA06EA1081DD9A32DD2000DAD0CDB3080 +:10632000DC601AD9E318D99C0ADA2808680A1DDA51 +:106330001F28823CADAA0B8000652F9BD320C0B0E4 +:1063400063FF9B00CA5CB1550050040A091963FF42 +:106350004BDCB06EB1091CD9938CC0D30F0CBC0CB4 +:106360001DD9D41EDA120DCD28AEDD1EDA112DE6B0 +:106370008163FF9B7FA7CE63FF6C00006C10041B42 +:10638000D98727221EC08008E4310002002AB28289 +:1063900019D985003104C06100661A2991020A6A80 +:1063A000022AB68209E43115D9DF0C3811A8532826 +:1063B00032822432842A8CFC7841102921022A3628 +:1063C0008297A0096902292502D10F002B21022CF6 +:1063D00032850B6B022CCCFC2C368297C02B25020D +:1063E000D10F00006C1006C0C71BD9681AD96A0DFE +:1063F0004E11D72088208522D98005450B02820CBA +:106400009572222CF4C8346F2E026000AB1FD96045 +:10641000A9E2AF7D72D334C93DC0212F0A00092FF4 +:10642000380F0F42C9F92AB67E6D4A050030880040 +:10643000908C22720002E20872D1749270D280D1E4 +:106440000FC05003253875C0DF63FFD9097D0CAF3D +:10645000DD0DEE0C64304ED2300D3F1296112F162A +:10646000002FFC100F4F36260A01250A0009653857 +:106470000505426450712AB67E6DFA050020880039 +:10648000908CC050A3D28910237C0C09440C290A9B +:106490000103953805054264505A2AB67E6D4A05B7 +:1064A00000208800308CD280A7EABCAA9A70D10F55 +:1064B000D280BC7B9B70D10F00023F14C1D0D23080 +:1064C0000FDD0C0D4D36298D08C0F1250A0009F5A8 +:1064D00038050542CA582AB67E6DDA0500208800C4 +:1064E000908C897063FF2500C061C05003653875CA +:1064F000C08663FF80C0D0029D387DC09F63FF9936 +:10650000C05003F53875C0D063FFCA006C1004D6C4 +:106510002068520F695324DA20DB30DC405800F049 +:10652000D2A0D10FDA20DB30DC405800ED9A2424D1 +:10653000240EC02122640FC020D10F00B83BB04C04 +:106540002A2C7489242D200E2E200FA4DDB1EE2ECE +:10655000240FB0DD2D240E2890072D9003A488B0C1 +:1065600088B1DD2D94032894075BFF9E69511DC0FF +:10657000E082242A600F18D9902A240329600E8F04 +:106580002029240708FF029F209E64D10FC020D13C +:106590000F0000006C1004942319D988C0B3083A86 +:1065A000110BAA02992019D8FD9A2128929D16D87C +:1065B000FAC0502564A2288C1828969DD10F00009F +:1065C0006C1004282066C038232406B78828246667 +:1065D000D10F00006C1006035A0C0D36110D5C1122 +:1065E000D8208B2282210CBB0C06550F9B820232D5 +:1065F0000B928113D8E7D920A38F6450531CD8E3A2 +:10660000C0D71BD8E4A256C0E1290A0004E9380922 +:10661000094276F34A044302C99E2BC67E6DAA0541 +:1066200000208800308C8981A95909FA0C64A0796E +:1066300099818A82C8ADD290D10FC06002E63876C7 +:10664000D0DA63FFD4C020BC89998199809282D12D +:106650000F7F2304292DF8998165BFD963FFE500D9 +:10666000028F0CA3FF0F3312931003AA0CD340CB5D +:106670009E2BC67E86106D6A0500208800308CBC7B +:1066800082290A0004F308240A010349380909424F +:10669000CA982BC67E6DAA0500208800308C0F5941 +:1066A0000CA989BC99998163FF87BC89998163FF93 +:1066B00080C06002E63876D0BA63FFB4C07002478B +:1066C0003877D0D063FFCA006C100414D8C0C15210 +:1066D000A424C93E28221D738119292102CD932AA1 +:1066E000300075A912DA20DB302C3007C0D25801F7 +:1066F000C4653FDFD10F00002B300703BB0BDAB0BE +:1067000074B3022ABDF8D3A063FFC6006C1004293D +:106710002006C0706E9741292102C08F2A2014C024 +:10672000B62B240606AA022A241479800227250201 +:106730002A221E2C221D7AC10EC8ABDA20DB302C97 +:106740000A00033D025BF8226450752D21020D0DF5 +:106750004CC9D3C020D10F00002E9CFB64E0822FD7 +:1067600021020F0F4C65F0911AD88D1CD88B29A2ED +:106770009EC08A798B5D2BC22668B0048D207BD9A0 +:106780005229A29DC0F364904A97901DD89E2E2155 +:10679000049D9608EE110FEE029E979E9127C4A2CB +:1067A00018D89A2F21022BA29DC0E52E24062BBCBF +:1067B0003008FF022BA69D2F2502C020D10F00001C +:1067C000002F300068F938DA20DB30DC4058004414 +:1067D00063FF7700022A022B0A065800D4220A001F +:1067E000D10F655010283000688924022A02033B2B +:1067F00002DC4058003BC020D10FD270D10F000006 +:106800002A2C74033B02044C025BFEF663FF3B0040 +:10681000DB30DC402A2C745BFEF3C020D10F00007B +:106820006C1004C83F89268829A399992609880CE9 +:10683000080848282525CC52C020D10FDB402A2C3F +:10684000745BF949D2A0D10F6C1004D820D73082E4 +:10685000220D451105220C928264207407420B130D +:10686000D84CD420A383732302242DF8858074513F +:106870004CBC82C0906D081600408800708C77393F +:1068800003D720C0918680743901D42074610263DB +:10689000FFE2CA98C097C0411BD8CAC0A00B8B0C9E +:1068A0000B4A380A0A42C9AA1DD8391CD83A2CD634 +:1068B0007EC140D30F6D4A0500208800308C978040 +:1068C000D270D10FBC8FC0E00F4E387E90E263FFD4 +:1068D000D6BC8292819280C0209282D10F000000AB +:1068E0006C1006C0D71CD8291BD82B0D4911D720F6 +:1068F0002A221F28221D0A4A0BD28007860C2A76DC +:106900001F266C80C8346F6E026000D02F0A801A78 +:10691000D82FA29EAA7A7EA33FC93FC0E1C05002F1 +:10692000E538050542CA552BC67EDB20D30F6D4ADC +:106930000500308800B08C2E721DAE9E0EA50C6432 +:10694000508AD2802E761DC091298403D10FC05069 +:1069500003E53875D0D363FFCD15D81C027E0CA596 +:10696000EE643055DA300E351296129511255C1012 +:10697000054536C0619510C0500265380505426472 +:1069800050892BC67E8510D30F6D5A0500A0880054 +:10699000208CC0A1A3E2C05023FA8003730C03A58E +:1069A00038AF730505426450722BC67E85110545CC +:1069B0000C6D5A0500208800308CD280C0A10E9B3F +:1069C0000CAB7BAFBB2B761D2A8403D10FD280C0CA +:1069D000C1AF7D2D761D2C8403D10F0000063F141E +:1069E000C1E0D2300FEE0C0E4E362A8D08C0F125D4 +:1069F0000A000AF538050542CA5C2BC67E6DEA0519 +:106A000000208800A08C22721D63FEFFC061C05070 +:106A100003653875D80263FF6B63FF65C05002A53C +:106A20003875D08763FF8100C06003F63876D0CC1C +:106A300063FFC6006C10042A201529201614D7D92C +:106A40000A990CCB9D2E200B04ED092BD11C09BCFF +:106A500036ACAA0CBB0C2BD51C0A0A472A2415CB32 +:106A6000A18B438F288942B0A800910400881AA8FE +:106A7000FF0FBB029B278F260FB80C783B1AC02054 +:106A8000D10F0000292102C0A20A9902292502C0C3 +:106A900021D10F008B2763FFDC2BD11C0CAA0C0A21 +:106AA0000A472A2415ACBB2BD51CC9AE8B438C28B6 +:106AB0008F42B0AD00F10400DD1AADCC0CBB029BDF +:106AC00027DA20B7EB580019C021D10F9F2763FFA9 +:106AD000EF0000006C100428203C64304705306053 +:106AE00000073E01053EB156076539054928C77FB5 +:106AF000A933030641076603B166060641A6337E45 +:106B0000871E222125291AFC732B1502380C0981B6 +:106B10006000063E01023EB12406423903220AD13A +:106B20000FD230D10FC05163FFC000006C10041DA4 +:106B3000D79B27221EC08008E4310002002CD2829D +:106B40001BD799003104C06100661A2BB1020C6C8E +:106B5000022CD6820BE43119D81B0C3A11AA9328C7 +:106B600032829780253282243284B455253682754C +:106B7000410A292102096902292502D10F2A21028D +:106B80002B32830A6A022B36822A2502D10F00009B +:106B90006C10041DD78219D78C27221EC08009775C +:106BA0000208E4310002002CD2821BD77E0031049F +:106BB000C06100661A2BB1020C6C022CD6820BE469 +:106BC0003119D8000C3A11AA9328328297802532C5 +:106BD00082243284B45525368275410B2A21020A5B +:106BE0006A022A2502D10F002B21022C32830B6B63 +:106BF000022C36822B2502D10F0000006C10041BE2 +:106C0000D7670C2A11ABAA29A286B438798B221B2C +:106C1000D76419D78B0B2B0A2BB2A309290868B0AC +:106C20000274B90D299D0129901F6E920822A28538 +:106C3000D10FC020D10FC892C020D10FDA205BEF56 +:106C40003DC020D10F0000006C100414D75428421E +:106C50009E19D7516F88026000B929922668900763 +:106C60008A2009AA0C65A0AB2A429DC0DC64A0A3BF +:106C70002B200C19D74B0CBC11A4CC2EC28609B901 +:106C80000A7ED3026000992992A36890078D20099B +:106C9000DD0C65D08B25C2856450852D2104C03064 +:106CA0006ED80D2C2066B8CC0C0C472C246665C021 +:106CB0007A1AD7521CD75B1DD7481ED74FC084986D +:106CC000519E5089209D569D54935793559C530A2D +:106CD00099021CD7BD1AD76499528F26995A985990 +:106CE0009E58935E9C5D935C9A5B0F0D4805DD1189 +:106CF0009D5FC0D81ED7320CB911A499289285AED9 +:106D0000BE23E4CF288C402896859F292D2406C0D9 +:106D100020D10F00CA32DA20C0B65BFF84C72FD162 +:106D20000FC939DA205BFF81C72FD10FDBD05BFEA3 +:106D3000192324662B200C63FF76C72FD10FC72F92 +:106D4000D10F00006C1004C85B29200668941C68F1 +:106D50009607C020D10FC020D10FDA20DB30DC40F5 +:106D6000DD502E0A005BFE69D2A0D10F2E200C1838 +:106D7000D70B0CEF11A8FF29F286C088798B751A02 +:106D8000D7080AEA0A2AA2A368A0048B207AB96469 +:106D900023F28564305E1CD7122A0A802D206829D0 +:106DA00020672821040B991104881109880208DD45 +:106DB00002C094284A1008DD0218D70A9931983089 +:106DC0008B2B9A379D340CBB029B32C0C09C359CE8 +:106DD000362A2C74DB40C0D318D6F929F285A8EEE8 +:106DE000299C2029F6852CE4CF2D2406DD405BFD6F +:106DF000F9D2A0D10FDA20DBE05BFF4CC020D10F2D +:106E00006C100AD6302A2006941028ACF86583FF4F +:106E10002B2122270A022A2124CC572AAC010A0A54 +:106E20004F2A25247ABB026003F72C21022A200C6A +:106E30000C0C4C65C38E2E22158D32C0F10EDD0C6C +:106E400065D40488381ED6D56483E18F37C0C8C0A6 +:106E5000960FC9399914B49B9B110D99119913C9B7 +:106E6000FB19D6D02990217F93138B148C205BFFC4 +:106E7000631ED6CADDA064A41C8F676000298C1134 +:106E80000CAD11AEDD28D2860AAB0278CB621AD6E1 +:106E9000C40ABA0A2AA2A368A0052C22007AC95003 +:106EA0002AD285DDA064A3D729212E09F9362A200C +:106EB0003C09F80C6F8D3ED7F0CB7F28211F08705E +:106EC00060010B3E00043EB1BC04CB39C74F0BBB85 +:106ED0000A07BB0A0B0C4104CC03B1CC0C0C41AC2F +:106EE000BBD4B0C0C27CA04C2A21257BAB4660003D +:106EF0002CC0A063FFACD79063FFBD00C092C74F0A +:106F00002C7C140C0B4104BB03B1BB0B0B41AB74C9 +:106F1000244C1479A01E2A212574AB18ACBB241A6A +:106F2000FC0ABC0C04C16000093E01043EB14809E2 +:106F300084390B440A8926882709880C74831DC06C +:106F40008098D88C649CD98B668A659BDB9ADA978B +:106F5000D57F730260013ACE5E600016009D15DA9F +:106F600020DB405BFEB48D151ED68D65A2568F6763 +:106F700063FFCB9D15DA20DB308C105BFE598D153D +:106F80001ED687C051D6A08FA7C0C08A6897DD9A49 +:106F9000DC8869896A98DE99DF8B6A8A69AB7B77BE +:106FA000BB022AAC019B6A9A698860C0A0088B1456 +:106FB000778701C0A1C09028203C9417951893169C +:106FC000C050C031C044048401043938089910C04D +:106FD00042048401043538083840832B0BA4100781 +:106FE00055102A211F0955020544020B19400A2A8F +:106FF000140799100585100433020A881114D6F37A +:10700000095502292104043302089911098802C094 +:107010009209880229212593D00929140499110A7B +:1070200099020955028A20891408AA110A99021A9C +:10703000D66F14D6E70A990299D1832A95D698D7A4 +:10704000851804330293D4841783168A658D66AA43 +:10705000CAAD7D77DB01B1AA07FF0C9A659D6688F2 +:10706000268C29A48808CC0C98260C0C482C2525A5 +:107070009F672A200CC0C01BD6510CA911AE99AB3A +:10708000AB2892852CB4CF8B13AB8828968563FDF3 +:10709000CD00C091C0F0C0B2C0C4886023203C982D +:1070A000120C3C010B3A010888140B88010A9F3826 +:1070B00007FF10089839C0A00C9A3807881008AA52 +:1070C000100AFF02C0A80A33010393392A210429B8 +:1070D0002125053C1008CC020A331108AA11092900 +:1070E0001403AA020499110BAA022B211F83140B6B +:1070F0002B140B99020C99028B201CD63C08BB1157 +:1071000003BB020CBB02832A8C2B647084886897B3 +:10711000DD98DC8769886A97DE98DF8812C070770F +:107120008701C0719BD199D60B78109AD717D6A931 +:1071300008F80208C80207880217D6A598D00737B2 +:107140000297D428200C295CFE2B2124C0F01AD6EB +:107150001B0C8D11AEDD2CD285AA882F84CF8F1306 +:10716000B0BBAFCC2CD6852A22152B2524B1AA2A58 +:1071700026156490DCC84F8C268B29A4CC9C260C49 +:10718000BB0C0B0B482B25256550E8C020D10F0008 +:107190000000C0709BD199D69AD7881293D4778774 +:1071A0000E18D600921A288022C021082738821A89 +:1071B00018D68A0B731003F30203C3020833029339 +:1071C000D063FF7E00CC57DA20DB608C105BFDC4FF +:1071D000292102689806689403C020D10F2B221E33 +:1071E000C09028221D2925027B8901C0B064BFE818 +:1071F00013D5EA2CB00728B000DA2003880A2882C9 +:107200004CC0D10B8000DBA065AFE763FFCA000074 +:1072100068A775DA20DB30DC40DD505BFECAD2A007 +:10722000D10FC1FDC19D29252C600003002F252C05 +:107230002F2467272468DA20DB308C10DD502E0ADB +:10724000805BFD32D2A0D10FC1F8C1A82A252C63E2 +:10725000FFDDC84F8C268B29A4CC9C260CBB0C0BC5 +:107260000B482B25252A2C74DB602C12005BFD7645 +:10727000D2A0D10F2A2C748B105BF6BBD2A0D10FF9 +:10728000DA205BFE2A63FF3C00DA20C0B15BFE6EB1 +:1072900065AF3163FB79DA202B200C5BFE3D63FF89 +:1072A0002300000012D64E8220028257C82163FFBD +:1072B000FC12D64A03E83004EE3005B13093209436 +:1072C00021952263FFFC000010D6469100920193A5 +:1072D00002940311D61D821001EA30A21101F0318F +:1072E000C04004E41600020011D63F8210234A0079 +:1072F000032202921011D609C021921004E43184B5 +:107300000383028201810000D230012300000000CB +:1073100010D636910092019302940311D60C82107C +:1073200001EA30A21101F131C04004E4160002006C +:1073300011D62D821013D5B4032202921004E43129 +:10734000840383028201810000D3300133000000F6 +:1073500010D6279100810165104981026510448192 +:1073600003CF1F92019302940311D5FA821001EA10 +:1073700030A21101F231C04004E41600020011D61F +:1073800019821013D59B032202921004E431840366 +:1073900083028201C010910391029101810000D407 +:1073A0003001430012D5CAC030283740283744285E +:1073B000374828374C233D017233ED03020063FF49 +:1073C000FC00000010D60B9100920193029403116F +:1073D000D6098210921011D5BC831003220292109C +:1073E00011D60612D5CD9210C04004E4160002005A +:1073F00011D5FD821013D5B5032202921004E43199 +:10740000840383028201810000D530015300000013 +:107410006C10026E322FD620056F04043F04745B9B +:107420002A05440C00410400331A220A006D490D5C +:1074300073630403660CB1220F22110313147363E8 +:1074400002222C01D10FC83BD10F000073630CC086 +:1074500021D10F000000000044495630C020D10F58 +:107460006C10020040046B4C07032318020219D170 +:107470000F020319C020D10F6C100202EA30D10FA5 +:107480006C1002CC2503F03160000F006F22050361 +:10749000F1316000056F230503F231000200D10FC6 +:1074A0006C1002CC2502F030D10F00006F220402D4 +:1074B000F130D10F6F230402F230D10FC020D10F71 +:1074C0006C1002220A20230A006D280E283740285B +:1074D000374428374828374C233D01030200D10F99 +:1074E0006C100202E431D10F0A004368656C7369C5 +:1074F0006F2046572044454255473D30202842756D +:10750000696C7420547565204175672031322030D4 +:10751000393A34333A303420504454203230303801 +:10752000206F6E2066656C69782E6173696364658F +:107530007369676E6572732E636F6D3A2F686F6D36 +:10754000652F66656C69782F772F66775F362E30EA +:10755000292C2056657273696F6E20543378782019 +:107560003030372E30302E3030202D203130303733 +:0C7570003030303010070000CC44A0D6B2 +:00000001FF diff --git a/fs/afs/proc.c b/fs/afs/proc.c index 9f7d1ae70269ac9de86404e5b6eb36b6a4d34f29..7578c1ab9e0be9ec3260c4cce41b78287f213bce 100644 --- a/fs/afs/proc.c +++ b/fs/afs/proc.c @@ -646,7 +646,7 @@ static int afs_proc_cell_vlservers_show(struct seq_file *m, void *v) } /* display one cell per line on subsequent lines */ - seq_printf(m, "%u.%u.%u.%u\n", NIPQUAD(addr->s_addr)); + seq_printf(m, "%pI4\n", &addr->s_addr); return 0; } @@ -737,7 +737,7 @@ static int afs_proc_cell_servers_show(struct seq_file *m, void *v) } /* display one cell per line on subsequent lines */ - sprintf(ipaddr, "%u.%u.%u.%u", NIPQUAD(server->addr)); + sprintf(ipaddr, "%pI4", &server->addr); seq_printf(m, "%3d %-15.15s %5d\n", atomic_read(&server->usage), ipaddr, server->fs_state); diff --git a/fs/afs/server.c b/fs/afs/server.c index 28f2451419e1406b3be0aa0a0258fe14f73a0834..f4909951667554b6e4263ebebedc6d2513599d48 100644 --- a/fs/afs/server.c +++ b/fs/afs/server.c @@ -105,7 +105,7 @@ struct afs_server *afs_lookup_server(struct afs_cell *cell, { struct afs_server *server, *candidate; - _enter("%p,"NIPQUAD_FMT, cell, NIPQUAD(addr->s_addr)); + _enter("%p,%pI4", cell, &addr->s_addr); /* quick scan of the list to see if we already have the server */ read_lock(&cell->servers_lock); @@ -168,9 +168,8 @@ found_server: server_in_two_cells: write_unlock(&cell->servers_lock); kfree(candidate); - printk(KERN_NOTICE "kAFS:" - " Server "NIPQUAD_FMT" appears to be in two cells\n", - NIPQUAD(*addr)); + printk(KERN_NOTICE "kAFS: Server %pI4 appears to be in two cells\n", + addr); _leave(" = -EEXIST"); return ERR_PTR(-EEXIST); } @@ -184,7 +183,7 @@ struct afs_server *afs_find_server(const struct in_addr *_addr) struct rb_node *p; struct in_addr addr = *_addr; - _enter(NIPQUAD_FMT, NIPQUAD(addr.s_addr)); + _enter("%pI4", &addr.s_addr); read_lock(&afs_servers_lock); diff --git a/fs/cifs/cifs_spnego.c b/fs/cifs/cifs_spnego.c index 0ab2fb5afef12a78a9ae2fdd0e79af761133468b..3fd3a9df043a6eee77c276563300be4c5ed390a7 100644 --- a/fs/cifs/cifs_spnego.c +++ b/fs/cifs/cifs_spnego.c @@ -121,11 +121,9 @@ cifs_get_spnego_key(struct cifsSesInfo *sesInfo) /* add the server address */ if (server->addr.sockAddr.sin_family == AF_INET) - sprintf(dp, "ip4=" NIPQUAD_FMT, - NIPQUAD(server->addr.sockAddr.sin_addr)); + sprintf(dp, "ip4=%pI4", &server->addr.sockAddr.sin_addr); else if (server->addr.sockAddr.sin_family == AF_INET6) - sprintf(dp, "ip6=" NIP6_SEQFMT, - NIP6(server->addr.sockAddr6.sin6_addr)); + sprintf(dp, "ip6=%pi6", &server->addr.sockAddr6.sin6_addr); else goto out; diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c index d2ea95bef1c1c0f344d55549899b3fa339aa1856..e9ea394ee075d0ef20ab7900d111c5bd6a6e20c6 100644 --- a/fs/cifs/connect.c +++ b/fs/cifs/connect.c @@ -2270,11 +2270,11 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb, /* new SMB session uses our srvTcp ref */ pSesInfo->server = srvTcp; if (srvTcp->addr.sockAddr6.sin6_family == AF_INET6) - sprintf(pSesInfo->serverName, NIP6_FMT, - NIP6(srvTcp->addr.sockAddr6.sin6_addr)); + sprintf(pSesInfo->serverName, "%pI6", + &srvTcp->addr.sockAddr6.sin6_addr); else - sprintf(pSesInfo->serverName, NIPQUAD_FMT, - NIPQUAD(srvTcp->addr.sockAddr.sin_addr.s_addr)); + sprintf(pSesInfo->serverName, "%pI4", + &srvTcp->addr.sockAddr.sin_addr.s_addr); write_lock(&cifs_tcp_ses_lock); list_add(&pSesInfo->smb_ses_list, &srvTcp->smb_ses_list); diff --git a/fs/dlm/netlink.c b/fs/dlm/netlink.c index 18bda83cc8925b3ecbb5f3b3fc5cacfb65eacadc..aa2a5775a0274f88ebc8eda63d3e4fbe49eeaeb4 100644 --- a/fs/dlm/netlink.c +++ b/fs/dlm/netlink.c @@ -127,8 +127,8 @@ static void fill_data(struct dlm_lock_data *data, struct dlm_lkb *lkb) void dlm_timeout_warn(struct dlm_lkb *lkb) { + struct sk_buff *uninitialized_var(send_skb); struct dlm_lock_data *data; - struct sk_buff *send_skb; size_t size; int rv; diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 70fc63a1727b131f496bc9a98186d61a022dc975..e05d044160378fefd2989674903c032d5668183a 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -115,14 +115,14 @@ static void nlm_display_address(const struct sockaddr *sap, snprintf(buf, len, "unspecified"); break; case AF_INET: - snprintf(buf, len, NIPQUAD_FMT, NIPQUAD(sin->sin_addr.s_addr)); + snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr); break; case AF_INET6: if (ipv6_addr_v4mapped(&sin6->sin6_addr)) - snprintf(buf, len, NIPQUAD_FMT, - NIPQUAD(sin6->sin6_addr.s6_addr32[3])); + snprintf(buf, len, "%pI4", + &sin6->sin6_addr.s6_addr32[3]); else - snprintf(buf, len, NIP6_FMT, NIP6(sin6->sin6_addr)); + snprintf(buf, len, "%pI6", &sin6->sin6_addr); break; default: snprintf(buf, len, "unsupported address family"); diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index 4e7e958e8f6753236832ed9ebd82f6bae0746899..ffd3461f75efb332f44d8ce5b7e87a179eb6c2ce 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -179,7 +179,7 @@ static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp) if (!nsm_use_hostnames) { snprintf(buffer, XDR_ADDRBUF_LEN, - NIPQUAD_FMT, NIPQUAD(argp->addr)); + "%pI4", &argp->addr); name = buffer; } diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index 8478fc25daee196383f3e40a34999795be41585e..d74d16ce0d49920ed710d0602c4797213aa79d38 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c @@ -329,7 +329,7 @@ static int __init root_nfs_addr(void) } snprintf(nfs_data.hostname, sizeof(nfs_data.hostname), - "%u.%u.%u.%u", NIPQUAD(servaddr)); + "%pI4", &servaddr); return 0; } @@ -421,8 +421,8 @@ static int __init root_nfs_getport(int program, int version, int proto) { struct sockaddr_in sin; - printk(KERN_NOTICE "Looking up port of RPC %d/%d on %u.%u.%u.%u\n", - program, version, NIPQUAD(servaddr)); + printk(KERN_NOTICE "Looking up port of RPC %d/%d on %pI4\n", + program, version, &servaddr); set_sockaddr(&sin, servaddr, 0); return rpcb_getport_sync(&sin, program, version, proto); } diff --git a/fs/nfs/super.c b/fs/nfs/super.c index f48db679a1c681aecdfef6ed2eb662fec9d7d2bc..bb0313ac9e1fa1a6b94ddb51229298e88b955bfd 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -462,14 +462,12 @@ static void nfs_show_mountd_options(struct seq_file *m, struct nfs_server *nfss, switch (sap->sa_family) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *)sap; - seq_printf(m, ",mountaddr=" NIPQUAD_FMT, - NIPQUAD(sin->sin_addr.s_addr)); + seq_printf(m, ",mountaddr=%pI4", &sin->sin_addr.s_addr); break; } case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; - seq_printf(m, ",mountaddr=" NIP6_FMT, - NIP6(sin6->sin6_addr)); + seq_printf(m, ",mountaddr=%pI6", &sin6->sin6_addr); break; } default: diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 1a052ac2bde90b6599194380124c61b1c4054134..bf4cd46a5a11489cfd4d726317362b1cc1c5a381 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -719,8 +719,8 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, status = nfserr_clid_inuse; if (!same_creds(&conf->cl_cred, &rqstp->rq_cred) || conf->cl_addr != sin->sin_addr.s_addr) { - dprintk("NFSD: setclientid: string in use by client" - "at %u.%u.%u.%u\n", NIPQUAD(conf->cl_addr)); + dprintk("NFSD: setclientid: string in use by clientat %pI4\n", + &conf->cl_addr); goto out; } } diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c index e3f9783fdcf7eba3872331b0c48f5aee7207fd62..77d7b8c531a6b14f351b280f84d98f0bf9e66401 100644 --- a/fs/nfsd/nfsctl.c +++ b/fs/nfsd/nfsctl.c @@ -330,7 +330,7 @@ static ssize_t failover_unlock_ip(struct file *file, char *buf, size_t size) return -EINVAL; /* get ipv4 address */ - if (sscanf(fo_path, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) != 4) + if (sscanf(fo_path, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) != 4) return -EINVAL; if (b1 > 255 || b2 > 255 || b3 > 255 || b4 > 255) return -EINVAL; diff --git a/fs/ocfs2/cluster/netdebug.c b/fs/ocfs2/cluster/netdebug.c index 52276c02f71041665ba3389b9d690e46e8c075dd..f8424874fa0725b95065d5ce7031f63d0cdde586 100644 --- a/fs/ocfs2/cluster/netdebug.c +++ b/fs/ocfs2/cluster/netdebug.c @@ -304,8 +304,8 @@ static int sc_seq_show(struct seq_file *seq, void *v) * use of it here generates a warning with -Wbitwise */ seq_printf(seq, "%p:\n" " krefs: %d\n" - " sock: %u.%u.%u.%u:%u -> " - "%u.%u.%u.%u:%u\n" + " sock: %pI4:%u -> " + "%pI4:%u\n" " remote node: %s\n" " page off: %zu\n" " handshake ok: %u\n" @@ -319,8 +319,8 @@ static int sc_seq_show(struct seq_file *seq, void *v) " func type: %u\n", sc, atomic_read(&sc->sc_kref.refcount), - NIPQUAD(saddr), inet ? ntohs(sport) : 0, - NIPQUAD(daddr), inet ? ntohs(dport) : 0, + &saddr, inet ? ntohs(sport) : 0, + &daddr, inet ? ntohs(dport) : 0, sc->sc_node->nd_name, sc->sc_page_off, sc->sc_handshake_ok, diff --git a/fs/ocfs2/cluster/nodemanager.c b/fs/ocfs2/cluster/nodemanager.c index 816a3f61330c6173ec04a360f4b7b40bb53ad0bf..70e8fa9e2539cdf210676778770e0de4405713e2 100644 --- a/fs/ocfs2/cluster/nodemanager.c +++ b/fs/ocfs2/cluster/nodemanager.c @@ -250,7 +250,7 @@ static ssize_t o2nm_node_ipv4_port_write(struct o2nm_node *node, static ssize_t o2nm_node_ipv4_address_read(struct o2nm_node *node, char *page) { - return sprintf(page, "%u.%u.%u.%u\n", NIPQUAD(node->nd_ipv4_address)); + return sprintf(page, "%pI4\n", &node->nd_ipv4_address); } static ssize_t o2nm_node_ipv4_address_write(struct o2nm_node *node, diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c index 2bcf706d9dd3c460d9bab05f963c74e08d21b188..9fbe849f634419d9f5418d6097e789906ba460b1 100644 --- a/fs/ocfs2/cluster/tcp.c +++ b/fs/ocfs2/cluster/tcp.c @@ -1597,8 +1597,8 @@ static void o2net_start_connect(struct work_struct *work) ret = sock->ops->bind(sock, (struct sockaddr *)&myaddr, sizeof(myaddr)); if (ret) { - mlog(ML_ERROR, "bind failed with %d at address %u.%u.%u.%u\n", - ret, NIPQUAD(mynode->nd_ipv4_address)); + mlog(ML_ERROR, "bind failed with %d at address %pI4\n", + ret, &mynode->nd_ipv4_address); goto out; } @@ -1790,17 +1790,16 @@ static int o2net_accept_one(struct socket *sock) node = o2nm_get_node_by_ip(sin.sin_addr.s_addr); if (node == NULL) { - mlog(ML_NOTICE, "attempt to connect from unknown node at " - "%u.%u.%u.%u:%d\n", NIPQUAD(sin.sin_addr.s_addr), - ntohs(sin.sin_port)); + mlog(ML_NOTICE, "attempt to connect from unknown node at %pI4:%d\n", + &sin.sin_addr.s_addr, ntohs(sin.sin_port)); ret = -EINVAL; goto out; } if (o2nm_this_node() > node->nd_num) { mlog(ML_NOTICE, "unexpected connect attempted from a lower " - "numbered node '%s' at " "%u.%u.%u.%u:%d with num %u\n", - node->nd_name, NIPQUAD(sin.sin_addr.s_addr), + "numbered node '%s' at " "%pI4:%d with num %u\n", + node->nd_name, &sin.sin_addr.s_addr, ntohs(sin.sin_port), node->nd_num); ret = -EINVAL; goto out; @@ -1810,8 +1809,8 @@ static int o2net_accept_one(struct socket *sock) * and tries to connect before we see their heartbeat */ if (!o2hb_check_node_heartbeating_from_callback(node->nd_num)) { mlog(ML_CONN, "attempt to connect from node '%s' at " - "%u.%u.%u.%u:%d but it isn't heartbeating\n", - node->nd_name, NIPQUAD(sin.sin_addr.s_addr), + "%pI4:%d but it isn't heartbeating\n", + node->nd_name, &sin.sin_addr.s_addr, ntohs(sin.sin_port)); ret = -EINVAL; goto out; @@ -1827,8 +1826,8 @@ static int o2net_accept_one(struct socket *sock) spin_unlock(&nn->nn_lock); if (ret) { mlog(ML_NOTICE, "attempt to connect from node '%s' at " - "%u.%u.%u.%u:%d but it already has an open connection\n", - node->nd_name, NIPQUAD(sin.sin_addr.s_addr), + "%pI4:%d but it already has an open connection\n", + node->nd_name, &sin.sin_addr.s_addr, ntohs(sin.sin_port)); goto out; } @@ -1924,15 +1923,15 @@ static int o2net_open_listening_sock(__be32 addr, __be16 port) sock->sk->sk_reuse = 1; ret = sock->ops->bind(sock, (struct sockaddr *)&sin, sizeof(sin)); if (ret < 0) { - mlog(ML_ERROR, "unable to bind socket at %u.%u.%u.%u:%u, " - "ret=%d\n", NIPQUAD(addr), ntohs(port), ret); + mlog(ML_ERROR, "unable to bind socket at %pI4:%u, " + "ret=%d\n", &addr, ntohs(port), ret); goto out; } ret = sock->ops->listen(sock, 64); if (ret < 0) { - mlog(ML_ERROR, "unable to listen on %u.%u.%u.%u:%u, ret=%d\n", - NIPQUAD(addr), ntohs(port), ret); + mlog(ML_ERROR, "unable to listen on %pI4:%u, ret=%d\n", + &addr, ntohs(port), ret); } out: diff --git a/include/linux/atm.h b/include/linux/atm.h index c791ddd969390578093843af29821e42ce0f460a..d3b292174aeb0821f8d63c3e6317a1f4d5e8b3d4 100644 --- a/include/linux/atm.h +++ b/include/linux/atm.h @@ -231,10 +231,21 @@ static __inline__ int atmpvc_addr_in_use(struct sockaddr_atmpvc addr) */ struct atmif_sioc { - int number; - int length; - void __user *arg; + int number; + int length; + void __user *arg; }; +#ifdef __KERNEL__ +#ifdef CONFIG_COMPAT +#include +struct compat_atmif_sioc { + int number; + int length; + compat_uptr_t arg; +}; +#endif +#endif + typedef unsigned short atm_backend_t; #endif diff --git a/include/linux/atmdev.h b/include/linux/atmdev.h index a3d07c29d16c65bc97b25027e15c6c5dbfe10c62..086e5c362d3a7c57064278135d36064f3a6c2a2a 100644 --- a/include/linux/atmdev.h +++ b/include/linux/atmdev.h @@ -100,6 +100,10 @@ struct atm_dev_stats { /* use backend to make new if */ #define ATM_ADDPARTY _IOW('a', ATMIOC_SPECIAL+4,struct atm_iobuf) /* add party to p2mp call */ +#ifdef CONFIG_COMPAT +/* It actually takes struct sockaddr_atmsvc, not struct atm_iobuf */ +#define COMPAT_ATM_ADDPARTY _IOW('a', ATMIOC_SPECIAL+4,struct compat_atm_iobuf) +#endif #define ATM_DROPPARTY _IOW('a', ATMIOC_SPECIAL+5,int) /* drop party from p2mp call */ @@ -224,6 +228,13 @@ struct atm_cirange { extern struct proc_dir_entry *atm_proc_root; #endif +#ifdef CONFIG_COMPAT +#include +struct compat_atm_iobuf { + int length; + compat_uptr_t buffer; +}; +#endif struct k_atm_aal_stats { #define __HANDLE_ITEM(i) atomic_t i @@ -379,6 +390,10 @@ struct atmdev_ops { /* only send is required */ int (*open)(struct atm_vcc *vcc); void (*close)(struct atm_vcc *vcc); int (*ioctl)(struct atm_dev *dev,unsigned int cmd,void __user *arg); +#ifdef CONFIG_COMPAT + int (*compat_ioctl)(struct atm_dev *dev,unsigned int cmd, + void __user *arg); +#endif int (*getsockopt)(struct atm_vcc *vcc,int level,int optname, void __user *optval,int optlen); int (*setsockopt)(struct atm_vcc *vcc,int level,int optname, diff --git a/include/linux/cgroup_subsys.h b/include/linux/cgroup_subsys.h index 9c22396e8b50355e3058e93807f293112622079f..9c8d31bacf46ca6acfc083a9a3c2be8e4cd4d2e8 100644 --- a/include/linux/cgroup_subsys.h +++ b/include/linux/cgroup_subsys.h @@ -54,3 +54,9 @@ SUBSYS(freezer) #endif /* */ + +#ifdef CONFIG_NET_CLS_CGROUP +SUBSYS(net_cls) +#endif + +/* */ diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h new file mode 100644 index 0000000000000000000000000000000000000000..b0ef274e00319d575082168ef3bb763fdf6447b9 --- /dev/null +++ b/include/linux/dcbnl.h @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2008, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * Author: Lucy Liu + */ + +#ifndef __LINUX_DCBNL_H__ +#define __LINUX_DCBNL_H__ + +#define DCB_PROTO_VERSION 1 + +struct dcbmsg { + unsigned char dcb_family; + __u8 cmd; + __u16 dcb_pad; +}; + +/** + * enum dcbnl_commands - supported DCB commands + * + * @DCB_CMD_UNDEFINED: unspecified command to catch errors + * @DCB_CMD_GSTATE: request the state of DCB in the device + * @DCB_CMD_SSTATE: set the state of DCB in the device + * @DCB_CMD_PGTX_GCFG: request the priority group configuration for Tx + * @DCB_CMD_PGTX_SCFG: set the priority group configuration for Tx + * @DCB_CMD_PGRX_GCFG: request the priority group configuration for Rx + * @DCB_CMD_PGRX_SCFG: set the priority group configuration for Rx + * @DCB_CMD_PFC_GCFG: request the priority flow control configuration + * @DCB_CMD_PFC_SCFG: set the priority flow control configuration + * @DCB_CMD_SET_ALL: apply all changes to the underlying device + * @DCB_CMD_GPERM_HWADDR: get the permanent MAC address of the underlying + * device. Only useful when using bonding. + * @DCB_CMD_GCAP: request the DCB capabilities of the device + * @DCB_CMD_GNUMTCS: get the number of traffic classes currently supported + * @DCB_CMD_SNUMTCS: set the number of traffic classes + * @DCB_CMD_GBCN: set backward congestion notification configuration + * @DCB_CMD_SBCN: get backward congestion notification configration. + */ +enum dcbnl_commands { + DCB_CMD_UNDEFINED, + + DCB_CMD_GSTATE, + DCB_CMD_SSTATE, + + DCB_CMD_PGTX_GCFG, + DCB_CMD_PGTX_SCFG, + DCB_CMD_PGRX_GCFG, + DCB_CMD_PGRX_SCFG, + + DCB_CMD_PFC_GCFG, + DCB_CMD_PFC_SCFG, + + DCB_CMD_SET_ALL, + + DCB_CMD_GPERM_HWADDR, + + DCB_CMD_GCAP, + + DCB_CMD_GNUMTCS, + DCB_CMD_SNUMTCS, + + DCB_CMD_PFC_GSTATE, + DCB_CMD_PFC_SSTATE, + + DCB_CMD_BCN_GCFG, + DCB_CMD_BCN_SCFG, + + __DCB_CMD_ENUM_MAX, + DCB_CMD_MAX = __DCB_CMD_ENUM_MAX - 1, +}; + +/** + * enum dcbnl_attrs - DCB top-level netlink attributes + * + * @DCB_ATTR_UNDEFINED: unspecified attribute to catch errors + * @DCB_ATTR_IFNAME: interface name of the underlying device (NLA_STRING) + * @DCB_ATTR_STATE: enable state of DCB in the device (NLA_U8) + * @DCB_ATTR_PFC_STATE: enable state of PFC in the device (NLA_U8) + * @DCB_ATTR_PFC_CFG: priority flow control configuration (NLA_NESTED) + * @DCB_ATTR_NUM_TC: number of traffic classes supported in the device (NLA_U8) + * @DCB_ATTR_PG_CFG: priority group configuration (NLA_NESTED) + * @DCB_ATTR_SET_ALL: bool to commit changes to hardware or not (NLA_U8) + * @DCB_ATTR_PERM_HWADDR: MAC address of the physical device (NLA_NESTED) + * @DCB_ATTR_CAP: DCB capabilities of the device (NLA_NESTED) + * @DCB_ATTR_NUMTCS: number of traffic classes supported (NLA_NESTED) + * @DCB_ATTR_BCN: backward congestion notification configuration (NLA_NESTED) + */ +enum dcbnl_attrs { + DCB_ATTR_UNDEFINED, + + DCB_ATTR_IFNAME, + DCB_ATTR_STATE, + DCB_ATTR_PFC_STATE, + DCB_ATTR_PFC_CFG, + DCB_ATTR_NUM_TC, + DCB_ATTR_PG_CFG, + DCB_ATTR_SET_ALL, + DCB_ATTR_PERM_HWADDR, + DCB_ATTR_CAP, + DCB_ATTR_NUMTCS, + DCB_ATTR_BCN, + + __DCB_ATTR_ENUM_MAX, + DCB_ATTR_MAX = __DCB_ATTR_ENUM_MAX - 1, +}; + +/** + * enum dcbnl_pfc_attrs - DCB Priority Flow Control user priority nested attrs + * + * @DCB_PFC_UP_ATTR_UNDEFINED: unspecified attribute to catch errors + * @DCB_PFC_UP_ATTR_0: Priority Flow Control value for User Priority 0 (NLA_U8) + * @DCB_PFC_UP_ATTR_1: Priority Flow Control value for User Priority 1 (NLA_U8) + * @DCB_PFC_UP_ATTR_2: Priority Flow Control value for User Priority 2 (NLA_U8) + * @DCB_PFC_UP_ATTR_3: Priority Flow Control value for User Priority 3 (NLA_U8) + * @DCB_PFC_UP_ATTR_4: Priority Flow Control value for User Priority 4 (NLA_U8) + * @DCB_PFC_UP_ATTR_5: Priority Flow Control value for User Priority 5 (NLA_U8) + * @DCB_PFC_UP_ATTR_6: Priority Flow Control value for User Priority 6 (NLA_U8) + * @DCB_PFC_UP_ATTR_7: Priority Flow Control value for User Priority 7 (NLA_U8) + * @DCB_PFC_UP_ATTR_MAX: highest attribute number currently defined + * @DCB_PFC_UP_ATTR_ALL: apply to all priority flow control attrs (NLA_FLAG) + * + */ +enum dcbnl_pfc_up_attrs { + DCB_PFC_UP_ATTR_UNDEFINED, + + DCB_PFC_UP_ATTR_0, + DCB_PFC_UP_ATTR_1, + DCB_PFC_UP_ATTR_2, + DCB_PFC_UP_ATTR_3, + DCB_PFC_UP_ATTR_4, + DCB_PFC_UP_ATTR_5, + DCB_PFC_UP_ATTR_6, + DCB_PFC_UP_ATTR_7, + DCB_PFC_UP_ATTR_ALL, + + __DCB_PFC_UP_ATTR_ENUM_MAX, + DCB_PFC_UP_ATTR_MAX = __DCB_PFC_UP_ATTR_ENUM_MAX - 1, +}; + +/** + * enum dcbnl_pg_attrs - DCB Priority Group attributes + * + * @DCB_PG_ATTR_UNDEFINED: unspecified attribute to catch errors + * @DCB_PG_ATTR_TC_0: Priority Group Traffic Class 0 configuration (NLA_NESTED) + * @DCB_PG_ATTR_TC_1: Priority Group Traffic Class 1 configuration (NLA_NESTED) + * @DCB_PG_ATTR_TC_2: Priority Group Traffic Class 2 configuration (NLA_NESTED) + * @DCB_PG_ATTR_TC_3: Priority Group Traffic Class 3 configuration (NLA_NESTED) + * @DCB_PG_ATTR_TC_4: Priority Group Traffic Class 4 configuration (NLA_NESTED) + * @DCB_PG_ATTR_TC_5: Priority Group Traffic Class 5 configuration (NLA_NESTED) + * @DCB_PG_ATTR_TC_6: Priority Group Traffic Class 6 configuration (NLA_NESTED) + * @DCB_PG_ATTR_TC_7: Priority Group Traffic Class 7 configuration (NLA_NESTED) + * @DCB_PG_ATTR_TC_MAX: highest attribute number currently defined + * @DCB_PG_ATTR_TC_ALL: apply to all traffic classes (NLA_NESTED) + * @DCB_PG_ATTR_BW_ID_0: Percent of link bandwidth for Priority Group 0 (NLA_U8) + * @DCB_PG_ATTR_BW_ID_1: Percent of link bandwidth for Priority Group 1 (NLA_U8) + * @DCB_PG_ATTR_BW_ID_2: Percent of link bandwidth for Priority Group 2 (NLA_U8) + * @DCB_PG_ATTR_BW_ID_3: Percent of link bandwidth for Priority Group 3 (NLA_U8) + * @DCB_PG_ATTR_BW_ID_4: Percent of link bandwidth for Priority Group 4 (NLA_U8) + * @DCB_PG_ATTR_BW_ID_5: Percent of link bandwidth for Priority Group 5 (NLA_U8) + * @DCB_PG_ATTR_BW_ID_6: Percent of link bandwidth for Priority Group 6 (NLA_U8) + * @DCB_PG_ATTR_BW_ID_7: Percent of link bandwidth for Priority Group 7 (NLA_U8) + * @DCB_PG_ATTR_BW_ID_MAX: highest attribute number currently defined + * @DCB_PG_ATTR_BW_ID_ALL: apply to all priority groups (NLA_FLAG) + * + */ +enum dcbnl_pg_attrs { + DCB_PG_ATTR_UNDEFINED, + + DCB_PG_ATTR_TC_0, + DCB_PG_ATTR_TC_1, + DCB_PG_ATTR_TC_2, + DCB_PG_ATTR_TC_3, + DCB_PG_ATTR_TC_4, + DCB_PG_ATTR_TC_5, + DCB_PG_ATTR_TC_6, + DCB_PG_ATTR_TC_7, + DCB_PG_ATTR_TC_MAX, + DCB_PG_ATTR_TC_ALL, + + DCB_PG_ATTR_BW_ID_0, + DCB_PG_ATTR_BW_ID_1, + DCB_PG_ATTR_BW_ID_2, + DCB_PG_ATTR_BW_ID_3, + DCB_PG_ATTR_BW_ID_4, + DCB_PG_ATTR_BW_ID_5, + DCB_PG_ATTR_BW_ID_6, + DCB_PG_ATTR_BW_ID_7, + DCB_PG_ATTR_BW_ID_MAX, + DCB_PG_ATTR_BW_ID_ALL, + + __DCB_PG_ATTR_ENUM_MAX, + DCB_PG_ATTR_MAX = __DCB_PG_ATTR_ENUM_MAX - 1, +}; + +/** + * enum dcbnl_tc_attrs - DCB Traffic Class attributes + * + * @DCB_TC_ATTR_PARAM_UNDEFINED: unspecified attribute to catch errors + * @DCB_TC_ATTR_PARAM_PGID: (NLA_U8) Priority group the traffic class belongs to + * Valid values are: 0-7 + * @DCB_TC_ATTR_PARAM_UP_MAPPING: (NLA_U8) Traffic class to user priority map + * Some devices may not support changing the + * user priority map of a TC. + * @DCB_TC_ATTR_PARAM_STRICT_PRIO: (NLA_U8) Strict priority setting + * 0 - none + * 1 - group strict + * 2 - link strict + * @DCB_TC_ATTR_PARAM_BW_PCT: optional - (NLA_U8) If supported by the device and + * not configured to use link strict priority, + * this is the percentage of bandwidth of the + * priority group this traffic class belongs to + * @DCB_TC_ATTR_PARAM_ALL: (NLA_FLAG) all traffic class parameters + * + */ +enum dcbnl_tc_attrs { + DCB_TC_ATTR_PARAM_UNDEFINED, + + DCB_TC_ATTR_PARAM_PGID, + DCB_TC_ATTR_PARAM_UP_MAPPING, + DCB_TC_ATTR_PARAM_STRICT_PRIO, + DCB_TC_ATTR_PARAM_BW_PCT, + DCB_TC_ATTR_PARAM_ALL, + + __DCB_TC_ATTR_PARAM_ENUM_MAX, + DCB_TC_ATTR_PARAM_MAX = __DCB_TC_ATTR_PARAM_ENUM_MAX - 1, +}; + +/** + * enum dcbnl_cap_attrs - DCB Capability attributes + * + * @DCB_CAP_ATTR_UNDEFINED: unspecified attribute to catch errors + * @DCB_CAP_ATTR_ALL: (NLA_FLAG) all capability parameters + * @DCB_CAP_ATTR_PG: (NLA_U8) device supports Priority Groups + * @DCB_CAP_ATTR_PFC: (NLA_U8) device supports Priority Flow Control + * @DCB_CAP_ATTR_UP2TC: (NLA_U8) device supports user priority to + * traffic class mapping + * @DCB_CAP_ATTR_PG_TCS: (NLA_U8) bitmap where each bit represents a + * number of traffic classes the device + * can be configured to use for Priority Groups + * @DCB_CAP_ATTR_PFC_TCS: (NLA_U8) bitmap where each bit represents a + * number of traffic classes the device can be + * configured to use for Priority Flow Control + * @DCB_CAP_ATTR_GSP: (NLA_U8) device supports group strict priority + * @DCB_CAP_ATTR_BCN: (NLA_U8) device supports Backwards Congestion + * Notification + */ +enum dcbnl_cap_attrs { + DCB_CAP_ATTR_UNDEFINED, + DCB_CAP_ATTR_ALL, + DCB_CAP_ATTR_PG, + DCB_CAP_ATTR_PFC, + DCB_CAP_ATTR_UP2TC, + DCB_CAP_ATTR_PG_TCS, + DCB_CAP_ATTR_PFC_TCS, + DCB_CAP_ATTR_GSP, + DCB_CAP_ATTR_BCN, + + __DCB_CAP_ATTR_ENUM_MAX, + DCB_CAP_ATTR_MAX = __DCB_CAP_ATTR_ENUM_MAX - 1, +}; + +/** + * enum dcbnl_numtcs_attrs - number of traffic classes + * + * @DCB_NUMTCS_ATTR_UNDEFINED: unspecified attribute to catch errors + * @DCB_NUMTCS_ATTR_ALL: (NLA_FLAG) all traffic class attributes + * @DCB_NUMTCS_ATTR_PG: (NLA_U8) number of traffic classes used for + * priority groups + * @DCB_NUMTCS_ATTR_PFC: (NLA_U8) number of traffic classes which can + * support priority flow control + */ +enum dcbnl_numtcs_attrs { + DCB_NUMTCS_ATTR_UNDEFINED, + DCB_NUMTCS_ATTR_ALL, + DCB_NUMTCS_ATTR_PG, + DCB_NUMTCS_ATTR_PFC, + + __DCB_NUMTCS_ATTR_ENUM_MAX, + DCB_NUMTCS_ATTR_MAX = __DCB_NUMTCS_ATTR_ENUM_MAX - 1, +}; + +enum dcbnl_bcn_attrs{ + DCB_BCN_ATTR_UNDEFINED = 0, + + DCB_BCN_ATTR_RP_0, + DCB_BCN_ATTR_RP_1, + DCB_BCN_ATTR_RP_2, + DCB_BCN_ATTR_RP_3, + DCB_BCN_ATTR_RP_4, + DCB_BCN_ATTR_RP_5, + DCB_BCN_ATTR_RP_6, + DCB_BCN_ATTR_RP_7, + DCB_BCN_ATTR_RP_ALL, + + DCB_BCN_ATTR_BCNA_0, + DCB_BCN_ATTR_BCNA_1, + DCB_BCN_ATTR_ALPHA, + DCB_BCN_ATTR_BETA, + DCB_BCN_ATTR_GD, + DCB_BCN_ATTR_GI, + DCB_BCN_ATTR_TMAX, + DCB_BCN_ATTR_TD, + DCB_BCN_ATTR_RMIN, + DCB_BCN_ATTR_W, + DCB_BCN_ATTR_RD, + DCB_BCN_ATTR_RU, + DCB_BCN_ATTR_WRTT, + DCB_BCN_ATTR_RI, + DCB_BCN_ATTR_C, + DCB_BCN_ATTR_ALL, + + __DCB_BCN_ATTR_ENUM_MAX, + DCB_BCN_ATTR_MAX = __DCB_BCN_ATTR_ENUM_MAX - 1, +}; + +/** + * enum dcb_general_attr_values - general DCB attribute values + * + * @DCB_ATTR_UNDEFINED: value used to indicate an attribute is not supported + * + */ +enum dcb_general_attr_values { + DCB_ATTR_VALUE_UNDEFINED = 0xff +}; + + +#endif /* __LINUX_DCBNL_H__ */ diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 6080449fbec942b7a1340c4a0c131f1957b33e81..61734e27abb7b6fc5e0c54d018c8969381a23c86 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h @@ -168,6 +168,8 @@ enum { DCCPO_MIN_CCID_SPECIFIC = 128, DCCPO_MAX_CCID_SPECIFIC = 255, }; +/* maximum size of a single TLV-encoded DCCP option (sans type/len bytes) */ +#define DCCP_SINGLE_OPT_MAXLEN 253 /* DCCP CCIDS */ enum { @@ -176,29 +178,23 @@ enum { }; /* DCCP features (RFC 4340 section 6.4) */ -enum { +enum dccp_feature_numbers { DCCPF_RESERVED = 0, DCCPF_CCID = 1, - DCCPF_SHORT_SEQNOS = 2, /* XXX: not yet implemented */ + DCCPF_SHORT_SEQNOS = 2, DCCPF_SEQUENCE_WINDOW = 3, - DCCPF_ECN_INCAPABLE = 4, /* XXX: not yet implemented */ + DCCPF_ECN_INCAPABLE = 4, DCCPF_ACK_RATIO = 5, DCCPF_SEND_ACK_VECTOR = 6, DCCPF_SEND_NDP_COUNT = 7, DCCPF_MIN_CSUM_COVER = 8, - DCCPF_DATA_CHECKSUM = 9, /* XXX: not yet implemented */ + DCCPF_DATA_CHECKSUM = 9, /* 10-127 reserved */ DCCPF_MIN_CCID_SPECIFIC = 128, + DCCPF_SEND_LEV_RATE = 192, /* RFC 4342, sec. 8.4 */ DCCPF_MAX_CCID_SPECIFIC = 255, }; -/* this structure is argument to DCCP_SOCKOPT_CHANGE_X */ -struct dccp_so_feat { - __u8 dccpsf_feat; - __u8 __user *dccpsf_val; - __u8 dccpsf_len; -}; - /* DCCP socket options */ #define DCCP_SOCKOPT_PACKET_SIZE 1 /* XXX deprecated, without effect */ #define DCCP_SOCKOPT_SERVICE 2 @@ -208,6 +204,10 @@ struct dccp_so_feat { #define DCCP_SOCKOPT_SERVER_TIMEWAIT 6 #define DCCP_SOCKOPT_SEND_CSCOV 10 #define DCCP_SOCKOPT_RECV_CSCOV 11 +#define DCCP_SOCKOPT_AVAILABLE_CCIDS 12 +#define DCCP_SOCKOPT_CCID 13 +#define DCCP_SOCKOPT_TX_CCID 14 +#define DCCP_SOCKOPT_RX_CCID 15 #define DCCP_SOCKOPT_CCID_RX_INFO 128 #define DCCP_SOCKOPT_CCID_TX_INFO 192 @@ -360,7 +360,6 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) #define DCCPF_INITIAL_SEQUENCE_WINDOW 100 #define DCCPF_INITIAL_ACK_RATIO 2 #define DCCPF_INITIAL_CCID DCCPC_CCID2 -#define DCCPF_INITIAL_SEND_ACK_VECTOR 1 /* FIXME: for now we're default to 1 but it should really be 0 */ #define DCCPF_INITIAL_SEND_NDP_COUNT 1 @@ -370,20 +369,11 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) * Will be used to pass the state from dccp_request_sock to dccp_sock. * * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2) - * @dccpms_ccid - Congestion Control Id (CCID) (section 10) - * @dccpms_send_ack_vector - Send Ack Vector Feature (section 11.5) - * @dccpms_send_ndp_count - Send NDP Count Feature (7.7.2) - * @dccpms_ack_ratio - Ack Ratio Feature (section 11.3) * @dccpms_pending - List of features being negotiated * @dccpms_conf - */ struct dccp_minisock { __u64 dccpms_sequence_window; - __u8 dccpms_rx_ccid; - __u8 dccpms_tx_ccid; - __u8 dccpms_send_ack_vector; - __u8 dccpms_send_ndp_count; - __u8 dccpms_ack_ratio; struct list_head dccpms_pending; struct list_head dccpms_conf; }; @@ -411,6 +401,7 @@ extern void dccp_minisock_init(struct dccp_minisock *dmsk); * @dreq_iss: initial sequence number sent on the Response (RFC 4340, 7.1) * @dreq_isr: initial sequence number received on the Request * @dreq_service: service code present on the Request (there is just one) + * @dreq_featneg: feature negotiation options for this connection * The following two fields are analogous to the ones in dccp_sock: * @dreq_timestamp_echo: last received timestamp to echo (13.1) * @dreq_timestamp_echo: the time of receiving the last @dreq_timestamp_echo @@ -420,6 +411,7 @@ struct dccp_request_sock { __u64 dreq_iss; __u64 dreq_isr; __be32 dreq_service; + struct list_head dreq_featneg; __u32 dreq_timestamp_echo; __u32 dreq_timestamp_time; }; @@ -493,10 +485,12 @@ struct dccp_ackvec; * @dccps_r_ack_ratio - feature-remote Ack Ratio * @dccps_pcslen - sender partial checksum coverage (via sockopt) * @dccps_pcrlen - receiver partial checksum coverage (via sockopt) + * @dccps_send_ndp_count - local Send NDP Count feature (7.7.2) * @dccps_ndp_count - number of Non Data Packets since last data packet * @dccps_mss_cache - current value of MSS (path MTU minus header sizes) * @dccps_rate_last - timestamp for rate-limiting DCCP-Sync (RFC 4340, 7.5.4) * @dccps_minisock - associated minisock (accessed via dccp_msk) + * @dccps_featneg - tracks feature-negotiation state (mostly during handshake) * @dccps_hc_rx_ackvec - rx half connection ack vector * @dccps_hc_rx_ccid - CCID used for the receiver (or receiving half-connection) * @dccps_hc_tx_ccid - CCID used for the sender (or sending half-connection) @@ -529,11 +523,13 @@ struct dccp_sock { __u32 dccps_timestamp_time; __u16 dccps_l_ack_ratio; __u16 dccps_r_ack_ratio; - __u16 dccps_pcslen; - __u16 dccps_pcrlen; + __u8 dccps_pcslen:4; + __u8 dccps_pcrlen:4; + __u8 dccps_send_ndp_count:1; __u64 dccps_ndp_count:48; unsigned long dccps_rate_last; struct dccp_minisock dccps_minisock; + struct list_head dccps_featneg; struct dccp_ackvec *dccps_hc_rx_ackvec; struct ccid *dccps_hc_rx_ccid; struct ccid *dccps_hc_tx_ccid; diff --git a/include/linux/etherdevice.h b/include/linux/etherdevice.h index 25d62e6e3290a58442ee8f5fd5c7ccd0b7b05809..1cb0f0b90926116cdbe854b85a6b144a3bf021ed 100644 --- a/include/linux/etherdevice.h +++ b/include/linux/etherdevice.h @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef __KERNEL__ extern __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev); @@ -41,6 +42,10 @@ extern int eth_header_cache(const struct neighbour *neigh, struct hh_cache *hh); extern void eth_header_cache_update(struct hh_cache *hh, const struct net_device *dev, const unsigned char *haddr); +extern int eth_mac_addr(struct net_device *dev, void *p); +extern int eth_change_mtu(struct net_device *dev, int new_mtu); +extern int eth_validate_addr(struct net_device *dev); + extern struct net_device *alloc_etherdev_mq(int sizeof_priv, unsigned int queue_count); @@ -136,6 +141,47 @@ static inline unsigned compare_ether_addr(const u8 *addr1, const u8 *addr2) BUILD_BUG_ON(ETH_ALEN != 6); return ((a[0] ^ b[0]) | (a[1] ^ b[1]) | (a[2] ^ b[2])) != 0; } + +static inline unsigned long zap_last_2bytes(unsigned long value) +{ +#ifdef __BIG_ENDIAN + return value >> 16; +#else + return value << 16; +#endif +} + +/** + * compare_ether_addr_64bits - Compare two Ethernet addresses + * @addr1: Pointer to an array of 8 bytes + * @addr2: Pointer to an other array of 8 bytes + * + * Compare two ethernet addresses, returns 0 if equal. + * Same result than "memcmp(addr1, addr2, ETH_ALEN)" but without conditional + * branches, and possibly long word memory accesses on CPU allowing cheap + * unaligned memory reads. + * arrays = { byte1, byte2, byte3, byte4, byte6, byte7, pad1, pad2} + * + * Please note that alignment of addr1 & addr2 is only guaranted to be 16 bits. + */ + +static inline unsigned compare_ether_addr_64bits(const u8 addr1[6+2], + const u8 addr2[6+2]) +{ +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS + unsigned long fold = ((*(unsigned long *)addr1) ^ + (*(unsigned long *)addr2)); + + if (sizeof(fold) == 8) + return zap_last_2bytes(fold) != 0; + + fold |= zap_last_2bytes((*(unsigned long *)(addr1 + 4)) ^ + (*(unsigned long *)(addr2 + 4))); + return fold != 0; +#else + return compare_ether_addr(addr1, addr2); +#endif +} #endif /* __KERNEL__ */ #endif /* _LINUX_ETHERDEVICE_H */ diff --git a/include/linux/ethtool.h b/include/linux/ethtool.h index b4b038b89ee639d098f26bf4ea683637b021377c..27c67a5422354dde23433ccd4c50676bd54b4198 100644 --- a/include/linux/ethtool.h +++ b/include/linux/ethtool.h @@ -467,6 +467,8 @@ struct ethtool_ops { #define ETHTOOL_GRXFH 0x00000029 /* Get RX flow hash configuration */ #define ETHTOOL_SRXFH 0x0000002a /* Set RX flow hash configuration */ +#define ETHTOOL_GGRO 0x0000002b /* Get GRO enable (ethtool_value) */ +#define ETHTOOL_SGRO 0x0000002c /* Set GRO enable (ethtool_value) */ /* compatibility with older code */ #define SPARC_ETH_GSET ETHTOOL_GSET diff --git a/include/linux/fddidevice.h b/include/linux/fddidevice.h index e61e42dfd3175c5436c8130b16963bfea2052d3e..155bafd9e886607f5ee6b9bd824c2a1fa8ec6c32 100644 --- a/include/linux/fddidevice.h +++ b/include/linux/fddidevice.h @@ -27,6 +27,7 @@ #ifdef __KERNEL__ extern __be16 fddi_type_trans(struct sk_buff *skb, struct net_device *dev); +extern int fddi_change_mtu(struct net_device *dev, int new_mtu); extern struct net_device *alloc_fddidev(int sizeof_priv); #endif diff --git a/include/linux/filter.h b/include/linux/filter.h index b6ea9aa9e853076cb597ed18afd5408e84a5590e..1354aaf6abbee4350baedc893a003a7e57481fe7 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -122,7 +122,8 @@ struct sock_fprog /* Required for SO_ATTACH_FILTER. */ #define SKF_AD_PKTTYPE 4 #define SKF_AD_IFINDEX 8 #define SKF_AD_NLATTR 12 -#define SKF_AD_MAX 16 +#define SKF_AD_NLATTR_NEST 16 +#define SKF_AD_MAX 20 #define SKF_NET_OFF (-0x100000) #define SKF_LL_OFF (-0x200000) diff --git a/include/linux/fsl_devices.h b/include/linux/fsl_devices.h index 708bab58d8d07dde74c3b8019a63b63405893c3a..d9051d717d27e6c96798ca34fe6600fe5f4189db 100644 --- a/include/linux/fsl_devices.h +++ b/include/linux/fsl_devices.h @@ -47,12 +47,7 @@ struct gianfar_platform_data { /* device specific information */ u32 device_flags; - /* board specific information */ - u32 board_flags; - int mdio_bus; /* Bus controlled by us */ - char bus_id[MII_BUS_ID_SIZE]; /* Bus PHY is on */ - u32 phy_id; - u8 mac_addr[6]; + char bus_id[BUS_ID_SIZE]; phy_interface_t interface; }; @@ -61,17 +56,6 @@ struct gianfar_mdio_data { int irq[32]; }; -/* Flags related to gianfar device features */ -#define FSL_GIANFAR_DEV_HAS_GIGABIT 0x00000001 -#define FSL_GIANFAR_DEV_HAS_COALESCE 0x00000002 -#define FSL_GIANFAR_DEV_HAS_RMON 0x00000004 -#define FSL_GIANFAR_DEV_HAS_MULTI_INTR 0x00000008 -#define FSL_GIANFAR_DEV_HAS_CSUM 0x00000010 -#define FSL_GIANFAR_DEV_HAS_VLAN 0x00000020 -#define FSL_GIANFAR_DEV_HAS_EXTENDED_HASH 0x00000040 -#define FSL_GIANFAR_DEV_HAS_PADDING 0x00000080 -#define FSL_GIANFAR_DEV_HAS_MAGIC_PACKET 0x00000100 - /* Flags in gianfar_platform_data */ #define FSL_GIANFAR_BRD_HAS_PHY_INTR 0x00000001 /* set or use a timer */ #define FSL_GIANFAR_BRD_IS_REDUCED 0x00000002 /* Set if RGMII, RMII */ diff --git a/include/linux/hdlc.h b/include/linux/hdlc.h index c59769693bee8876718b0410fdd2f46522fb65b1..fd47a151665e363a5d9cdb63f33810ccd55f9a1d 100644 --- a/include/linux/hdlc.h +++ b/include/linux/hdlc.h @@ -43,7 +43,7 @@ struct hdlc_proto { }; -/* Pointed to by dev->priv */ +/* Pointed to by netdev_priv(dev) */ typedef struct hdlc_device { /* used by HDLC layer to take control over HDLC device from hw driver*/ int (*attach)(struct net_device *dev, @@ -80,7 +80,7 @@ struct net_device *alloc_hdlcdev(void *priv); static inline struct hdlc_device* dev_to_hdlc(struct net_device *dev) { - return dev->priv; + return netdev_priv(dev); } static __inline__ void debug_frame(const struct sk_buff *skb) diff --git a/include/linux/hippidevice.h b/include/linux/hippidevice.h index bab303dafd6e1e4005d3d021ae7239788a3c2c63..f148e49084106fca84ae61b2880420dc0bc2798d 100644 --- a/include/linux/hippidevice.h +++ b/include/linux/hippidevice.h @@ -32,7 +32,9 @@ struct hippi_cb { }; extern __be16 hippi_type_trans(struct sk_buff *skb, struct net_device *dev); - +extern int hippi_change_mtu(struct net_device *dev, int new_mtu); +extern int hippi_mac_addr(struct net_device *dev, void *p); +extern int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p); extern struct net_device *alloc_hippi_dev(int sizeof_priv); #endif diff --git a/include/linux/ieee80211.h b/include/linux/ieee80211.h index 14126bc36641df1d654102136aa8903d2859d994..c4e6ca1a630668755ce78903e55e6510b6991487 100644 --- a/include/linux/ieee80211.h +++ b/include/linux/ieee80211.h @@ -12,8 +12,8 @@ * published by the Free Software Foundation. */ -#ifndef IEEE80211_H -#define IEEE80211_H +#ifndef LINUX_IEEE80211_H +#define LINUX_IEEE80211_H #include #include @@ -97,7 +97,10 @@ #define IEEE80211_MAX_FRAME_LEN 2352 #define IEEE80211_MAX_SSID_LEN 32 + #define IEEE80211_MAX_MESH_ID_LEN 32 +#define IEEE80211_MESH_CONFIG_LEN 19 + #define IEEE80211_QOS_CTL_LEN 2 #define IEEE80211_QOS_CTL_TID_MASK 0x000F #define IEEE80211_QOS_CTL_TAG1D_MASK 0x0007 @@ -666,6 +669,13 @@ struct ieee80211_cts { u8 ra[6]; } __attribute__ ((packed)); +struct ieee80211_pspoll { + __le16 frame_control; + __le16 aid; + u8 bssid[6]; + u8 ta[6]; +} __attribute__ ((packed)); + /** * struct ieee80211_bar - HT Block Ack Request * @@ -685,28 +695,88 @@ struct ieee80211_bar { #define IEEE80211_BAR_CTRL_ACK_POLICY_NORMAL 0x0000 #define IEEE80211_BAR_CTRL_CBMTID_COMPRESSED_BA 0x0004 + +#define IEEE80211_HT_MCS_MASK_LEN 10 + +/** + * struct ieee80211_mcs_info - MCS information + * @rx_mask: RX mask + * @rx_highest: highest supported RX rate + * @tx_params: TX parameters + */ +struct ieee80211_mcs_info { + u8 rx_mask[IEEE80211_HT_MCS_MASK_LEN]; + __le16 rx_highest; + u8 tx_params; + u8 reserved[3]; +} __attribute__((packed)); + +/* 802.11n HT capability MSC set */ +#define IEEE80211_HT_MCS_RX_HIGHEST_MASK 0x3ff +#define IEEE80211_HT_MCS_TX_DEFINED 0x01 +#define IEEE80211_HT_MCS_TX_RX_DIFF 0x02 +/* value 0 == 1 stream etc */ +#define IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK 0x0C +#define IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT 2 +#define IEEE80211_HT_MCS_TX_MAX_STREAMS 4 +#define IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION 0x10 + +/* + * 802.11n D5.0 20.3.5 / 20.6 says: + * - indices 0 to 7 and 32 are single spatial stream + * - 8 to 31 are multiple spatial streams using equal modulation + * [8..15 for two streams, 16..23 for three and 24..31 for four] + * - remainder are multiple spatial streams using unequal modulation + */ +#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START 33 +#define IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE \ + (IEEE80211_HT_MCS_UNEQUAL_MODULATION_START / 8) + /** * struct ieee80211_ht_cap - HT capabilities * - * This structure refers to "HT capabilities element" as - * described in 802.11n draft section 7.3.2.52 + * This structure is the "HT capabilities element" as + * described in 802.11n D5.0 7.3.2.57 */ struct ieee80211_ht_cap { __le16 cap_info; u8 ampdu_params_info; - u8 supp_mcs_set[16]; + + /* 16 bytes MCS information */ + struct ieee80211_mcs_info mcs; + __le16 extended_ht_cap_info; __le32 tx_BF_cap_info; u8 antenna_selection_info; } __attribute__ ((packed)); +/* 802.11n HT capabilities masks (for cap_info) */ +#define IEEE80211_HT_CAP_LDPC_CODING 0x0001 +#define IEEE80211_HT_CAP_SUP_WIDTH_20_40 0x0002 +#define IEEE80211_HT_CAP_SM_PS 0x000C +#define IEEE80211_HT_CAP_GRN_FLD 0x0010 +#define IEEE80211_HT_CAP_SGI_20 0x0020 +#define IEEE80211_HT_CAP_SGI_40 0x0040 +#define IEEE80211_HT_CAP_TX_STBC 0x0080 +#define IEEE80211_HT_CAP_RX_STBC 0x0300 +#define IEEE80211_HT_CAP_DELAY_BA 0x0400 +#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 +#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 +#define IEEE80211_HT_CAP_PSMP_SUPPORT 0x2000 +#define IEEE80211_HT_CAP_40MHZ_INTOLERANT 0x4000 +#define IEEE80211_HT_CAP_LSIG_TXOP_PROT 0x8000 + +/* 802.11n HT capability AMPDU settings (for ampdu_params_info) */ +#define IEEE80211_HT_AMPDU_PARM_FACTOR 0x03 +#define IEEE80211_HT_AMPDU_PARM_DENSITY 0x1C + /** - * struct ieee80211_ht_cap - HT additional information + * struct ieee80211_ht_info - HT information * - * This structure refers to "HT information element" as - * described in 802.11n draft section 7.3.2.53 + * This structure is the "HT information element" as + * described in 802.11n D5.0 7.3.2.58 */ -struct ieee80211_ht_addt_info { +struct ieee80211_ht_info { u8 control_chan; u8 ht_param; __le16 operation_mode; @@ -714,36 +784,33 @@ struct ieee80211_ht_addt_info { u8 basic_set[16]; } __attribute__ ((packed)); -/* 802.11n HT capabilities masks */ -#define IEEE80211_HT_CAP_SUP_WIDTH 0x0002 -#define IEEE80211_HT_CAP_SM_PS 0x000C -#define IEEE80211_HT_CAP_GRN_FLD 0x0010 -#define IEEE80211_HT_CAP_SGI_20 0x0020 -#define IEEE80211_HT_CAP_SGI_40 0x0040 -#define IEEE80211_HT_CAP_DELAY_BA 0x0400 -#define IEEE80211_HT_CAP_MAX_AMSDU 0x0800 -#define IEEE80211_HT_CAP_DSSSCCK40 0x1000 -/* 802.11n HT capability AMPDU settings */ -#define IEEE80211_HT_CAP_AMPDU_FACTOR 0x03 -#define IEEE80211_HT_CAP_AMPDU_DENSITY 0x1C -/* 802.11n HT capability MSC set */ -#define IEEE80211_SUPP_MCS_SET_UEQM 4 -#define IEEE80211_HT_CAP_MAX_STREAMS 4 -#define IEEE80211_SUPP_MCS_SET_LEN 10 -/* maximum streams the spec allows */ -#define IEEE80211_HT_CAP_MCS_TX_DEFINED 0x01 -#define IEEE80211_HT_CAP_MCS_TX_RX_DIFF 0x02 -#define IEEE80211_HT_CAP_MCS_TX_STREAMS 0x0C -#define IEEE80211_HT_CAP_MCS_TX_UEQM 0x10 -/* 802.11n HT IE masks */ -#define IEEE80211_HT_IE_CHA_SEC_OFFSET 0x03 -#define IEEE80211_HT_IE_CHA_SEC_NONE 0x00 -#define IEEE80211_HT_IE_CHA_SEC_ABOVE 0x01 -#define IEEE80211_HT_IE_CHA_SEC_BELOW 0x03 -#define IEEE80211_HT_IE_CHA_WIDTH 0x04 -#define IEEE80211_HT_IE_HT_PROTECTION 0x0003 -#define IEEE80211_HT_IE_NON_GF_STA_PRSNT 0x0004 -#define IEEE80211_HT_IE_NON_HT_STA_PRSNT 0x0010 +/* for ht_param */ +#define IEEE80211_HT_PARAM_CHA_SEC_OFFSET 0x03 +#define IEEE80211_HT_PARAM_CHA_SEC_NONE 0x00 +#define IEEE80211_HT_PARAM_CHA_SEC_ABOVE 0x01 +#define IEEE80211_HT_PARAM_CHA_SEC_BELOW 0x03 +#define IEEE80211_HT_PARAM_CHAN_WIDTH_ANY 0x04 +#define IEEE80211_HT_PARAM_RIFS_MODE 0x08 +#define IEEE80211_HT_PARAM_SPSMP_SUPPORT 0x10 +#define IEEE80211_HT_PARAM_SERV_INTERVAL_GRAN 0xE0 + +/* for operation_mode */ +#define IEEE80211_HT_OP_MODE_PROTECTION 0x0003 +#define IEEE80211_HT_OP_MODE_PROTECTION_NONE 0 +#define IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER 1 +#define IEEE80211_HT_OP_MODE_PROTECTION_20MHZ 2 +#define IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED 3 +#define IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT 0x0004 +#define IEEE80211_HT_OP_MODE_NON_HT_STA_PRSNT 0x0010 + +/* for stbc_param */ +#define IEEE80211_HT_STBC_PARAM_DUAL_BEACON 0x0040 +#define IEEE80211_HT_STBC_PARAM_DUAL_CTS_PROT 0x0080 +#define IEEE80211_HT_STBC_PARAM_STBC_BEACON 0x0100 +#define IEEE80211_HT_STBC_PARAM_LSIG_TXOP_FULLPROT 0x0200 +#define IEEE80211_HT_STBC_PARAM_PCO_ACTIVE 0x0400 +#define IEEE80211_HT_STBC_PARAM_PCO_PHASE 0x0800 + /* block-ack parameters */ #define IEEE80211_ADDBA_PARAM_POLICY_MASK 0x0002 @@ -769,7 +836,6 @@ struct ieee80211_ht_addt_info { /* Authentication algorithms */ #define WLAN_AUTH_OPEN 0 #define WLAN_AUTH_SHARED_KEY 1 -#define WLAN_AUTH_FAST_BSS_TRANSITION 2 #define WLAN_AUTH_LEAP 128 #define WLAN_AUTH_CHALLENGE_LEN 128 @@ -949,7 +1015,7 @@ enum ieee80211_eid { WLAN_EID_EXT_SUPP_RATES = 50, /* 802.11n */ WLAN_EID_HT_CAPABILITY = 45, - WLAN_EID_HT_EXTRA_INFO = 61, + WLAN_EID_HT_INFORMATION = 61, /* 802.11i */ WLAN_EID_RSN = 48, WLAN_EID_WPA = 221, @@ -976,6 +1042,68 @@ enum ieee80211_spectrum_mgmt_actioncode { WLAN_ACTION_SPCT_CHL_SWITCH = 4, }; +/* + * IEEE 802.11-2007 7.3.2.9 Country information element + * + * Minimum length is 8 octets, ie len must be evenly + * divisible by 2 + */ + +/* Although the spec says 8 I'm seeing 6 in practice */ +#define IEEE80211_COUNTRY_IE_MIN_LEN 6 + +/* + * For regulatory extension stuff see IEEE 802.11-2007 + * Annex I (page 1141) and Annex J (page 1147). Also + * review 7.3.2.9. + * + * When dot11RegulatoryClassesRequired is true and the + * first_channel/reg_extension_id is >= 201 then the IE + * compromises of the 'ext' struct represented below: + * + * - Regulatory extension ID - when generating IE this just needs + * to be monotonically increasing for each triplet passed in + * the IE + * - Regulatory class - index into set of rules + * - Coverage class - index into air propagation time (Table 7-27), + * in microseconds, you can compute the air propagation time from + * the index by multiplying by 3, so index 10 yields a propagation + * of 10 us. Valid values are 0-31, values 32-255 are not defined + * yet. A value of 0 inicates air propagation of <= 1 us. + * + * See also Table I.2 for Emission limit sets and table + * I.3 for Behavior limit sets. Table J.1 indicates how to map + * a reg_class to an emission limit set and behavior limit set. + */ +#define IEEE80211_COUNTRY_EXTENSION_ID 201 + +/* + * Channels numbers in the IE must be monotonically increasing + * if dot11RegulatoryClassesRequired is not true. + * + * If dot11RegulatoryClassesRequired is true consecutive + * subband triplets following a regulatory triplet shall + * have monotonically increasing first_channel number fields. + * + * Channel numbers shall not overlap. + * + * Note that max_power is signed. + */ +struct ieee80211_country_ie_triplet { + union { + struct { + u8 first_channel; + u8 num_channels; + s8 max_power; + } __attribute__ ((packed)) chans; + struct { + u8 reg_extension_id; + u8 reg_class; + u8 coverage_class; + } __attribute__ ((packed)) ext; + }; +} __attribute__ ((packed)); + /* BACK action code */ enum ieee80211_back_actioncode { WLAN_ACTION_ADDBA_REQ = 0, @@ -1057,4 +1185,4 @@ static inline u8 *ieee80211_get_DA(struct ieee80211_hdr *hdr) return hdr->addr1; } -#endif /* IEEE80211_H */ +#endif /* LINUX_IEEE80211_H */ diff --git a/include/linux/if.h b/include/linux/if.h index 65246846c844089e5eef7fce7054789f26ffe817..2a6e29620a963bcbfbd9195859fbab7c07f84266 100644 --- a/include/linux/if.h +++ b/include/linux/if.h @@ -65,6 +65,7 @@ #define IFF_BONDING 0x20 /* bonding master or slave */ #define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */ #define IFF_ISATAP 0x80 /* ISATAP interface (RFC4214) */ +#define IFF_MASTER_ARPMON 0x100 /* bonding master, ARP mon in use */ #define IF_GET_IFACE 0x0001 /* for querying only */ #define IF_GET_PROTO 0x0002 diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index 4d3401812e6cbfe237902c51a00e7123a96fc4cb..5ff89809a581b507cdae24e501316849175b9528 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -87,6 +87,9 @@ #define ARPHRD_IEEE80211_PRISM 802 /* IEEE 802.11 + Prism2 header */ #define ARPHRD_IEEE80211_RADIOTAP 803 /* IEEE 802.11 + radiotap header */ +#define ARPHRD_PHONET 820 /* PhoNet media type */ +#define ARPHRD_PHONET_PIPE 821 /* PhoNet pipe header */ + #define ARPHRD_VOID 0xFFFF /* Void type, nothing is known */ #define ARPHRD_NONE 0xFFFE /* zero header length */ diff --git a/include/linux/in.h b/include/linux/in.h index db458beef19dabe156b52eecab7bd30e11a7e5f9..d60122a3a0886310e9221405ad1c022f9d3d2fa7 100644 --- a/include/linux/in.h +++ b/include/linux/in.h @@ -80,6 +80,10 @@ struct in_addr { /* BSD compatibility */ #define IP_RECVRETOPTS IP_RETOPTS +/* TProxy original addresses */ +#define IP_ORIGDSTADDR 20 +#define IP_RECVORIGDSTADDR IP_ORIGDSTADDR + /* IP_MTU_DISCOVER values */ #define IP_PMTUDISC_DONT 0 /* Never send DF frames */ #define IP_PMTUDISC_WANT 1 /* Use per route hints */ diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h index 641e026eee8f1e3301a3297b85b0d6bafbcaadf5..0b816cae533eea35ece747f5c7921a3df8c979e3 100644 --- a/include/linux/ipv6.h +++ b/include/linux/ipv6.h @@ -278,6 +278,7 @@ struct ipv6_pinfo { struct in6_addr saddr; struct in6_addr rcv_saddr; struct in6_addr daddr; + struct in6_pktinfo sticky_pktinfo; struct in6_addr *daddr_cache; #ifdef CONFIG_IPV6_SUBTREES struct in6_addr *saddr_cache; diff --git a/include/linux/kernel.h b/include/linux/kernel.h index dc7e0d0a6474448aba71b4c32d2045afc44e240e..6002ae76785c9aeba493c0960aa5de508b139b49 100644 --- a/include/linux/kernel.h +++ b/include/linux/kernel.h @@ -361,18 +361,6 @@ static inline char *pack_hex_byte(char *buf, u8 byte) ((unsigned char *)&addr)[3] #define NIPQUAD_FMT "%u.%u.%u.%u" -#define NIP6(addr) \ - ntohs((addr).s6_addr16[0]), \ - ntohs((addr).s6_addr16[1]), \ - ntohs((addr).s6_addr16[2]), \ - ntohs((addr).s6_addr16[3]), \ - ntohs((addr).s6_addr16[4]), \ - ntohs((addr).s6_addr16[5]), \ - ntohs((addr).s6_addr16[6]), \ - ntohs((addr).s6_addr16[7]) -#define NIP6_FMT "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x" -#define NIP6_SEQFMT "%04x%04x%04x%04x%04x%04x%04x%04x" - #if defined(__LITTLE_ENDIAN) #define HIPQUAD(addr) \ ((unsigned char *)&addr)[3], \ diff --git a/include/linux/list_nulls.h b/include/linux/list_nulls.h new file mode 100644 index 0000000000000000000000000000000000000000..93150ecf3ea404d1b5bcb9c1090ea290c22d64ae --- /dev/null +++ b/include/linux/list_nulls.h @@ -0,0 +1,94 @@ +#ifndef _LINUX_LIST_NULLS_H +#define _LINUX_LIST_NULLS_H + +/* + * Special version of lists, where end of list is not a NULL pointer, + * but a 'nulls' marker, which can have many different values. + * (up to 2^31 different values guaranteed on all platforms) + * + * In the standard hlist, termination of a list is the NULL pointer. + * In this special 'nulls' variant, we use the fact that objects stored in + * a list are aligned on a word (4 or 8 bytes alignment). + * We therefore use the last significant bit of 'ptr' : + * Set to 1 : This is a 'nulls' end-of-list marker (ptr >> 1) + * Set to 0 : This is a pointer to some object (ptr) + */ + +struct hlist_nulls_head { + struct hlist_nulls_node *first; +}; + +struct hlist_nulls_node { + struct hlist_nulls_node *next, **pprev; +}; +#define INIT_HLIST_NULLS_HEAD(ptr, nulls) \ + ((ptr)->first = (struct hlist_nulls_node *) (1UL | (((long)nulls) << 1))) + +#define hlist_nulls_entry(ptr, type, member) container_of(ptr,type,member) +/** + * ptr_is_a_nulls - Test if a ptr is a nulls + * @ptr: ptr to be tested + * + */ +static inline int is_a_nulls(const struct hlist_nulls_node *ptr) +{ + return ((unsigned long)ptr & 1); +} + +/** + * get_nulls_value - Get the 'nulls' value of the end of chain + * @ptr: end of chain + * + * Should be called only if is_a_nulls(ptr); + */ +static inline unsigned long get_nulls_value(const struct hlist_nulls_node *ptr) +{ + return ((unsigned long)ptr) >> 1; +} + +static inline int hlist_nulls_unhashed(const struct hlist_nulls_node *h) +{ + return !h->pprev; +} + +static inline int hlist_nulls_empty(const struct hlist_nulls_head *h) +{ + return is_a_nulls(h->first); +} + +static inline void __hlist_nulls_del(struct hlist_nulls_node *n) +{ + struct hlist_nulls_node *next = n->next; + struct hlist_nulls_node **pprev = n->pprev; + *pprev = next; + if (!is_a_nulls(next)) + next->pprev = pprev; +} + +/** + * hlist_nulls_for_each_entry - iterate over list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_node within the struct. + * + */ +#define hlist_nulls_for_each_entry(tpos, pos, head, member) \ + for (pos = (head)->first; \ + (!is_a_nulls(pos)) && \ + ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +/** + * hlist_nulls_for_each_entry_from - iterate over a hlist continuing from current point + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_node to use as a loop cursor. + * @member: the name of the hlist_node within the struct. + * + */ +#define hlist_nulls_for_each_entry_from(tpos, pos, member) \ + for (; (!is_a_nulls(pos)) && \ + ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1;}); \ + pos = pos->next) + +#endif diff --git a/include/linux/mdio-gpio.h b/include/linux/mdio-gpio.h new file mode 100644 index 0000000000000000000000000000000000000000..e9d3fdfe41d71a9dc42c1b456a928e93e049bbc7 --- /dev/null +++ b/include/linux/mdio-gpio.h @@ -0,0 +1,25 @@ +/* + * MDIO-GPIO bus platform data structures + * + * Copyright (C) 2008, Paulius Zaleckas + * + * This file is licensed under the terms of the GNU General Public License + * version 2. This program is licensed "as is" without any warranty of any + * kind, whether express or implied. + */ + +#ifndef __LINUX_MDIO_GPIO_H +#define __LINUX_MDIO_GPIO_H + +#include + +struct mdio_gpio_platform_data { + /* GPIO numbers for bus pins */ + unsigned int mdc; + unsigned int mdio; + + unsigned int phy_mask; + int irqs[PHY_MAX_ADDR]; +}; + +#endif /* __LINUX_MDIO_GPIO_H */ diff --git a/include/linux/mii.h b/include/linux/mii.h index 151b7e0182c7e6dcce9574a0b3f60dc96a544016..ad748588faf1a2c0e6af662dfd1e790ecc766aa9 100644 --- a/include/linux/mii.h +++ b/include/linux/mii.h @@ -135,6 +135,10 @@ #define LPA_1000FULL 0x0800 /* Link partner 1000BASE-T full duplex */ #define LPA_1000HALF 0x0400 /* Link partner 1000BASE-T half duplex */ +/* Flow control flags */ +#define FLOW_CTRL_TX 0x01 +#define FLOW_CTRL_RX 0x02 + /* This structure is used in all SIOCxMIIxxx ioctl calls */ struct mii_ioctl_data { __u16 phy_id; @@ -235,5 +239,34 @@ static inline unsigned int mii_duplex (unsigned int duplex_lock, return 0; } +/** + * mii_resolve_flowctrl_fdx + * @lcladv: value of MII ADVERTISE register + * @rmtadv: value of MII LPA register + * + * Resolve full duplex flow control as per IEEE 802.3-2005 table 28B-3 + */ +static inline u8 mii_resolve_flowctrl_fdx(u16 lcladv, u16 rmtadv) +{ + u8 cap = 0; + + if (lcladv & ADVERTISE_PAUSE_CAP) { + if (lcladv & ADVERTISE_PAUSE_ASYM) { + if (rmtadv & LPA_PAUSE_CAP) + cap = FLOW_CTRL_TX | FLOW_CTRL_RX; + else if (rmtadv & LPA_PAUSE_ASYM) + cap = FLOW_CTRL_RX; + } else { + if (rmtadv & LPA_PAUSE_CAP) + cap = FLOW_CTRL_TX | FLOW_CTRL_RX; + } + } else if (lcladv & ADVERTISE_PAUSE_ASYM) { + if ((rmtadv & LPA_PAUSE_CAP) && (rmtadv & LPA_PAUSE_ASYM)) + cap = FLOW_CTRL_TX; + } + + return cap; +} + #endif /* __KERNEL__ */ #endif /* __LINUX_MII_H__ */ diff --git a/include/linux/mroute6.h b/include/linux/mroute6.h index 6f4c180179e2ef34fd06e2829bc2c99ba4bd39d3..5375faca1f72db1134d67d6c8feaedb0e18948ca 100644 --- a/include/linux/mroute6.h +++ b/include/linux/mroute6.h @@ -117,6 +117,7 @@ struct sioc_mif_req6 #include #include /* for struct sk_buff_head */ +#include #ifdef CONFIG_IPV6_MROUTE static inline int ip6_mroute_opt(int opt) @@ -187,6 +188,9 @@ struct mif_device struct mfc6_cache { struct mfc6_cache *next; /* Next entry on cache line */ +#ifdef CONFIG_NET_NS + struct net *mfc6_net; +#endif struct in6_addr mf6c_mcastgrp; /* Group the entry belongs to */ struct in6_addr mf6c_origin; /* Source of packet */ mifi_t mf6c_parent; /* Source interface */ @@ -209,6 +213,18 @@ struct mfc6_cache } mfc_un; }; +static inline +struct net *mfc6_net(const struct mfc6_cache *mfc) +{ + return read_pnet(&mfc->mfc6_net); +} + +static inline +void mfc6_net_set(struct mfc6_cache *mfc, struct net *net) +{ + write_pnet(&mfc->mfc6_net, hold_net(net)); +} + #define MFC_STATIC 1 #define MFC_NOTIFY 2 @@ -229,13 +245,17 @@ struct mfc6_cache #ifdef __KERNEL__ struct rtmsg; -extern int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait); +extern int ip6mr_get_route(struct net *net, struct sk_buff *skb, + struct rtmsg *rtm, int nowait); #ifdef CONFIG_IPV6_MROUTE -extern struct sock *mroute6_socket; +static inline struct sock *mroute6_socket(struct net *net) +{ + return net->ipv6.mroute6_sk; +} extern int ip6mr_sk_done(struct sock *sk); #else -#define mroute6_socket NULL +static inline struct sock *mroute6_socket(struct net *net) { return NULL; } static inline int ip6mr_sk_done(struct sock *sk) { return 0; } #endif #endif diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index e26f54952892e9c46be142344e36ceb37f19f6f0..41e1224651cf98dacc97acf74d999a7c89233ec4 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -43,6 +43,9 @@ #include #include +#ifdef CONFIG_DCB +#include +#endif struct vlan_group; struct ethtool_ops; @@ -311,8 +314,9 @@ struct napi_struct { spinlock_t poll_lock; int poll_owner; struct net_device *dev; - struct list_head dev_list; #endif + struct list_head dev_list; + struct sk_buff *gro_list; }; enum @@ -373,22 +377,8 @@ static inline int napi_reschedule(struct napi_struct *napi) * * Mark NAPI processing as complete. */ -static inline void __napi_complete(struct napi_struct *n) -{ - BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); - list_del(&n->poll_list); - smp_mb__before_clear_bit(); - clear_bit(NAPI_STATE_SCHED, &n->state); -} - -static inline void napi_complete(struct napi_struct *n) -{ - unsigned long flags; - - local_irq_save(flags); - __napi_complete(n); - local_irq_restore(flags); -} +extern void __napi_complete(struct napi_struct *n); +extern void napi_complete(struct napi_struct *n); /** * napi_disable - prevent NAPI from scheduling @@ -452,6 +442,147 @@ struct netdev_queue { struct Qdisc *qdisc_sleeping; } ____cacheline_aligned_in_smp; + +/* + * This structure defines the management hooks for network devices. + * The following hooks can be defined; unless noted otherwise, they are + * optional and can be filled with a null pointer. + * + * int (*ndo_init)(struct net_device *dev); + * This function is called once when network device is registered. + * The network device can use this to any late stage initializaton + * or semantic validattion. It can fail with an error code which will + * be propogated back to register_netdev + * + * void (*ndo_uninit)(struct net_device *dev); + * This function is called when device is unregistered or when registration + * fails. It is not called if init fails. + * + * int (*ndo_open)(struct net_device *dev); + * This function is called when network device transistions to the up + * state. + * + * int (*ndo_stop)(struct net_device *dev); + * This function is called when network device transistions to the down + * state. + * + * int (*ndo_hard_start_xmit)(struct sk_buff *skb, struct net_device *dev); + * Called when a packet needs to be transmitted. + * Must return NETDEV_TX_OK , NETDEV_TX_BUSY, or NETDEV_TX_LOCKED, + * Required can not be NULL. + * + * u16 (*ndo_select_queue)(struct net_device *dev, struct sk_buff *skb); + * Called to decide which queue to when device supports multiple + * transmit queues. + * + * void (*ndo_change_rx_flags)(struct net_device *dev, int flags); + * This function is called to allow device receiver to make + * changes to configuration when multicast or promiscious is enabled. + * + * void (*ndo_set_rx_mode)(struct net_device *dev); + * This function is called device changes address list filtering. + * + * void (*ndo_set_multicast_list)(struct net_device *dev); + * This function is called when the multicast address list changes. + * + * int (*ndo_set_mac_address)(struct net_device *dev, void *addr); + * This function is called when the Media Access Control address + * needs to be changed. If not this interface is not defined, the + * mac address can not be changed. + * + * int (*ndo_validate_addr)(struct net_device *dev); + * Test if Media Access Control address is valid for the device. + * + * int (*ndo_do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); + * Called when a user request an ioctl which can't be handled by + * the generic interface code. If not defined ioctl's return + * not supported error code. + * + * int (*ndo_set_config)(struct net_device *dev, struct ifmap *map); + * Used to set network devices bus interface parameters. This interface + * is retained for legacy reason, new devices should use the bus + * interface (PCI) for low level management. + * + * int (*ndo_change_mtu)(struct net_device *dev, int new_mtu); + * Called when a user wants to change the Maximum Transfer Unit + * of a device. If not defined, any request to change MTU will + * will return an error. + * + * void (*ndo_tx_timeout)(struct net_device *dev); + * Callback uses when the transmitter has not made any progress + * for dev->watchdog ticks. + * + * struct net_device_stats* (*get_stats)(struct net_device *dev); + * Called when a user wants to get the network device usage + * statistics. If not defined, the counters in dev->stats will + * be used. + * + * void (*ndo_vlan_rx_register)(struct net_device *dev, struct vlan_group *grp); + * If device support VLAN receive accleration + * (ie. dev->features & NETIF_F_HW_VLAN_RX), then this function is called + * when vlan groups for the device changes. Note: grp is NULL + * if no vlan's groups are being used. + * + * void (*ndo_vlan_rx_add_vid)(struct net_device *dev, unsigned short vid); + * If device support VLAN filtering (dev->features & NETIF_F_HW_VLAN_FILTER) + * this function is called when a VLAN id is registered. + * + * void (*ndo_vlan_rx_kill_vid)(struct net_device *dev, unsigned short vid); + * If device support VLAN filtering (dev->features & NETIF_F_HW_VLAN_FILTER) + * this function is called when a VLAN id is unregistered. + * + * void (*ndo_poll_controller)(struct net_device *dev); + */ +#define HAVE_NET_DEVICE_OPS +struct net_device_ops { + int (*ndo_init)(struct net_device *dev); + void (*ndo_uninit)(struct net_device *dev); + int (*ndo_open)(struct net_device *dev); + int (*ndo_stop)(struct net_device *dev); + int (*ndo_start_xmit) (struct sk_buff *skb, + struct net_device *dev); + u16 (*ndo_select_queue)(struct net_device *dev, + struct sk_buff *skb); +#define HAVE_CHANGE_RX_FLAGS + void (*ndo_change_rx_flags)(struct net_device *dev, + int flags); +#define HAVE_SET_RX_MODE + void (*ndo_set_rx_mode)(struct net_device *dev); +#define HAVE_MULTICAST + void (*ndo_set_multicast_list)(struct net_device *dev); +#define HAVE_SET_MAC_ADDR + int (*ndo_set_mac_address)(struct net_device *dev, + void *addr); +#define HAVE_VALIDATE_ADDR + int (*ndo_validate_addr)(struct net_device *dev); +#define HAVE_PRIVATE_IOCTL + int (*ndo_do_ioctl)(struct net_device *dev, + struct ifreq *ifr, int cmd); +#define HAVE_SET_CONFIG + int (*ndo_set_config)(struct net_device *dev, + struct ifmap *map); +#define HAVE_CHANGE_MTU + int (*ndo_change_mtu)(struct net_device *dev, + int new_mtu); + int (*ndo_neigh_setup)(struct net_device *dev, + struct neigh_parms *); +#define HAVE_TX_TIMEOUT + void (*ndo_tx_timeout) (struct net_device *dev); + + struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); + + void (*ndo_vlan_rx_register)(struct net_device *dev, + struct vlan_group *grp); + void (*ndo_vlan_rx_add_vid)(struct net_device *dev, + unsigned short vid); + void (*ndo_vlan_rx_kill_vid)(struct net_device *dev, + unsigned short vid); +#ifdef CONFIG_NET_POLL_CONTROLLER +#define HAVE_NETDEV_POLL + void (*ndo_poll_controller)(struct net_device *dev); +#endif +}; + /* * The DEVICE structure. * Actually, this whole structure is a big mistake. It mixes I/O @@ -496,14 +627,7 @@ struct net_device unsigned long state; struct list_head dev_list; -#ifdef CONFIG_NETPOLL struct list_head napi_list; -#endif - - /* The device initialization function. Called only once. */ - int (*init)(struct net_device *dev); - - /* ------- Fields preinitialized in Space.c finish here ------- */ /* Net device features */ unsigned long features; @@ -522,6 +646,7 @@ struct net_device #define NETIF_F_LLTX 4096 /* LockLess TX - deprecated. Please */ /* do not use LLTX in new drivers */ #define NETIF_F_NETNS_LOCAL 8192 /* Does not change network namespaces */ +#define NETIF_F_GRO 16384 /* Generic receive offload */ #define NETIF_F_LRO 32768 /* large receive offload */ /* Segmentation offload features */ @@ -547,15 +672,13 @@ struct net_device * for all in netdev_increment_features. */ #define NETIF_F_ONE_FOR_ALL (NETIF_F_GSO_SOFTWARE | NETIF_F_GSO_ROBUST | \ - NETIF_F_SG | NETIF_F_HIGHDMA | \ + NETIF_F_SG | NETIF_F_HIGHDMA | \ NETIF_F_FRAGLIST) /* Interface index. Unique device identifier */ int ifindex; int iflink; - - struct net_device_stats* (*get_stats)(struct net_device *dev); struct net_device_stats stats; #ifdef CONFIG_WIRELESS_EXT @@ -565,18 +688,13 @@ struct net_device /* Instance data managed by the core of Wireless Extensions. */ struct iw_public_data * wireless_data; #endif + /* Management operations */ + const struct net_device_ops *netdev_ops; const struct ethtool_ops *ethtool_ops; /* Hardware header description */ const struct header_ops *header_ops; - /* - * This marks the end of the "visible" part of the structure. All - * fields hereafter are internal to the system, and may change at - * will (read: may be cleaned up at will). - */ - - unsigned int flags; /* interface flags (a la BSD) */ unsigned short gflags; unsigned short priv_flags; /* Like 'flags' but invisible to userspace. */ @@ -635,7 +753,7 @@ struct net_device unsigned long last_rx; /* Time of last Rx */ /* Interface address info used in eth_type_trans() */ unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address, (before bcast - because most packets are unicast) */ + because most packets are unicast) */ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ @@ -654,18 +772,12 @@ struct net_device /* * One part is mostly used on xmit path (device) */ - void *priv; /* pointer to private data */ - int (*hard_start_xmit) (struct sk_buff *skb, - struct net_device *dev); /* These may be needed for future network-power-down code. */ unsigned long trans_start; /* Time (in jiffies) of last Tx */ int watchdog_timeo; /* used by dev_watchdog() */ struct timer_list watchdog_timer; -/* - * refcnt is a very hot point, so align it on SMP - */ /* Number of references to this device */ atomic_t refcnt ____cacheline_aligned_in_smp; @@ -684,56 +796,12 @@ struct net_device NETREG_RELEASED, /* called free_netdev */ } reg_state; - /* Called after device is detached from network. */ - void (*uninit)(struct net_device *dev); - /* Called after last user reference disappears. */ - void (*destructor)(struct net_device *dev); - - /* Pointers to interface service routines. */ - int (*open)(struct net_device *dev); - int (*stop)(struct net_device *dev); -#define HAVE_NETDEV_POLL -#define HAVE_CHANGE_RX_FLAGS - void (*change_rx_flags)(struct net_device *dev, - int flags); -#define HAVE_SET_RX_MODE - void (*set_rx_mode)(struct net_device *dev); -#define HAVE_MULTICAST - void (*set_multicast_list)(struct net_device *dev); -#define HAVE_SET_MAC_ADDR - int (*set_mac_address)(struct net_device *dev, - void *addr); -#define HAVE_VALIDATE_ADDR - int (*validate_addr)(struct net_device *dev); -#define HAVE_PRIVATE_IOCTL - int (*do_ioctl)(struct net_device *dev, - struct ifreq *ifr, int cmd); -#define HAVE_SET_CONFIG - int (*set_config)(struct net_device *dev, - struct ifmap *map); -#define HAVE_CHANGE_MTU - int (*change_mtu)(struct net_device *dev, int new_mtu); - -#define HAVE_TX_TIMEOUT - void (*tx_timeout) (struct net_device *dev); - - void (*vlan_rx_register)(struct net_device *dev, - struct vlan_group *grp); - void (*vlan_rx_add_vid)(struct net_device *dev, - unsigned short vid); - void (*vlan_rx_kill_vid)(struct net_device *dev, - unsigned short vid); + /* Called from unregister, can be used to call free_netdev */ + void (*destructor)(struct net_device *dev); - int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); #ifdef CONFIG_NETPOLL struct netpoll_info *npinfo; #endif -#ifdef CONFIG_NET_POLL_CONTROLLER - void (*poll_controller)(struct net_device *dev); -#endif - - u16 (*select_queue)(struct net_device *dev, - struct sk_buff *skb); #ifdef CONFIG_NET_NS /* Network namespace this network device is inside */ @@ -764,6 +832,49 @@ struct net_device /* for setting kernel sock attribute on TCP connection setup */ #define GSO_MAX_SIZE 65536 unsigned int gso_max_size; + +#ifdef CONFIG_DCB + /* Data Center Bridging netlink ops */ + struct dcbnl_rtnl_ops *dcbnl_ops; +#endif + +#ifdef CONFIG_COMPAT_NET_DEV_OPS + struct { + int (*init)(struct net_device *dev); + void (*uninit)(struct net_device *dev); + int (*open)(struct net_device *dev); + int (*stop)(struct net_device *dev); + int (*hard_start_xmit) (struct sk_buff *skb, + struct net_device *dev); + u16 (*select_queue)(struct net_device *dev, + struct sk_buff *skb); + void (*change_rx_flags)(struct net_device *dev, + int flags); + void (*set_rx_mode)(struct net_device *dev); + void (*set_multicast_list)(struct net_device *dev); + int (*set_mac_address)(struct net_device *dev, + void *addr); + int (*validate_addr)(struct net_device *dev); + int (*do_ioctl)(struct net_device *dev, + struct ifreq *ifr, int cmd); + int (*set_config)(struct net_device *dev, + struct ifmap *map); + int (*change_mtu)(struct net_device *dev, int new_mtu); + int (*neigh_setup)(struct net_device *dev, + struct neigh_parms *); + void (*tx_timeout) (struct net_device *dev); + struct net_device_stats* (*get_stats)(struct net_device *dev); + void (*vlan_rx_register)(struct net_device *dev, + struct vlan_group *grp); + void (*vlan_rx_add_vid)(struct net_device *dev, + unsigned short vid); + void (*vlan_rx_kill_vid)(struct net_device *dev, + unsigned short vid); +#ifdef CONFIG_NET_POLL_CONTROLLER + void (*poll_controller)(struct net_device *dev); +#endif + }; +#endif }; #define to_net_dev(d) container_of(d, struct net_device, dev) @@ -859,22 +970,8 @@ static inline void *netdev_priv(const struct net_device *dev) * netif_napi_add() must be used to initialize a napi context prior to calling * *any* of the other napi related functions. */ -static inline void netif_napi_add(struct net_device *dev, - struct napi_struct *napi, - int (*poll)(struct napi_struct *, int), - int weight) -{ - INIT_LIST_HEAD(&napi->poll_list); - napi->poll = poll; - napi->weight = weight; -#ifdef CONFIG_NETPOLL - napi->dev = dev; - list_add(&napi->dev_list, &dev->napi_list); - spin_lock_init(&napi->poll_lock); - napi->poll_owner = -1; -#endif - set_bit(NAPI_STATE_SCHED, &napi->state); -} +void netif_napi_add(struct net_device *dev, struct napi_struct *napi, + int (*poll)(struct napi_struct *, int), int weight); /** * netif_napi_del - remove a napi context @@ -882,12 +979,20 @@ static inline void netif_napi_add(struct net_device *dev, * * netif_napi_del() removes a napi context from the network device napi list */ -static inline void netif_napi_del(struct napi_struct *napi) -{ -#ifdef CONFIG_NETPOLL - list_del(&napi->dev_list); -#endif -} +void netif_napi_del(struct napi_struct *napi); + +struct napi_gro_cb { + /* This is non-zero if the packet may be of the same flow. */ + int same_flow; + + /* This is non-zero if the packet cannot be merged with the new skb. */ + int flush; + + /* Number of segments aggregated. */ + int count; +}; + +#define NAPI_GRO_CB(skb) ((struct napi_gro_cb *)(skb)->cb) struct packet_type { __be16 type; /* This is really htons(ether_type). */ @@ -899,6 +1004,9 @@ struct packet_type { struct sk_buff *(*gso_segment)(struct sk_buff *skb, int features); int (*gso_send_check)(struct sk_buff *skb); + struct sk_buff **(*gro_receive)(struct sk_buff **head, + struct sk_buff *skb); + int (*gro_complete)(struct sk_buff *skb); void *af_packet_priv; struct list_head list; }; @@ -1252,6 +1360,9 @@ extern int netif_rx(struct sk_buff *skb); extern int netif_rx_ni(struct sk_buff *skb); #define HAVE_NETIF_RECEIVE_SKB 1 extern int netif_receive_skb(struct sk_buff *skb); +extern void napi_gro_flush(struct napi_struct *napi); +extern int napi_gro_receive(struct napi_struct *napi, + struct sk_buff *skb); extern void netif_nit_deliver(struct sk_buff *skb); extern int dev_valid_name(const char *name); extern int dev_ioctl(struct net *net, unsigned int cmd, void __user *); @@ -1444,8 +1555,7 @@ static inline u32 netif_msg_init(int debug_value, int default_msg_enable_bits) } /* Test if receive needs to be scheduled but only if up */ -static inline int netif_rx_schedule_prep(struct net_device *dev, - struct napi_struct *napi) +static inline int netif_rx_schedule_prep(struct napi_struct *napi) { return napi_schedule_prep(napi); } @@ -1453,27 +1563,24 @@ static inline int netif_rx_schedule_prep(struct net_device *dev, /* Add interface to tail of rx poll list. This assumes that _prep has * already been called and returned 1. */ -static inline void __netif_rx_schedule(struct net_device *dev, - struct napi_struct *napi) +static inline void __netif_rx_schedule(struct napi_struct *napi) { __napi_schedule(napi); } /* Try to reschedule poll. Called by irq handler. */ -static inline void netif_rx_schedule(struct net_device *dev, - struct napi_struct *napi) +static inline void netif_rx_schedule(struct napi_struct *napi) { - if (netif_rx_schedule_prep(dev, napi)) - __netif_rx_schedule(dev, napi); + if (netif_rx_schedule_prep(napi)) + __netif_rx_schedule(napi); } /* Try to reschedule poll. Called by dev->poll() after netif_rx_complete(). */ -static inline int netif_rx_reschedule(struct net_device *dev, - struct napi_struct *napi) +static inline int netif_rx_reschedule(struct napi_struct *napi) { if (napi_schedule_prep(napi)) { - __netif_rx_schedule(dev, napi); + __netif_rx_schedule(napi); return 1; } return 0; @@ -1482,8 +1589,7 @@ static inline int netif_rx_reschedule(struct net_device *dev, /* same as netif_rx_complete, except that local_irq_save(flags) * has already been issued */ -static inline void __netif_rx_complete(struct net_device *dev, - struct napi_struct *napi) +static inline void __netif_rx_complete(struct napi_struct *napi) { __napi_complete(napi); } @@ -1493,20 +1599,9 @@ static inline void __netif_rx_complete(struct net_device *dev, * it completes the work. The device cannot be out of poll list at this * moment, it is BUG(). */ -static inline void netif_rx_complete(struct net_device *dev, - struct napi_struct *napi) +static inline void netif_rx_complete(struct napi_struct *napi) { - unsigned long flags; - - /* - * don't let napi dequeue from the cpu poll list - * just in case its running on a different cpu - */ - if (unlikely(test_bit(NAPI_STATE_NPSVC, &napi->state))) - return; - local_irq_save(flags); - __netif_rx_complete(dev, napi); - local_irq_restore(flags); + napi_complete(napi); } static inline void __netif_tx_lock(struct netdev_queue *txq, int cpu) @@ -1683,6 +1778,8 @@ extern void netdev_features_change(struct net_device *dev); /* Load a device via the kmod */ extern void dev_load(struct net *net, const char *name); extern void dev_mcast_init(void); +extern const struct net_device_stats *dev_get_stats(struct net_device *dev); + extern int netdev_max_backlog; extern int weight_p; extern int netdev_set_master(struct net_device *dev, struct net_device *master); @@ -1731,6 +1828,8 @@ static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb) { return skb_is_gso(skb) && (!skb_gso_ok(skb, dev->features) || + (skb_shinfo(skb)->frag_list && + !(dev->features & NETIF_F_FRAGLIST)) || unlikely(skb->ip_summed != CHECKSUM_PARTIAL)); } @@ -1749,26 +1848,31 @@ static inline int skb_bond_should_drop(struct sk_buff *skb) struct net_device *dev = skb->dev; struct net_device *master = dev->master; - if (master && - (dev->priv_flags & IFF_SLAVE_INACTIVE)) { - if ((dev->priv_flags & IFF_SLAVE_NEEDARP) && - skb->protocol == __constant_htons(ETH_P_ARP)) - return 0; + if (master) { + if (master->priv_flags & IFF_MASTER_ARPMON) + dev->last_rx = jiffies; - if (master->priv_flags & IFF_MASTER_ALB) { - if (skb->pkt_type != PACKET_BROADCAST && - skb->pkt_type != PACKET_MULTICAST) + if (dev->priv_flags & IFF_SLAVE_INACTIVE) { + if ((dev->priv_flags & IFF_SLAVE_NEEDARP) && + skb->protocol == __constant_htons(ETH_P_ARP)) return 0; - } - if (master->priv_flags & IFF_MASTER_8023AD && - skb->protocol == __constant_htons(ETH_P_SLOW)) - return 0; - return 1; + if (master->priv_flags & IFF_MASTER_ALB) { + if (skb->pkt_type != PACKET_BROADCAST && + skb->pkt_type != PACKET_MULTICAST) + return 0; + } + if (master->priv_flags & IFF_MASTER_8023AD && + skb->protocol == __constant_htons(ETH_P_SLOW)) + return 0; + + return 1; + } } return 0; } +extern struct pernet_operations __net_initdata loopback_net_ops; #endif /* __KERNEL__ */ #endif /* _LINUX_DEV_H */ diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h index d45e29cd1cfb9dc35d3953edcccfaa408bf39f0f..e40ddb94b1af8b4bf39b9989b1f51136e7d7f56d 100644 --- a/include/linux/netfilter_bridge/ebtables.h +++ b/include/linux/netfilter_bridge/ebtables.h @@ -300,7 +300,8 @@ struct ebt_table #define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \ ~(__alignof__(struct ebt_replace)-1)) -extern int ebt_register_table(struct ebt_table *table); +extern struct ebt_table *ebt_register_table(struct net *net, + struct ebt_table *table); extern void ebt_unregister_table(struct ebt_table *table); extern unsigned int ebt_do_table(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, diff --git a/include/linux/netfilter_ipv4/ipt_policy.h b/include/linux/netfilter_ipv4/ipt_policy.h index b9478a255301b6db9b730ff53f9c17434e133cf1..1037fb2cd2061f44d7bdde6e8cacf5e891b05569 100644 --- a/include/linux/netfilter_ipv4/ipt_policy.h +++ b/include/linux/netfilter_ipv4/ipt_policy.h @@ -1,6 +1,8 @@ #ifndef _IPT_POLICY_H #define _IPT_POLICY_H +#include + #define IPT_POLICY_MAX_ELEM XT_POLICY_MAX_ELEM /* ipt_policy_flags */ diff --git a/include/linux/netfilter_ipv6/ip6t_policy.h b/include/linux/netfilter_ipv6/ip6t_policy.h index 6bab3163d2fb6700b11c326a309d1079f7b73c5f..b1c449d7ec89626bfa8b88a3e0fc03aed46df0d6 100644 --- a/include/linux/netfilter_ipv6/ip6t_policy.h +++ b/include/linux/netfilter_ipv6/ip6t_policy.h @@ -1,6 +1,8 @@ #ifndef _IP6T_POLICY_H #define _IP6T_POLICY_H +#include + #define IP6T_POLICY_MAX_ELEM XT_POLICY_MAX_ELEM /* ip6t_policy_flags */ diff --git a/include/linux/netlink.h b/include/linux/netlink.h index 9ff1b54908f3a2260a01bea28b81ab811713fdd5..51b09a1f46c3bde1da65df6d096cbaa4b409c541 100644 --- a/include/linux/netlink.h +++ b/include/linux/netlink.h @@ -242,7 +242,8 @@ __nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len, int flags) nlh->nlmsg_flags = flags; nlh->nlmsg_pid = pid; nlh->nlmsg_seq = seq; - memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size); + if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0) + memset(NLMSG_DATA(nlh) + len, 0, NLMSG_ALIGN(size) - size); return nlh; } diff --git a/include/linux/netpoll.h b/include/linux/netpoll.h index e3d79593fb3a53186523071b4e22d6fbee47e79a..e38d3c9dccda9471e62f0102a6e20c5a3140e032 100644 --- a/include/linux/netpoll.h +++ b/include/linux/netpoll.h @@ -94,11 +94,6 @@ static inline void netpoll_poll_unlock(void *have) rcu_read_unlock(); } -static inline void netpoll_netdev_init(struct net_device *dev) -{ - INIT_LIST_HEAD(&dev->napi_list); -} - #else static inline int netpoll_rx(struct sk_buff *skb) { diff --git a/include/linux/nl80211.h b/include/linux/nl80211.h index 9bad65400fba76cad80e742b3784adbd4ca50637..e86ed59f9ad59b25317ce2be2f084a73063704c5 100644 --- a/include/linux/nl80211.h +++ b/include/linux/nl80211.h @@ -3,7 +3,26 @@ /* * 802.11 netlink interface public header * - * Copyright 2006, 2007 Johannes Berg + * Copyright 2006, 2007, 2008 Johannes Berg + * Copyright 2008 Michael Wu + * Copyright 2008 Luis Carlos Cobo + * Copyright 2008 Michael Buesch + * Copyright 2008 Luis R. Rodriguez + * Copyright 2008 Jouni Malinen + * Copyright 2008 Colin McCabe + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * */ /** @@ -25,8 +44,10 @@ * * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request * to get a list of all present wiphys. - * @NL80211_CMD_SET_WIPHY: set wiphy name, needs %NL80211_ATTR_WIPHY and - * %NL80211_ATTR_WIPHY_NAME. + * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or + * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME, + * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ, and/or + * %NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET. * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request * or rename notification. Has attributes %NL80211_ATTR_WIPHY and * %NL80211_ATTR_WIPHY_NAME. @@ -106,6 +127,12 @@ * to the the specified ISO/IEC 3166-1 alpha2 country code. The core will * store this as a valid request and then query userspace for it. * + * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the + * interface identified by %NL80211_ATTR_IFINDEX + * + * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the + * interface identified by %NL80211_ATTR_IFINDEX + * * @NL80211_CMD_MAX: highest used command number * @__NL80211_CMD_AFTER_LAST: internal use */ @@ -148,6 +175,9 @@ enum nl80211_commands { NL80211_CMD_SET_REG, NL80211_CMD_REQ_SET_REG, + NL80211_CMD_GET_MESH_PARAMS, + NL80211_CMD_SET_MESH_PARAMS, + /* add new commands above here */ /* used to define NL80211_CMD_MAX below */ @@ -169,6 +199,15 @@ enum nl80211_commands { * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf. * /sys/class/ieee80211//index * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming) + * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters + * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz + * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ + * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included): + * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including + * this attribute) + * NL80211_CHAN_HT20 = HT20 only + * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel + * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel * * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on * @NL80211_ATTR_IFNAME: network interface name @@ -234,6 +273,9 @@ enum nl80211_commands { * (u8, 0 or 1) * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled * (u8, 0 or 1) + * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic + * rates in format defined by IEEE 802.11 7.3.2.2 but without the length + * restriction (at most %NL80211_MAX_SUPP_RATES). * * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from * association request when used with NL80211_CMD_NEW_STATION) @@ -296,6 +338,14 @@ enum nl80211_attrs { NL80211_ATTR_REG_ALPHA2, NL80211_ATTR_REG_RULES, + NL80211_ATTR_MESH_PARAMS, + + NL80211_ATTR_BSS_BASIC_RATES, + + NL80211_ATTR_WIPHY_TXQ_PARAMS, + NL80211_ATTR_WIPHY_FREQ, + NL80211_ATTR_WIPHY_CHANNEL_TYPE, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, @@ -307,6 +357,10 @@ enum nl80211_attrs { * here */ #define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY +#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES +#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS +#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ +#define NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET NL80211_ATTR_WIPHY_SEC_CHAN_OFFSET #define NL80211_MAX_SUPP_RATES 32 #define NL80211_MAX_SUPP_REG_RULES 32 @@ -370,6 +424,32 @@ enum nl80211_sta_flags { NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1 }; +/** + * enum nl80211_rate_info - bitrate information + * + * These attribute types are used with %NL80211_STA_INFO_TXRATE + * when getting information about the bitrate of a station. + * + * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved + * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s) + * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8) + * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate + * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval + * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined + * @__NL80211_RATE_INFO_AFTER_LAST: internal use + */ +enum nl80211_rate_info { + __NL80211_RATE_INFO_INVALID, + NL80211_RATE_INFO_BITRATE, + NL80211_RATE_INFO_MCS, + NL80211_RATE_INFO_40_MHZ_WIDTH, + NL80211_RATE_INFO_SHORT_GI, + + /* keep last */ + __NL80211_RATE_INFO_AFTER_LAST, + NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1 +}; + /** * enum nl80211_sta_info - station information * @@ -382,6 +462,9 @@ enum nl80211_sta_flags { * @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 + * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm) + * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute + * containing info as possible, see &enum nl80211_sta_info_txrate. */ enum nl80211_sta_info { __NL80211_STA_INFO_INVALID, @@ -391,6 +474,8 @@ enum nl80211_sta_info { NL80211_STA_INFO_LLID, NL80211_STA_INFO_PLID, NL80211_STA_INFO_PLINK_STATE, + NL80211_STA_INFO_SIGNAL, + NL80211_STA_INFO_TX_BITRATE, /* keep last */ __NL80211_STA_INFO_AFTER_LAST, @@ -452,17 +537,29 @@ enum nl80211_mpath_info { * an array of nested frequency attributes * @NL80211_BAND_ATTR_RATES: supported bitrates in this band, * an array of nested bitrate attributes + * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as + * defined in 802.11n + * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE + * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n + * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n */ enum nl80211_band_attr { __NL80211_BAND_ATTR_INVALID, NL80211_BAND_ATTR_FREQS, NL80211_BAND_ATTR_RATES, + NL80211_BAND_ATTR_HT_MCS_SET, + NL80211_BAND_ATTR_HT_CAPA, + NL80211_BAND_ATTR_HT_AMPDU_FACTOR, + NL80211_BAND_ATTR_HT_AMPDU_DENSITY, + /* keep last */ __NL80211_BAND_ATTR_AFTER_LAST, NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1 }; +#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA + /** * enum nl80211_frequency_attr - frequency attributes * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz @@ -474,6 +571,8 @@ enum nl80211_band_attr { * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm + * (100 * dBm). */ enum nl80211_frequency_attr { __NL80211_FREQUENCY_ATTR_INVALID, @@ -482,12 +581,15 @@ enum nl80211_frequency_attr { NL80211_FREQUENCY_ATTR_PASSIVE_SCAN, NL80211_FREQUENCY_ATTR_NO_IBSS, NL80211_FREQUENCY_ATTR_RADAR, + NL80211_FREQUENCY_ATTR_MAX_TX_POWER, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1 }; +#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER + /** * enum nl80211_bitrate_attr - bitrate attributes * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps @@ -594,4 +696,119 @@ enum nl80211_mntr_flags { NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1 }; +/** + * enum nl80211_meshconf_params - mesh configuration parameters + * + * Mesh configuration parameters + * + * @__NL80211_MESHCONF_INVALID: internal use + * + * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in + * millisecond units, used by the Peer Link Open message + * + * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in + * millisecond units, used by the peer link management to close a peer link + * + * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in + * millisecond units + * + * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed + * on this mesh interface + * + * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link + * open retries that can be sent to establish a new peer link instance in a + * mesh + * + * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh + * point. + * + * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically + * open peer links when we detect compatible mesh peers. + * + * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames + * containing a PREQ that an MP can send to a particular destination (path + * target) + * + * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths + * (in milliseconds) + * + * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait + * until giving up on a path discovery (in milliseconds) + * + * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh + * points receiving a PREQ shall consider the forwarding information from the + * root to be valid. (TU = time unit) + * + * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in + * TUs) during which an MP can send only one action frame containing a PREQ + * reference element + * + * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs) + * that it takes for an HWMP information element to propagate across the mesh + * + * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute + * + * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use + */ +enum nl80211_meshconf_params { + __NL80211_MESHCONF_INVALID, + NL80211_MESHCONF_RETRY_TIMEOUT, + NL80211_MESHCONF_CONFIRM_TIMEOUT, + NL80211_MESHCONF_HOLDING_TIMEOUT, + NL80211_MESHCONF_MAX_PEER_LINKS, + NL80211_MESHCONF_MAX_RETRIES, + NL80211_MESHCONF_TTL, + NL80211_MESHCONF_AUTO_OPEN_PLINKS, + NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, + NL80211_MESHCONF_PATH_REFRESH_TIME, + NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, + NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, + NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, + NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, + + /* keep last */ + __NL80211_MESHCONF_ATTR_AFTER_LAST, + NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1 +}; + +/** + * enum nl80211_txq_attr - TX queue parameter attributes + * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved + * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*) + * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning + * disabled + * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form + * 2^n-1 in the range 1..32767] + * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form + * 2^n-1 in the range 1..32767] + * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255] + * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal + * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number + */ +enum nl80211_txq_attr { + __NL80211_TXQ_ATTR_INVALID, + NL80211_TXQ_ATTR_QUEUE, + NL80211_TXQ_ATTR_TXOP, + NL80211_TXQ_ATTR_CWMIN, + NL80211_TXQ_ATTR_CWMAX, + NL80211_TXQ_ATTR_AIFS, + + /* keep last */ + __NL80211_TXQ_ATTR_AFTER_LAST, + NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1 +}; + +enum nl80211_txq_q { + NL80211_TXQ_Q_VO, + NL80211_TXQ_Q_VI, + NL80211_TXQ_Q_BE, + NL80211_TXQ_Q_BK +}; + +enum nl80211_channel_type { + NL80211_CHAN_NO_HT, + NL80211_CHAN_HT20, + NL80211_CHAN_HT40MINUS, + NL80211_CHAN_HT40PLUS +}; #endif /* __LINUX_NL80211_H */ diff --git a/include/linux/phy.h b/include/linux/phy.h index 77c4ed60b98222103a981a23778af6a215287efb..d7e54d98869f8881666d927caf956074d42b4f97 100644 --- a/include/linux/phy.h +++ b/include/linux/phy.h @@ -467,6 +467,8 @@ int genphy_restart_aneg(struct phy_device *phydev); int genphy_config_aneg(struct phy_device *phydev); int genphy_update_link(struct phy_device *phydev); int genphy_read_status(struct phy_device *phydev); +int genphy_suspend(struct phy_device *phydev); +int genphy_resume(struct phy_device *phydev); void phy_driver_unregister(struct phy_driver *drv); int phy_driver_register(struct phy_driver *new_driver); void phy_prepare_link(struct phy_device *phydev, diff --git a/include/linux/pkt_cls.h b/include/linux/pkt_cls.h index 7cf7824df77814b327b1fb4abbd263273bd55bf4..e6aa8482ad7a910fdbf256b8d2cd7203d13f0e4b 100644 --- a/include/linux/pkt_cls.h +++ b/include/linux/pkt_cls.h @@ -394,6 +394,20 @@ enum #define TCA_BASIC_MAX (__TCA_BASIC_MAX - 1) + +/* Cgroup classifier */ + +enum +{ + TCA_CGROUP_UNSPEC, + TCA_CGROUP_ACT, + TCA_CGROUP_POLICE, + TCA_CGROUP_EMATCHES, + __TCA_CGROUP_MAX, +}; + +#define TCA_CGROUP_MAX (__TCA_CGROUP_MAX - 1) + /* Extended Matches */ struct tcf_ematch_tree_hdr diff --git a/include/linux/pkt_sched.h b/include/linux/pkt_sched.h index 5d921fa91a5bdb9e59ac2eec0036ed58082c9475..e3f133adba7828e62b620796ca6dcee345e08d86 100644 --- a/include/linux/pkt_sched.h +++ b/include/linux/pkt_sched.h @@ -500,4 +500,20 @@ struct tc_netem_corrupt #define NETEM_DIST_SCALE 8192 +/* DRR */ + +enum +{ + TCA_DRR_UNSPEC, + TCA_DRR_QUANTUM, + __TCA_DRR_MAX +}; + +#define TCA_DRR_MAX (__TCA_DRR_MAX - 1) + +struct tc_drr_stats +{ + u32 deficit; +}; + #endif diff --git a/include/linux/rculist_nulls.h b/include/linux/rculist_nulls.h new file mode 100644 index 0000000000000000000000000000000000000000..f9ddd03961a8a5e1abe1ac05a2803702263edb07 --- /dev/null +++ b/include/linux/rculist_nulls.h @@ -0,0 +1,110 @@ +#ifndef _LINUX_RCULIST_NULLS_H +#define _LINUX_RCULIST_NULLS_H + +#ifdef __KERNEL__ + +/* + * RCU-protected list version + */ +#include +#include + +/** + * hlist_nulls_del_init_rcu - deletes entry from hash list with re-initialization + * @n: the element to delete from the hash list. + * + * Note: hlist_nulls_unhashed() on the node return true after this. It is + * useful for RCU based read lockfree traversal if the writer side + * must know if the list entry is still hashed or already unhashed. + * + * In particular, it means that we can not poison the forward pointers + * that may still be used for walking the hash list and we can only + * zero the pprev pointer so list_unhashed() will return true after + * this. + * + * The caller must take whatever precautions are necessary (such as + * holding appropriate locks) to avoid racing with another + * list-mutation primitive, such as hlist_nulls_add_head_rcu() or + * hlist_nulls_del_rcu(), running on this same list. However, it is + * perfectly legal to run concurrently with the _rcu list-traversal + * primitives, such as hlist_nulls_for_each_entry_rcu(). + */ +static inline void hlist_nulls_del_init_rcu(struct hlist_nulls_node *n) +{ + if (!hlist_nulls_unhashed(n)) { + __hlist_nulls_del(n); + n->pprev = NULL; + } +} + +/** + * hlist_nulls_del_rcu - deletes entry from hash list without re-initialization + * @n: the element to delete from the hash list. + * + * Note: hlist_nulls_unhashed() on entry does not return true after this, + * the entry is in an undefined state. It is useful for RCU based + * lockfree traversal. + * + * In particular, it means that we can not poison the forward + * pointers that may still be used for walking the hash list. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_nulls_add_head_rcu() + * or hlist_nulls_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_nulls_for_each_entry(). + */ +static inline void hlist_nulls_del_rcu(struct hlist_nulls_node *n) +{ + __hlist_nulls_del(n); + n->pprev = LIST_POISON2; +} + +/** + * hlist_nulls_add_head_rcu + * @n: the element to add to the hash list. + * @h: the list to add to. + * + * Description: + * Adds the specified element to the specified hlist_nulls, + * while permitting racing traversals. + * + * The caller must take whatever precautions are necessary + * (such as holding appropriate locks) to avoid racing + * with another list-mutation primitive, such as hlist_nulls_add_head_rcu() + * or hlist_nulls_del_rcu(), running on this same list. + * However, it is perfectly legal to run concurrently with + * the _rcu list-traversal primitives, such as + * hlist_nulls_for_each_entry_rcu(), used to prevent memory-consistency + * problems on Alpha CPUs. Regardless of the type of CPU, the + * list-traversal primitive must be guarded by rcu_read_lock(). + */ +static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n, + struct hlist_nulls_head *h) +{ + struct hlist_nulls_node *first = h->first; + + n->next = first; + n->pprev = &h->first; + rcu_assign_pointer(h->first, n); + if (!is_a_nulls(first)) + first->pprev = &n->next; +} +/** + * hlist_nulls_for_each_entry_rcu - iterate over rcu list of given type + * @tpos: the type * to use as a loop cursor. + * @pos: the &struct hlist_nulls_node to use as a loop cursor. + * @head: the head for your list. + * @member: the name of the hlist_nulls_node within the struct. + * + */ +#define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member) \ + for (pos = rcu_dereference((head)->first); \ + (!is_a_nulls(pos)) && \ + ({ tpos = hlist_nulls_entry(pos, typeof(*tpos), member); 1; }); \ + pos = rcu_dereference(pos->next)) + +#endif +#endif diff --git a/include/linux/rfkill.h b/include/linux/rfkill.h index 4cd64b0d9825a6b2bbe33b9a584b1233a03ac54d..164332cbb77c81e7623dc5c9c193739cd7f87313 100644 --- a/include/linux/rfkill.h +++ b/include/linux/rfkill.h @@ -108,6 +108,7 @@ struct rfkill { struct device dev; struct list_head node; + enum rfkill_state state_for_resume; }; #define to_rfkill(d) container_of(d, struct rfkill, dev) @@ -148,11 +149,4 @@ static inline char *rfkill_get_led_name(struct rfkill *rfkill) #endif } -/* rfkill notification chain */ -#define RFKILL_STATE_CHANGED 0x0001 /* state of a normal rfkill - switch has changed */ - -int register_rfkill_notifier(struct notifier_block *nb); -int unregister_rfkill_notifier(struct notifier_block *nb); - #endif /* RFKILL_H */ diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h index 2b3d51c6ec9c706ae1049894340c5a00a9de169f..e88f7058b3a11b5764950e0ec95488ddc7610158 100644 --- a/include/linux/rtnetlink.h +++ b/include/linux/rtnetlink.h @@ -107,6 +107,11 @@ enum { RTM_GETADDRLABEL, #define RTM_GETADDRLABEL RTM_GETADDRLABEL + RTM_GETDCB = 78, +#define RTM_GETDCB RTM_GETDCB + RTM_SETDCB, +#define RTM_SETDCB RTM_SETDCB + __RTM_MAX, #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) }; diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 2725f4e5a9bf837f691ddc88361fcc280af4fb96..cf2cb50f77d1fe5f19e9894b78f4532789054ce7 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -250,6 +250,9 @@ typedef unsigned char *sk_buff_data_t; * @tc_verd: traffic control verdict * @ndisc_nodetype: router type (from link layer) * @do_not_encrypt: set to prevent encryption of this frame + * @requeue: set to indicate that the wireless core should attempt + * a software retry on this frame if we failed to + * receive an ACK for it * @dma_cookie: a cookie to one of several possible DMA operations * done by skb DMA functions * @secmark: security marking @@ -269,8 +272,9 @@ struct sk_buff { struct dst_entry *dst; struct rtable *rtable; }; +#ifdef CONFIG_XFRM struct sec_path *sp; - +#endif /* * This is the control buffer. It is free to use for every * layer. Please put your private variables there. If you @@ -325,6 +329,7 @@ struct sk_buff { #endif #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) __u8 do_not_encrypt:1; + __u8 requeue:1; #endif /* 0/13/14 bit hole */ @@ -487,6 +492,19 @@ static inline bool skb_queue_is_last(const struct sk_buff_head *list, return (skb->next == (struct sk_buff *) list); } +/** + * skb_queue_is_first - check if skb is the first entry in the queue + * @list: queue head + * @skb: buffer + * + * Returns true if @skb is the first buffer on the list. + */ +static inline bool skb_queue_is_first(const struct sk_buff_head *list, + const struct sk_buff *skb) +{ + return (skb->prev == (struct sk_buff *) list); +} + /** * skb_queue_next - return the next packet in the queue * @list: queue head @@ -505,6 +523,24 @@ static inline struct sk_buff *skb_queue_next(const struct sk_buff_head *list, return skb->next; } +/** + * skb_queue_prev - return the prev packet in the queue + * @list: queue head + * @skb: current buffer + * + * Return the prev packet in @list before @skb. It is only valid to + * call this if skb_queue_is_first() evaluates to false. + */ +static inline struct sk_buff *skb_queue_prev(const struct sk_buff_head *list, + const struct sk_buff *skb) +{ + /* This BUG_ON may seem severe, but if we just return then we + * are going to dereference garbage. + */ + BUG_ON(skb_queue_is_first(list, skb)); + return skb->prev; +} + /** * skb_get - reference buffer * @skb: buffer to reference @@ -1647,8 +1683,12 @@ extern int skb_splice_bits(struct sk_buff *skb, extern void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to); extern void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len); +extern int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, + int shiftlen); extern struct sk_buff *skb_segment(struct sk_buff *skb, int features); +extern int skb_gro_receive(struct sk_buff **head, + struct sk_buff *skb); static inline void *skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer) @@ -1864,6 +1904,18 @@ static inline void skb_copy_queue_mapping(struct sk_buff *to, const struct sk_bu to->queue_mapping = from->queue_mapping; } +#ifdef CONFIG_XFRM +static inline struct sec_path *skb_sec_path(struct sk_buff *skb) +{ + return skb->sp; +} +#else +static inline struct sec_path *skb_sec_path(struct sk_buff *skb) +{ + return NULL; +} +#endif + static inline int skb_is_gso(const struct sk_buff *skb) { return skb_shinfo(skb)->gso_size; diff --git a/include/linux/smsc911x.h b/include/linux/smsc911x.h new file mode 100644 index 0000000000000000000000000000000000000000..1cbf0313adde93f0971e56a89a7a907a08fcb8d6 --- /dev/null +++ b/include/linux/smsc911x.h @@ -0,0 +1,47 @@ +/*************************************************************************** + * + * Copyright (C) 2004-2008 SMSC + * Copyright (C) 2005-2008 ARM + * + * 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. + * + ***************************************************************************/ +#ifndef __LINUX_SMSC911X_H__ +#define __LINUX_SMSC911X_H__ + +#include + +/* platform_device configuration data, should be assigned to + * the platform_device's dev.platform_data */ +struct smsc911x_platform_config { + unsigned int irq_polarity; + unsigned int irq_type; + unsigned int flags; + phy_interface_t phy_interface; +}; + +/* Constants for platform_device irq polarity configuration */ +#define SMSC911X_IRQ_POLARITY_ACTIVE_LOW 0 +#define SMSC911X_IRQ_POLARITY_ACTIVE_HIGH 1 + +/* Constants for platform_device irq type configuration */ +#define SMSC911X_IRQ_TYPE_OPEN_DRAIN 0 +#define SMSC911X_IRQ_TYPE_PUSH_PULL 1 + +/* Constants for flags */ +#define SMSC911X_USE_16BIT (BIT(0)) +#define SMSC911X_USE_32BIT (BIT(1)) + +#endif /* __LINUX_SMSC911X_H__ */ diff --git a/include/linux/snmp.h b/include/linux/snmp.h index 7a6e6bba4a71d5a3a18ac3151e61d4c28b82737f..aee3f1e1d1ce18405626b9adf80e820193259a63 100644 --- a/include/linux/snmp.h +++ b/include/linux/snmp.h @@ -216,6 +216,9 @@ enum LINUX_MIB_TCPSPURIOUSRTOS, /* TCPSpuriousRTOs */ LINUX_MIB_TCPMD5NOTFOUND, /* TCPMD5NotFound */ LINUX_MIB_TCPMD5UNEXPECTED, /* TCPMD5Unexpected */ + LINUX_MIB_SACKSHIFTED, + LINUX_MIB_SACKMERGED, + LINUX_MIB_SACKSHIFTFALLBACK, __LINUX_MIB_MAX }; diff --git a/include/linux/sunrpc/svc_xprt.h b/include/linux/sunrpc/svc_xprt.h index 6fd7b016517f4e588f9cba7de616af751547e2c7..0127daca43548c85c219abc6445101165380eef9 100644 --- a/include/linux/sunrpc/svc_xprt.h +++ b/include/linux/sunrpc/svc_xprt.h @@ -139,14 +139,14 @@ static inline char *__svc_print_addr(struct sockaddr *addr, { switch (addr->sa_family) { case AF_INET: - snprintf(buf, len, "%u.%u.%u.%u, port=%u", - NIPQUAD(((struct sockaddr_in *) addr)->sin_addr), + snprintf(buf, len, "%pI4, port=%u", + &((struct sockaddr_in *)addr)->sin_addr, ntohs(((struct sockaddr_in *) addr)->sin_port)); break; case AF_INET6: - snprintf(buf, len, "%x:%x:%x:%x:%x:%x:%x:%x, port=%u", - NIP6(((struct sockaddr_in6 *) addr)->sin6_addr), + snprintf(buf, len, "%pI6, port=%u", + &((struct sockaddr_in6 *)addr)->sin6_addr, ntohs(((struct sockaddr_in6 *) addr)->sin6_port)); break; diff --git a/include/linux/virtio_net.h b/include/linux/virtio_net.h index 5e33761b9b8a9d7c038d6e062221f5f68a0def3b..5cdd0aa8bde94b0d53c37fe8bf463b9d07845c15 100644 --- a/include/linux/virtio_net.h +++ b/include/linux/virtio_net.h @@ -20,6 +20,7 @@ #define VIRTIO_NET_F_HOST_TSO6 12 /* Host can handle TSOv6 in. */ #define VIRTIO_NET_F_HOST_ECN 13 /* Host can handle TSO[6] w/ ECN in. */ #define VIRTIO_NET_F_HOST_UFO 14 /* Host can handle UFO in. */ +#define VIRTIO_NET_F_MRG_RXBUF 15 /* Host can merge receive buffers. */ struct virtio_net_config { @@ -44,4 +45,12 @@ struct virtio_net_hdr __u16 csum_start; /* Position to start checksumming from */ __u16 csum_offset; /* Offset after that to place checksum */ }; + +/* This is the version of the header to use when the MRG_RXBUF + * feature has been negotiated. */ +struct virtio_net_hdr_mrg_rxbuf { + struct virtio_net_hdr hdr; + __u16 num_buffers; /* Number of merged rx buffers */ +}; + #endif /* _LINUX_VIRTIO_NET_H */ diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h index 4bc1e6b86cb21ae1b0bc3ab24fd26806e4e3445e..52f3abd453a1386953963e6765725eb3d60fc025 100644 --- a/include/linux/xfrm.h +++ b/include/linux/xfrm.h @@ -199,6 +199,9 @@ enum { #define XFRM_MSG_NEWSPDINFO XFRM_MSG_NEWSPDINFO XFRM_MSG_GETSPDINFO, #define XFRM_MSG_GETSPDINFO XFRM_MSG_GETSPDINFO + + XFRM_MSG_MAPPING, +#define XFRM_MSG_MAPPING XFRM_MSG_MAPPING __XFRM_MSG_MAX }; #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) @@ -438,6 +441,15 @@ struct xfrm_user_migrate { __u16 new_family; }; +struct xfrm_user_mapping { + struct xfrm_usersa_id id; + __u32 reqid; + xfrm_address_t old_saddr; + xfrm_address_t new_saddr; + __be16 old_sport; + __be16 new_sport; +}; + #ifndef __KERNEL__ /* backwards compatibility for userspace */ #define XFRMGRP_ACQUIRE 1 @@ -464,6 +476,8 @@ enum xfrm_nlgroups { #define XFRMNLGRP_REPORT XFRMNLGRP_REPORT XFRMNLGRP_MIGRATE, #define XFRMNLGRP_MIGRATE XFRMNLGRP_MIGRATE + XFRMNLGRP_MAPPING, +#define XFRMNLGRP_MAPPING XFRMNLGRP_MAPPING __XFRMNLGRP_MAX }; #define XFRMNLGRP_MAX (__XFRMNLGRP_MAX - 1) diff --git a/include/net/bluetooth/bluetooth.h b/include/net/bluetooth/bluetooth.h index 996d12df75940f1ac722b52d764e5cd6c6d9a4c5..a04f8463ac7eec813cba0f9dfcb23e0e484036a5 100644 --- a/include/net/bluetooth/bluetooth.h +++ b/include/net/bluetooth/bluetooth.h @@ -54,8 +54,8 @@ #define SOL_RFCOMM 18 #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg) -#define BT_DBG(fmt, arg...) printk(KERN_INFO "%s: " fmt "\n" , __func__ , ## arg) -#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg) +#define BT_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg) +#define BT_DBG(fmt, arg...) pr_debug("%s: " fmt "\n" , __func__ , ## arg) /* Connection and socket states */ enum { diff --git a/include/net/bluetooth/hci.h b/include/net/bluetooth/hci.h index 3cc29491931268fab71e4c9663c0f6c13c671510..3645139e68c7d804dc53132435934f3325bb40f2 100644 --- a/include/net/bluetooth/hci.h +++ b/include/net/bluetooth/hci.h @@ -54,7 +54,7 @@ /* HCI device quirks */ enum { - HCI_QUIRK_RESET_ON_INIT, + HCI_QUIRK_NO_RESET, HCI_QUIRK_RAW_DEVICE, HCI_QUIRK_FIXUP_BUFFER_SIZE }; diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h index 0e85ec39b6380de904efe8c2ac0c89b3cb6f12e0..23c0ab74ded63bfbc9f57a36751872be3e195f77 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h @@ -5,6 +5,8 @@ #include #include #include +/* remove once we remove the wext stuff */ +#include /* * 802.11 configuration in-kernel interface @@ -167,6 +169,9 @@ struct station_parameters { * @STATION_INFO_LLID: @llid filled * @STATION_INFO_PLID: @plid filled * @STATION_INFO_PLINK_STATE: @plink_state filled + * @STATION_INFO_SIGNAL: @signal filled + * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled + * (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs) */ enum station_info_flags { STATION_INFO_INACTIVE_TIME = 1<<0, @@ -175,6 +180,39 @@ enum station_info_flags { STATION_INFO_LLID = 1<<3, STATION_INFO_PLID = 1<<4, STATION_INFO_PLINK_STATE = 1<<5, + STATION_INFO_SIGNAL = 1<<6, + STATION_INFO_TX_BITRATE = 1<<7, +}; + +/** + * enum station_info_rate_flags - bitrate info flags + * + * Used by the driver to indicate the specific rate transmission + * type for 802.11n transmissions. + * + * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled + * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission + * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval + */ +enum rate_info_flags { + RATE_INFO_FLAGS_MCS = 1<<0, + RATE_INFO_FLAGS_40_MHZ_WIDTH = 1<<1, + RATE_INFO_FLAGS_SHORT_GI = 1<<2, +}; + +/** + * struct rate_info - bitrate information + * + * Information about a receiving or transmitting bitrate + * + * @flags: bitflag of flags from &enum rate_info_flags + * @mcs: mcs index if struct describes a 802.11n bitrate + * @legacy: bitrate in 100kbit/s for 802.11abg + */ +struct rate_info { + u8 flags; + u8 mcs; + u16 legacy; }; /** @@ -189,6 +227,8 @@ enum station_info_flags { * @llid: mesh local link id * @plid: mesh peer link id * @plink_state: mesh peer link state + * @signal: signal strength of last received packet in dBm + * @txrate: current unicast bitrate to this station */ struct station_info { u32 filled; @@ -198,6 +238,8 @@ struct station_info { u16 llid; u16 plid; u8 plink_state; + s8 signal; + struct rate_info txrate; }; /** @@ -280,11 +322,16 @@ struct mpath_info { * (0 = no, 1 = yes, -1 = do not change) * @use_short_slot_time: Whether the use of short slot time is allowed * (0 = no, 1 = yes, -1 = do not change) + * @basic_rates: basic rates in IEEE 802.11 format + * (or NULL for no change) + * @basic_rates_len: number of basic rates */ struct bss_parameters { int use_cts_prot; int use_short_preamble; int use_short_slot_time; + u8 *basic_rates; + u8 basic_rates_len; }; /** @@ -331,25 +378,65 @@ struct ieee80211_regdomain { struct ieee80211_reg_rule reg_rules[]; }; -#define MHZ_TO_KHZ(freq) (freq * 1000) -#define KHZ_TO_MHZ(freq) (freq / 1000) -#define DBI_TO_MBI(gain) (gain * 100) -#define MBI_TO_DBI(gain) (gain / 100) -#define DBM_TO_MBM(gain) (gain * 100) -#define MBM_TO_DBM(gain) (gain / 100) +#define MHZ_TO_KHZ(freq) ((freq) * 1000) +#define KHZ_TO_MHZ(freq) ((freq) / 1000) +#define DBI_TO_MBI(gain) ((gain) * 100) +#define MBI_TO_DBI(gain) ((gain) / 100) +#define DBM_TO_MBM(gain) ((gain) * 100) +#define MBM_TO_DBM(gain) ((gain) / 100) #define REG_RULE(start, end, bw, gain, eirp, reg_flags) { \ - .freq_range.start_freq_khz = (start) * 1000, \ - .freq_range.end_freq_khz = (end) * 1000, \ - .freq_range.max_bandwidth_khz = (bw) * 1000, \ - .power_rule.max_antenna_gain = (gain) * 100, \ - .power_rule.max_eirp = (eirp) * 100, \ + .freq_range.start_freq_khz = MHZ_TO_KHZ(start), \ + .freq_range.end_freq_khz = MHZ_TO_KHZ(end), \ + .freq_range.max_bandwidth_khz = MHZ_TO_KHZ(bw), \ + .power_rule.max_antenna_gain = DBI_TO_MBI(gain), \ + .power_rule.max_eirp = DBM_TO_MBM(eirp), \ .flags = reg_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 */ + u8 dot11MeshHWMPmaxPREQretries; + u32 path_refresh_time; + u16 min_discovery_timeout; + u32 dot11MeshHWMPactivePathTimeout; + u16 dot11MeshHWMPpreqMinInterval; + u16 dot11MeshHWMPnetDiameterTraversalTime; +}; + +/** + * struct ieee80211_txq_params - TX queue parameters + * @queue: TX queue identifier (NL80211_TXQ_Q_*) + * @txop: Maximum burst time in units of 32 usecs, 0 meaning disabled + * @cwmin: Minimum contention window [a value of the form 2^n-1 in the range + * 1..32767] + * @cwmax: Maximum contention window [a value of the form 2^n-1 in the range + * 1..32767] + * @aifs: Arbitration interframe space [0..255] + */ +struct ieee80211_txq_params { + enum nl80211_txq_q queue; + u16 txop; + u16 cwmin; + u16 cwmax; + u8 aifs; +}; + /* from net/wireless.h */ struct wiphy; +/* from net/ieee80211.h */ +struct ieee80211_channel; + /** * struct cfg80211_ops - backend description for wireless configuration * @@ -397,9 +484,19 @@ struct wiphy; * * @change_station: Modify a given station. * + * @get_mesh_params: Put the current mesh parameters into *params + * + * @set_mesh_params: Set mesh parameters. + * The mask is a bitfield which tells us which parameters to + * set, and which to leave alone. + * * @set_mesh_cfg: set mesh parameters (by now, just mesh id) * * @change_bss: Modify parameters for a given BSS. + * + * @set_txq_params: Set TX queue parameters + * + * @set_channel: Set channel */ struct cfg80211_ops { int (*add_virtual_intf)(struct wiphy *wiphy, char *name, @@ -452,9 +549,30 @@ struct cfg80211_ops { int (*dump_mpath)(struct wiphy *wiphy, struct net_device *dev, int idx, u8 *dst, u8 *next_hop, struct mpath_info *pinfo); - + int (*get_mesh_params)(struct wiphy *wiphy, + struct net_device *dev, + struct mesh_config *conf); + int (*set_mesh_params)(struct wiphy *wiphy, + struct net_device *dev, + const struct mesh_config *nconf, u32 mask); int (*change_bss)(struct wiphy *wiphy, struct net_device *dev, struct bss_parameters *params); + + int (*set_txq_params)(struct wiphy *wiphy, + struct ieee80211_txq_params *params); + + int (*set_channel)(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type); }; +/* temporary wext handlers */ +int cfg80211_wext_giwname(struct net_device *dev, + struct iw_request_info *info, + char *name, char *extra); +int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, + u32 *mode, char *extra); +int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, + u32 *mode, char *extra); + #endif /* __NET_CFG80211_H */ diff --git a/include/net/checksum.h b/include/net/checksum.h index 07602b7fa2185970d14f7af67f6a5f996c92bfe3..ba55d8b8c87cb5438f87fad5ae01d2aee77d59ab 100644 --- a/include/net/checksum.h +++ b/include/net/checksum.h @@ -98,7 +98,7 @@ static inline void csum_replace4(__sum16 *sum, __be32 from, __be32 to) { __be32 diff[] = { ~from, to }; - *sum = csum_fold(csum_partial((char *)diff, sizeof(diff), ~csum_unfold(*sum))); + *sum = csum_fold(csum_partial(diff, sizeof(diff), ~csum_unfold(*sum))); } static inline void csum_replace2(__sum16 *sum, __be16 from, __be16 to) diff --git a/include/net/dcbnl.h b/include/net/dcbnl.h new file mode 100644 index 0000000000000000000000000000000000000000..775cfc8055bed122d9e54f30b83c186cccf3a185 --- /dev/null +++ b/include/net/dcbnl.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2008, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * Author: Lucy Liu + */ + +#ifndef __NET_DCBNL_H__ +#define __NET_DCBNL_H__ + +/* + * Ops struct for the netlink callbacks. Used by DCB-enabled drivers through + * the netdevice struct. + */ +struct dcbnl_rtnl_ops { + u8 (*getstate)(struct net_device *); + u8 (*setstate)(struct net_device *, u8); + void (*getpermhwaddr)(struct net_device *, u8 *); + void (*setpgtccfgtx)(struct net_device *, int, u8, u8, u8, u8); + void (*setpgbwgcfgtx)(struct net_device *, int, u8); + void (*setpgtccfgrx)(struct net_device *, int, u8, u8, u8, u8); + void (*setpgbwgcfgrx)(struct net_device *, int, u8); + void (*getpgtccfgtx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *); + void (*getpgbwgcfgtx)(struct net_device *, int, u8 *); + void (*getpgtccfgrx)(struct net_device *, int, u8 *, u8 *, u8 *, u8 *); + void (*getpgbwgcfgrx)(struct net_device *, int, u8 *); + void (*setpfccfg)(struct net_device *, int, u8); + void (*getpfccfg)(struct net_device *, int, u8 *); + u8 (*setall)(struct net_device *); + u8 (*getcap)(struct net_device *, int, u8 *); + u8 (*getnumtcs)(struct net_device *, int, u8 *); + u8 (*setnumtcs)(struct net_device *, int, u8); + u8 (*getpfcstate)(struct net_device *); + void (*setpfcstate)(struct net_device *, u8); + void (*getbcncfg)(struct net_device *, int, u32 *); + void (*setbcncfg)(struct net_device *, int, u32); + void (*getbcnrp)(struct net_device *, int, u8 *); + void (*setbcnrp)(struct net_device *, int, u8); +}; + +#endif /* __NET_DCBNL_H__ */ diff --git a/include/net/dn.h b/include/net/dn.h index 627778384c84cff9583636abebdd3b210df0ad63..e5469f7b67a3b17d7916188a822348214120a81e 100644 --- a/include/net/dn.h +++ b/include/net/dn.h @@ -4,9 +4,7 @@ #include #include #include - -#define dn_ntohs(x) le16_to_cpu(x) -#define dn_htons(x) cpu_to_le16(x) +#include struct dn_scp /* Session Control Port */ { @@ -175,7 +173,7 @@ struct dn_skb_cb { static inline __le16 dn_eth2dn(unsigned char *ethaddr) { - return dn_htons(ethaddr[4] | (ethaddr[5] << 8)); + return get_unaligned((__le16 *)(ethaddr + 4)); } static inline __le16 dn_saddr2dn(struct sockaddr_dn *saddr) @@ -185,7 +183,7 @@ static inline __le16 dn_saddr2dn(struct sockaddr_dn *saddr) static inline void dn_dn2eth(unsigned char *ethaddr, __le16 addr) { - __u16 a = dn_ntohs(addr); + __u16 a = le16_to_cpu(addr); ethaddr[0] = 0xAA; ethaddr[1] = 0x00; ethaddr[2] = 0x04; diff --git a/include/net/dn_fib.h b/include/net/dn_fib.h index 30125119c950f764c3d42773fa1786c3fe7343a5..c378be7bf96002118edcd65d2aa2be87ba842e7d 100644 --- a/include/net/dn_fib.h +++ b/include/net/dn_fib.h @@ -181,9 +181,9 @@ static inline void dn_fib_res_put(struct dn_fib_res *res) static inline __le16 dnet_make_mask(int n) { - if (n) - return dn_htons(~((1<<(16-n))-1)); - return 0; + if (n) + return cpu_to_le16(~((1 << (16 - n)) - 1)); + return cpu_to_le16(0); } #endif /* _NET_DN_FIB_H */ diff --git a/include/net/dst.h b/include/net/dst.h index 8a8b71e5f3f13578a2004fe84ee6e17dc7caa9a4..6be3b082a070332187ff6134ad04fd0e09da3279 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -59,8 +59,11 @@ struct dst_entry struct neighbour *neighbour; struct hh_cache *hh; +#ifdef CONFIG_XFRM struct xfrm_state *xfrm; - +#else + void *__pad1; +#endif int (*input)(struct sk_buff*); int (*output)(struct sk_buff*); @@ -70,8 +73,20 @@ struct dst_entry #ifdef CONFIG_NET_CLS_ROUTE __u32 tclassid; +#else + __u32 __pad2; #endif + + /* + * Align __refcnt to a 64 bytes alignment + * (L1_CACHE_SIZE would be too much) + */ +#ifdef CONFIG_64BIT + long __pad_to_align_refcnt[2]; +#else + long __pad_to_align_refcnt[1]; +#endif /* * __refcnt wants to be on a different cache line from * input/output/ops or performance tanks badly @@ -103,7 +118,6 @@ struct dst_ops void (*link_failure)(struct sk_buff *); void (*update_pmtu)(struct dst_entry *dst, u32 mtu); int (*local_out)(struct sk_buff *skb); - int entry_size; atomic_t entries; struct kmem_cache *kmem_cachep; @@ -157,6 +171,11 @@ dst_metric_locked(struct dst_entry *dst, int metric) static inline void dst_hold(struct dst_entry * dst) { + /* + * If your kernel compilation stops here, please check + * __pad_to_align_refcnt declaration in struct dst_entry + */ + BUILD_BUG_ON(offsetof(struct dst_entry, __refcnt) & 63); atomic_inc(&dst->__refcnt); } @@ -272,21 +291,21 @@ enum { struct flowi; #ifndef CONFIG_XFRM -static inline int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, - struct sock *sk, int flags) +static inline int xfrm_lookup(struct net *net, struct dst_entry **dst_p, + struct flowi *fl, struct sock *sk, int flags) { return 0; } -static inline int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, - struct sock *sk, int flags) +static inline int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, + struct flowi *fl, struct sock *sk, int flags) { return 0; } #else -extern int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, - struct sock *sk, int flags); -extern int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, - struct sock *sk, int flags); +extern int xfrm_lookup(struct net *net, struct dst_entry **dst_p, + struct flowi *fl, struct sock *sk, int flags); +extern int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, + struct flowi *fl, struct sock *sk, int flags); #endif #endif diff --git a/include/net/flow.h b/include/net/flow.h index b45a5e4fcadd83545fb48b5b9a9daec347811f71..809970b7dfee71670ac9a8c1bf753923a96a264e 100644 --- a/include/net/flow.h +++ b/include/net/flow.h @@ -84,12 +84,13 @@ struct flowi { #define FLOW_DIR_OUT 1 #define FLOW_DIR_FWD 2 +struct net; struct sock; -typedef int (*flow_resolve_t)(struct flowi *key, u16 family, u8 dir, - void **objp, atomic_t **obj_refp); +typedef int (*flow_resolve_t)(struct net *net, struct flowi *key, u16 family, + u8 dir, void **objp, atomic_t **obj_refp); -extern void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, - flow_resolve_t resolver); +extern void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, + u8 dir, flow_resolve_t resolver); extern void flow_cache_flush(void); extern atomic_t flow_cache_genid; diff --git a/include/net/gen_stats.h b/include/net/gen_stats.h index 8cd8185fa2ed59a320b393d96812c32eb7ab0748..d136b5240ef24a2e41cb6843b27d724295b4b9d3 100644 --- a/include/net/gen_stats.h +++ b/include/net/gen_stats.h @@ -45,5 +45,6 @@ extern void gen_kill_estimator(struct gnet_stats_basic *bstats, extern int gen_replace_estimator(struct gnet_stats_basic *bstats, struct gnet_stats_rate_est *rate_est, spinlock_t *stats_lock, struct nlattr *opt); - +extern bool gen_estimator_active(const struct gnet_stats_basic *bstats, + const struct gnet_stats_rate_est *rate_est); #endif diff --git a/include/net/ieee80211.h b/include/net/ieee80211.h index 93a56de3594be63de5c2a2847ea78fbb68db940b..adb7cf31f781f48cd564df727400f173b8e93d66 100644 --- a/include/net/ieee80211.h +++ b/include/net/ieee80211.h @@ -28,6 +28,9 @@ #include /* ETH_ALEN */ #include /* ARRAY_SIZE */ #include +#include + +#include #define IEEE80211_VERSION "git-1.1.13" @@ -127,10 +130,6 @@ static inline bool ieee80211_ratelimit_debug(u32 level) } #endif /* CONFIG_IEEE80211_DEBUG */ -/* escape_essid() is intended to be used in debug (and possibly error) - * messages. It should never be used for passing essid to user space. */ -const char *escape_essid(const char *essid, u8 essid_len); - /* * To use the debug system: * @@ -218,94 +217,6 @@ struct ieee80211_snap_hdr { #define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG) #define WLAN_GET_SEQ_SEQ(seq) (((seq) & IEEE80211_SCTL_SEQ) >> 4) -/* Authentication algorithms */ -#define WLAN_AUTH_OPEN 0 -#define WLAN_AUTH_SHARED_KEY 1 -#define WLAN_AUTH_LEAP 2 - -#define WLAN_AUTH_CHALLENGE_LEN 128 - -#define WLAN_CAPABILITY_ESS (1<<0) -#define WLAN_CAPABILITY_IBSS (1<<1) -#define WLAN_CAPABILITY_CF_POLLABLE (1<<2) -#define WLAN_CAPABILITY_CF_POLL_REQUEST (1<<3) -#define WLAN_CAPABILITY_PRIVACY (1<<4) -#define WLAN_CAPABILITY_SHORT_PREAMBLE (1<<5) -#define WLAN_CAPABILITY_PBCC (1<<6) -#define WLAN_CAPABILITY_CHANNEL_AGILITY (1<<7) -#define WLAN_CAPABILITY_SPECTRUM_MGMT (1<<8) -#define WLAN_CAPABILITY_QOS (1<<9) -#define WLAN_CAPABILITY_SHORT_SLOT_TIME (1<<10) -#define WLAN_CAPABILITY_DSSS_OFDM (1<<13) - -/* 802.11g ERP information element */ -#define WLAN_ERP_NON_ERP_PRESENT (1<<0) -#define WLAN_ERP_USE_PROTECTION (1<<1) -#define WLAN_ERP_BARKER_PREAMBLE (1<<2) - -/* Status codes */ -enum ieee80211_statuscode { - WLAN_STATUS_SUCCESS = 0, - WLAN_STATUS_UNSPECIFIED_FAILURE = 1, - WLAN_STATUS_CAPS_UNSUPPORTED = 10, - WLAN_STATUS_REASSOC_NO_ASSOC = 11, - WLAN_STATUS_ASSOC_DENIED_UNSPEC = 12, - WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG = 13, - WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION = 14, - WLAN_STATUS_CHALLENGE_FAIL = 15, - WLAN_STATUS_AUTH_TIMEOUT = 16, - WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17, - WLAN_STATUS_ASSOC_DENIED_RATES = 18, - /* 802.11b */ - WLAN_STATUS_ASSOC_DENIED_NOSHORTPREAMBLE = 19, - WLAN_STATUS_ASSOC_DENIED_NOPBCC = 20, - WLAN_STATUS_ASSOC_DENIED_NOAGILITY = 21, - /* 802.11h */ - WLAN_STATUS_ASSOC_DENIED_NOSPECTRUM = 22, - WLAN_STATUS_ASSOC_REJECTED_BAD_POWER = 23, - WLAN_STATUS_ASSOC_REJECTED_BAD_SUPP_CHAN = 24, - /* 802.11g */ - WLAN_STATUS_ASSOC_DENIED_NOSHORTTIME = 25, - WLAN_STATUS_ASSOC_DENIED_NODSSSOFDM = 26, - /* 802.11i */ - WLAN_STATUS_INVALID_IE = 40, - WLAN_STATUS_INVALID_GROUP_CIPHER = 41, - WLAN_STATUS_INVALID_PAIRWISE_CIPHER = 42, - WLAN_STATUS_INVALID_AKMP = 43, - WLAN_STATUS_UNSUPP_RSN_VERSION = 44, - WLAN_STATUS_INVALID_RSN_IE_CAP = 45, - WLAN_STATUS_CIPHER_SUITE_REJECTED = 46, -}; - -/* Reason codes */ -enum ieee80211_reasoncode { - WLAN_REASON_UNSPECIFIED = 1, - WLAN_REASON_PREV_AUTH_NOT_VALID = 2, - WLAN_REASON_DEAUTH_LEAVING = 3, - WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY = 4, - WLAN_REASON_DISASSOC_AP_BUSY = 5, - WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA = 6, - WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA = 7, - WLAN_REASON_DISASSOC_STA_HAS_LEFT = 8, - WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH = 9, - /* 802.11h */ - WLAN_REASON_DISASSOC_BAD_POWER = 10, - WLAN_REASON_DISASSOC_BAD_SUPP_CHAN = 11, - /* 802.11i */ - WLAN_REASON_INVALID_IE = 13, - WLAN_REASON_MIC_FAILURE = 14, - WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT = 15, - WLAN_REASON_GROUP_KEY_HANDSHAKE_TIMEOUT = 16, - WLAN_REASON_IE_DIFFERENT = 17, - WLAN_REASON_INVALID_GROUP_CIPHER = 18, - WLAN_REASON_INVALID_PAIRWISE_CIPHER = 19, - WLAN_REASON_INVALID_AKMP = 20, - WLAN_REASON_UNSUPP_RSN_VERSION = 21, - WLAN_REASON_INVALID_RSN_IE_CAP = 22, - WLAN_REASON_IEEE8021X_FAILED = 23, - WLAN_REASON_CIPHER_SUITE_REJECTED = 24, -}; - /* Action categories - 802.11h */ enum ieee80211_actioncategories { WLAN_ACTION_SPECTRUM_MGMT = 0, @@ -446,8 +357,6 @@ struct ieee80211_stats { struct ieee80211_device; -#include "ieee80211_crypt.h" - #define SEC_KEY_1 (1<<0) #define SEC_KEY_2 (1<<1) #define SEC_KEY_3 (1<<2) @@ -476,9 +385,8 @@ struct ieee80211_device; #define SCM_TEMPORAL_KEY_LENGTH 16 struct ieee80211_security { - u16 active_key:2, - enabled:1, - auth_mode:2, auth_algo:4, unicast_uses_group:1, encrypt:1; + u16 active_key:2, enabled:1, unicast_uses_group:1, encrypt:1; + u8 auth_mode; u8 encode_alg[WEP_KEYS]; u8 key_sizes[WEP_KEYS]; u8 keys[WEP_KEYS][SCM_KEY_LEN]; @@ -534,15 +442,6 @@ enum ieee80211_mfie { MFIE_TYPE_QOS_PARAMETER = 222, }; -/* Minimal header; can be used for passing 802.11 frames with sufficient - * information to determine what type of underlying data type is actually - * stored in the data. */ -struct ieee80211_hdr { - __le16 frame_ctl; - __le16 duration_id; - u8 payload[0]; -} __attribute__ ((packed)); - struct ieee80211_hdr_1addr { __le16 frame_ctl; __le16 duration_id; @@ -590,18 +489,6 @@ struct ieee80211_hdr_3addrqos { __le16 qos_ctl; } __attribute__ ((packed)); -struct ieee80211_hdr_4addrqos { - __le16 frame_ctl; - __le16 duration_id; - u8 addr1[ETH_ALEN]; - u8 addr2[ETH_ALEN]; - u8 addr3[ETH_ALEN]; - __le16 seq_ctl; - u8 addr4[ETH_ALEN]; - u8 payload[0]; - __le16 qos_ctl; -} __attribute__ ((packed)); - struct ieee80211_info_element { u8 id; u8 len; @@ -733,7 +620,6 @@ struct ieee80211_txb { #define MAX_WPA_IE_LEN 64 -#define NETWORK_EMPTY_ESSID (1<<0) #define NETWORK_HAS_OFDM (1<<1) #define NETWORK_HAS_CCK (1<<2) @@ -1050,11 +936,7 @@ struct ieee80211_device { size_t wpa_ie_len; u8 *wpa_ie; - struct list_head crypt_deinit_list; - struct ieee80211_crypt_data *crypt[WEP_KEYS]; - int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ - struct timer_list crypt_deinit_timer; - int crypt_quiesced; + struct lib80211_crypt_info crypt_info; int bcrx_sta_key; /* use individual keys to override default keys even * with RX of broad/multicast frames */ @@ -1135,22 +1017,6 @@ static inline void *ieee80211_priv(struct net_device *dev) return ((struct ieee80211_device *)netdev_priv(dev))->priv; } -static inline int ieee80211_is_empty_essid(const char *essid, int essid_len) -{ - /* Single white space is for Linksys APs */ - if (essid_len == 1 && essid[0] == ' ') - return 1; - - /* Otherwise, if the entire essid is 0, we assume it is hidden */ - while (essid_len) { - essid_len--; - if (essid[essid_len] != '\0') - return 0; - } - - return 1; -} - static inline int ieee80211_is_valid_mode(struct ieee80211_device *ieee, int mode) { @@ -1208,7 +1074,7 @@ static inline int ieee80211_get_hdrlen(u16 fc) static inline u8 *ieee80211_get_payload(struct ieee80211_hdr *hdr) { - switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl))) { + switch (ieee80211_get_hdrlen(le16_to_cpu(hdr->frame_control))) { case IEEE80211_1ADDR_LEN: return ((struct ieee80211_hdr_1addr *)hdr)->payload; case IEEE80211_2ADDR_LEN: diff --git a/include/net/ieee80211_radiotap.h b/include/net/ieee80211_radiotap.h index d364fd594ea4d7f2b3f088f460e2e2bc09ae6697..384698cb773a81b2667a4e7dea8c2c8e763de4d5 100644 --- a/include/net/ieee80211_radiotap.h +++ b/include/net/ieee80211_radiotap.h @@ -1,7 +1,4 @@ -/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */ -/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */ - -/*- +/* * Copyright (c) 2003, 2004 David Young. All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -42,8 +39,6 @@ #include #include -/* Radiotap header version (from official NetBSD feed) */ -#define IEEE80211RADIOTAP_VERSION "1.5" /* Base version of the radiotap packet header data */ #define PKTHDR_RADIOTAP_VERSION 0 @@ -62,12 +57,8 @@ * readers. */ -/* XXX tcpdump/libpcap do not tolerate variable-length headers, - * yet, so we pad every radiotap header to 64 bytes. Ugh. - */ -#define IEEE80211_RADIOTAP_HDRLEN 64 - -/* The radio capture header precedes the 802.11 header. +/* + * The radio capture header precedes the 802.11 header. * All data in the header is little endian on all platforms. */ struct ieee80211_radiotap_header { diff --git a/include/net/inet_hashtables.h b/include/net/inet_hashtables.h index 5cc182f9ecae58154b9d0a0d175887822d81dc2b..f44bb5c77a70cdb4d5cfdea2688a1a8ec3492b20 100644 --- a/include/net/inet_hashtables.h +++ b/include/net/inet_hashtables.h @@ -41,8 +41,8 @@ * I'll experiment with dynamic table growth later. */ struct inet_ehash_bucket { - struct hlist_head chain; - struct hlist_head twchain; + struct hlist_nulls_head chain; + struct hlist_nulls_head twchain; }; /* There are a few simple rules, which allow for local port reuse by @@ -77,13 +77,20 @@ struct inet_ehash_bucket { * ports are created in O(1) time? I thought so. ;-) -DaveM */ struct inet_bind_bucket { +#ifdef CONFIG_NET_NS struct net *ib_net; +#endif unsigned short port; signed short fastreuse; struct hlist_node node; struct hlist_head owners; }; +static inline struct net *ib_net(struct inet_bind_bucket *ib) +{ + return read_pnet(&ib->ib_net); +} + #define inet_bind_bucket_for_each(tb, node, head) \ hlist_for_each_entry(tb, node, head, node) @@ -92,6 +99,18 @@ struct inet_bind_hashbucket { struct hlist_head chain; }; +/* + * Sockets can be hashed in established or listening table + * We must use different 'nulls' end-of-chain value for listening + * hash table, or we might find a socket that was closed and + * reallocated/inserted into established hash table + */ +#define LISTENING_NULLS_BASE (1U << 29) +struct inet_listen_hashbucket { + spinlock_t lock; + struct hlist_nulls_head head; +}; + /* This is for listening sockets, thus all sockets which possess wildcards. */ #define INET_LHTABLE_SIZE 32 /* Yes, really, this is all you need. */ @@ -104,7 +123,7 @@ struct inet_hashinfo { * TIME_WAIT sockets use a separate chain (twchain). */ struct inet_ehash_bucket *ehash; - rwlock_t *ehash_locks; + spinlock_t *ehash_locks; unsigned int ehash_size; unsigned int ehash_locks_mask; @@ -116,22 +135,21 @@ struct inet_hashinfo { unsigned int bhash_size; /* Note : 4 bytes padding on 64 bit arches */ - /* All sockets in TCP_LISTEN state will be in here. This is the only - * table where wildcard'd TCP sockets can exist. Hash function here - * is just local port number. - */ - struct hlist_head listening_hash[INET_LHTABLE_SIZE]; + struct kmem_cache *bind_bucket_cachep; /* All the above members are written once at bootup and * never written again _or_ are predominantly read-access. * * Now align to a new cache line as all the following members - * are often dirty. + * might be often dirty. */ - rwlock_t lhash_lock ____cacheline_aligned; - atomic_t lhash_users; - wait_queue_head_t lhash_wait; - struct kmem_cache *bind_bucket_cachep; + /* All sockets in TCP_LISTEN state will be in here. This is the only + * table where wildcard'd TCP sockets can exist. Hash function here + * is just local port number. + */ + struct inet_listen_hashbucket listening_hash[INET_LHTABLE_SIZE] + ____cacheline_aligned_in_smp; + }; static inline struct inet_ehash_bucket *inet_ehash_bucket( @@ -141,7 +159,7 @@ static inline struct inet_ehash_bucket *inet_ehash_bucket( return &hashinfo->ehash[hash & (hashinfo->ehash_size - 1)]; } -static inline rwlock_t *inet_ehash_lockp( +static inline spinlock_t *inet_ehash_lockp( struct inet_hashinfo *hashinfo, unsigned int hash) { @@ -166,16 +184,16 @@ static inline int inet_ehash_locks_alloc(struct inet_hashinfo *hashinfo) size = 4096; if (sizeof(rwlock_t) != 0) { #ifdef CONFIG_NUMA - if (size * sizeof(rwlock_t) > PAGE_SIZE) - hashinfo->ehash_locks = vmalloc(size * sizeof(rwlock_t)); + if (size * sizeof(spinlock_t) > PAGE_SIZE) + hashinfo->ehash_locks = vmalloc(size * sizeof(spinlock_t)); else #endif - hashinfo->ehash_locks = kmalloc(size * sizeof(rwlock_t), + hashinfo->ehash_locks = kmalloc(size * sizeof(spinlock_t), GFP_KERNEL); if (!hashinfo->ehash_locks) return ENOMEM; for (i = 0; i < size; i++) - rwlock_init(&hashinfo->ehash_locks[i]); + spin_lock_init(&hashinfo->ehash_locks[i]); } hashinfo->ehash_locks_mask = size - 1; return 0; @@ -186,7 +204,7 @@ static inline void inet_ehash_locks_free(struct inet_hashinfo *hashinfo) if (hashinfo->ehash_locks) { #ifdef CONFIG_NUMA unsigned int size = (hashinfo->ehash_locks_mask + 1) * - sizeof(rwlock_t); + sizeof(spinlock_t); if (size > PAGE_SIZE) vfree(hashinfo->ehash_locks); else @@ -229,26 +247,7 @@ extern void __inet_inherit_port(struct sock *sk, struct sock *child); extern void inet_put_port(struct sock *sk); -extern void inet_listen_wlock(struct inet_hashinfo *hashinfo); - -/* - * - We may sleep inside this lock. - * - If sleeping is not required (or called from BH), - * use plain read_(un)lock(&inet_hashinfo.lhash_lock). - */ -static inline void inet_listen_lock(struct inet_hashinfo *hashinfo) -{ - /* read_lock synchronizes to candidates to writers */ - read_lock(&hashinfo->lhash_lock); - atomic_inc(&hashinfo->lhash_users); - read_unlock(&hashinfo->lhash_lock); -} - -static inline void inet_listen_unlock(struct inet_hashinfo *hashinfo) -{ - if (atomic_dec_and_test(&hashinfo->lhash_users)) - wake_up(&hashinfo->lhash_wait); -} +void inet_hashinfo_init(struct inet_hashinfo *h); extern void __inet_hash_nolisten(struct sock *sk); extern void inet_hash(struct sock *sk); @@ -299,25 +298,25 @@ typedef __u64 __bitwise __addrpair; ((__force __u64)(__be32)(__saddr))); #endif /* __BIG_ENDIAN */ #define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ - (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ + (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ ((*((__addrpair *)&(inet_sk(__sk)->daddr))) == (__cookie)) && \ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET_TW_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif)\ - (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ + (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ ((*((__addrpair *)&(inet_twsk(__sk)->tw_daddr))) == (__cookie)) && \ ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #else /* 32-bit arch */ #define INET_ADDR_COOKIE(__name, __saddr, __daddr) #define INET_MATCH(__sk, __net, __hash, __cookie, __saddr, __daddr, __ports, __dif) \ - (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ + (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ (inet_sk(__sk)->daddr == (__saddr)) && \ (inet_sk(__sk)->rcv_saddr == (__daddr)) && \ ((*((__portpair *)&(inet_sk(__sk)->dport))) == (__ports)) && \ (!((__sk)->sk_bound_dev_if) || ((__sk)->sk_bound_dev_if == (__dif)))) #define INET_TW_MATCH(__sk, __net, __hash,__cookie, __saddr, __daddr, __ports, __dif) \ - (((__sk)->sk_hash == (__hash)) && sock_net((__sk)) == (__net) && \ + (((__sk)->sk_hash == (__hash)) && net_eq(sock_net(__sk), (__net)) && \ (inet_twsk(__sk)->tw_daddr == (__saddr)) && \ (inet_twsk(__sk)->tw_rcv_saddr == (__daddr)) && \ ((*((__portpair *)&(inet_twsk(__sk)->tw_dport))) == (__ports)) && \ diff --git a/include/net/inet_timewait_sock.h b/include/net/inet_timewait_sock.h index 80e4977631b8b18ba67e44024895fee03adbe7f9..4b8ece22b8e94417879a6504e87afe5bd0ecc371 100644 --- a/include/net/inet_timewait_sock.h +++ b/include/net/inet_timewait_sock.h @@ -110,7 +110,7 @@ struct inet_timewait_sock { #define tw_state __tw_common.skc_state #define tw_reuse __tw_common.skc_reuse #define tw_bound_dev_if __tw_common.skc_bound_dev_if -#define tw_node __tw_common.skc_node +#define tw_node __tw_common.skc_nulls_node #define tw_bind_node __tw_common.skc_bind_node #define tw_refcnt __tw_common.skc_refcnt #define tw_hash __tw_common.skc_hash @@ -137,10 +137,10 @@ struct inet_timewait_sock { struct hlist_node tw_death_node; }; -static inline void inet_twsk_add_node(struct inet_timewait_sock *tw, - struct hlist_head *list) +static inline void inet_twsk_add_node_rcu(struct inet_timewait_sock *tw, + struct hlist_nulls_head *list) { - hlist_add_head(&tw->tw_node, list); + hlist_nulls_add_head_rcu(&tw->tw_node, list); } static inline void inet_twsk_add_bind_node(struct inet_timewait_sock *tw, @@ -175,7 +175,7 @@ static inline int inet_twsk_del_dead_node(struct inet_timewait_sock *tw) } #define inet_twsk_for_each(tw, node, head) \ - hlist_for_each_entry(tw, node, head, tw_node) + hlist_nulls_for_each_entry(tw, node, head, tw_node) #define inet_twsk_for_each_inmate(tw, node, jail) \ hlist_for_each_entry(tw, node, jail, tw_death_node) diff --git a/include/net/ip.h b/include/net/ip.h index bc026ecb513f7c57f1d836017f4a02b6d8e72a57..10868139e656464dea5076e8b5672a9536b0ea01 100644 --- a/include/net/ip.h +++ b/include/net/ip.h @@ -110,7 +110,7 @@ extern int ip_append_data(struct sock *sk, int odd, struct sk_buff *skb), void *from, int len, int protolen, struct ipcm_cookie *ipc, - struct rtable *rt, + struct rtable **rt, unsigned int flags); extern int ip_generic_getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb); extern ssize_t ip_append_page(struct sock *sk, struct page *page, @@ -187,6 +187,7 @@ extern void inet_get_local_port_range(int *low, int *high); extern int sysctl_ip_default_ttl; extern int sysctl_ip_nonlocal_bind; +extern struct ctl_path net_core_path[]; extern struct ctl_path net_ipv4_ctl_path[]; /* From inetpeer.c */ diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index fe9fcf73c85ed26135b802a959382a85e5d64e43..ab9b003ab671b0755cb5467804adc16a89058a9c 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -87,12 +87,12 @@ static inline const char *ip_vs_dbg_addr(int af, char *buf, size_t buf_len, int len; #ifdef CONFIG_IP_VS_IPV6 if (af == AF_INET6) - len = snprintf(&buf[*idx], buf_len - *idx, "[" NIP6_FMT "]", - NIP6(addr->in6)) + 1; + len = snprintf(&buf[*idx], buf_len - *idx, "[%pI6]", + &addr->in6) + 1; else #endif - len = snprintf(&buf[*idx], buf_len - *idx, NIPQUAD_FMT, - NIPQUAD(addr->ip)) + 1; + len = snprintf(&buf[*idx], buf_len - *idx, "%pI4", + &addr->ip) + 1; *idx += len; BUG_ON(*idx > buf_len + 1); @@ -503,9 +503,6 @@ struct ip_vs_scheduler { char *name; /* scheduler name */ atomic_t refcnt; /* reference counter */ struct module *module; /* THIS_MODULE/NULL */ -#ifdef CONFIG_IP_VS_IPV6 - int supports_ipv6; /* scheduler has IPv6 support */ -#endif /* scheduler initializing service */ int (*init_service)(struct ip_vs_service *svc); @@ -916,7 +913,7 @@ static inline __wsum ip_vs_check_diff4(__be32 old, __be32 new, __wsum oldsum) { __be32 diff[2] = { ~old, new }; - return csum_partial((char *) diff, sizeof(diff), oldsum); + return csum_partial(diff, sizeof(diff), oldsum); } #ifdef CONFIG_IP_VS_IPV6 @@ -926,7 +923,7 @@ static inline __wsum ip_vs_check_diff16(const __be32 *old, const __be32 *new, __be32 diff[8] = { ~old[3], ~old[2], ~old[1], ~old[0], new[3], new[2], new[1], new[0] }; - return csum_partial((char *) diff, sizeof(diff), oldsum); + return csum_partial(diff, sizeof(diff), oldsum); } #endif @@ -934,7 +931,7 @@ static inline __wsum ip_vs_check_diff2(__be16 old, __be16 new, __wsum oldsum) { __be16 diff[2] = { ~old, new }; - return csum_partial((char *) diff, sizeof(diff), oldsum); + return csum_partial(diff, sizeof(diff), oldsum); } #endif /* __KERNEL__ */ diff --git a/include/net/ieee80211_crypt.h b/include/net/lib80211.h similarity index 58% rename from include/net/ieee80211_crypt.h rename to include/net/lib80211.h index b3d65e0bedd31fbe370094a421c95c36430703c4..fb4e2784857d93c23b5358803e7591345073f499 100644 --- a/include/net/ieee80211_crypt.h +++ b/include/net/lib80211.h @@ -1,4 +1,11 @@ /* + * lib80211.h -- common bits for IEEE802.11 wireless drivers + * + * Copyright (c) 2008, John W. Linville + * + * Some bits copied from old ieee80211 component, w/ original copyright + * notices below: + * * Original code based on Host AP (software wireless LAN access point) driver * for Intersil Prism2/2.5/3. * @@ -11,31 +18,31 @@ * * Copyright (c) 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 version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. */ -/* - * This file defines the interface to the ieee80211 crypto module. - */ -#ifndef IEEE80211_CRYPT_H -#define IEEE80211_CRYPT_H +#ifndef LIB80211_H +#define LIB80211_H #include #include -#include +#include #include +#include +#include +#include +#include +/* print_ssid() is intended to be used in debug (and possibly error) + * messages. It should never be used for passing ssid to user space. */ +const char *print_ssid(char *buf, const char *ssid, u8 ssid_len); +#define DECLARE_SSID_BUF(var) char var[IEEE80211_MAX_SSID_LEN * 4 + 1] __maybe_unused + +#define NUM_WEP_KEYS 4 enum { IEEE80211_CRYPTO_TKIP_COUNTERMEASURES = (1 << 0), }; -struct sk_buff; -struct module; - -struct ieee80211_crypto_ops { +struct lib80211_crypto_ops { const char *name; struct list_head list; @@ -87,22 +94,36 @@ struct ieee80211_crypto_ops { struct module *owner; }; -struct ieee80211_crypt_data { +struct lib80211_crypt_data { struct list_head list; /* delayed deletion list */ - struct ieee80211_crypto_ops *ops; + struct lib80211_crypto_ops *ops; void *priv; atomic_t refcnt; }; -struct ieee80211_device; - -int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops); -int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops); -struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name); -void ieee80211_crypt_deinit_entries(struct ieee80211_device *, int); -void ieee80211_crypt_deinit_handler(unsigned long); -void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, - struct ieee80211_crypt_data **crypt); -void ieee80211_crypt_quiescing(struct ieee80211_device *ieee); +struct lib80211_crypt_info { + char *name; + /* Most clients will already have a lock, + so just point to that. */ + spinlock_t *lock; + + struct lib80211_crypt_data *crypt[NUM_WEP_KEYS]; + int tx_keyidx; /* default TX key index (crypt[tx_keyidx]) */ + struct list_head crypt_deinit_list; + struct timer_list crypt_deinit_timer; + int crypt_quiesced; +}; -#endif +int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name, + spinlock_t *lock); +void lib80211_crypt_info_free(struct lib80211_crypt_info *info); +int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops); +int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops); +struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name); +void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *, int); +void lib80211_crypt_deinit_handler(unsigned long); +void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info, + struct lib80211_crypt_data **crypt); +void lib80211_crypt_quiescing(struct lib80211_crypt_info *info); + +#endif /* LIB80211_H */ diff --git a/include/net/mac80211.h b/include/net/mac80211.h index 73d81bc6aa75e94eb5ce87cb26326e5093cafa1a..b3bd00a9d9928ce228c1e3d6e855cdf8a9b17682 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h @@ -3,7 +3,7 @@ * * Copyright 2002-2005, Devicescape Software, Inc. * Copyright 2006-2007 Jiri Benc - * Copyright 2007 Johannes Berg + * Copyright 2007-2008 Johannes Berg * * 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 @@ -107,7 +107,7 @@ enum ieee80211_max_queues { * The information provided in this structure is required for QoS * transmit queue configuration. Cf. IEEE 802.11 7.3.2.29. * - * @aifs: arbitration interface space [0..255] + * @aifs: arbitration interframe space [0..255] * @cw_min: minimum contention window [a value of the form * 2^n-1 in the range 1..32767] * @cw_max: maximum contention window [like @cw_min] @@ -163,6 +163,14 @@ enum ieee80211_bss_change { BSS_CHANGED_BASIC_RATES = 1<<5, }; +/** + * struct ieee80211_bss_ht_conf - BSS's changing HT configuration + * @operation_mode: HT operation mode (like in &struct ieee80211_ht_info) + */ +struct ieee80211_bss_ht_conf { + u16 operation_mode; +}; + /** * struct ieee80211_bss_conf - holds the BSS's changing parameters * @@ -172,15 +180,17 @@ enum ieee80211_bss_change { * @assoc: association status * @aid: association ID number, valid only when @assoc is true * @use_cts_prot: use CTS protection - * @use_short_preamble: use 802.11b short preamble - * @use_short_slot: use short slot time (only relevant for ERP) + * @use_short_preamble: use 802.11b short preamble; + * if the hardware cannot handle this it must set the + * IEEE80211_HW_2GHZ_SHORT_PREAMBLE_INCAPABLE hardware flag + * @use_short_slot: use short slot time (only relevant for ERP); + * if the hardware cannot handle this it must set the + * IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE hardware flag * @dtim_period: num of beacons before the next DTIM, for PSM * @timestamp: beacon timestamp * @beacon_int: beacon interval * @assoc_capability: capabilities taken from assoc resp - * @assoc_ht: association in HT mode - * @ht_conf: ht capabilities - * @ht_bss_conf: ht extended capabilities + * @ht: BSS's HT configuration * @basic_rates: bitmap of basic rates, each bit stands for an * index into the rate table configured by the driver in * the current band. @@ -198,10 +208,7 @@ struct ieee80211_bss_conf { u16 assoc_capability; u64 timestamp; u64 basic_rates; - /* ht related data */ - bool assoc_ht; - struct ieee80211_ht_info *ht_conf; - struct ieee80211_ht_bss_info *ht_bss_conf; + struct ieee80211_bss_ht_conf ht; }; /** @@ -210,29 +217,24 @@ struct ieee80211_bss_conf { * These flags are used with the @flags member of &ieee80211_tx_info. * * @IEEE80211_TX_CTL_REQ_TX_STATUS: request TX status callback for this frame. - * @IEEE80211_TX_CTL_USE_RTS_CTS: use RTS-CTS before sending frame - * @IEEE80211_TX_CTL_USE_CTS_PROTECT: use CTS protection for the frame (e.g., - * for combined 802.11g / 802.11b networks) + * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence + * number to this frame, taking care of not overwriting the fragment + * number and increasing the sequence number only when the + * IEEE80211_TX_CTL_FIRST_FRAGMENT flag is set. mac80211 will properly + * assign sequence numbers to QoS-data frames but cannot do so correctly + * for non-QoS-data and management frames because beacons need them from + * that counter as well and mac80211 cannot guarantee proper sequencing. + * If this flag is set, the driver should instruct the hardware to + * assign a sequence number to the frame or assign one itself. Cf. IEEE + * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for + * beacons and always be clear for frames without a sequence number field. * @IEEE80211_TX_CTL_NO_ACK: tell the low level not to wait for an ack - * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: TBD * @IEEE80211_TX_CTL_CLEAR_PS_FILT: clear powersave filter for destination * station - * @IEEE80211_TX_CTL_REQUEUE: TBD * @IEEE80211_TX_CTL_FIRST_FRAGMENT: this is a first fragment of the frame - * @IEEE80211_TX_CTL_SHORT_PREAMBLE: TBD - * @IEEE80211_TX_CTL_LONG_RETRY_LIMIT: this frame should be send using the - * through set_retry_limit configured long retry value * @IEEE80211_TX_CTL_SEND_AFTER_DTIM: send this frame after DTIM beacon * @IEEE80211_TX_CTL_AMPDU: this frame should be sent as part of an A-MPDU - * @IEEE80211_TX_CTL_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_TX_CTL_GREEN_FIELD: use green field protection for this frame - * @IEEE80211_TX_CTL_40_MHZ_WIDTH: send this frame using 40 Mhz channel width - * @IEEE80211_TX_CTL_DUP_DATA: duplicate data frame on both 20 Mhz channels - * @IEEE80211_TX_CTL_SHORT_GI: send this frame using short guard interval - * @IEEE80211_TX_CTL_INJECTED: TBD + * @IEEE80211_TX_CTL_INJECTED: Frame was injected, internal to mac80211. * @IEEE80211_TX_STAT_TX_FILTERED: The frame was not transmitted * because the destination STA was in powersave mode. * @IEEE80211_TX_STAT_ACK: Frame was acknowledged @@ -240,63 +242,67 @@ struct ieee80211_bss_conf { * is for the whole aggregation. * @IEEE80211_TX_STAT_AMPDU_NO_BACK: no block ack was returned, * so consider using block ack request (BAR). - * @IEEE80211_TX_CTL_ASSIGN_SEQ: The driver has to assign a sequence - * number to this frame, taking care of not overwriting the fragment - * number and increasing the sequence number only when the - * IEEE80211_TX_CTL_FIRST_FRAGMENT flags is set. mac80211 will properly - * assign sequence numbers to QoS-data frames but cannot do so correctly - * for non-QoS-data and management frames because beacons need them from - * that counter as well and mac80211 cannot guarantee proper sequencing. - * If this flag is set, the driver should instruct the hardware to - * assign a sequence number to the frame or assign one itself. Cf. IEEE - * 802.11-2007 7.1.3.4.1 paragraph 3. This flag will always be set for - * beacons always be clear for frames without a sequence number field. + * @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be + * set by rate control algorithms to indicate probe rate, will + * be cleared for fragmented frames (except on the last fragment) */ enum mac80211_tx_control_flags { IEEE80211_TX_CTL_REQ_TX_STATUS = BIT(0), - IEEE80211_TX_CTL_USE_RTS_CTS = BIT(2), - IEEE80211_TX_CTL_USE_CTS_PROTECT = BIT(3), - IEEE80211_TX_CTL_NO_ACK = BIT(4), - IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(5), - IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(6), - IEEE80211_TX_CTL_REQUEUE = BIT(7), - IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(8), - IEEE80211_TX_CTL_SHORT_PREAMBLE = BIT(9), - IEEE80211_TX_CTL_LONG_RETRY_LIMIT = BIT(10), - IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(12), - IEEE80211_TX_CTL_AMPDU = BIT(13), - IEEE80211_TX_CTL_OFDM_HT = BIT(14), - IEEE80211_TX_CTL_GREEN_FIELD = BIT(15), - IEEE80211_TX_CTL_40_MHZ_WIDTH = BIT(16), - IEEE80211_TX_CTL_DUP_DATA = BIT(17), - IEEE80211_TX_CTL_SHORT_GI = BIT(18), - IEEE80211_TX_CTL_INJECTED = BIT(19), - IEEE80211_TX_STAT_TX_FILTERED = BIT(20), - IEEE80211_TX_STAT_ACK = BIT(21), - IEEE80211_TX_STAT_AMPDU = BIT(22), - IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(23), - IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(24), + IEEE80211_TX_CTL_ASSIGN_SEQ = BIT(1), + IEEE80211_TX_CTL_NO_ACK = BIT(2), + IEEE80211_TX_CTL_CLEAR_PS_FILT = BIT(3), + IEEE80211_TX_CTL_FIRST_FRAGMENT = BIT(4), + IEEE80211_TX_CTL_SEND_AFTER_DTIM = BIT(5), + IEEE80211_TX_CTL_AMPDU = BIT(6), + IEEE80211_TX_CTL_INJECTED = BIT(7), + IEEE80211_TX_STAT_TX_FILTERED = BIT(8), + IEEE80211_TX_STAT_ACK = BIT(9), + IEEE80211_TX_STAT_AMPDU = BIT(10), + IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11), + IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12), +}; + +enum mac80211_rate_control_flags { + IEEE80211_TX_RC_USE_RTS_CTS = BIT(0), + IEEE80211_TX_RC_USE_CTS_PROTECT = BIT(1), + IEEE80211_TX_RC_USE_SHORT_PREAMBLE = BIT(2), + + /* rate index is an MCS rate number instead of an index */ + IEEE80211_TX_RC_MCS = BIT(3), + IEEE80211_TX_RC_GREEN_FIELD = BIT(4), + IEEE80211_TX_RC_40_MHZ_WIDTH = BIT(5), + IEEE80211_TX_RC_DUP_DATA = BIT(6), + IEEE80211_TX_RC_SHORT_GI = BIT(7), }; -#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE \ - (sizeof(((struct sk_buff *)0)->cb) - 8) -#define IEEE80211_TX_INFO_DRIVER_DATA_PTRS \ - (IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)) +/* there are 40 bytes if you don't need the rateset to be kept */ +#define IEEE80211_TX_INFO_DRIVER_DATA_SIZE 40 -/* maximum number of alternate rate retry stages */ -#define IEEE80211_TX_MAX_ALTRATE 3 +/* if you do need the rateset, then you have less space */ +#define IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE 24 + +/* maximum number of rate stages */ +#define IEEE80211_TX_MAX_RATES 5 /** - * struct ieee80211_tx_altrate - alternate rate selection/status + * struct ieee80211_tx_rate - rate selection/status + * + * @idx: rate index to attempt to send with + * @flags: rate control flags (&enum mac80211_rate_control_flags) + * @count: number of tries in this rate before going to the next rate * - * @rate_idx: rate index to attempt to send with - * @limit: number of retries before fallback + * A value of -1 for @idx indicates an invalid rate and, if used + * in an array of retry rates, that no more rates should be tried. + * + * When used for transmit status reporting, the driver should + * always report the rate along with the flags it used. */ -struct ieee80211_tx_altrate { - s8 rate_idx; - u8 limit; -}; +struct ieee80211_tx_rate { + s8 idx; + u8 count; + u8 flags; +} __attribute__((packed)); /** * struct ieee80211_tx_info - skb transmit information @@ -310,15 +316,13 @@ struct ieee80211_tx_altrate { * it may be NULL. * * @flags: transmit info flags, defined above - * @band: TBD - * @tx_rate_idx: TBD - * @antenna_sel_tx: TBD + * @band: the band to transmit on (use for checking for races) + * @antenna_sel_tx: antenna to use, 0 for automatic diversity + * @pad: padding, ignore * @control: union for control data * @status: union for status data * @driver_data: array of driver_data pointers * @retry_count: number of retries - * @excessive_retries: set to 1 if the frame was retried many times - * but not acknowledged * @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. @@ -329,31 +333,44 @@ struct ieee80211_tx_info { /* common information */ u32 flags; u8 band; - s8 tx_rate_idx; + u8 antenna_sel_tx; - /* 1 byte hole */ + /* 2 byte hole */ + u8 pad[2]; union { struct { + union { + /* rate control */ + struct { + struct ieee80211_tx_rate rates[ + IEEE80211_TX_MAX_RATES]; + s8 rts_cts_rate_idx; + }; + /* only needed before rate control */ + unsigned long jiffies; + }; /* NB: vif can be NULL for injected frames */ struct ieee80211_vif *vif; struct ieee80211_key_conf *hw_key; struct ieee80211_sta *sta; - unsigned long jiffies; - s8 rts_cts_rate_idx; - u8 retry_limit; - struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE]; } control; struct { + struct ieee80211_tx_rate rates[IEEE80211_TX_MAX_RATES]; + u8 ampdu_ack_len; u64 ampdu_ack_map; int ack_signal; - struct ieee80211_tx_altrate retries[IEEE80211_TX_MAX_ALTRATE + 1]; - u8 retry_count; - bool excessive_retries; - u8 ampdu_ack_len; + /* 8 bytes free */ } status; - void *driver_data[IEEE80211_TX_INFO_DRIVER_DATA_PTRS]; + struct { + struct ieee80211_tx_rate driver_rates[ + IEEE80211_TX_MAX_RATES]; + void *rate_driver_data[ + IEEE80211_TX_INFO_RATE_DRIVER_DATA_SIZE / sizeof(void *)]; + }; + void *driver_data[ + IEEE80211_TX_INFO_DRIVER_DATA_SIZE / sizeof(void *)]; }; }; @@ -362,6 +379,41 @@ static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) return (struct ieee80211_tx_info *)skb->cb; } +/** + * ieee80211_tx_info_clear_status - clear TX status + * + * @info: The &struct ieee80211_tx_info to be cleared. + * + * When the driver passes an skb back to mac80211, it must report + * a number of things in TX status. This function clears everything + * in the TX status but the rate control information (it does clear + * the count since you need to fill that in anyway). + * + * NOTE: You can only use this function if you do NOT use + * info->driver_data! Use info->rate_driver_data + * instead if you need only the less space that allows. + */ +static inline void +ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) +{ + int i; + + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != + offsetof(struct ieee80211_tx_info, control.rates)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != + offsetof(struct ieee80211_tx_info, driver_rates)); + BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, status.rates) != 8); + /* clear the rate counts */ + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) + info->status.rates[i].count = 0; + + BUILD_BUG_ON( + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len) != 23); + memset(&info->status.ampdu_ack_len, 0, + sizeof(struct ieee80211_tx_info) - + offsetof(struct ieee80211_tx_info, status.ampdu_ack_len)); +} + /** * enum mac80211_rx_flags - receive flags @@ -384,6 +436,9 @@ static inline struct ieee80211_tx_info *IEEE80211_SKB_CB(struct sk_buff *skb) * is valid. This is useful in monitor mode and necessary for beacon frames * to enable IBSS merging. * @RX_FLAG_SHORTPRE: Short preamble was used for this frame + * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index + * @RX_FLAG_40MHZ: HT40 (40 MHz) was used + * @RX_FLAG_SHORT_GI: Short guard interval was used */ enum mac80211_rx_flags { RX_FLAG_MMIC_ERROR = 1<<0, @@ -394,7 +449,10 @@ enum mac80211_rx_flags { RX_FLAG_FAILED_FCS_CRC = 1<<5, RX_FLAG_FAILED_PLCP_CRC = 1<<6, RX_FLAG_TSFT = 1<<7, - RX_FLAG_SHORTPRE = 1<<8 + RX_FLAG_SHORTPRE = 1<<8, + RX_FLAG_HT = 1<<9, + RX_FLAG_40MHZ = 1<<10, + RX_FLAG_SHORT_GI = 1<<11, }; /** @@ -414,7 +472,8 @@ enum mac80211_rx_flags { * @noise: noise when receiving this frame, in dBm. * @qual: overall signal quality indication, in percent (0-100). * @antenna: antenna used - * @rate_idx: index of data rate into band's supported rates + * @rate_idx: index of data rate into band's supported rates or MCS index if + * HT rates are use (RX_FLAG_HT) * @flag: %RX_FLAG_* */ struct ieee80211_rx_status { @@ -434,21 +493,49 @@ struct ieee80211_rx_status { * * Flags to define PHY configuration options * - * @IEEE80211_CONF_SHORT_SLOT_TIME: use 802.11g short slot time * @IEEE80211_CONF_RADIOTAP: add radiotap header at receive time (if supported) - * @IEEE80211_CONF_SUPPORT_HT_MODE: use 802.11n HT capabilities (if supported) * @IEEE80211_CONF_PS: Enable 802.11 power save mode */ enum ieee80211_conf_flags { - /* - * TODO: IEEE80211_CONF_SHORT_SLOT_TIME will be removed once drivers - * have been converted to use bss_info_changed() for slot time - * configuration - */ - IEEE80211_CONF_SHORT_SLOT_TIME = (1<<0), - IEEE80211_CONF_RADIOTAP = (1<<1), - IEEE80211_CONF_SUPPORT_HT_MODE = (1<<2), - IEEE80211_CONF_PS = (1<<3), + IEEE80211_CONF_RADIOTAP = (1<<0), + IEEE80211_CONF_PS = (1<<1), +}; + +/* XXX: remove all this once drivers stop trying to use it */ +static inline int __deprecated __IEEE80211_CONF_SHORT_SLOT_TIME(void) +{ + return 0; +} +#define IEEE80211_CONF_SHORT_SLOT_TIME (__IEEE80211_CONF_SHORT_SLOT_TIME()) + +struct ieee80211_ht_conf { + bool enabled; + enum nl80211_channel_type channel_type; +}; + +/** + * enum ieee80211_conf_changed - denotes which configuration changed + * + * @IEEE80211_CONF_CHANGE_RADIO_ENABLED: the value of radio_enabled changed + * @IEEE80211_CONF_CHANGE_BEACON_INTERVAL: the beacon interval changed + * @IEEE80211_CONF_CHANGE_LISTEN_INTERVAL: the listen interval changed + * @IEEE80211_CONF_CHANGE_RADIOTAP: the radiotap flag changed + * @IEEE80211_CONF_CHANGE_PS: the PS flag changed + * @IEEE80211_CONF_CHANGE_POWER: the TX power changed + * @IEEE80211_CONF_CHANGE_CHANNEL: the channel changed + * @IEEE80211_CONF_CHANGE_RETRY_LIMITS: retry limits changed + * @IEEE80211_CONF_CHANGE_HT: HT configuration changed + */ +enum ieee80211_conf_changed { + IEEE80211_CONF_CHANGE_RADIO_ENABLED = BIT(0), + IEEE80211_CONF_CHANGE_BEACON_INTERVAL = BIT(1), + IEEE80211_CONF_CHANGE_LISTEN_INTERVAL = BIT(2), + IEEE80211_CONF_CHANGE_RADIOTAP = BIT(3), + IEEE80211_CONF_CHANGE_PS = BIT(4), + IEEE80211_CONF_CHANGE_POWER = BIT(5), + IEEE80211_CONF_CHANGE_CHANNEL = BIT(6), + IEEE80211_CONF_CHANGE_RETRY_LIMITS = BIT(7), + IEEE80211_CONF_CHANGE_HT = BIT(8), }; /** @@ -457,34 +544,31 @@ enum ieee80211_conf_flags { * This struct indicates how the driver shall configure the hardware. * * @radio_enabled: when zero, driver is required to switch off the radio. - * TODO make a flag * @beacon_int: beacon interval (TODO make interface config) * @listen_interval: listen interval in units of beacon interval * @flags: configuration flags defined above * @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 + * @ht: the HT configuration for the device + * @long_frame_max_tx_count: Maximum number of transmissions for a "long" frame + * (a frame not RTS protected), called "dot11LongRetryLimit" in 802.11, + * but actually means the number of transmissions not the number of retries + * @short_frame_max_tx_count: Maximum number of transmissions for a "short" + * frame, called "dot11ShortRetryLimit" in 802.11, but actually means the + * number of transmissions not the number of retries */ struct ieee80211_conf { - int radio_enabled; - int beacon_int; - u16 listen_interval; u32 flags; int power_level; - int max_antenna_gain; - u8 antenna_sel_tx; - u8 antenna_sel_rx; - struct ieee80211_channel *channel; + u16 listen_interval; + bool radio_enabled; + + u8 long_frame_max_tx_count, short_frame_max_tx_count; - struct ieee80211_ht_info ht_conf; - struct ieee80211_ht_bss_info ht_bss_conf; + struct ieee80211_channel *channel; + struct ieee80211_ht_conf ht; }; /** @@ -494,11 +578,14 @@ struct ieee80211_conf { * use during the life of a virtual interface. * * @type: type of this virtual interface + * @bss_conf: BSS configuration for this interface, either our own + * or the BSS we're associated to * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *). */ struct ieee80211_vif { enum nl80211_iftype type; + struct ieee80211_bss_conf bss_conf; /* must be last */ u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); }; @@ -542,14 +629,12 @@ struct ieee80211_if_init_conf { * enum ieee80211_if_conf_change - interface config change flags * * @IEEE80211_IFCC_BSSID: The BSSID changed. - * @IEEE80211_IFCC_SSID: The SSID changed. * @IEEE80211_IFCC_BEACON: The beacon for this interface changed * (currently AP and MESH only), use ieee80211_beacon_get(). */ enum ieee80211_if_conf_change { IEEE80211_IFCC_BSSID = BIT(0), - IEEE80211_IFCC_SSID = BIT(1), - IEEE80211_IFCC_BEACON = BIT(2), + IEEE80211_IFCC_BEACON = BIT(1), }; /** @@ -557,11 +642,6 @@ enum ieee80211_if_conf_change { * * @changed: parameters that have changed, see &enum ieee80211_if_conf_change. * @bssid: BSSID of the network we are associated to/creating. - * @ssid: used (together with @ssid_len) by drivers for hardware that - * generate beacons independently. The pointer is valid only during the - * config_interface() call, so copy the value somewhere if you need - * it. - * @ssid_len: length of the @ssid field. * * This structure is passed to the config_interface() callback of * &struct ieee80211_hw. @@ -569,8 +649,6 @@ enum ieee80211_if_conf_change { struct ieee80211_if_conf { u32 changed; u8 *bssid; - u8 *ssid; - size_t ssid_len; }; /** @@ -677,7 +755,7 @@ enum set_key_cmd { * @addr: MAC address * @aid: AID we assigned to the station if we're an AP * @supp_rates: Bitmap of supported rates (per band) - * @ht_info: HT capabilities of this STA + * @ht_cap: HT capabilities of this STA; restricted to our own TX capabilities * @drv_priv: data area for driver use, will always be aligned to * sizeof(void *), size is determined in hw information. */ @@ -685,7 +763,7 @@ struct ieee80211_sta { u64 supp_rates[IEEE80211_NUM_BANDS]; u8 addr[ETH_ALEN]; u16 aid; - struct ieee80211_ht_info ht_info; + struct ieee80211_sta_ht_cap ht_cap; /* must be last */ u8 drv_priv[0] __attribute__((__aligned__(sizeof(void *)))); @@ -695,13 +773,17 @@ struct ieee80211_sta { * enum sta_notify_cmd - sta notify command * * Used with the sta_notify() callback in &struct ieee80211_ops, this - * indicates addition and removal of a station to station table. + * indicates addition and removal of a station to station table, + * or if a associated station made a power state transition. * * @STA_NOTIFY_ADD: a station was added to the station table * @STA_NOTIFY_REMOVE: a station being removed from the station table + * @STA_NOTIFY_SLEEP: a station is now sleeping + * @STA_NOTIFY_AWAKE: a sleeping station woke up */ enum sta_notify_cmd { - STA_NOTIFY_ADD, STA_NOTIFY_REMOVE + STA_NOTIFY_ADD, STA_NOTIFY_REMOVE, + STA_NOTIFY_SLEEP, STA_NOTIFY_AWAKE, }; /** @@ -769,6 +851,14 @@ enum ieee80211_tkip_key_type { * @IEEE80211_HW_SPECTRUM_MGMT: * Hardware supports spectrum management defined in 802.11h * Measurement, Channel Switch, Quieting, TPC + * + * @IEEE80211_HW_AMPDU_AGGREGATION: + * Hardware supports 11n A-MPDU aggregation. + * + * @IEEE80211_HW_NO_STACK_DYNAMIC_PS: + * Hardware which has dynamic power save support, meaning + * that power save is enabled in idle periods, and don't need support + * from stack. */ enum ieee80211_hw_flags { IEEE80211_HW_RX_INCLUDES_FCS = 1<<1, @@ -780,6 +870,8 @@ enum ieee80211_hw_flags { IEEE80211_HW_SIGNAL_DBM = 1<<7, IEEE80211_HW_NOISE_DBM = 1<<8, IEEE80211_HW_SPECTRUM_MGMT = 1<<9, + IEEE80211_HW_AMPDU_AGGREGATION = 1<<10, + IEEE80211_HW_NO_STACK_DYNAMIC_PS = 1<<11, }; /** @@ -838,8 +930,8 @@ enum ieee80211_hw_flags { * @sta_data_size: size (in bytes) of the drv_priv data area * within &struct ieee80211_sta. * - * @max_altrates: maximum number of alternate rate retry stages - * @max_altrate_tries: maximum number of tries for each stage + * @max_rates: maximum number of alternate rate retry stages + * @max_rate_tries: maximum number of tries for each stage */ struct ieee80211_hw { struct ieee80211_conf conf; @@ -856,12 +948,10 @@ struct ieee80211_hw { u16 ampdu_queues; u16 max_listen_interval; s8 max_signal; - u8 max_altrates; - u8 max_altrate_tries; + u8 max_rates; + u8 max_rate_tries; }; -struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy); - /** * SET_IEEE80211_DEV - set device for 802.11 hardware * @@ -874,7 +964,7 @@ static inline void SET_IEEE80211_DEV(struct ieee80211_hw *hw, struct device *dev } /** - * SET_IEEE80211_PERM_ADDR - set the permanenet MAC address for 802.11 hardware + * SET_IEEE80211_PERM_ADDR - set the permanent MAC address for 802.11 hardware * * @hw: the &struct ieee80211_hw to set the MAC address for * @addr: the address to set @@ -898,9 +988,9 @@ static inline struct ieee80211_rate * ieee80211_get_tx_rate(const struct ieee80211_hw *hw, const struct ieee80211_tx_info *c) { - if (WARN_ON(c->tx_rate_idx < 0)) + if (WARN_ON(c->control.rates[0].idx < 0)) return NULL; - return &hw->wiphy->bands[c->band]->bitrates[c->tx_rate_idx]; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[0].idx]; } static inline struct ieee80211_rate * @@ -916,9 +1006,9 @@ static inline struct ieee80211_rate * ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, const struct ieee80211_tx_info *c, int idx) { - if (c->control.retries[idx].rate_idx < 0) + if (c->control.rates[idx + 1].idx < 0) return NULL; - return &hw->wiphy->bands[c->band]->bitrates[c->control.retries[idx].rate_idx]; + return &hw->wiphy->bands[c->band]->bitrates[c->control.rates[idx + 1].idx]; } /** @@ -967,7 +1057,7 @@ ieee80211_get_alt_retry_rate(const struct ieee80211_hw *hw, * This happens everytime the iv16 wraps around (every 65536 packets). The * set_key() call will happen only once for each key (unless the AP did * rekeying), it will not include a valid phase 1 key. The valid phase 1 key is - * provided by udpate_tkip_key only. The trigger that makes mac80211 call this + * provided by update_tkip_key only. The trigger that makes mac80211 call this * handler is software decryption with wrap around of iv16. */ @@ -1060,12 +1150,14 @@ enum ieee80211_filter_flags { * @IEEE80211_AMPDU_RX_STOP: stop Rx aggregation * @IEEE80211_AMPDU_TX_START: start Tx aggregation * @IEEE80211_AMPDU_TX_STOP: stop Tx aggregation + * @IEEE80211_AMPDU_TX_RESUME: resume TX aggregation */ enum ieee80211_ampdu_mlme_action { IEEE80211_AMPDU_RX_START, IEEE80211_AMPDU_RX_STOP, IEEE80211_AMPDU_TX_START, IEEE80211_AMPDU_TX_STOP, + IEEE80211_AMPDU_TX_RESUME, }; /** @@ -1101,7 +1193,7 @@ enum ieee80211_ampdu_mlme_action { * Must be implemented. * * @add_interface: Called when a netdevice attached to the hardware is - * enabled. Because it is not called for monitor mode devices, @open + * enabled. Because it is not called for monitor mode devices, @start * and @stop must be implemented. * The driver should perform any initialization it needs before * the device can be enabled. The initial configuration for the @@ -1163,14 +1255,9 @@ enum ieee80211_ampdu_mlme_action { * * @set_rts_threshold: Configuration of RTS threshold (if device needs it) * - * @set_frag_threshold: Configuration of fragmentation threshold. Assign this if - * the device does fragmentation by itself; if this method is assigned then - * the stack will not do fragmentation. - * - * @set_retry_limit: Configuration of retry limits (if device needs it) - * - * @sta_notify: Notifies low level driver about addition or removal - * of assocaited station or AP. + * @sta_notify: Notifies low level driver about addition, removal or power + * state transition of an associated station, AP, IBSS/WDS/mesh peer etc. + * Must be atomic. * * @conf_tx: Configure TX queue parameters (EDCF (aifs, cw_min, cw_max), * bursting) for a hardware TX queue. @@ -1194,8 +1281,6 @@ enum ieee80211_ampdu_mlme_action { * This is needed only for IBSS mode and the result of this function is * used to determine whether to reply to Probe Requests. * - * @conf_ht: Configures low level driver with 802.11n HT data. Must be atomic. - * * @ampdu_action: Perform a certain A-MPDU action * The RA/TID combination determines the destination and TID we want * the ampdu action to be performed for. The action is defined through @@ -1211,7 +1296,7 @@ struct ieee80211_ops { struct ieee80211_if_init_conf *conf); void (*remove_interface)(struct ieee80211_hw *hw, struct ieee80211_if_init_conf *conf); - int (*config)(struct ieee80211_hw *hw, struct ieee80211_conf *conf); + int (*config)(struct ieee80211_hw *hw, u32 changed); int (*config_interface)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, struct ieee80211_if_conf *conf); @@ -1237,9 +1322,6 @@ struct ieee80211_ops { void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx, u32 *iv32, u16 *iv16); int (*set_rts_threshold)(struct ieee80211_hw *hw, u32 value); - int (*set_frag_threshold)(struct ieee80211_hw *hw, u32 value); - int (*set_retry_limit)(struct ieee80211_hw *hw, - u32 short_retry, u32 long_retr); void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, enum sta_notify_cmd, struct ieee80211_sta *sta); int (*conf_tx)(struct ieee80211_hw *hw, u16 queue, @@ -1472,7 +1554,7 @@ void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, * the next beacon frame from the 802.11 code. The low-level is responsible * for calling this function before beacon data is needed (e.g., based on * hardware interrupt). Returned skb is used only once and low-level driver - * is responsible of freeing it. + * is responsible for freeing it. */ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_vif *vif); @@ -1803,24 +1885,38 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, /* Rate control API */ + /** - * struct rate_selection - rate information for/from rate control algorithms - * - * @rate_idx: selected transmission rate index - * @nonerp_idx: Non-ERP rate to use instead if ERP cannot be used - * @probe_idx: rate for probing (or -1) - * @max_rate_idx: maximum rate index that can be used, this is - * input to the algorithm and will be enforced - */ -struct rate_selection { - s8 rate_idx, nonerp_idx, probe_idx, max_rate_idx; + * struct ieee80211_tx_rate_control - rate control information for/from RC algo + * + * @hw: The hardware the algorithm is invoked for. + * @sband: The band this frame is being transmitted on. + * @bss_conf: the current BSS configuration + * @reported_rate: The rate control algorithm can fill this in to indicate + * which rate should be reported to userspace as the current rate and + * used for rate calculations in the mesh network. + * @rts: whether RTS will be used for this frame because it is longer than the + * RTS threshold + * @short_preamble: whether mac80211 will request short-preamble transmission + * if the selected rate supports it + * @max_rate_idx: user-requested maximum rate (not MCS for now) + * @skb: the skb that will be transmitted, the control information in it needs + * to be filled in + */ +struct ieee80211_tx_rate_control { + struct ieee80211_hw *hw; + struct ieee80211_supported_band *sband; + struct ieee80211_bss_conf *bss_conf; + struct sk_buff *skb; + struct ieee80211_tx_rate reported_rate; + bool rts, short_preamble; + u8 max_rate_idx; }; struct rate_control_ops { struct module *module; const char *name; void *(*alloc)(struct ieee80211_hw *hw, struct dentry *debugfsdir); - void (*clear)(void *priv); void (*free)(void *priv); void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp); @@ -1832,10 +1928,8 @@ struct rate_control_ops { void (*tx_status)(void *priv, struct ieee80211_supported_band *sband, struct ieee80211_sta *sta, void *priv_sta, struct sk_buff *skb); - void (*get_rate)(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, - struct rate_selection *sel); + void (*get_rate)(void *priv, struct ieee80211_sta *sta, void *priv_sta, + struct ieee80211_tx_rate_control *txrc); void (*add_sta_debugfs)(void *priv, void *priv_sta, struct dentry *dir); diff --git a/include/net/ndisc.h b/include/net/ndisc.h index 11dd0137c6a5b34ee1434c4b699b68d304ce5d46..ce532f2222ce723daf21eaea7429bcbb5a26b4a8 100644 --- a/include/net/ndisc.h +++ b/include/net/ndisc.h @@ -108,6 +108,20 @@ extern void ndisc_send_redirect(struct sk_buff *skb, extern int ndisc_mc_map(struct in6_addr *addr, char *buf, struct net_device *dev, int dir); +extern struct sk_buff *ndisc_build_skb(struct net_device *dev, + const struct in6_addr *daddr, + const struct in6_addr *saddr, + struct icmp6hdr *icmp6h, + const struct in6_addr *target, + int llinfo); + +extern void ndisc_send_skb(struct sk_buff *skb, + struct net_device *dev, + struct neighbour *neigh, + const struct in6_addr *daddr, + const struct in6_addr *saddr, + struct icmp6hdr *icmp6h); + /* diff --git a/include/net/neighbour.h b/include/net/neighbour.h index aa4b708654a497a318732f7c5cfb6f00fdc65d1a..d8d790e56d3daa2d7b1751220ca1fa4314a57346 100644 --- a/include/net/neighbour.h +++ b/include/net/neighbour.h @@ -180,9 +180,6 @@ struct neigh_table __u32 hash_rnd; unsigned int hash_chain_gc; struct pneigh_entry **phash_buckets; -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *pde; -#endif }; /* flags for neigh_update() */ @@ -223,11 +220,7 @@ extern void neigh_parms_release(struct neigh_table *tbl, struct neigh_parms *p static inline struct net *neigh_parms_net(const struct neigh_parms *parms) { -#ifdef CONFIG_NET_NS - return parms->net; -#else - return &init_net; -#endif + return read_pnet(&parms->net); } extern unsigned long neigh_rand_reach_time(unsigned long base); @@ -244,11 +237,7 @@ extern int pneigh_delete(struct neigh_table *tbl, struct net *net, const void static inline struct net *pneigh_net(const struct pneigh_entry *pneigh) { -#ifdef CONFIG_NET_NS - return pneigh->net; -#else - return &init_net; -#endif + return read_pnet(&pneigh->net); } extern void neigh_app_ns(struct neighbour *n); diff --git a/include/net/net_namespace.h b/include/net/net_namespace.h index 700c53a3c6fa22d9e49f522616da870b99522d3c..6fc13d905c5ffaced2e1658038ab97934d61f42d 100644 --- a/include/net/net_namespace.h +++ b/include/net/net_namespace.h @@ -19,6 +19,7 @@ #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) #include #endif +#include struct proc_dir_entry; struct net_device; @@ -73,6 +74,9 @@ struct net { #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) struct netns_ct ct; #endif +#endif +#ifdef CONFIG_XFRM + struct netns_xfrm xfrm; #endif struct net_generic *gen; }; @@ -192,6 +196,24 @@ static inline void release_net(struct net *net) } #endif +#ifdef CONFIG_NET_NS + +static inline void write_pnet(struct net **pnet, struct net *net) +{ + *pnet = net; +} + +static inline struct net *read_pnet(struct net * const *pnet) +{ + return *pnet; +} + +#else + +#define write_pnet(pnet, net) do { (void)(net);} while (0) +#define read_pnet(pnet) (&init_net) + +#endif #define for_each_net(VAR) \ list_for_each_entry(VAR, &net_namespace_list, list) diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h index b76a8685b5b5ae96073d1c54a3e03878141d6d55..2e0c53641cbe2f7edcabd209db372b394d7bc6c0 100644 --- a/include/net/netfilter/nf_conntrack.h +++ b/include/net/netfilter/nf_conntrack.h @@ -199,7 +199,7 @@ __nf_conntrack_find(struct net *net, const struct nf_conntrack_tuple *tuple); extern void nf_conntrack_hash_insert(struct nf_conn *ct); -extern void nf_conntrack_flush(struct net *net); +extern void nf_conntrack_flush(struct net *net, u32 pid, int report); extern bool nf_ct_get_tuplepr(const struct sk_buff *skb, unsigned int nhoff, u_int16_t l3num, @@ -298,5 +298,8 @@ do { \ local_bh_enable(); \ } while (0) +#define MODULE_ALIAS_NFCT_HELPER(helper) \ + MODULE_ALIAS("nfct-helper-" helper) + #endif /* __KERNEL__ */ #endif /* _NF_CONNTRACK_H */ diff --git a/include/net/netfilter/nf_conntrack_ecache.h b/include/net/netfilter/nf_conntrack_ecache.h index 1285ff26a0145fc408dd8ca6b4035bca69d91f28..0ff0dc69ca4a53b9b3827122e715f1a15c1fa0cc 100644 --- a/include/net/netfilter/nf_conntrack_ecache.h +++ b/include/net/netfilter/nf_conntrack_ecache.h @@ -17,6 +17,13 @@ struct nf_conntrack_ecache { unsigned int events; }; +/* This structure is passed to event handler */ +struct nf_ct_event { + struct nf_conn *ct; + u32 pid; + int report; +}; + extern struct atomic_notifier_head nf_conntrack_chain; extern int nf_conntrack_register_notifier(struct notifier_block *nb); extern int nf_conntrack_unregister_notifier(struct notifier_block *nb); @@ -39,22 +46,56 @@ nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) local_bh_enable(); } -static inline void nf_conntrack_event(enum ip_conntrack_events event, - struct nf_conn *ct) +static inline void +nf_conntrack_event_report(enum ip_conntrack_events event, + struct nf_conn *ct, + u32 pid, + int report) { + struct nf_ct_event item = { + .ct = ct, + .pid = pid, + .report = report + }; if (nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct)) - atomic_notifier_call_chain(&nf_conntrack_chain, event, ct); + atomic_notifier_call_chain(&nf_conntrack_chain, event, &item); } +static inline void +nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) +{ + nf_conntrack_event_report(event, ct, 0, 0); +} + +struct nf_exp_event { + struct nf_conntrack_expect *exp; + u32 pid; + int report; +}; + extern struct atomic_notifier_head nf_ct_expect_chain; extern int nf_ct_expect_register_notifier(struct notifier_block *nb); extern int nf_ct_expect_unregister_notifier(struct notifier_block *nb); +static inline void +nf_ct_expect_event_report(enum ip_conntrack_expect_events event, + struct nf_conntrack_expect *exp, + u32 pid, + int report) +{ + struct nf_exp_event item = { + .exp = exp, + .pid = pid, + .report = report + }; + atomic_notifier_call_chain(&nf_ct_expect_chain, event, &item); +} + static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, struct nf_conntrack_expect *exp) { - atomic_notifier_call_chain(&nf_ct_expect_chain, event, exp); + nf_ct_expect_event_report(event, exp, 0, 0); } extern int nf_conntrack_ecache_init(struct net *net); @@ -66,9 +107,17 @@ static inline void nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct) {} static inline void nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct) {} +static inline void nf_conntrack_event_report(enum ip_conntrack_events event, + struct nf_conn *ct, + u32 pid, + int report) {} static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct) {} static inline void nf_ct_expect_event(enum ip_conntrack_expect_events event, struct nf_conntrack_expect *exp) {} +static inline void nf_ct_expect_event_report(enum ip_conntrack_expect_events e, + struct nf_conntrack_expect *exp, + u32 pid, + int report) {} static inline void nf_ct_event_cache_flush(struct net *net) {} static inline int nf_conntrack_ecache_init(struct net *net) diff --git a/include/net/netfilter/nf_conntrack_expect.h b/include/net/netfilter/nf_conntrack_expect.h index 37a7fc1164b00588ff390305d335e51f49b93c0f..ab17a159ac66192bdc4e6a445f3f1325653c571e 100644 --- a/include/net/netfilter/nf_conntrack_expect.h +++ b/include/net/netfilter/nf_conntrack_expect.h @@ -100,6 +100,8 @@ void nf_ct_expect_init(struct nf_conntrack_expect *, unsigned int, u_int8_t, u_int8_t, const __be16 *, const __be16 *); void nf_ct_expect_put(struct nf_conntrack_expect *exp); int nf_ct_expect_related(struct nf_conntrack_expect *expect); +int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, + u32 pid, int report); #endif /*_NF_CONNTRACK_EXPECT_H*/ diff --git a/include/net/netfilter/nf_conntrack_helper.h b/include/net/netfilter/nf_conntrack_helper.h index f8060ab5a0839d39373249d778db5b8e1fbe6830..66d65a7caa394164776c8559d3c5bd41c55bc8d8 100644 --- a/include/net/netfilter/nf_conntrack_helper.h +++ b/include/net/netfilter/nf_conntrack_helper.h @@ -38,9 +38,6 @@ struct nf_conntrack_helper unsigned int expect_class_max; }; -extern struct nf_conntrack_helper * -__nf_ct_helper_find(const struct nf_conntrack_tuple *tuple); - extern struct nf_conntrack_helper * __nf_conntrack_helper_find_byname(const char *name); @@ -49,6 +46,8 @@ extern void nf_conntrack_helper_unregister(struct nf_conntrack_helper *); extern struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp); +extern int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags); + static inline struct nf_conn_help *nfct_help(const struct nf_conn *ct) { return nf_ct_ext_find(ct, NF_CT_EXT_HELPER); diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h index 7f2f43c77284a7f6eb485fecac6f5ed7277420da..debdaf75cecf7563def7f6d8421a91e71bb08ca7 100644 --- a/include/net/netfilter/nf_conntrack_l4proto.h +++ b/include/net/netfilter/nf_conntrack_l4proto.h @@ -129,7 +129,7 @@ extern const struct nla_policy nf_ct_port_nla_policy[]; && net_ratelimit()) #endif #else -#define LOG_INVALID(net, proto) 0 +static inline int LOG_INVALID(struct net *net, int proto) { return 0; } #endif /* CONFIG_SYSCTL */ #endif /*_NF_CONNTRACK_PROTOCOL_H*/ diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h index a6874ba22d546322dc5ef9c2c86271003ec156e4..f2f6aa73dc10fd3ec65d3428118c486c2b51b20a 100644 --- a/include/net/netfilter/nf_conntrack_tuple.h +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -112,20 +112,20 @@ struct nf_conntrack_tuple_mask static inline void nf_ct_dump_tuple_ip(const struct nf_conntrack_tuple *t) { #ifdef DEBUG - printk("tuple %p: %u " NIPQUAD_FMT ":%hu -> " NIPQUAD_FMT ":%hu\n", + printk("tuple %p: %u %pI4:%hu -> %pI4:%hu\n", t, t->dst.protonum, - NIPQUAD(t->src.u3.ip), ntohs(t->src.u.all), - NIPQUAD(t->dst.u3.ip), ntohs(t->dst.u.all)); + &t->src.u3.ip, ntohs(t->src.u.all), + &t->dst.u3.ip, ntohs(t->dst.u.all)); #endif } static inline void nf_ct_dump_tuple_ipv6(const struct nf_conntrack_tuple *t) { #ifdef DEBUG - printk("tuple %p: %u " NIP6_FMT " %hu -> " NIP6_FMT " %hu\n", + printk("tuple %p: %u %pI6 %hu -> %pI6 %hu\n", t, t->dst.protonum, - NIP6(*(struct in6_addr *)t->src.u3.all), ntohs(t->src.u.all), - NIP6(*(struct in6_addr *)t->dst.u3.all), ntohs(t->dst.u.all)); + t->src.u3.all, ntohs(t->src.u.all), + t->dst.u3.all, ntohs(t->dst.u.all)); #endif } diff --git a/include/net/netfilter/nfnetlink_log.h b/include/net/netfilter/nfnetlink_log.h new file mode 100644 index 0000000000000000000000000000000000000000..b0569ff0775ed649fd07fa460bfcbd43cc91f746 --- /dev/null +++ b/include/net/netfilter/nfnetlink_log.h @@ -0,0 +1,14 @@ +#ifndef _KER_NFNETLINK_LOG_H +#define _KER_NFNETLINK_LOG_H + +void +nfulnl_log_packet(u_int8_t pf, + unsigned int hooknum, + const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct nf_loginfo *li_user, + const char *prefix); + +#endif /* _KER_NFNETLINK_LOG_H */ + diff --git a/include/net/netlink.h b/include/net/netlink.h index 3643bbb8e585e4018cbd66606d64c12a7edf84ac..8a6150a3f4c74a5a6a150947c5e1ff6ec494eca9 100644 --- a/include/net/netlink.h +++ b/include/net/netlink.h @@ -233,7 +233,7 @@ extern int nla_parse(struct nlattr *tb[], int maxtype, extern struct nlattr * nla_find(struct nlattr *head, int len, int attrtype); extern size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize); -extern int nla_memcpy(void *dest, struct nlattr *src, int count); +extern int nla_memcpy(void *dest, const struct nlattr *src, int count); extern int nla_memcmp(const struct nlattr *nla, const void *data, size_t size); extern int nla_strcmp(const struct nlattr *nla, const char *str); @@ -332,7 +332,7 @@ static inline int nlmsg_attrlen(const struct nlmsghdr *nlh, int hdrlen) */ static inline int nlmsg_ok(const struct nlmsghdr *nlh, int remaining) { - return (remaining >= sizeof(struct nlmsghdr) && + return (remaining >= (int) sizeof(struct nlmsghdr) && nlh->nlmsg_len >= sizeof(struct nlmsghdr) && nlh->nlmsg_len <= remaining); } @@ -741,7 +741,7 @@ static inline struct nlattr *nla_find_nested(struct nlattr *nla, int attrtype) * See nla_parse() */ static inline int nla_parse_nested(struct nlattr *tb[], int maxtype, - struct nlattr *nla, + const struct nlattr *nla, const struct nla_policy *policy) { return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy); @@ -875,7 +875,7 @@ static inline int nla_put_msecs(struct sk_buff *skb, int attrtype, * nla_get_u32 - return payload of u32 attribute * @nla: u32 netlink attribute */ -static inline u32 nla_get_u32(struct nlattr *nla) +static inline u32 nla_get_u32(const struct nlattr *nla) { return *(u32 *) nla_data(nla); } @@ -884,7 +884,7 @@ static inline u32 nla_get_u32(struct nlattr *nla) * nla_get_be32 - return payload of __be32 attribute * @nla: __be32 netlink attribute */ -static inline __be32 nla_get_be32(struct nlattr *nla) +static inline __be32 nla_get_be32(const struct nlattr *nla) { return *(__be32 *) nla_data(nla); } @@ -893,7 +893,7 @@ static inline __be32 nla_get_be32(struct nlattr *nla) * nla_get_u16 - return payload of u16 attribute * @nla: u16 netlink attribute */ -static inline u16 nla_get_u16(struct nlattr *nla) +static inline u16 nla_get_u16(const struct nlattr *nla) { return *(u16 *) nla_data(nla); } @@ -902,7 +902,7 @@ static inline u16 nla_get_u16(struct nlattr *nla) * nla_get_be16 - return payload of __be16 attribute * @nla: __be16 netlink attribute */ -static inline __be16 nla_get_be16(struct nlattr *nla) +static inline __be16 nla_get_be16(const struct nlattr *nla) { return *(__be16 *) nla_data(nla); } @@ -911,7 +911,7 @@ static inline __be16 nla_get_be16(struct nlattr *nla) * nla_get_le16 - return payload of __le16 attribute * @nla: __le16 netlink attribute */ -static inline __le16 nla_get_le16(struct nlattr *nla) +static inline __le16 nla_get_le16(const struct nlattr *nla) { return *(__le16 *) nla_data(nla); } @@ -920,7 +920,7 @@ static inline __le16 nla_get_le16(struct nlattr *nla) * nla_get_u8 - return payload of u8 attribute * @nla: u8 netlink attribute */ -static inline u8 nla_get_u8(struct nlattr *nla) +static inline u8 nla_get_u8(const struct nlattr *nla) { return *(u8 *) nla_data(nla); } @@ -929,7 +929,7 @@ static inline u8 nla_get_u8(struct nlattr *nla) * nla_get_u64 - return payload of u64 attribute * @nla: u64 netlink attribute */ -static inline u64 nla_get_u64(struct nlattr *nla) +static inline u64 nla_get_u64(const struct nlattr *nla) { u64 tmp; @@ -942,7 +942,7 @@ static inline u64 nla_get_u64(struct nlattr *nla) * nla_get_flag - return payload of flag attribute * @nla: flag netlink attribute */ -static inline int nla_get_flag(struct nlattr *nla) +static inline int nla_get_flag(const struct nlattr *nla) { return !!nla; } @@ -953,7 +953,7 @@ static inline int nla_get_flag(struct nlattr *nla) * * Returns the number of milliseconds in jiffies. */ -static inline unsigned long nla_get_msecs(struct nlattr *nla) +static inline unsigned long nla_get_msecs(const struct nlattr *nla) { u64 msecs = nla_get_u64(nla); diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h index ece1c926b5d18204855d484349148bb442823c6e..977f482d97a95144f0f777df1b0bbbacb7f1b11e 100644 --- a/include/net/netns/ipv4.h +++ b/include/net/netns/ipv4.h @@ -49,6 +49,8 @@ struct netns_ipv4 { int sysctl_icmp_ratelimit; int sysctl_icmp_ratemask; int sysctl_icmp_errors_use_inbound_ifaddr; + int sysctl_rt_cache_rebuild_count; + int current_rt_cache_rebuild_count; struct timer_list rt_secret_timer; atomic_t rt_genid; diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h index 2932721180c0902e5fdd42076208332a36a0242c..afab4e4cbac78ebfeb1d57497379bf515bade0ac 100644 --- a/include/net/netns/ipv6.h +++ b/include/net/netns/ipv6.h @@ -55,5 +55,17 @@ struct netns_ipv6 { struct sock *ndisc_sk; struct sock *tcp_sk; struct sock *igmp_sk; +#ifdef CONFIG_IPV6_MROUTE + struct sock *mroute6_sk; + struct mfc6_cache **mfc6_cache_array; + struct mif_device *vif6_table; + int maxvif; + atomic_t cache_resolve_queue_len; + int mroute_do_assert; + int mroute_do_pim; +#ifdef CONFIG_IPV6_PIMSM_V2 + int mroute_reg_vif_num; +#endif +#endif }; #endif diff --git a/include/net/netns/mib.h b/include/net/netns/mib.h index 10cb7c336de5a0ba8665bd8ae8979261794b1f2b..0b44112e2366e535a8d6ab7a8fcc726f4aad8de6 100644 --- a/include/net/netns/mib.h +++ b/include/net/netns/mib.h @@ -20,6 +20,9 @@ struct netns_mib { DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); DEFINE_SNMP_STAT(struct icmpv6msg_mib, icmpv6msg_statistics); #endif +#ifdef CONFIG_XFRM_STATISTICS + DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics); +#endif }; #endif diff --git a/include/net/netns/x_tables.h b/include/net/netns/x_tables.h index b8093971ccb476e5288037a8c653cb06a8addf49..9554a644a8f85150c80792f666557cdde6ec4642 100644 --- a/include/net/netns/x_tables.h +++ b/include/net/netns/x_tables.h @@ -4,7 +4,12 @@ #include #include +struct ebt_table; + struct netns_xt { struct list_head tables[NFPROTO_NUMPROTO]; + struct ebt_table *broute_table; + struct ebt_table *frame_filter; + struct ebt_table *frame_nat; }; #endif diff --git a/include/net/netns/xfrm.h b/include/net/netns/xfrm.h new file mode 100644 index 0000000000000000000000000000000000000000..1ba912749caac2c64c5c223416dc6b9cb6be360b --- /dev/null +++ b/include/net/netns/xfrm.h @@ -0,0 +1,56 @@ +#ifndef __NETNS_XFRM_H +#define __NETNS_XFRM_H + +#include +#include +#include +#include + +struct ctl_table_header; + +struct xfrm_policy_hash { + struct hlist_head *table; + unsigned int hmask; +}; + +struct netns_xfrm { + struct list_head state_all; + /* + * Hash table to find appropriate SA towards given target (endpoint of + * tunnel or destination of transport mode) allowed by selector. + * + * 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. + */ + struct hlist_head *state_bydst; + struct hlist_head *state_bysrc; + struct hlist_head *state_byspi; + unsigned int state_hmask; + unsigned int state_num; + struct work_struct state_hash_work; + struct hlist_head state_gc_list; + struct work_struct state_gc_work; + + wait_queue_head_t km_waitq; + + struct list_head policy_all; + struct hlist_head *policy_byidx; + unsigned int policy_idx_hmask; + struct hlist_head policy_inexact[XFRM_POLICY_MAX * 2]; + struct xfrm_policy_hash policy_bydst[XFRM_POLICY_MAX * 2]; + unsigned int policy_count[XFRM_POLICY_MAX * 2]; + struct work_struct policy_hash_work; + + struct sock *nlsk; + + u32 sysctl_aevent_etime; + u32 sysctl_aevent_rseqth; + int sysctl_larval_drop; + u32 sysctl_acq_expires; +#ifdef CONFIG_SYSCTL + struct ctl_table_header *sysctl_hdr; +#endif +}; + +#endif diff --git a/include/net/phonet/pep.h b/include/net/phonet/pep.h index fcd793030e4dfdbf9889bdf10757c84edd486d87..4c61cdce4e5fc3827af2d0d3064bf1bfd55718f6 100644 --- a/include/net/phonet/pep.h +++ b/include/net/phonet/pep.h @@ -35,12 +35,12 @@ struct pep_sock { struct sock *listener; struct sk_buff_head ctrlreq_queue; #define PNPIPE_CTRLREQ_MAX 10 + atomic_t tx_credits; int ifindex; u16 peer_type; /* peer type/subtype */ u8 pipe_handle; u8 rx_credits; - u8 tx_credits; u8 rx_fc; /* RX flow control */ u8 tx_fc; /* TX flow control */ u8 init_enable; /* auto-enable at creation */ diff --git a/include/net/phonet/phonet.h b/include/net/phonet/phonet.h index c6a24518446039844f384e31265df66b3c01791f..057b0a8a28859f519a6fc85694de0ee69913b8bf 100644 --- a/include/net/phonet/phonet.h +++ b/include/net/phonet/phonet.h @@ -46,7 +46,7 @@ static inline struct pn_sock *pn_sk(struct sock *sk) extern const struct proto_ops phonet_dgram_ops; -struct sock *pn_find_sock_by_sa(const struct sockaddr_pn *sa); +struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *sa); void phonet_get_local_port_range(int *min, int *max); void pn_sock_hash(struct sock *sk); void pn_sock_unhash(struct sock *sk); diff --git a/include/net/phonet/pn_dev.h b/include/net/phonet/pn_dev.h index bbd2a836e04cd6f4c414a240f0aec9466cf3bea2..aa1c59a1d33f6f5245b330b6e0f3e9fe9988420b 100644 --- a/include/net/phonet/pn_dev.h +++ b/include/net/phonet/pn_dev.h @@ -43,7 +43,7 @@ struct net_device *phonet_device_get(struct net *net); int phonet_address_add(struct net_device *dev, u8 addr); int phonet_address_del(struct net_device *dev, u8 addr); u8 phonet_address_get(struct net_device *dev, u8 addr); -int phonet_address_lookup(u8 addr); +int phonet_address_lookup(struct net *net, u8 addr); #define PN_NO_ADDR 0xff diff --git a/include/net/pkt_cls.h b/include/net/pkt_cls.h index aa9e282db4855ffe0733f72f6e25b3cc89b913bc..d1ca3144464438f6ba1dc442ec36315d6f7e195f 100644 --- a/include/net/pkt_cls.h +++ b/include/net/pkt_cls.h @@ -246,7 +246,7 @@ struct tcf_ematch_ops }; extern int tcf_em_register(struct tcf_ematch_ops *); -extern int tcf_em_unregister(struct tcf_ematch_ops *); +extern void tcf_em_unregister(struct tcf_ematch_ops *); extern int tcf_em_tree_validate(struct tcf_proto *, struct nlattr *, struct tcf_ematch_tree *); extern void tcf_em_tree_destroy(struct tcf_proto *, struct tcf_ematch_tree *); diff --git a/include/net/protocol.h b/include/net/protocol.h index 8d024d7cb7414727e5b9c512d0a23d827a3bfe49..cb2965aa1b62e9f1ff2b3928689cdc02dda360a2 100644 --- a/include/net/protocol.h +++ b/include/net/protocol.h @@ -39,6 +39,9 @@ struct net_protocol { int (*gso_send_check)(struct sk_buff *skb); struct sk_buff *(*gso_segment)(struct sk_buff *skb, int features); + struct sk_buff **(*gro_receive)(struct sk_buff **head, + struct sk_buff *skb); + int (*gro_complete)(struct sk_buff *skb); unsigned int no_policy:1, netns_ok:1; }; diff --git a/include/net/sch_generic.h b/include/net/sch_generic.h index 3fe49d808957309f29f1cb9532892fc06e936f2e..f8c47429044aee1db7ddf54a14e405305be51b0a 100644 --- a/include/net/sch_generic.h +++ b/include/net/sch_generic.h @@ -53,7 +53,6 @@ struct Qdisc atomic_t refcnt; unsigned long state; struct sk_buff *gso_skb; - struct sk_buff_head requeue; struct sk_buff_head q; struct netdev_queue *dev_queue; struct Qdisc *next_sched; @@ -111,7 +110,7 @@ struct Qdisc_ops int (*enqueue)(struct sk_buff *, struct Qdisc *); struct sk_buff * (*dequeue)(struct Qdisc *); - int (*requeue)(struct sk_buff *, struct Qdisc *); + struct sk_buff * (*peek)(struct Qdisc *); unsigned int (*drop)(struct Qdisc *); int (*init)(struct Qdisc *, struct nlattr *arg); @@ -432,19 +431,38 @@ static inline struct sk_buff *qdisc_dequeue_tail(struct Qdisc *sch) return __qdisc_dequeue_tail(sch, &sch->q); } -static inline int __qdisc_requeue(struct sk_buff *skb, struct Qdisc *sch, - struct sk_buff_head *list) +static inline struct sk_buff *qdisc_peek_head(struct Qdisc *sch) { - __skb_queue_head(list, skb); - sch->qstats.backlog += qdisc_pkt_len(skb); - sch->qstats.requeues++; + return skb_peek(&sch->q); +} - return NET_XMIT_SUCCESS; +/* generic pseudo peek method for non-work-conserving qdisc */ +static inline struct sk_buff *qdisc_peek_dequeued(struct Qdisc *sch) +{ + /* we can reuse ->gso_skb because peek isn't called for root qdiscs */ + if (!sch->gso_skb) { + sch->gso_skb = sch->dequeue(sch); + if (sch->gso_skb) + /* it's still part of the queue */ + sch->q.qlen++; + } + + return sch->gso_skb; } -static inline int qdisc_requeue(struct sk_buff *skb, struct Qdisc *sch) +/* use instead of qdisc->dequeue() for all qdiscs queried with ->peek() */ +static inline struct sk_buff *qdisc_dequeue_peeked(struct Qdisc *sch) { - return __qdisc_requeue(skb, sch, &sch->q); + struct sk_buff *skb = sch->gso_skb; + + if (skb) { + sch->gso_skb = NULL; + sch->q.qlen--; + } else { + skb = sch->dequeue(sch); + } + + return skb; } static inline void __qdisc_reset_queue(struct Qdisc *sch, diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index ed71b110edf795094336e436816d9bdd5e6a1aab..bbb7742195b0df31e4498b19e909e7a97a7b47e7 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -138,6 +138,7 @@ void sctp_write_space(struct sock *sk); unsigned int sctp_poll(struct file *file, struct socket *sock, poll_table *wait); void sctp_sock_rfree(struct sk_buff *skb); +extern struct percpu_counter sctp_sockets_allocated; /* * sctp/primitive.c @@ -285,15 +286,15 @@ extern int sctp_debug_flag; if (sctp_debug_flag) { \ if (saddr->sa.sa_family == AF_INET6) { \ printk(KERN_DEBUG \ - lead NIP6_FMT trail, \ + lead "%pI6" trail, \ leadparm, \ - NIP6(saddr->v6.sin6_addr), \ + &saddr->v6.sin6_addr, \ otherparms); \ } else { \ printk(KERN_DEBUG \ - lead NIPQUAD_FMT trail, \ + lead "%pI4" trail, \ leadparm, \ - NIPQUAD(saddr->v4.sin_addr.s_addr), \ + &saddr->v4.sin_addr.s_addr, \ otherparms); \ } \ } diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index f205b10f0ab95f05ec3cef5aea549991c4f0f0d7..b259fc5798fb2f909fda0cc80be04d906b3879cc 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -118,6 +118,8 @@ enum sctp_optname { #define SCTP_PEER_AUTH_CHUNKS SCTP_PEER_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS, /* Read only */ #define SCTP_LOCAL_AUTH_CHUNKS SCTP_LOCAL_AUTH_CHUNKS + SCTP_GET_ASSOC_NUMBER, /* Read only */ +#define SCTP_GET_ASSOC_NUMBER SCTP_GET_ASSOC_NUMBER /* Internal Socket Options. Some of the sctp library functions are diff --git a/include/net/sock.h b/include/net/sock.h index 2f47107f6d0f8f018feaba3a75eeff4dd64d14ec..5a3a151bd7300455d6da16d6b34ac39a785fb4c7 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -52,6 +53,7 @@ #include #include +#include #include #include @@ -106,6 +108,7 @@ struct net; * @skc_reuse: %SO_REUSEADDR setting * @skc_bound_dev_if: bound device index if != 0 * @skc_node: main hash linkage for various protocol lookup tables + * @skc_nulls_node: main hash linkage for UDP/UDP-Lite protocol * @skc_bind_node: bind hash linkage for various protocol lookup tables * @skc_refcnt: reference count * @skc_hash: hash value used with various protocol lookup tables @@ -120,7 +123,10 @@ struct sock_common { volatile unsigned char skc_state; unsigned char skc_reuse; int skc_bound_dev_if; - struct hlist_node skc_node; + union { + struct hlist_node skc_node; + struct hlist_nulls_node skc_nulls_node; + }; struct hlist_node skc_bind_node; atomic_t skc_refcnt; unsigned int skc_hash; @@ -206,6 +212,7 @@ struct sock { #define sk_reuse __sk_common.skc_reuse #define sk_bound_dev_if __sk_common.skc_bound_dev_if #define sk_node __sk_common.skc_node +#define sk_nulls_node __sk_common.skc_nulls_node #define sk_bind_node __sk_common.skc_bind_node #define sk_refcnt __sk_common.skc_refcnt #define sk_hash __sk_common.skc_hash @@ -229,7 +236,9 @@ struct sock { } sk_backlog; wait_queue_head_t *sk_sleep; struct dst_entry *sk_dst_cache; +#ifdef CONFIG_XFRM struct xfrm_policy *sk_policy[2]; +#endif rwlock_t sk_dst_lock; atomic_t sk_rmem_alloc; atomic_t sk_wmem_alloc; @@ -237,7 +246,9 @@ struct sock { int sk_sndbuf; struct sk_buff_head sk_receive_queue; struct sk_buff_head sk_write_queue; +#ifdef CONFIG_NET_DMA struct sk_buff_head sk_async_wait_queue; +#endif int sk_wmem_queued; int sk_forward_alloc; gfp_t sk_allocation; @@ -269,7 +280,9 @@ struct sock { struct sk_buff *sk_send_head; __u32 sk_sndmsg_off; int sk_write_pending; +#ifdef CONFIG_SECURITY void *sk_security; +#endif __u32 sk_mark; /* XXX 4 bytes hole on 64 bit */ void (*sk_state_change)(struct sock *sk); @@ -294,12 +307,30 @@ static inline struct sock *sk_head(const struct hlist_head *head) return hlist_empty(head) ? NULL : __sk_head(head); } +static inline struct sock *__sk_nulls_head(const struct hlist_nulls_head *head) +{ + return hlist_nulls_entry(head->first, struct sock, sk_nulls_node); +} + +static inline struct sock *sk_nulls_head(const struct hlist_nulls_head *head) +{ + return hlist_nulls_empty(head) ? NULL : __sk_nulls_head(head); +} + static inline struct sock *sk_next(const struct sock *sk) { return sk->sk_node.next ? hlist_entry(sk->sk_node.next, struct sock, sk_node) : NULL; } +static inline struct sock *sk_nulls_next(const struct sock *sk) +{ + return (!is_a_nulls(sk->sk_nulls_node.next)) ? + hlist_nulls_entry(sk->sk_nulls_node.next, + struct sock, sk_nulls_node) : + NULL; +} + static inline int sk_unhashed(const struct sock *sk) { return hlist_unhashed(&sk->sk_node); @@ -315,6 +346,11 @@ static __inline__ void sk_node_init(struct hlist_node *node) node->pprev = NULL; } +static __inline__ void sk_nulls_node_init(struct hlist_nulls_node *node) +{ + node->pprev = NULL; +} + static __inline__ void __sk_del_node(struct sock *sk) { __hlist_del(&sk->sk_node); @@ -361,6 +397,27 @@ static __inline__ int sk_del_node_init(struct sock *sk) return rc; } +static __inline__ int __sk_nulls_del_node_init_rcu(struct sock *sk) +{ + if (sk_hashed(sk)) { + hlist_nulls_del_init_rcu(&sk->sk_nulls_node); + return 1; + } + return 0; +} + +static __inline__ int sk_nulls_del_node_init_rcu(struct sock *sk) +{ + int rc = __sk_nulls_del_node_init_rcu(sk); + + if (rc) { + /* paranoid for a while -acme */ + WARN_ON(atomic_read(&sk->sk_refcnt) == 1); + __sock_put(sk); + } + return rc; +} + static __inline__ void __sk_add_node(struct sock *sk, struct hlist_head *list) { hlist_add_head(&sk->sk_node, list); @@ -372,6 +429,17 @@ static __inline__ void sk_add_node(struct sock *sk, struct hlist_head *list) __sk_add_node(sk, list); } +static __inline__ void __sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list) +{ + hlist_nulls_add_head_rcu(&sk->sk_nulls_node, list); +} + +static __inline__ void sk_nulls_add_node_rcu(struct sock *sk, struct hlist_nulls_head *list) +{ + sock_hold(sk); + __sk_nulls_add_node_rcu(sk, list); +} + static __inline__ void __sk_del_bind_node(struct sock *sk) { __hlist_del(&sk->sk_bind_node); @@ -385,9 +453,16 @@ static __inline__ void sk_add_bind_node(struct sock *sk, #define sk_for_each(__sk, node, list) \ hlist_for_each_entry(__sk, node, list, sk_node) +#define sk_nulls_for_each(__sk, node, list) \ + hlist_nulls_for_each_entry(__sk, node, list, sk_nulls_node) +#define sk_nulls_for_each_rcu(__sk, node, list) \ + hlist_nulls_for_each_entry_rcu(__sk, node, list, sk_nulls_node) #define sk_for_each_from(__sk, node) \ if (__sk && ({ node = &(__sk)->sk_node; 1; })) \ hlist_for_each_entry_from(__sk, node, sk_node) +#define sk_nulls_for_each_from(__sk, node) \ + if (__sk && ({ node = &(__sk)->sk_nulls_node; 1; })) \ + hlist_nulls_for_each_entry_from(__sk, node, sk_nulls_node) #define sk_for_each_continue(__sk, node) \ if (__sk && ({ node = &(__sk)->sk_node; 1; })) \ hlist_for_each_entry_continue(__sk, node, sk_node) @@ -574,7 +649,7 @@ struct proto { /* Memory pressure */ void (*enter_memory_pressure)(struct sock *sk); atomic_t *memory_allocated; /* Current allocated memory. */ - atomic_t *sockets_allocated; /* Current number of sockets. */ + struct percpu_counter *sockets_allocated; /* Current number of sockets. */ /* * Pressure flag: try to collapse. * Technical note: it is used by multiple contexts non atomically. @@ -587,17 +662,18 @@ struct proto { int *sysctl_rmem; int max_header; - struct kmem_cache *slab; + struct kmem_cache *slab; unsigned int obj_size; + int slab_flags; - atomic_t *orphan_count; + struct percpu_counter *orphan_count; struct request_sock_ops *rsk_prot; struct timewait_sock_ops *twsk_prot; union { struct inet_hashinfo *hashinfo; - struct hlist_head *udp_hash; + struct udp_table *udp_table; struct raw_hashinfo *raw_hash; } h; diff --git a/include/net/syncppp.h b/include/net/syncppp.h deleted file mode 100644 index 9e306f7f579ad5b7e5bd1f7b4aeabc261263ced8..0000000000000000000000000000000000000000 --- a/include/net/syncppp.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Defines for synchronous PPP/Cisco link level subroutines. - * - * Copyright (C) 1994 Cronyx Ltd. - * Author: Serge Vakulenko, - * - * This software is distributed with NO WARRANTIES, not even the implied - * warranties for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * - * Authors grant any other persons or organizations permission to use - * or modify this software as long as this message is kept with the software, - * all derivative works or modified versions. - * - * Version 1.7, Wed Jun 7 22:12:02 MSD 1995 - * - * - * - */ - -#ifndef _SYNCPPP_H_ -#define _SYNCPPP_H_ 1 - -#ifdef __KERNEL__ -struct slcp { - u16 state; /* state machine */ - u32 magic; /* local magic number */ - u_char echoid; /* id of last keepalive echo request */ - u_char confid; /* id of last configuration request */ -}; - -struct sipcp { - u16 state; /* state machine */ - u_char confid; /* id of last configuration request */ -}; - -struct sppp -{ - struct sppp * pp_next; /* next interface in keepalive list */ - u32 pp_flags; /* use Cisco protocol instead of PPP */ - u16 pp_alivecnt; /* keepalive packets counter */ - u16 pp_loopcnt; /* loopback detection counter */ - u32 pp_seq; /* local sequence number */ - u32 pp_rseq; /* remote sequence number */ - struct slcp lcp; /* LCP params */ - struct sipcp ipcp; /* IPCP params */ - struct timer_list pp_timer; - struct net_device *pp_if; - char pp_link_state; /* Link status */ - spinlock_t lock; -}; - -struct ppp_device -{ - struct net_device *dev; /* Network device pointer */ - struct sppp sppp; /* Synchronous PPP */ -}; - -static inline struct sppp *sppp_of(struct net_device *dev) -{ - struct ppp_device **ppp = dev->ml_priv; - BUG_ON((*ppp)->dev != dev); - return &(*ppp)->sppp; -} - -#define PP_KEEPALIVE 0x01 /* use keepalive protocol */ -#define PP_CISCO 0x02 /* use Cisco protocol instead of PPP */ -#define PP_TIMO 0x04 /* cp_timeout routine active */ -#define PP_DEBUG 0x08 - -#define PPP_MTU 1500 /* max. transmit unit */ - -#define LCP_STATE_CLOSED 0 /* LCP state: closed (conf-req sent) */ -#define LCP_STATE_ACK_RCVD 1 /* LCP state: conf-ack received */ -#define LCP_STATE_ACK_SENT 2 /* LCP state: conf-ack sent */ -#define LCP_STATE_OPENED 3 /* LCP state: opened */ - -#define IPCP_STATE_CLOSED 0 /* IPCP state: closed (conf-req sent) */ -#define IPCP_STATE_ACK_RCVD 1 /* IPCP state: conf-ack received */ -#define IPCP_STATE_ACK_SENT 2 /* IPCP state: conf-ack sent */ -#define IPCP_STATE_OPENED 3 /* IPCP state: opened */ - -#define SPPP_LINK_DOWN 0 /* link down - no keepalive */ -#define SPPP_LINK_UP 1 /* link is up - keepalive ok */ - -void sppp_attach (struct ppp_device *pd); -void sppp_detach (struct net_device *dev); -int sppp_do_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd); -struct sk_buff *sppp_dequeue (struct net_device *dev); -int sppp_isempty (struct net_device *dev); -void sppp_flush (struct net_device *dev); -int sppp_open (struct net_device *dev); -int sppp_reopen (struct net_device *dev); -int sppp_close (struct net_device *dev); -#endif - -#define SPPPIOCCISCO (SIOCDEVPRIVATE) -#define SPPPIOCPPP (SIOCDEVPRIVATE+1) -#define SPPPIOCDEBUG (SIOCDEVPRIVATE+2) -#define SPPPIOCSFLAGS (SIOCDEVPRIVATE+3) -#define SPPPIOCGFLAGS (SIOCDEVPRIVATE+4) - -#endif /* _SYNCPPP_H_ */ diff --git a/include/net/tcp.h b/include/net/tcp.h index 438014d57610d3c22355746e7f73e73ec73a3785..218235de89637f9471027f299dfd19fcd9d6c858 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -46,7 +46,7 @@ extern struct inet_hashinfo tcp_hashinfo; -extern atomic_t tcp_orphan_count; +extern struct percpu_counter tcp_orphan_count; extern void tcp_time_wait(struct sock *sk, int state, int timeo); #define MAX_TCP_HEADER (128 + MAX_HEADER) @@ -238,7 +238,7 @@ extern int sysctl_tcp_slow_start_after_idle; extern int sysctl_tcp_max_ssthresh; extern atomic_t tcp_memory_allocated; -extern atomic_t tcp_sockets_allocated; +extern struct percpu_counter tcp_sockets_allocated; extern int tcp_memory_pressure; /* @@ -472,8 +472,6 @@ extern void tcp_send_delayed_ack(struct sock *sk); /* tcp_input.c */ extern void tcp_cwnd_application_limited(struct sock *sk); -extern void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, - struct sk_buff *skb); /* tcp_timer.c */ extern void tcp_init_xmit_timers(struct sock *); @@ -590,7 +588,6 @@ struct tcp_skb_cb { #define TCPCB_EVER_RETRANS 0x80 /* Ever retransmitted frame */ #define TCPCB_RETRANS (TCPCB_SACKED_RETRANS|TCPCB_EVER_RETRANS) - __u16 urg_ptr; /* Valid w/URG flags is set. */ __u32 ack_seq; /* Sequence number ACK'd */ }; @@ -764,8 +761,6 @@ static inline unsigned int tcp_packets_in_flight(const struct tcp_sock *tp) return tp->packets_out - tcp_left_out(tp) + tp->retrans_out; } -extern int tcp_limit_reno_sacked(struct tcp_sock *tp); - /* If cwnd > ssthresh, we may raise ssthresh to be half-way to cwnd. * The exception is rate halving phase, when cwnd is decreasing towards * ssthresh. @@ -1195,6 +1190,11 @@ static inline struct sk_buff *tcp_write_queue_next(struct sock *sk, struct sk_bu return skb_queue_next(&sk->sk_write_queue, skb); } +static inline struct sk_buff *tcp_write_queue_prev(struct sock *sk, struct sk_buff *skb) +{ + return skb_queue_prev(&sk->sk_write_queue, skb); +} + #define tcp_for_write_queue(skb, sk) \ skb_queue_walk(&(sk)->sk_write_queue, skb) @@ -1358,6 +1358,12 @@ extern void tcp_v4_destroy_sock(struct sock *sk); extern int tcp_v4_gso_send_check(struct sk_buff *skb); extern struct sk_buff *tcp_tso_segment(struct sk_buff *skb, int features); +extern struct sk_buff **tcp_gro_receive(struct sk_buff **head, + struct sk_buff *skb); +extern struct sk_buff **tcp4_gro_receive(struct sk_buff **head, + struct sk_buff *skb); +extern int tcp_gro_complete(struct sk_buff *skb); +extern int tcp4_gro_complete(struct sk_buff *skb); #ifdef CONFIG_PROC_FS extern int tcp4_proc_init(void); diff --git a/include/net/udp.h b/include/net/udp.h index 1e205095ea687aee5f76913a1d03d47c1121e948..90e6ce56be6576826ef51f9c85d4ae0d91791dbb 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -50,8 +50,15 @@ struct udp_skb_cb { }; #define UDP_SKB_CB(__skb) ((struct udp_skb_cb *)((__skb)->cb)) -extern struct hlist_head udp_hash[UDP_HTABLE_SIZE]; -extern rwlock_t udp_hash_lock; +struct udp_hslot { + struct hlist_nulls_head head; + spinlock_t lock; +} __attribute__((aligned(2 * sizeof(long)))); +struct udp_table { + struct udp_hslot hash[UDP_HTABLE_SIZE]; +}; +extern struct udp_table udp_table; +extern void udp_table_init(struct udp_table *); /* Note: this must match 'valbool' in sock_setsockopt */ @@ -110,15 +117,7 @@ static inline void udp_lib_hash(struct sock *sk) BUG(); } -static inline void udp_lib_unhash(struct sock *sk) -{ - write_lock_bh(&udp_hash_lock); - if (sk_del_node_init(sk)) { - inet_sk(sk)->num = 0; - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - } - write_unlock_bh(&udp_hash_lock); -} +extern void udp_lib_unhash(struct sock *sk); static inline void udp_lib_close(struct sock *sk, long timeout) { @@ -187,7 +186,7 @@ extern struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, struct udp_seq_afinfo { char *name; sa_family_t family; - struct hlist_head *hashtable; + struct udp_table *udp_table; struct file_operations seq_fops; struct seq_operations seq_ops; }; @@ -196,7 +195,7 @@ struct udp_iter_state { struct seq_net_private p; sa_family_t family; int bucket; - struct hlist_head *hashtable; + struct udp_table *udp_table; }; #ifdef CONFIG_PROC_FS diff --git a/include/net/udplite.h b/include/net/udplite.h index b76b2e377af4540bc8336328f55485d87a26947b..afdffe607b2425fd66a2a1c8ae30b3bca1eb1494 100644 --- a/include/net/udplite.h +++ b/include/net/udplite.h @@ -11,7 +11,7 @@ #define UDPLITE_RECV_CSCOV 11 /* receiver partial coverage (threshold ) */ extern struct proto udplite_prot; -extern struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; +extern struct udp_table udplite_table; /* * Checksum computation is all in software, hence simpler getfrag. diff --git a/include/net/wireless.h b/include/net/wireless.h index 721efb363db73cd0bb06270e5c1463a6e7ffe930..21c5d966142d9cc3b5964364c482068a03f25c0b 100644 --- a/include/net/wireless.h +++ b/include/net/wireless.h @@ -10,6 +10,7 @@ #include #include #include +#include #include /** @@ -133,23 +134,23 @@ struct ieee80211_rate { }; /** - * struct ieee80211_ht_info - describing STA's HT capabilities + * struct ieee80211_sta_ht_cap - 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 + * @ht_supported: is HT supported by the STA * @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 + * @mcs: Supported MCS rates */ -struct ieee80211_ht_info { +struct ieee80211_sta_ht_cap { u16 cap; /* use IEEE80211_HT_CAP_ */ - u8 ht_supported; + bool ht_supported; u8 ampdu_factor; u8 ampdu_density; - u8 supp_mcs_set[16]; + struct ieee80211_mcs_info mcs; }; /** @@ -173,13 +174,18 @@ struct ieee80211_supported_band { enum ieee80211_band band; int n_channels; int n_bitrates; - struct ieee80211_ht_info ht_info; + struct ieee80211_sta_ht_cap ht_cap; }; /** * struct wiphy - wireless hardware description * @idx: the wiphy index assigned to this item * @class_dev: the class device representing /sys/class/ieee80211/ + * @fw_handles_regulatory: tells us the firmware for this device + * has its own regulatory solution and cannot identify the + * ISO / IEC 3166 alpha2 it belongs to. When this is enabled + * we will disregard the first regulatory hint (when the + * initiator is %REGDOM_SET_BY_CORE). * @reg_notifier: the driver's regulatory notification callback */ struct wiphy { @@ -191,6 +197,8 @@ struct wiphy { /* Supported interface modes, OR together BIT(NL80211_IFTYPE_...) */ u16 interface_modes; + bool fw_handles_regulatory; + /* If multiple wiphys are registered and you're handed e.g. * a regular netdev with assigned ieee80211_ptr, you won't * know whether it points to a wiphy your driver has registered @@ -262,9 +270,9 @@ static inline struct device *wiphy_dev(struct wiphy *wiphy) /** * wiphy_name - get wiphy name */ -static inline char *wiphy_name(struct wiphy *wiphy) +static inline const char *wiphy_name(struct wiphy *wiphy) { - return wiphy->dev.bus_id; + return dev_name(&wiphy->dev); } /** @@ -340,55 +348,51 @@ ieee80211_get_channel(struct wiphy *wiphy, int freq) } /** - * __regulatory_hint - hint to the wireless core a regulatory domain - * @wiphy: if a driver is providing the hint this is the driver's very - * own &struct wiphy - * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain - * should be in. If @rd is set this should be NULL - * @rd: a complete regulatory domain, if passed the caller need not worry - * about freeing it - * - * The Wireless subsystem can use this function to hint to the wireless core - * what it believes should be the current regulatory domain by - * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory - * domain should be in or by providing a completely build regulatory domain. + * ieee80211_get_response_rate - get basic rate for a given rate * - * Returns -EALREADY if *a regulatory domain* has already been set. Note that - * this could be by another driver. It is safe for drivers to continue if - * -EALREADY is returned, if drivers are not capable of world roaming they - * should not register more channels than they support. Right now we only - * support listening to the first driver hint. If the driver is capable - * of world roaming but wants to respect its own EEPROM mappings for - * specific regulatory domains it should register the @reg_notifier callback - * on the &struct wiphy. Returns 0 if the hint went through fine or through an - * intersection operation. Otherwise a standard error code is returned. + * @sband: the band to look for rates in + * @basic_rates: bitmap of basic rates + * @bitrate: the bitrate for which to find the basic rate * + * This function returns the basic rate corresponding to a given + * bitrate, that is the next lower bitrate contained in the basic + * rate map, which is, for this function, given as a bitmap of + * indices of rates in the band's bitrate table. */ -extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, - const char *alpha2, struct ieee80211_regdomain *rd); +struct ieee80211_rate * +ieee80211_get_response_rate(struct ieee80211_supported_band *sband, + u64 basic_rates, int bitrate); + /** * regulatory_hint - driver hint to the wireless core a regulatory domain - * @wiphy: the driver's very own &struct wiphy + * @wiphy: the wireless device giving the hint (used only for reporting + * conflicts) * @alpha2: the ISO/IEC 3166 alpha2 the driver claims its regulatory domain * should be in. If @rd is set this should be NULL. Note that if you * set this to NULL you should still set rd->alpha2 to some accepted * alpha2. - * @rd: a complete regulatory domain provided by the driver. If passed - * the driver does not need to worry about freeing it. * * Wireless drivers can use this function to hint to the wireless core * what it believes should be the current regulatory domain by * giving it an ISO/IEC 3166 alpha2 country code it knows its regulatory * domain should be in or by providing a completely build regulatory domain. * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried - * for a regulatory domain structure for the respective country. If - * a regulatory domain is build and passed you should set the alpha2 - * if possible, otherwise set it to the special value of "99" which tells - * the wireless core it is unknown. If you pass a built regulatory domain - * and we return non zero you are in charge of kfree()'ing the structure. + * for a regulatory domain structure for the respective country. + */ +extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2); + +/** + * regulatory_hint_11d - hints a country IE as a regulatory domain + * @wiphy: the wireless device giving the hint (used only for reporting + * conflicts) + * @country_ie: pointer to the country IE + * @country_ie_len: length of the country IE * - * See __regulatory_hint() documentation for possible return values. + * We will intersect the rd with the what CRDA tells us should apply + * for the alpha2 this country IE belongs to, this prevents APs from + * sending us incorrect or outdated information against a country. */ -extern int regulatory_hint(struct wiphy *wiphy, - const char *alpha2, struct ieee80211_regdomain *rd); +extern void regulatory_hint_11d(struct wiphy *wiphy, + u8 *country_ie, + u8 country_ie_len); #endif /* __NET_WIRELESS_H */ diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 11c890ad8ebb83fad2aebbebbcd49a2c00a1b261..2e9f5c0018ae34d25320141366594ce3f22d558f 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -38,22 +38,15 @@ MODULE_ALIAS("xfrm-type-" __stringify(family) "-" __stringify(proto)) #ifdef CONFIG_XFRM_STATISTICS -DECLARE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics); -#define XFRM_INC_STATS(field) SNMP_INC_STATS(xfrm_statistics, field) -#define XFRM_INC_STATS_BH(field) SNMP_INC_STATS_BH(xfrm_statistics, field) -#define XFRM_INC_STATS_USER(field) SNMP_INC_STATS_USER(xfrm_statistics, field) +#define XFRM_INC_STATS(net, field) SNMP_INC_STATS((net)->mib.xfrm_statistics, field) +#define XFRM_INC_STATS_BH(net, field) SNMP_INC_STATS_BH((net)->mib.xfrm_statistics, field) +#define XFRM_INC_STATS_USER(net, field) SNMP_INC_STATS_USER((net)-mib.xfrm_statistics, field) #else -#define XFRM_INC_STATS(field) -#define XFRM_INC_STATS_BH(field) -#define XFRM_INC_STATS_USER(field) +#define XFRM_INC_STATS(net, field) ((void)(net)) +#define XFRM_INC_STATS_BH(net, field) ((void)(net)) +#define XFRM_INC_STATS_USER(net, field) ((void)(net)) #endif -extern struct sock *xfrm_nl; -extern u32 sysctl_xfrm_aevent_etime; -extern u32 sysctl_xfrm_aevent_rseqth; -extern int sysctl_xfrm_larval_drop; -extern u32 sysctl_xfrm_acq_expires; - extern struct mutex xfrm_cfg_mutex; /* Organization of SPD aka "XFRM rules" @@ -130,6 +123,9 @@ struct xfrm_state_walk { /* Full description of state of transformer. */ struct xfrm_state { +#ifdef CONFIG_NET_NS + struct net *xs_net; +#endif union { struct hlist_node gclist; struct hlist_node bydst; @@ -223,6 +219,11 @@ struct xfrm_state void *data; }; +static inline struct net *xs_net(struct xfrm_state *x) +{ + return read_pnet(&x->xs_net); +} + /* xflags - make enum if more show up */ #define XFRM_TIME_DEFER 1 @@ -249,6 +250,7 @@ struct km_event u32 seq; u32 pid; u32 event; + struct net *net; }; struct net_device; @@ -257,10 +259,11 @@ struct xfrm_dst; struct xfrm_policy_afinfo { unsigned short family; struct dst_ops *dst_ops; - void (*garbage_collect)(void); - struct dst_entry *(*dst_lookup)(int tos, xfrm_address_t *saddr, + void (*garbage_collect)(struct net *net); + struct dst_entry *(*dst_lookup)(struct net *net, int tos, + xfrm_address_t *saddr, xfrm_address_t *daddr); - int (*get_saddr)(xfrm_address_t *saddr, xfrm_address_t *daddr); + int (*get_saddr)(struct net *net, xfrm_address_t *saddr, xfrm_address_t *daddr); struct dst_entry *(*find_bundle)(struct flowi *fl, struct xfrm_policy *policy); void (*decode_session)(struct sk_buff *skb, struct flowi *fl, @@ -467,7 +470,9 @@ struct xfrm_policy_walk { struct xfrm_policy { - struct xfrm_policy *next; +#ifdef CONFIG_NET_NS + struct net *xp_net; +#endif struct hlist_node bydst; struct hlist_node byidx; @@ -492,6 +497,11 @@ struct xfrm_policy struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; }; +static inline struct net *xp_net(struct xfrm_policy *xp) +{ + return read_pnet(&xp->xp_net); +} + struct xfrm_kmaddress { xfrm_address_t local; xfrm_address_t remote; @@ -537,15 +547,13 @@ struct xfrm_mgr struct xfrm_policy *(*compile_policy)(struct sock *sk, int opt, u8 *data, int len, int *dir); int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); - int (*report)(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); + int (*report)(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); int (*migrate)(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_bundles, struct xfrm_kmaddress *k); }; extern int xfrm_register_km(struct xfrm_mgr *km); extern int xfrm_unregister_km(struct xfrm_mgr *km); -extern unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; - /* * This structure is used for the duration where packets are being * transformed by IPsec. As soon as the packet leaves IPsec the @@ -882,6 +890,7 @@ struct xfrm_dst u32 path_cookie; }; +#ifdef CONFIG_XFRM static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) { dst_release(xdst->route); @@ -894,6 +903,7 @@ static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) xdst->partner = NULL; #endif } +#endif extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev); @@ -977,12 +987,13 @@ static inline int __xfrm_policy_check2(struct sock *sk, int dir, struct sk_buff *skb, unsigned int family, int reverse) { + struct net *net = dev_net(skb->dev); int ndir = dir | (reverse ? XFRM_POLICY_MASK + 1 : 0); if (sk && sk->sk_policy[XFRM_POLICY_IN]) return __xfrm_policy_check(sk, ndir, skb, family); - return (!xfrm_policy_count[dir] && !skb->sp) || + return (!net->xfrm.policy_count[dir] && !skb->sp) || (skb->dst->flags & DST_NOPOLICY) || __xfrm_policy_check(sk, ndir, skb, family); } @@ -1034,7 +1045,9 @@ extern int __xfrm_route_forward(struct sk_buff *skb, unsigned short family); static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) { - return !xfrm_policy_count[XFRM_POLICY_OUT] || + struct net *net = dev_net(skb->dev); + + return !net->xfrm.policy_count[XFRM_POLICY_OUT] || (skb->dst->flags & DST_NOXFRM) || __xfrm_route_forward(skb, family); } @@ -1268,7 +1281,8 @@ struct xfrm6_tunnel { extern void xfrm_init(void); extern void xfrm4_init(void); -extern void xfrm_state_init(void); +extern int xfrm_state_init(struct net *net); +extern void xfrm_state_fini(struct net *net); extern void xfrm4_state_init(void); #ifdef CONFIG_XFRM extern int xfrm6_init(void); @@ -1287,19 +1301,30 @@ static inline void xfrm6_fini(void) #endif #ifdef CONFIG_XFRM_STATISTICS -extern int xfrm_proc_init(void); +extern int xfrm_proc_init(struct net *net); +extern void xfrm_proc_fini(struct net *net); +#endif + +extern int xfrm_sysctl_init(struct net *net); +#ifdef CONFIG_SYSCTL +extern void xfrm_sysctl_fini(struct net *net); +#else +static inline void xfrm_sysctl_fini(struct net *net) +{ +} #endif extern void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto); -extern int xfrm_state_walk(struct xfrm_state_walk *walk, +extern int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, int (*func)(struct xfrm_state *, int, void*), void *); extern void xfrm_state_walk_done(struct xfrm_state_walk *walk); -extern struct xfrm_state *xfrm_state_alloc(void); +extern struct xfrm_state *xfrm_state_alloc(struct net *net); extern struct xfrm_state *xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, struct flowi *fl, struct xfrm_tmpl *tmpl, struct xfrm_policy *pol, int *err, unsigned short family); -extern struct xfrm_state * xfrm_stateonly_find(xfrm_address_t *daddr, +extern struct xfrm_state * xfrm_stateonly_find(struct net *net, + xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, u8 mode, u8 proto, u32 reqid); @@ -1307,8 +1332,8 @@ extern int xfrm_state_check_expire(struct xfrm_state *x); extern void xfrm_state_insert(struct xfrm_state *x); extern int xfrm_state_add(struct xfrm_state *x); extern int xfrm_state_update(struct xfrm_state *x); -extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family); -extern struct xfrm_state *xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family); +extern struct xfrm_state *xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family); +extern struct xfrm_state *xfrm_state_lookup_byaddr(struct net *net, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family); #ifdef CONFIG_XFRM_SUB_POLICY extern int xfrm_tmpl_sort(struct xfrm_tmpl **dst, struct xfrm_tmpl **src, int n, unsigned short family); @@ -1345,9 +1370,9 @@ struct xfrmk_spdinfo { u32 spdhmcnt; }; -extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); +extern struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 seq); extern int xfrm_state_delete(struct xfrm_state *x); -extern int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info); +extern int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info); extern void xfrm_sad_getinfo(struct xfrmk_sadinfo *si); extern void xfrm_spd_getinfo(struct xfrmk_spdinfo *si); extern int xfrm_replay_check(struct xfrm_state *x, @@ -1415,22 +1440,22 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) } #endif -struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); +struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp); extern void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type); -extern int xfrm_policy_walk(struct xfrm_policy_walk *walk, +extern int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, int (*func)(struct xfrm_policy *, int, int, void*), void *); extern void xfrm_policy_walk_done(struct xfrm_policy_walk *walk); 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_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir, struct xfrm_selector *sel, struct xfrm_sec_ctx *ctx, int delete, int *err); -struct xfrm_policy *xfrm_policy_byid(u8, int dir, u32 id, int delete, int *err); -int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info); +struct xfrm_policy *xfrm_policy_byid(struct net *net, u8, int dir, u32 id, int delete, int *err); +int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info); u32 xfrm_get_acqseq(void); extern int xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi); -struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, +struct xfrm_state * xfrm_find_acq(struct net *net, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create, unsigned short family); extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); @@ -1449,10 +1474,9 @@ extern int xfrm_migrate(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_kmaddress *k); #endif -extern wait_queue_head_t km_waitq; extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid); -extern int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); +extern int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); extern void xfrm_input_init(void); extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq); @@ -1497,18 +1521,20 @@ static inline int xfrm_policy_id2dir(u32 index) return index & 7; } -static inline int xfrm_aevent_is_on(void) +#ifdef CONFIG_XFRM +static inline int xfrm_aevent_is_on(struct net *net) { struct sock *nlsk; int ret = 0; rcu_read_lock(); - nlsk = rcu_dereference(xfrm_nl); + nlsk = rcu_dereference(net->xfrm.nlsk); if (nlsk) ret = netlink_has_listeners(nlsk, XFRMNLGRP_AEVENTS); rcu_read_unlock(); return ret; } +#endif static inline int xfrm_alg_len(struct xfrm_algo *alg) { @@ -1536,9 +1562,11 @@ static inline void xfrm_states_delete(struct xfrm_state **states, int n) } #endif +#ifdef CONFIG_XFRM static inline struct xfrm_state *xfrm_input_state(struct sk_buff *skb) { return skb->sp->xvec[skb->sp->len - 1]; } +#endif #endif /* _NET_XFRM_H */ diff --git a/lib/vsprintf.c b/lib/vsprintf.c index a013bbc237178c1bc86c522b0e3ee4a66f47a2c9..3b777025d8769e4ae07838ad12aa7f2d1b82240e 100644 --- a/lib/vsprintf.c +++ b/lib/vsprintf.c @@ -581,6 +581,62 @@ static char *resource_string(char *buf, char *end, struct resource *res, int fie return string(buf, end, sym, field_width, precision, flags); } +static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, + int precision, int flags) +{ + char mac_addr[6 * 3]; /* (6 * 2 hex digits), 5 colons and trailing zero */ + char *p = mac_addr; + int i; + + for (i = 0; i < 6; i++) { + p = pack_hex_byte(p, addr[i]); + if (!(flags & SPECIAL) && i != 5) + *p++ = ':'; + } + *p = '\0'; + + return string(buf, end, mac_addr, field_width, precision, flags & ~SPECIAL); +} + +static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width, + int precision, int flags) +{ + char ip6_addr[8 * 5]; /* (8 * 4 hex digits), 7 colons and trailing zero */ + char *p = ip6_addr; + int i; + + for (i = 0; i < 8; i++) { + p = pack_hex_byte(p, addr[2 * i]); + p = pack_hex_byte(p, addr[2 * i + 1]); + if (!(flags & SPECIAL) && i != 7) + *p++ = ':'; + } + *p = '\0'; + + return string(buf, end, ip6_addr, field_width, precision, flags & ~SPECIAL); +} + +static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, + int precision, int flags) +{ + char ip4_addr[4 * 4]; /* (4 * 3 decimal digits), 3 dots and trailing zero */ + char temp[3]; /* hold each IP quad in reverse order */ + char *p = ip4_addr; + int i, digits; + + for (i = 0; i < 4; i++) { + digits = put_dec_trunc(temp, addr[i]) - temp; + /* reverse the digits in the quad */ + while (digits--) + *p++ = temp[digits]; + if (i != 3) + *p++ = '.'; + } + *p = '\0'; + + return string(buf, end, ip4_addr, field_width, precision, flags & ~SPECIAL); +} + /* * Show a '%p' thing. A kernel extension is that the '%p' is followed * by an extra set of alphanumeric characters that are extended format @@ -592,6 +648,12 @@ static char *resource_string(char *buf, char *end, struct resource *res, int fie * - 'S' For symbolic direct pointers * - 'R' For a struct resource pointer, it prints the range of * addresses (not the name nor the flags) + * - 'M' For a 6-byte MAC address, it prints the address in the + * usual colon-separated hex notation + * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated + * decimal for v4 and colon separated network-order 16 bit hex for v6) + * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is + * currently the same * * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 * function pointers are really function descriptors, which contain a @@ -607,6 +669,21 @@ static char *pointer(const char *fmt, char *buf, char *end, void *ptr, int field return symbol_string(buf, end, ptr, field_width, precision, flags); case 'R': return resource_string(buf, end, ptr, field_width, precision, flags); + case 'm': + flags |= SPECIAL; + /* Fallthrough */ + case 'M': + return mac_address_string(buf, end, ptr, field_width, precision, flags); + case 'i': + flags |= SPECIAL; + /* Fallthrough */ + case 'I': + if (fmt[1] == '6') + return ip6_addr_string(buf, end, ptr, field_width, precision, flags); + if (fmt[1] == '4') + return ip4_addr_string(buf, end, ptr, field_width, precision, flags); + flags &= ~SPECIAL; + break; } flags |= SMALL; if (field_width == -1) { diff --git a/net/802/fddi.c b/net/802/fddi.c index 0549317b935699f76c604bb06dabbee90492fec4..f1611a1e06a724b155ce6b4768f605fb78d1bc0c 100644 --- a/net/802/fddi.c +++ b/net/802/fddi.c @@ -167,23 +167,27 @@ __be16 fddi_type_trans(struct sk_buff *skb, struct net_device *dev) EXPORT_SYMBOL(fddi_type_trans); -static int fddi_change_mtu(struct net_device *dev, int new_mtu) +int fddi_change_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < FDDI_K_SNAP_HLEN) || (new_mtu > FDDI_K_SNAP_DLEN)) return(-EINVAL); dev->mtu = new_mtu; return(0); } +EXPORT_SYMBOL(fddi_change_mtu); static const struct header_ops fddi_header_ops = { .create = fddi_header, .rebuild = fddi_rebuild_header, }; + static void fddi_setup(struct net_device *dev) { - dev->change_mtu = fddi_change_mtu; dev->header_ops = &fddi_header_ops; +#ifdef CONFIG_COMPAT_NET_DEV_OPS + dev->change_mtu = fddi_change_mtu, +#endif dev->type = ARPHRD_FDDI; dev->hard_header_len = FDDI_K_SNAP_HLEN+3; /* Assume 802.2 SNAP hdr len + 3 pad bytes */ diff --git a/net/802/hippi.c b/net/802/hippi.c index e35dc1e0915d27ad3b99da056541689327a7a70c..313b9ebf92ee23fb4b2b6e6d1dfb2ce75432368c 100644 --- a/net/802/hippi.c +++ b/net/802/hippi.c @@ -144,7 +144,7 @@ __be16 hippi_type_trans(struct sk_buff *skb, struct net_device *dev) EXPORT_SYMBOL(hippi_type_trans); -static int hippi_change_mtu(struct net_device *dev, int new_mtu) +int hippi_change_mtu(struct net_device *dev, int new_mtu) { /* * HIPPI's got these nice large MTUs. @@ -154,12 +154,13 @@ static int hippi_change_mtu(struct net_device *dev, int new_mtu) dev->mtu = new_mtu; return(0); } +EXPORT_SYMBOL(hippi_change_mtu); /* * For HIPPI we will actually use the lower 4 bytes of the hardware * address as the I-FIELD rather than the actual hardware address. */ -static int hippi_mac_addr(struct net_device *dev, void *p) +int hippi_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr = p; if (netif_running(dev)) @@ -167,8 +168,9 @@ static int hippi_mac_addr(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); return 0; } +EXPORT_SYMBOL(hippi_mac_addr); -static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) +int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) { /* Never send broadcast/multicast ARP messages */ p->mcast_probes = 0; @@ -181,6 +183,7 @@ static int hippi_neigh_setup_dev(struct net_device *dev, struct neigh_parms *p) p->ucast_probes = 0; return 0; } +EXPORT_SYMBOL(hippi_neigh_setup_dev); static const struct header_ops hippi_header_ops = { .create = hippi_header, @@ -190,11 +193,12 @@ static const struct header_ops hippi_header_ops = { static void hippi_setup(struct net_device *dev) { - dev->set_multicast_list = NULL; +#ifdef CONFIG_COMPAT_NET_DEV_OPS dev->change_mtu = hippi_change_mtu; - dev->header_ops = &hippi_header_ops; dev->set_mac_address = hippi_mac_addr; dev->neigh_setup = hippi_neigh_setup_dev; +#endif + dev->header_ops = &hippi_header_ops; /* * We don't support HIPPI `ARP' for the time being, and probably diff --git a/net/802/tr.c b/net/802/tr.c index 18c66475d8c39f8cd9c28a4d5ea0a0b5bc84491e..158150fee462fdbca4a2fa2175532b71dd2f862d 100644 --- a/net/802/tr.c +++ b/net/802/tr.c @@ -285,10 +285,7 @@ void tr_source_route(struct sk_buff *skb,struct trh_hdr *trh, if(entry) { #if TR_SR_DEBUG -{ -DECLARE_MAC_BUF(mac); -printk("source routing for %s\n",print_mac(mac, trh->daddr)); -} +printk("source routing for %pM\n", trh->daddr); #endif if(!entry->local_ring && (ntohs(entry->rcf) & TR_RCF_LEN_MASK) >> 8) { @@ -370,9 +367,8 @@ static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev) if(entry==NULL) { #if TR_SR_DEBUG - DECLARE_MAC_BUF(mac); - printk("adding rif_entry: addr:%s rcf:%04X\n", - print_mac(mac, trh->saddr), ntohs(trh->rcf)); + printk("adding rif_entry: addr:%pM rcf:%04X\n", + trh->saddr, ntohs(trh->rcf)); #endif /* * Allocate our new entry. A failure to allocate loses @@ -417,11 +413,8 @@ static void tr_add_rif_info(struct trh_hdr *trh, struct net_device *dev) !(trh->rcf & htons(TR_RCF_BROADCAST_MASK))) { #if TR_SR_DEBUG -{ -DECLARE_MAC_BUF(mac); -printk("updating rif_entry: addr:%s rcf:%04X\n", - print_mac(mac, trh->saddr), ntohs(trh->rcf)); -} +printk("updating rif_entry: addr:%pM rcf:%04X\n", + trh->saddr, ntohs(trh->rcf)); #endif entry->rcf = trh->rcf & htons((unsigned short)~TR_RCF_BROADCAST_MASK); memcpy(&(entry->rseg[0]),&(trh->rseg[0]),8*sizeof(unsigned short)); @@ -532,7 +525,6 @@ static int rif_seq_show(struct seq_file *seq, void *v) { int j, rcf_len, segment, brdgnmb; struct rif_cache *entry = v; - DECLARE_MAC_BUF(mac); if (v == SEQ_START_TOKEN) seq_puts(seq, @@ -542,9 +534,9 @@ static int rif_seq_show(struct seq_file *seq, void *v) long ttl = (long) (entry->last_used + sysctl_tr_rif_timeout) - (long) jiffies; - seq_printf(seq, "%s %s %7li ", + seq_printf(seq, "%s %pM %7li ", dev?dev->name:"?", - print_mac(mac, entry->addr), + entry->addr, ttl/HZ); if (entry->local_ring) @@ -643,7 +635,7 @@ static struct ctl_table tr_table[] = { .data = &sysctl_tr_rif_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { 0 }, }; diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index f0e335aa20df43370d947ebbee52a23013491ae3..41e8f65bd3f0f6ea0a121ad4bc48f68ffd569a61 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -46,10 +46,10 @@ int vlan_net_id; /* Our listing of VLAN group(s) */ static struct hlist_head vlan_group_hash[VLAN_GRP_HASH_SIZE]; -static char vlan_fullname[] = "802.1Q VLAN Support"; -static char vlan_version[] = DRV_VERSION; -static char vlan_copyright[] = "Ben Greear "; -static char vlan_buggyright[] = "David S. Miller "; +const char vlan_fullname[] = "802.1Q VLAN Support"; +const char vlan_version[] = DRV_VERSION; +static const char vlan_copyright[] = "Ben Greear "; +static const char vlan_buggyright[] = "David S. Miller "; static struct packet_type vlan_packet_type = { .type = __constant_htons(ETH_P_8021Q), @@ -144,6 +144,7 @@ void unregister_vlan_dev(struct net_device *dev) { struct vlan_dev_info *vlan = vlan_dev_info(dev); struct net_device *real_dev = vlan->real_dev; + const struct net_device_ops *ops = real_dev->netdev_ops; struct vlan_group *grp; u16 vlan_id = vlan->vlan_id; @@ -156,7 +157,7 @@ void unregister_vlan_dev(struct net_device *dev) * HW accelerating devices or SW vlan input packet processing. */ if (real_dev->features & NETIF_F_HW_VLAN_FILTER) - real_dev->vlan_rx_kill_vid(real_dev, vlan_id); + ops->ndo_vlan_rx_kill_vid(real_dev, vlan_id); vlan_group_set_device(grp, vlan_id, NULL); grp->nr_vlans--; @@ -170,7 +171,7 @@ void unregister_vlan_dev(struct net_device *dev) vlan_gvrp_uninit_applicant(real_dev); if (real_dev->features & NETIF_F_HW_VLAN_RX) - real_dev->vlan_rx_register(real_dev, NULL); + ops->ndo_vlan_rx_register(real_dev, NULL); hlist_del_rcu(&grp->hlist); @@ -205,21 +206,21 @@ static void vlan_transfer_operstate(const struct net_device *dev, int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id) { - char *name = real_dev->name; + const char *name = real_dev->name; + const struct net_device_ops *ops = real_dev->netdev_ops; if (real_dev->features & NETIF_F_VLAN_CHALLENGED) { pr_info("8021q: VLANs not supported on %s\n", name); return -EOPNOTSUPP; } - if ((real_dev->features & NETIF_F_HW_VLAN_RX) && - !real_dev->vlan_rx_register) { + if ((real_dev->features & NETIF_F_HW_VLAN_RX) && !ops->ndo_vlan_rx_register) { pr_info("8021q: device %s has buggy VLAN hw accel\n", name); return -EOPNOTSUPP; } if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) && - (!real_dev->vlan_rx_add_vid || !real_dev->vlan_rx_kill_vid)) { + (!ops->ndo_vlan_rx_add_vid || !ops->ndo_vlan_rx_kill_vid)) { pr_info("8021q: Device %s has buggy VLAN hw accel\n", name); return -EOPNOTSUPP; } @@ -240,6 +241,7 @@ int register_vlan_dev(struct net_device *dev) { struct vlan_dev_info *vlan = vlan_dev_info(dev); struct net_device *real_dev = vlan->real_dev; + const struct net_device_ops *ops = real_dev->netdev_ops; u16 vlan_id = vlan->vlan_id; struct vlan_group *grp, *ngrp = NULL; int err; @@ -275,9 +277,9 @@ int register_vlan_dev(struct net_device *dev) grp->nr_vlans++; if (ngrp && real_dev->features & NETIF_F_HW_VLAN_RX) - real_dev->vlan_rx_register(real_dev, ngrp); + ops->ndo_vlan_rx_register(real_dev, ngrp); if (real_dev->features & NETIF_F_HW_VLAN_FILTER) - real_dev->vlan_rx_add_vid(real_dev, vlan_id); + ops->ndo_vlan_rx_add_vid(real_dev, vlan_id); return 0; diff --git a/net/8021q/vlan.h b/net/8021q/vlan.h index a6603a4d917f850f9aead87eecaf6ce99cfc4803..82570bc2a18034058dfba13d0ab9765f63ae3d32 100644 --- a/net/8021q/vlan.h +++ b/net/8021q/vlan.h @@ -108,8 +108,10 @@ static inline int vlan_gvrp_init(void) { return 0; } static inline void vlan_gvrp_uninit(void) {} #endif -int vlan_netlink_init(void); -void vlan_netlink_fini(void); +extern const char vlan_fullname[]; +extern const char vlan_version[]; +extern int vlan_netlink_init(void); +extern void vlan_netlink_fini(void); extern struct rtnl_link_ops vlan_link_ops; diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c index 68ced4bf158c7558977e3c4a44ef4567157e80d5..dd86a1dc4cd00f597ceb58cccefe2625bb1541fa 100644 --- a/net/8021q/vlan_core.c +++ b/net/8021q/vlan_core.c @@ -47,8 +47,6 @@ int vlan_hwaccel_do_receive(struct sk_buff *skb) skb->priority = vlan_get_ingress_priority(dev, skb->vlan_tci); skb->vlan_tci = 0; - dev->last_rx = jiffies; - stats = &dev->stats; stats->rx_packets++; stats->rx_bytes += skb->len; diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index 8883e9c8a2230ccb993cd4bcc86131e6babbaece..89a3bbdfca3fe96e786044ed8ea8b5022ab4e5b1 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -163,8 +163,6 @@ int vlan_skb_recv(struct sk_buff *skb, struct net_device *dev, goto err_unlock; } - skb->dev->last_rx = jiffies; - stats = &skb->dev->stats; stats->rx_packets++; stats->rx_bytes += skb->len; @@ -526,6 +524,7 @@ out: static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; + const struct net_device_ops *ops = real_dev->netdev_ops; struct ifreq ifrr; int err = -EOPNOTSUPP; @@ -536,8 +535,8 @@ static int vlan_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) case SIOCGMIIPHY: case SIOCGMIIREG: case SIOCSMIIREG: - if (real_dev->do_ioctl && netif_device_present(real_dev)) - err = real_dev->do_ioctl(real_dev, &ifrr, cmd); + if (netif_device_present(real_dev) && ops->ndo_do_ioctl) + err = ops->ndo_do_ioctl(real_dev, &ifrr, cmd); break; } @@ -594,6 +593,8 @@ static const struct header_ops vlan_header_ops = { .parse = eth_header_parse, }; +static const struct net_device_ops vlan_netdev_ops, vlan_netdev_accel_ops; + static int vlan_dev_init(struct net_device *dev) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; @@ -620,11 +621,11 @@ static int vlan_dev_init(struct net_device *dev) if (real_dev->features & NETIF_F_HW_VLAN_TX) { dev->header_ops = real_dev->header_ops; dev->hard_header_len = real_dev->hard_header_len; - dev->hard_start_xmit = vlan_dev_hwaccel_hard_start_xmit; + dev->netdev_ops = &vlan_netdev_accel_ops; } else { dev->header_ops = &vlan_header_ops; dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN; - dev->hard_start_xmit = vlan_dev_hard_start_xmit; + dev->netdev_ops = &vlan_netdev_ops; } if (is_vlan_dev(real_dev)) @@ -648,6 +649,26 @@ static void vlan_dev_uninit(struct net_device *dev) } } +static int vlan_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + const struct vlan_dev_info *vlan = vlan_dev_info(dev); + struct net_device *real_dev = vlan->real_dev; + + if (!real_dev->ethtool_ops->get_settings) + return -EOPNOTSUPP; + + return real_dev->ethtool_ops->get_settings(real_dev, cmd); +} + +static void vlan_ethtool_get_drvinfo(struct net_device *dev, + struct ethtool_drvinfo *info) +{ + strcpy(info->driver, vlan_fullname); + strcpy(info->version, vlan_version); + strcpy(info->fw_version, "N/A"); +} + static u32 vlan_ethtool_get_rx_csum(struct net_device *dev) { const struct vlan_dev_info *vlan = vlan_dev_info(dev); @@ -672,11 +693,43 @@ static u32 vlan_ethtool_get_flags(struct net_device *dev) } static const struct ethtool_ops vlan_ethtool_ops = { + .get_settings = vlan_ethtool_get_settings, + .get_drvinfo = vlan_ethtool_get_drvinfo, .get_link = ethtool_op_get_link, .get_rx_csum = vlan_ethtool_get_rx_csum, .get_flags = vlan_ethtool_get_flags, }; +static const struct net_device_ops vlan_netdev_ops = { + .ndo_change_mtu = vlan_dev_change_mtu, + .ndo_init = vlan_dev_init, + .ndo_uninit = vlan_dev_uninit, + .ndo_open = vlan_dev_open, + .ndo_stop = vlan_dev_stop, + .ndo_start_xmit = vlan_dev_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = vlan_dev_set_mac_address, + .ndo_set_rx_mode = vlan_dev_set_rx_mode, + .ndo_set_multicast_list = vlan_dev_set_rx_mode, + .ndo_change_rx_flags = vlan_dev_change_rx_flags, + .ndo_do_ioctl = vlan_dev_ioctl, +}; + +static const struct net_device_ops vlan_netdev_accel_ops = { + .ndo_change_mtu = vlan_dev_change_mtu, + .ndo_init = vlan_dev_init, + .ndo_uninit = vlan_dev_uninit, + .ndo_open = vlan_dev_open, + .ndo_stop = vlan_dev_stop, + .ndo_start_xmit = vlan_dev_hwaccel_hard_start_xmit, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = vlan_dev_set_mac_address, + .ndo_set_rx_mode = vlan_dev_set_rx_mode, + .ndo_set_multicast_list = vlan_dev_set_rx_mode, + .ndo_change_rx_flags = vlan_dev_change_rx_flags, + .ndo_do_ioctl = vlan_dev_ioctl, +}; + void vlan_setup(struct net_device *dev) { ether_setup(dev); @@ -684,16 +737,7 @@ void vlan_setup(struct net_device *dev) dev->priv_flags |= IFF_802_1Q_VLAN; dev->tx_queue_len = 0; - dev->change_mtu = vlan_dev_change_mtu; - dev->init = vlan_dev_init; - dev->uninit = vlan_dev_uninit; - dev->open = vlan_dev_open; - dev->stop = vlan_dev_stop; - dev->set_mac_address = vlan_dev_set_mac_address; - dev->set_rx_mode = vlan_dev_set_rx_mode; - dev->set_multicast_list = vlan_dev_set_rx_mode; - dev->change_rx_flags = vlan_dev_change_rx_flags; - dev->do_ioctl = vlan_dev_ioctl; + dev->netdev_ops = &vlan_netdev_ops; dev->destructor = free_netdev; dev->ethtool_ops = &vlan_ethtool_ops; diff --git a/net/9p/trans_rdma.c b/net/9p/trans_rdma.c index 2f1fe5fc1228273cce9b23b9a8a2cd31e184ec31..7fa0eb20b2f6e7912299b35d6cc720203396e420 100644 --- a/net/9p/trans_rdma.c +++ b/net/9p/trans_rdma.c @@ -528,8 +528,6 @@ static void rdma_close(struct p9_client *client) /** * alloc_rdma - Allocate and initialize the rdma transport structure - * @msize: MTU - * @dotu: Extension attribute * @opts: Mount options structure */ static struct p9_trans_rdma *alloc_rdma(struct p9_rdma_opts *opts) diff --git a/net/Kconfig b/net/Kconfig index d789d79551ae4207d37e0b386a3db743dde05611..6ec2cce7c167ca733c6fbc15e3d53003fe1d53fb 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -27,11 +27,14 @@ menu "Networking options" config NET_NS bool "Network namespace support" default n - depends on EXPERIMENTAL && !SYSFS && NAMESPACES + depends on EXPERIMENTAL && NAMESPACES help Allow user space to create what appear to be multiple instances of the network stack. +config COMPAT_NET_DEV_OPS + def_bool y + source "net/packet/Kconfig" source "net/unix/Kconfig" source "net/xfrm/Kconfig" @@ -191,6 +194,7 @@ source "net/lapb/Kconfig" source "net/econet/Kconfig" source "net/wanrouter/Kconfig" source "net/sched/Kconfig" +source "net/dcb/Kconfig" menu "Network testing" @@ -247,7 +251,6 @@ if WIRELESS source "net/wireless/Kconfig" source "net/mac80211/Kconfig" -source "net/ieee80211/Kconfig" endif # WIRELESS diff --git a/net/Makefile b/net/Makefile index 27d1f10dc0e078e06c030f385f78a00e924fe763..ba4460432b7cc49a71d2ce5ef8d7990ac1a5ee60 100644 --- a/net/Makefile +++ b/net/Makefile @@ -51,12 +51,14 @@ obj-$(CONFIG_IP_DCCP) += dccp/ obj-$(CONFIG_IP_SCTP) += sctp/ obj-y += wireless/ obj-$(CONFIG_MAC80211) += mac80211/ -obj-$(CONFIG_IEEE80211) += ieee80211/ obj-$(CONFIG_TIPC) += tipc/ obj-$(CONFIG_NETLABEL) += netlabel/ obj-$(CONFIG_IUCV) += iucv/ obj-$(CONFIG_RFKILL) += rfkill/ obj-$(CONFIG_NET_9P) += 9p/ +ifneq ($(CONFIG_DCB),) +obj-y += dcb/ +endif ifeq ($(CONFIG_NET),y) obj-$(CONFIG_SYSCTL) += sysctl_net.o diff --git a/net/appletalk/aarp.c b/net/appletalk/aarp.c index b25c1e909d14fdabadf150693dd80252345f4f26..b03ff58e9308666f1dc0dec54c8aabde99b0e263 100644 --- a/net/appletalk/aarp.c +++ b/net/appletalk/aarp.c @@ -995,7 +995,6 @@ static int aarp_seq_show(struct seq_file *seq, void *v) struct aarp_iter_state *iter = seq->private; struct aarp_entry *entry = v; unsigned long now = jiffies; - DECLARE_MAC_BUF(mac); if (v == SEQ_START_TOKEN) seq_puts(seq, @@ -1006,7 +1005,7 @@ static int aarp_seq_show(struct seq_file *seq, void *v) ntohs(entry->target_addr.s_net), (unsigned int) entry->target_addr.s_node, entry->dev ? entry->dev->name : "????"); - seq_printf(seq, "%s", print_mac(mac, entry->hwaddr)); + seq_printf(seq, "%pM", entry->hwaddr); seq_printf(seq, " %8s", dt2str((long)entry->expires_at - (long)now)); if (iter->table == unresolved) diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c index d3134e7e6ee8e3a6960806259ce4266fabdb6a82..5abce07fb50a195b1f280af8dbe588e2fefc2d6c 100644 --- a/net/appletalk/ddp.c +++ b/net/appletalk/ddp.c @@ -815,9 +815,6 @@ static int atif_ioctl(int cmd, void __user *arg) return -EPERM; if (sa->sat_family != AF_APPLETALK) return -EINVAL; - if (!atif) - return -EADDRNOTAVAIL; - /* * for now, we only support proxy AARP on ELAP; * we should be able to do it for LocalTalk, too. @@ -1284,7 +1281,7 @@ static int handle_ip_over_ddp(struct sk_buff *skb) skb->dev = dev; skb_reset_transport_header(skb); - stats = dev->priv; + stats = netdev_priv(dev); stats->rx_packets++; stats->rx_bytes += skb->len + 13; netif_rx(skb); /* Send the SKB up to a higher place. */ diff --git a/net/appletalk/sysctl_net_atalk.c b/net/appletalk/sysctl_net_atalk.c index 621805dfa2f4a4f84c9c0264dfc027935f2a85ac..8d237b15183b8acdf8a71fba259dc0c58fceb4cf 100644 --- a/net/appletalk/sysctl_net_atalk.c +++ b/net/appletalk/sysctl_net_atalk.c @@ -17,8 +17,8 @@ static struct ctl_table atalk_table[] = { .data = &sysctl_aarp_expiry_time, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_ATALK_AARP_TICK_TIME, @@ -26,8 +26,8 @@ static struct ctl_table atalk_table[] = { .data = &sysctl_aarp_tick_time, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_ATALK_AARP_RETRANSMIT_LIMIT, @@ -35,7 +35,7 @@ static struct ctl_table atalk_table[] = { .data = &sysctl_aarp_retransmit_limit, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_ATALK_AARP_RESOLVE_TIME, @@ -43,8 +43,8 @@ static struct ctl_table atalk_table[] = { .data = &sysctl_aarp_resolve_time, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { 0 }, }; diff --git a/net/atm/atm_sysfs.c b/net/atm/atm_sysfs.c index 1b88311f2130b57598bc13ee82dc74bab3cc3fc2..b5674dc2083d6766bbe4754d3951439fde141c0c 100644 --- a/net/atm/atm_sysfs.c +++ b/net/atm/atm_sysfs.c @@ -149,7 +149,7 @@ int atm_register_sysfs(struct atm_dev *adev) cdev->class = &atm_class; dev_set_drvdata(cdev, adev); - snprintf(cdev->bus_id, BUS_ID_SIZE, "%s%d", adev->type, adev->number); + dev_set_name(cdev, "%s%d", adev->type, adev->number); err = device_register(cdev); if (err < 0) return err; diff --git a/net/atm/br2684.c b/net/atm/br2684.c index 280de481edc7e0dd64f03112bfcb90105074f38e..ea9438fc6855fb3a569e7e25a2064d5191a14989 100644 --- a/net/atm/br2684.c +++ b/net/atm/br2684.c @@ -101,7 +101,7 @@ static LIST_HEAD(br2684_devs); static inline struct br2684_dev *BRPRIV(const struct net_device *net_dev) { - return (struct br2684_dev *)net_dev->priv; + return (struct br2684_dev *)netdev_priv(net_dev); } static inline struct net_device *list_entry_brdev(const struct list_head *le) @@ -698,12 +698,11 @@ static int br2684_seq_show(struct seq_file *seq, void *v) br2684_devs); const struct net_device *net_dev = brdev->net_dev; const struct br2684_vcc *brvcc; - DECLARE_MAC_BUF(mac); - seq_printf(seq, "dev %.16s: num=%d, mac=%s (%s)\n", + seq_printf(seq, "dev %.16s: num=%d, mac=%pM (%s)\n", net_dev->name, brdev->number, - print_mac(mac, net_dev->dev_addr), + net_dev->dev_addr, brdev->mac_was_set ? "set" : "auto"); list_for_each_entry(brvcc, &brdev->brvccs, brvccs) { diff --git a/net/atm/clip.c b/net/atm/clip.c index 5b5b96344ce60fba334fb291a8fe21393aa8bb26..2d33a83be799c36dec054340553610d64e61070c 100644 --- a/net/atm/clip.c +++ b/net/atm/clip.c @@ -822,8 +822,8 @@ static void atmarp_info(struct seq_file *seq, struct net_device *dev, seq_printf(seq, "%-6s%-4s%-4s%5ld ", dev->name, svc ? "SVC" : "PVC", llc ? "LLC" : "NULL", exp); - off = scnprintf(buf, sizeof(buf) - 1, "%d.%d.%d.%d", - NIPQUAD(entry->ip)); + off = scnprintf(buf, sizeof(buf) - 1, "%pI4", + &entry->ip); while (off < 16) buf[off++] = ' '; buf[off] = '\0'; diff --git a/net/atm/common.h b/net/atm/common.h index 16f32c1fa1c9314d8bef751f6185a9173727cc62..92e2981f479f920f0dfe3815cd9c5734af81a3aa 100644 --- a/net/atm/common.h +++ b/net/atm/common.h @@ -19,6 +19,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m, size_t total_len); unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait); int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); +int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg); int vcc_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen); int vcc_getsockopt(struct socket *sock, int level, int optname, diff --git a/net/atm/ioctl.c b/net/atm/ioctl.c index 7afd8e7754fd147dfa213dbd03f6fdab8ef9d97a..76ed3c8d26e603935754e71460213ef701165af5 100644 --- a/net/atm/ioctl.c +++ b/net/atm/ioctl.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "resources.h" #include "signaling.h" /* for WAITING and sigd_attach */ @@ -46,7 +47,7 @@ void deregister_atm_ioctl(struct atm_ioctl *ioctl) EXPORT_SYMBOL(register_atm_ioctl); EXPORT_SYMBOL(deregister_atm_ioctl); -int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg, int compat) { struct sock *sk = sock->sk; struct atm_vcc *vcc; @@ -80,13 +81,25 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) goto done; } case SIOCGSTAMP: /* borrowed from IP */ - error = sock_get_timestamp(sk, argp); +#ifdef CONFIG_COMPAT + if (compat) + error = compat_sock_get_timestamp(sk, argp); + else +#endif + error = sock_get_timestamp(sk, argp); goto done; case SIOCGSTAMPNS: /* borrowed from IP */ - error = sock_get_timestampns(sk, argp); +#ifdef CONFIG_COMPAT + if (compat) + error = compat_sock_get_timestampns(sk, argp); + else +#endif + error = sock_get_timestampns(sk, argp); goto done; case ATM_SETSC: - printk(KERN_WARNING "ATM_SETSC is obsolete\n"); + if (net_ratelimit()) + printk(KERN_WARNING "ATM_SETSC is obsolete; used by %s:%d\n", + current->comm, task_pid_nr(current)); error = 0; goto done; case ATMSIGD_CTRL: @@ -99,12 +112,23 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) * info uses kernel pointers as opaque references, * so the holder of the file descriptor can scribble * on the kernel... so we should make sure that we - * have the same privledges that /proc/kcore needs + * have the same privileges that /proc/kcore needs */ if (!capable(CAP_SYS_RAWIO)) { error = -EPERM; goto done; } +#ifdef CONFIG_COMPAT + /* WTF? I don't even want to _think_ about making this + work for 32-bit userspace. TBH I don't really want + to think about it at all. dwmw2. */ + if (compat) { + if (net_ratelimit()) + printk(KERN_WARNING "32-bit task cannot be atmsigd\n"); + error = -EINVAL; + goto done; + } +#endif error = sigd_attach(vcc); if (!error) sock->state = SS_CONNECTED; @@ -155,8 +179,21 @@ int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) if (error != -ENOIOCTLCMD) goto done; - error = atm_dev_ioctl(cmd, argp); + error = atm_dev_ioctl(cmd, argp, compat); done: return error; } + + +int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + return do_vcc_ioctl(sock, cmd, arg, 0); +} + +#ifdef CONFIG_COMPAT +int vcc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + return do_vcc_ioctl(sock, cmd, arg, 1); +} +#endif diff --git a/net/atm/lec.c b/net/atm/lec.c index 8f701cde5945b0f8ee7d9c6d6a3412130ce840a8..e5e301550e8a72ce7897fce6729bd2a82f844ea0 100644 --- a/net/atm/lec.c +++ b/net/atm/lec.c @@ -152,7 +152,7 @@ static void lec_handle_bridge(struct sk_buff *skb, struct net_device *dev) buff += 4; mesg->content.normal.flag = *buff & 0x01; /* 0x01 is topology change */ - priv = (struct lec_priv *)dev->priv; + priv = netdev_priv(dev); atm_force_charge(priv->lecd, skb2->truesize); sk = sk_atm(priv->lecd); skb_queue_tail(&sk->sk_receive_queue, skb2); @@ -218,7 +218,7 @@ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc) static int lec_open(struct net_device *dev) { - struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lec_priv *priv = netdev_priv(dev); netif_start_queue(dev); memset(&priv->stats, 0, sizeof(struct net_device_stats)); @@ -252,7 +252,7 @@ static void lec_tx_timeout(struct net_device *dev) static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct sk_buff *skb2; - struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lec_priv *priv = netdev_priv(dev); struct lecdatahdr_8023 *lec_h; struct atm_vcc *vcc; struct lec_arp_table *entry; @@ -373,19 +373,13 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) if (entry && (entry->tx_wait.qlen < LEC_UNRES_QUE_LEN)) { pr_debug("%s:lec_start_xmit: queuing packet, ", dev->name); - pr_debug("MAC address " MAC_FMT "\n", - lec_h->h_dest[0], lec_h->h_dest[1], - lec_h->h_dest[2], lec_h->h_dest[3], - lec_h->h_dest[4], lec_h->h_dest[5]); + pr_debug("MAC address %pM\n", lec_h->h_dest); skb_queue_tail(&entry->tx_wait, skb); } else { pr_debug ("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ", dev->name); - pr_debug("MAC address " MAC_FMT "\n", - lec_h->h_dest[0], lec_h->h_dest[1], - lec_h->h_dest[2], lec_h->h_dest[3], - lec_h->h_dest[4], lec_h->h_dest[5]); + pr_debug("MAC address %pM\n", lec_h->h_dest); priv->stats.tx_dropped++; dev_kfree_skb(skb); } @@ -397,10 +391,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev) while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) { pr_debug("lec.c: emptying tx queue, "); - pr_debug("MAC address " MAC_FMT "\n", - lec_h->h_dest[0], lec_h->h_dest[1], - lec_h->h_dest[2], lec_h->h_dest[3], - lec_h->h_dest[4], lec_h->h_dest[5]); + pr_debug("MAC address %pM\n", lec_h->h_dest); lec_send(vcc, skb2, priv); } @@ -442,14 +433,14 @@ static int lec_close(struct net_device *dev) */ static struct net_device_stats *lec_get_stats(struct net_device *dev) { - return &((struct lec_priv *)dev->priv)->stats; + return &((struct lec_priv *)netdev_priv(dev))->stats; } static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) { unsigned long flags; struct net_device *dev = (struct net_device *)vcc->proto_data; - struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lec_priv *priv = netdev_priv(dev); struct atmlec_msg *mesg; struct lec_arp_table *entry; int i; @@ -539,15 +530,8 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb) { struct net_bridge_fdb_entry *f; - pr_debug - ("%s: bridge zeppelin asks about " MAC_FMT "\n", - dev->name, - mesg->content.proxy.mac_addr[0], - mesg->content.proxy.mac_addr[1], - mesg->content.proxy.mac_addr[2], - mesg->content.proxy.mac_addr[3], - mesg->content.proxy.mac_addr[4], - mesg->content.proxy.mac_addr[5]); + pr_debug("%s: bridge zeppelin asks about %pM\n", + dev->name, mesg->content.proxy.mac_addr); if (br_fdb_get_hook == NULL || dev->br_port == NULL) break; @@ -596,7 +580,7 @@ static void lec_atm_close(struct atm_vcc *vcc) { struct sk_buff *skb; struct net_device *dev = (struct net_device *)vcc->proto_data; - struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lec_priv *priv = netdev_priv(dev); priv->lecd = NULL; /* Do something needful? */ @@ -727,7 +711,7 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb) { unsigned long flags; struct net_device *dev = (struct net_device *)vcc->proto_data; - struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lec_priv *priv = netdev_priv(dev); #if DUMP_PACKETS >0 int i = 0; @@ -874,7 +858,7 @@ static int lec_vcc_attach(struct atm_vcc *vcc, void __user *arg) vpriv->old_pop = vcc->pop; vcc->user_back = vpriv; vcc->pop = lec_pop; - lec_vcc_added(dev_lec[ioc_data.dev_num]->priv, + lec_vcc_added(netdev_priv(dev_lec[ioc_data.dev_num]), &ioc_data, vcc, vcc->push); vcc->proto_data = dev_lec[ioc_data.dev_num]; vcc->push = lec_push; @@ -886,7 +870,8 @@ static int lec_mcast_attach(struct atm_vcc *vcc, int arg) if (arg < 0 || arg >= MAX_LEC_ITF || !dev_lec[arg]) return -EINVAL; vcc->proto_data = dev_lec[arg]; - return (lec_mcast_make((struct lec_priv *)dev_lec[arg]->priv, vcc)); + return lec_mcast_make((struct lec_priv *)netdev_priv(dev_lec[arg]), + vcc); } /* Initialize device. */ @@ -928,11 +913,11 @@ static int lecd_attach(struct atm_vcc *vcc, int arg) return -EINVAL; } - priv = dev_lec[i]->priv; + priv = netdev_priv(dev_lec[i]); priv->is_trdev = is_trdev; lec_init(dev_lec[i]); } else { - priv = dev_lec[i]->priv; + priv = netdev_priv(dev_lec[i]); if (priv->lecd) return -EADDRINUSE; } @@ -1093,7 +1078,8 @@ static void *lec_itf_walk(struct lec_state *state, loff_t *l) void *v; dev = state->dev ? state->dev : dev_lec[state->itf]; - v = (dev && dev->priv) ? lec_priv_walk(state, l, dev->priv) : NULL; + v = (dev && netdev_priv(dev)) ? + lec_priv_walk(state, l, netdev_priv(dev)) : NULL; if (!v && dev) { dev_put(dev); /* Partial state reset for the next time we get called */ @@ -1255,7 +1241,7 @@ static void __exit lane_module_cleanup(void) for (i = 0; i < MAX_LEC_ITF; i++) { if (dev_lec[i] != NULL) { - priv = (struct lec_priv *)dev_lec[i]->priv; + priv = netdev_priv(dev_lec[i]); unregister_netdev(dev_lec[i]); free_netdev(dev_lec[i]); dev_lec[i] = NULL; @@ -1279,7 +1265,7 @@ static int lane2_resolve(struct net_device *dev, const u8 *dst_mac, int force, u8 **tlvs, u32 *sizeoftlvs) { unsigned long flags; - struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lec_priv *priv = netdev_priv(dev); struct lec_arp_table *table; struct sk_buff *skb; int retval; @@ -1326,7 +1312,7 @@ static int lane2_associate_req(struct net_device *dev, const u8 *lan_dst, { int retval; struct sk_buff *skb; - struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lec_priv *priv = netdev_priv(dev); if (compare_ether_addr(lan_dst, dev->dev_addr)) return (0); /* not our mac address */ @@ -1363,7 +1349,7 @@ static void lane2_associate_ind(struct net_device *dev, const u8 *mac_addr, #if 0 int i = 0; #endif - struct lec_priv *priv = (struct lec_priv *)dev->priv; + struct lec_priv *priv = netdev_priv(dev); #if 0 /* * Why have the TLVs in LE_ARP entries * since we do not use them? When you diff --git a/net/atm/mpc.c b/net/atm/mpc.c index 11b16d16661c18e458c9d624b8fcc4cfe4f4a67b..039d5cc72c3df648d1b413ed042a296b7071a65f 100644 --- a/net/atm/mpc.c +++ b/net/atm/mpc.c @@ -232,8 +232,8 @@ void atm_mpoa_disp_qos(struct seq_file *m) seq_printf(m, "IP address\n TX:max_pcr pcr min_pcr max_cdv max_sdu\n RX:max_pcr pcr min_pcr max_cdv max_sdu\n"); while (qos != NULL) { - seq_printf(m, "%u.%u.%u.%u\n %-7d %-7d %-7d %-7d %-7d\n %-7d %-7d %-7d %-7d %-7d\n", - NIPQUAD(qos->ipaddr), + seq_printf(m, "%pI4\n %-7d %-7d %-7d %-7d %-7d\n %-7d %-7d %-7d %-7d %-7d\n", + &qos->ipaddr, qos->qos.txtp.max_pcr, qos->qos.txtp.pcr, qos->qos.txtp.min_pcr, qos->qos.txtp.max_cdv, qos->qos.txtp.max_sdu, qos->qos.rxtp.max_pcr, qos->qos.rxtp.pcr, qos->qos.rxtp.min_pcr, qos->qos.rxtp.max_cdv, qos->qos.rxtp.max_sdu); qos = qos->next; @@ -341,8 +341,8 @@ static const char *mpoa_device_type_string(char type) } /* - * lec device calls this via its dev->priv->lane2_ops->associate_indicator() - * when it sees a TLV in LE_ARP packet. + * lec device calls this via its netdev_priv(dev)->lane2_ops + * ->associate_indicator() when it sees a TLV in LE_ARP packet. * We fill in the pointer above when we see a LANE2 lec initializing * See LANE2 spec 3.1.5 * @@ -595,8 +595,8 @@ static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg) if (in_entry != NULL) mpc->in_ops->put(in_entry); return -EINVAL; } - printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %u.%u.%u.%u\n", - mpc->dev->name, NIPQUAD(in_entry->ctrl_info.in_dst_ip)); + printk("mpoa: (%s) mpc_vcc_attach: attaching ingress SVC, entry = %pI4\n", + mpc->dev->name, &in_entry->ctrl_info.in_dst_ip); in_entry->shortcut = vcc; mpc->in_ops->put(in_entry); } else { @@ -627,8 +627,8 @@ static void mpc_vcc_close(struct atm_vcc *vcc, struct net_device *dev) dprintk("mpoa: (%s) mpc_vcc_close:\n", dev->name); in_entry = mpc->in_ops->get_by_vcc(vcc, mpc); if (in_entry) { - dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %u.%u.%u.%u\n", - mpc->dev->name, NIPQUAD(in_entry->ctrl_info.in_dst_ip)); + dprintk("mpoa: (%s) mpc_vcc_close: ingress SVC closed ip = %pI4\n", + mpc->dev->name, &in_entry->ctrl_info.in_dst_ip); in_entry->shortcut = NULL; mpc->in_ops->put(in_entry); } @@ -785,7 +785,7 @@ static int atm_mpoa_mpoad_attach (struct atm_vcc *vcc, int arg) } if (mpc->dev) { /* check if the lec is LANE2 capable */ - priv = (struct lec_priv *)mpc->dev->priv; + priv = netdev_priv(mpc->dev); if (priv->lane_version < 2) { dev_put(mpc->dev); mpc->dev = NULL; @@ -845,7 +845,7 @@ static void mpoad_close(struct atm_vcc *vcc) mpc->mpoad_vcc = NULL; if (mpc->dev) { - struct lec_priv *priv = (struct lec_priv *)mpc->dev->priv; + struct lec_priv *priv = netdev_priv(mpc->dev); priv->lane2_ops->associate_indicator = NULL; stop_mpc(mpc); dev_put(mpc->dev); @@ -976,7 +976,7 @@ static int mpoa_event_listener(struct notifier_block *mpoa_notifier, unsigned lo switch (event) { case NETDEV_REGISTER: /* a new lec device was allocated */ - priv = (struct lec_priv *)dev->priv; + priv = netdev_priv(dev); if (priv->lane_version < 2) break; priv->lane2_ops->associate_indicator = lane2_assoc_ind; @@ -1098,7 +1098,8 @@ static void check_qos_and_open_shortcut(struct k_message *msg, struct mpoa_clien entry->shortcut = eg_entry->shortcut; } if(entry->shortcut){ - dprintk("mpoa: (%s) using egress SVC to reach %u.%u.%u.%u\n",client->dev->name, NIPQUAD(dst_ip)); + dprintk("mpoa: (%s) using egress SVC to reach %pI4\n", + client->dev->name, &dst_ip); client->eg_ops->put(eg_entry); return; } @@ -1123,7 +1124,8 @@ static void MPOA_res_reply_rcvd(struct k_message *msg, struct mpoa_client *mpc) __be32 dst_ip = msg->content.in_info.in_dst_ip; in_cache_entry *entry = mpc->in_ops->get(dst_ip, mpc); - dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %u.%u.%u.%u\n", mpc->dev->name, NIPQUAD(dst_ip)); + dprintk("mpoa: (%s) MPOA_res_reply_rcvd: ip %pI4\n", + mpc->dev->name, &dst_ip); ddprintk("mpoa: (%s) MPOA_res_reply_rcvd() entry = %p", mpc->dev->name, entry); if(entry == NULL){ printk("\nmpoa: (%s) ARGH, received res. reply for an entry that doesn't exist.\n", mpc->dev->name); @@ -1171,14 +1173,14 @@ static void ingress_purge_rcvd(struct k_message *msg, struct mpoa_client *mpc) in_cache_entry *entry = mpc->in_ops->get_with_mask(dst_ip, mpc, mask); if(entry == NULL){ - printk("mpoa: (%s) ingress_purge_rcvd: purge for a non-existing entry, ", mpc->dev->name); - printk("ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip)); + printk("mpoa: (%s) ingress_purge_rcvd: purge for a non-existing entry, ip = %pI4\n", + mpc->dev->name, &dst_ip); return; } do { - dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %u.%u.%u.%u\n" , - mpc->dev->name, NIPQUAD(dst_ip)); + dprintk("mpoa: (%s) ingress_purge_rcvd: removing an ingress entry, ip = %pI4\n", + mpc->dev->name, &dst_ip); write_lock_bh(&mpc->ingress_lock); mpc->in_ops->remove_entry(entry, mpc); write_unlock_bh(&mpc->ingress_lock); @@ -1322,7 +1324,7 @@ static void set_mpc_ctrl_addr_rcvd(struct k_message *mesg, struct mpoa_client *m dprintk("\n"); if (mpc->dev) { - priv = (struct lec_priv *)mpc->dev->priv; + priv = netdev_priv(mpc->dev); retval = priv->lane2_ops->associate_req(mpc->dev, mpc->dev->dev_addr, tlv, sizeof(tlv)); if (retval == 0) printk("mpoa: (%s) MPOA device type TLV association failed\n", mpc->dev->name); @@ -1472,7 +1474,7 @@ static void __exit atm_mpoa_cleanup(void) tmp = mpc->next; if (mpc->dev != NULL) { stop_mpc(mpc); - priv = (struct lec_priv *)mpc->dev->priv; + priv = netdev_priv(mpc->dev); if (priv->lane2_ops != NULL) priv->lane2_ops->associate_indicator = NULL; } diff --git a/net/atm/mpoa_caches.c b/net/atm/mpoa_caches.c index 24799e3e78f786398e679823c3d29feea384bef8..4504a4b339bb8fb66e4c2e743815462157984c95 100644 --- a/net/atm/mpoa_caches.c +++ b/net/atm/mpoa_caches.c @@ -94,7 +94,7 @@ static in_cache_entry *in_cache_add_entry(__be32 dst_ip, return NULL; } - dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %u.%u.%u.%u\n", NIPQUAD(dst_ip)); + dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %pI4\n", &dst_ip); atomic_set(&entry->use, 1); dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lock\n"); @@ -150,7 +150,8 @@ static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc) if( entry->count > mpc->parameters.mpc_p1 && entry->entry_state == INGRESS_INVALID){ - dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %u.%u.%u.%u, sending MPOA res req\n", mpc->dev->name, NIPQUAD(entry->ctrl_info.in_dst_ip)); + dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %pI4, sending MPOA res req\n", + mpc->dev->name, &entry->ctrl_info.in_dst_ip); entry->entry_state = INGRESS_RESOLVING; msg.type = SND_MPOA_RES_RQST; memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN ); @@ -184,7 +185,8 @@ static void in_cache_remove_entry(in_cache_entry *entry, struct k_message msg; vcc = entry->shortcut; - dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %u.%u.%u.%u\n",NIPQUAD(entry->ctrl_info.in_dst_ip)); + dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %pI4\n", + &entry->ctrl_info.in_dst_ip); if (entry->prev != NULL) entry->prev->next = entry->next; @@ -228,7 +230,8 @@ static void clear_count_and_expired(struct mpoa_client *client) next_entry = entry->next; if((now.tv_sec - entry->tv.tv_sec) > entry->ctrl_info.holding_time){ - dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %u.%u.%u.%u\n", NIPQUAD(entry->ctrl_info.in_dst_ip)); + dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %pI4\n", + &entry->ctrl_info.in_dst_ip); client->in_ops->remove_entry(entry, client); } entry = next_entry; @@ -453,7 +456,8 @@ static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_cli return NULL; } - dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %u.%u.%u.%u, this should be our IP\n", NIPQUAD(msg->content.eg_info.eg_dst_ip)); + dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %pI4, this should be our IP\n", + &msg->content.eg_info.eg_dst_ip); atomic_set(&entry->use, 1); dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lock\n"); @@ -469,8 +473,8 @@ static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_cli do_gettimeofday(&(entry->tv)); entry->entry_state = EGRESS_RESOLVED; dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id)); - dprintk("mpoa: mpoa_caches.c: mps_ip = %u.%u.%u.%u\n", - NIPQUAD(entry->ctrl_info.mps_ip)); + dprintk("mpoa: mpoa_caches.c: mps_ip = %pI4\n", + &entry->ctrl_info.mps_ip); atomic_inc(&entry->use); write_unlock_irq(&client->egress_lock); diff --git a/net/atm/pvc.c b/net/atm/pvc.c index 43e8bf5ed0019ceceea7737bf7edbe983c4d8892..e1d22d9430dd2c0b40469d134b82ab7ad5942bc8 100644 --- a/net/atm/pvc.c +++ b/net/atm/pvc.c @@ -113,6 +113,9 @@ static const struct proto_ops pvc_proto_ops = { .getname = pvc_getname, .poll = vcc_poll, .ioctl = vcc_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = vcc_compat_ioctl, +#endif .listen = sock_no_listen, .shutdown = pvc_shutdown, .setsockopt = pvc_setsockopt, diff --git a/net/atm/resources.c b/net/atm/resources.c index a34ba948af96dd5a471adeecd201198556e59340..56b7322ff461c0dc9ebc652a85320cc249b4b8e8 100644 --- a/net/atm/resources.c +++ b/net/atm/resources.c @@ -195,20 +195,39 @@ static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, in } -int atm_dev_ioctl(unsigned int cmd, void __user *arg) +int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat) { void __user *buf; int error, len, number, size = 0; struct atm_dev *dev; struct list_head *p; int *tmp_buf, *tmp_p; - struct atm_iobuf __user *iobuf = arg; - struct atmif_sioc __user *sioc = arg; + int __user *sioc_len; + int __user *iobuf_len; + +#ifndef CONFIG_COMPAT + compat = 0; /* Just so the compiler _knows_ */ +#endif + switch (cmd) { case ATM_GETNAMES: - if (get_user(buf, &iobuf->buffer)) - return -EFAULT; - if (get_user(len, &iobuf->length)) + + if (compat) { +#ifdef CONFIG_COMPAT + struct compat_atm_iobuf __user *ciobuf = arg; + compat_uptr_t cbuf; + iobuf_len = &ciobuf->length; + if (get_user(cbuf, &ciobuf->buffer)) + return -EFAULT; + buf = compat_ptr(cbuf); +#endif + } else { + struct atm_iobuf __user *iobuf = arg; + iobuf_len = &iobuf->length; + if (get_user(buf, &iobuf->buffer)) + return -EFAULT; + } + if (get_user(len, iobuf_len)) return -EFAULT; mutex_lock(&atm_dev_mutex); list_for_each(p, &atm_devs) @@ -229,7 +248,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) } mutex_unlock(&atm_dev_mutex); error = ((copy_to_user(buf, tmp_buf, size)) || - put_user(size, &iobuf->length)) + put_user(size, iobuf_len)) ? -EFAULT : 0; kfree(tmp_buf); return error; @@ -237,13 +256,32 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) break; } - if (get_user(buf, &sioc->arg)) - return -EFAULT; - if (get_user(len, &sioc->length)) - return -EFAULT; - if (get_user(number, &sioc->number)) - return -EFAULT; - + if (compat) { +#ifdef CONFIG_COMPAT + struct compat_atmif_sioc __user *csioc = arg; + compat_uptr_t carg; + + sioc_len = &csioc->length; + if (get_user(carg, &csioc->arg)) + return -EFAULT; + buf = compat_ptr(carg); + + if (get_user(len, &csioc->length)) + return -EFAULT; + if (get_user(number, &csioc->number)) + return -EFAULT; +#endif + } else { + struct atmif_sioc __user *sioc = arg; + + sioc_len = &sioc->length; + if (get_user(buf, &sioc->arg)) + return -EFAULT; + if (get_user(len, &sioc->length)) + return -EFAULT; + if (get_user(number, &sioc->number)) + return -EFAULT; + } if (!(dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d", number))) return -ENODEV; @@ -358,7 +396,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) size = error; /* may return 0, but later on size == 0 means "don't write the length" */ - error = put_user(size, &sioc->length) + error = put_user(size, sioc_len) ? -EFAULT : 0; goto done; case ATM_SETLOOP: @@ -380,11 +418,21 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) } /* fall through */ default: - if (!dev->ops->ioctl) { - error = -EINVAL; - goto done; + if (compat) { +#ifdef CONFIG_COMPAT + if (!dev->ops->compat_ioctl) { + error = -EINVAL; + goto done; + } + size = dev->ops->compat_ioctl(dev, cmd, buf); +#endif + } else { + if (!dev->ops->ioctl) { + error = -EINVAL; + goto done; + } + size = dev->ops->ioctl(dev, cmd, buf); } - size = dev->ops->ioctl(dev, cmd, buf); if (size < 0) { error = (size == -ENOIOCTLCMD ? -EINVAL : size); goto done; @@ -392,7 +440,7 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg) } if (size) - error = put_user(size, &sioc->length) + error = put_user(size, sioc_len) ? -EFAULT : 0; else error = 0; diff --git a/net/atm/resources.h b/net/atm/resources.h index 1d004aaaeec1ac69d48b0b8deddb51737de668c2..126fb1840dfbb2ddd853602892e1a5e740bd90ac 100644 --- a/net/atm/resources.h +++ b/net/atm/resources.h @@ -13,7 +13,7 @@ extern struct list_head atm_devs; extern struct mutex atm_dev_mutex; -int atm_dev_ioctl(unsigned int cmd, void __user *arg); +int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat); #ifdef CONFIG_PROC_FS diff --git a/net/atm/svc.c b/net/atm/svc.c index 8fb54dc870b393d61373e308dfa8bec722d591a5..7b831b526d0bce4fccb9204a4c9ee7adc3c3bafc 100644 --- a/net/atm/svc.c +++ b/net/atm/svc.c @@ -608,6 +608,22 @@ static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) return error; } +#ifdef CONFIG_COMPAT +static int svc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + /* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf. + But actually it takes a struct sockaddr_atmsvc, which doesn't need + compat handling. So all we have to do is fix up cmd... */ + if (cmd == COMPAT_ATM_ADDPARTY) + cmd = ATM_ADDPARTY; + + if (cmd == ATM_ADDPARTY || cmd == ATM_DROPPARTY) + return svc_ioctl(sock, cmd, arg); + else + return vcc_compat_ioctl(sock, cmd, arg); +} +#endif /* CONFIG_COMPAT */ + static const struct proto_ops svc_proto_ops = { .family = PF_ATMSVC, .owner = THIS_MODULE, @@ -620,6 +636,9 @@ static const struct proto_ops svc_proto_ops = { .getname = svc_getname, .poll = vcc_poll, .ioctl = svc_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = svc_compat_ioctl, +#endif .listen = svc_listen, .shutdown = svc_shutdown, .setsockopt = svc_setsockopt, diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 4a5ba978a804ea3d85e04de4e04446974e188512..5f1d2107a1dd70f7628f18d7649d92e2a1bd9d76 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -200,19 +200,15 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, skb_reset_transport_header(skb); - if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) { - kfree_skb(skb); - return 0; - } + if ((ax25_dev = ax25_dev_ax25dev(dev)) == NULL) + goto free; /* * Parse the address header. */ - if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) { - kfree_skb(skb); - return 0; - } + if (ax25_addr_parse(skb->data, skb->len, &src, &dest, &dp, &type, &dama) == NULL) + goto free; /* * Ours perhaps ? @@ -239,10 +235,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, ax25_send_to_raw(&dest, skb, skb->data[1]); - if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) { - kfree_skb(skb); - return 0; - } + if (!mine && ax25cmp(&dest, (ax25_address *)dev->broadcast) != 0) + goto free; /* Now we are pointing at the pid byte */ switch (skb->data[1]) { @@ -301,10 +295,8 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, * If not, should we DM the incoming frame (except DMs) or * silently ignore them. For now we stay quiet. */ - if (ax25_dev->values[AX25_VALUES_CONMODE] == 0) { - kfree_skb(skb); - return 0; - } + if (ax25_dev->values[AX25_VALUES_CONMODE] == 0) + goto free; /* LAPB */ @@ -339,8 +331,7 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, if ((*skb->data & ~AX25_PF) != AX25_DM && mine) ax25_return_dm(dev, &src, &dest, &dp); - kfree_skb(skb); - return 0; + goto free; } /* b) received SABM(E) */ @@ -372,15 +363,12 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, sk->sk_ack_backlog++; bh_unlock_sock(sk); } else { - if (!mine) { - kfree_skb(skb); - return 0; - } + if (!mine) + goto free; if ((ax25 = ax25_create_cb()) == NULL) { ax25_return_dm(dev, &src, &dest, &dp); - kfree_skb(skb); - return 0; + goto free; } ax25_fillin_cb(ax25, ax25_dev); @@ -436,9 +424,10 @@ static int ax25_rcv(struct sk_buff *skb, struct net_device *dev, if (!sock_flag(sk, SOCK_DEAD)) sk->sk_data_ready(sk, skb->len); sock_put(sk); - } else + } else { +free: kfree_skb(skb); - + } return 0; } diff --git a/net/ax25/sysctl_net_ax25.c b/net/ax25/sysctl_net_ax25.c index f288fc4aef9bcd64a16add98a0b7ed86acb232da..62ee3fb34732840515de53d7932d8eebf09e54e8 100644 --- a/net/ax25/sysctl_net_ax25.c +++ b/net/ax25/sysctl_net_ax25.c @@ -24,7 +24,9 @@ static int min_idle[1], max_idle[] = {65535000}; static int min_n2[] = {1}, max_n2[] = {31}; static int min_paclen[] = {1}, max_paclen[] = {512}; static int min_proto[1], max_proto[] = { AX25_PROTO_MAX }; +#ifdef CONFIG_AX25_DAMA_SLAVE static int min_ds_timeout[1], max_ds_timeout[] = {65535000}; +#endif static struct ctl_table_header *ax25_table_header; @@ -43,8 +45,8 @@ static const ctl_table ax25_param_table[] = { .procname = "ip_default_mode", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_ipdefmode, .extra2 = &max_ipdefmode }, @@ -53,8 +55,8 @@ static const ctl_table ax25_param_table[] = { .procname = "ax25_default_mode", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_axdefmode, .extra2 = &max_axdefmode }, @@ -63,8 +65,8 @@ static const ctl_table ax25_param_table[] = { .procname = "backoff_type", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_backoff, .extra2 = &max_backoff }, @@ -73,8 +75,8 @@ static const ctl_table ax25_param_table[] = { .procname = "connect_mode", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_conmode, .extra2 = &max_conmode }, @@ -83,8 +85,8 @@ static const ctl_table ax25_param_table[] = { .procname = "standard_window_size", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_window, .extra2 = &max_window }, @@ -93,8 +95,8 @@ static const ctl_table ax25_param_table[] = { .procname = "extended_window_size", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_ewindow, .extra2 = &max_ewindow }, @@ -103,8 +105,8 @@ static const ctl_table ax25_param_table[] = { .procname = "t1_timeout", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_t1, .extra2 = &max_t1 }, @@ -113,8 +115,8 @@ static const ctl_table ax25_param_table[] = { .procname = "t2_timeout", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_t2, .extra2 = &max_t2 }, @@ -123,8 +125,8 @@ static const ctl_table ax25_param_table[] = { .procname = "t3_timeout", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_t3, .extra2 = &max_t3 }, @@ -133,8 +135,8 @@ static const ctl_table ax25_param_table[] = { .procname = "idle_timeout", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_idle, .extra2 = &max_idle }, @@ -143,8 +145,8 @@ static const ctl_table ax25_param_table[] = { .procname = "maximum_retry_count", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_n2, .extra2 = &max_n2 }, @@ -153,8 +155,8 @@ static const ctl_table ax25_param_table[] = { .procname = "maximum_packet_length", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_paclen, .extra2 = &max_paclen }, @@ -163,8 +165,8 @@ static const ctl_table ax25_param_table[] = { .procname = "protocol", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_proto, .extra2 = &max_proto }, @@ -174,8 +176,8 @@ static const ctl_table ax25_param_table[] = { .procname = "dama_slave_timeout", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_ds_timeout, .extra2 = &max_ds_timeout }, diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c index 8f9431a12c6f36ed5f8d3ad2b28f765120824d7b..744ed3f07ef38374f6c1b0480d56954d4cf77eac 100644 --- a/net/bluetooth/af_bluetooth.c +++ b/net/bluetooth/af_bluetooth.c @@ -41,18 +41,14 @@ #include -#ifndef CONFIG_BT_SOCK_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - -#define VERSION "2.13" +#define VERSION "2.14" /* Bluetooth sockets */ #define BT_MAX_PROTO 8 static struct net_proto_family *bt_proto[BT_MAX_PROTO]; +static DEFINE_RWLOCK(bt_proto_lock); -static struct lock_class_key bt_slock_key[BT_MAX_PROTO]; +#ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key bt_lock_key[BT_MAX_PROTO]; static const char *bt_key_strings[BT_MAX_PROTO] = { "sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP", @@ -65,6 +61,7 @@ static const char *bt_key_strings[BT_MAX_PROTO] = { "sk_lock-AF_BLUETOOTH-BTPROTO_AVDTP", }; +static struct lock_class_key bt_slock_key[BT_MAX_PROTO]; static const char *bt_slock_key_strings[BT_MAX_PROTO] = { "slock-AF_BLUETOOTH-BTPROTO_L2CAP", "slock-AF_BLUETOOTH-BTPROTO_HCI", @@ -75,7 +72,25 @@ static const char *bt_slock_key_strings[BT_MAX_PROTO] = { "slock-AF_BLUETOOTH-BTPROTO_HIDP", "slock-AF_BLUETOOTH-BTPROTO_AVDTP", }; -static DEFINE_RWLOCK(bt_proto_lock); + +static inline void bt_sock_reclassify_lock(struct socket *sock, int proto) +{ + struct sock *sk = sock->sk; + + if (!sk) + return; + + BUG_ON(sock_owned_by_user(sk)); + + sock_lock_init_class_and_name(sk, + bt_slock_key_strings[proto], &bt_slock_key[proto], + bt_key_strings[proto], &bt_lock_key[proto]); +} +#else +static inline void bt_sock_reclassify_lock(struct socket *sock, int proto) +{ +} +#endif int bt_sock_register(int proto, struct net_proto_family *ops) { @@ -117,21 +132,6 @@ int bt_sock_unregister(int proto) } EXPORT_SYMBOL(bt_sock_unregister); -static void bt_reclassify_sock_lock(struct socket *sock, int proto) -{ - struct sock *sk = sock->sk; - - if (!sk) - return; - BUG_ON(sock_owned_by_user(sk)); - - sock_lock_init_class_and_name(sk, - bt_slock_key_strings[proto], - &bt_slock_key[proto], - bt_key_strings[proto], - &bt_lock_key[proto]); -} - static int bt_sock_create(struct net *net, struct socket *sock, int proto) { int err; @@ -151,7 +151,7 @@ static int bt_sock_create(struct net *net, struct socket *sock, int proto) if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) { err = bt_proto[proto]->create(net, sock, proto); - bt_reclassify_sock_lock(sock, proto); + bt_sock_reclassify_lock(sock, proto); module_put(bt_proto[proto]->owner); } @@ -240,7 +240,7 @@ int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock, size_t copied; int err; - BT_DBG("sock %p sk %p len %d", sock, sk, len); + BT_DBG("sock %p sk %p len %zu", sock, sk, len); if (flags & (MSG_OOB)) return -EOPNOTSUPP; diff --git a/net/bluetooth/bnep/bnep.h b/net/bluetooth/bnep/bnep.h index b69bf4e7c48b8f8ab9d874ba691d6f21397f531e..d20f8a40f36e735ff6073b680e2b41793168386e 100644 --- a/net/bluetooth/bnep/bnep.h +++ b/net/bluetooth/bnep/bnep.h @@ -161,7 +161,7 @@ struct bnep_session { struct msghdr msg; struct bnep_proto_filter proto_filter[BNEP_MAX_PROTO_FILTERS]; - u64 mc_filter; + unsigned long long mc_filter; struct socket *sock; struct net_device *dev; diff --git a/net/bluetooth/bnep/core.c b/net/bluetooth/bnep/core.c index 80ba30cf4b682556252587e2ed57468f6663efa0..70fea8bdb4e51d7d20b616a91a9753e93317433f 100644 --- a/net/bluetooth/bnep/core.c +++ b/net/bluetooth/bnep/core.c @@ -52,11 +52,6 @@ #include "bnep.h" -#ifndef CONFIG_BT_BNEP_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "1.3" static int compress_src = 1; @@ -311,7 +306,6 @@ static inline int bnep_rx_frame(struct bnep_session *s, struct sk_buff *skb) struct sk_buff *nskb; u8 type; - dev->last_rx = jiffies; s->stats.rx_bytes += skb->len; type = *(u8 *) skb->data; skb_pull(skb, 1); @@ -566,7 +560,7 @@ int bnep_add_connection(struct bnep_connadd_req *req, struct socket *sock) goto failed; } - s = dev->priv; + s = netdev_priv(dev); /* This is rx header therefore addresses are swapped. * ie eh.h_dest is our local address. */ diff --git a/net/bluetooth/bnep/netdev.c b/net/bluetooth/bnep/netdev.c index d9fa0ab2c87f42cacf1dc91199a1b982ae07da2c..f897da6e044490e58904256ba67b07f246094b7f 100644 --- a/net/bluetooth/bnep/netdev.c +++ b/net/bluetooth/bnep/netdev.c @@ -41,11 +41,6 @@ #include "bnep.h" -#ifndef CONFIG_BT_BNEP_DEBUG -#undef BT_DBG -#define BT_DBG( A... ) -#endif - #define BNEP_TX_QUEUE_LEN 20 static int bnep_net_open(struct net_device *dev) @@ -62,14 +57,14 @@ static int bnep_net_close(struct net_device *dev) static struct net_device_stats *bnep_net_get_stats(struct net_device *dev) { - struct bnep_session *s = dev->priv; + struct bnep_session *s = netdev_priv(dev); return &s->stats; } static void bnep_net_set_mc_list(struct net_device *dev) { #ifdef CONFIG_BT_BNEP_MC_FILTER - struct bnep_session *s = dev->priv; + struct bnep_session *s = netdev_priv(dev); struct sock *sk = s->sock->sk; struct bnep_set_filter_req *r; struct sk_buff *skb; @@ -183,7 +178,7 @@ static inline int bnep_net_proto_filter(struct sk_buff *skb, struct bnep_session static int bnep_net_xmit(struct sk_buff *skb, struct net_device *dev) { - struct bnep_session *s = dev->priv; + struct bnep_session *s = netdev_priv(dev); struct sock *sk = s->sock->sk; BT_DBG("skb %p, dev %p", skb, dev); diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c index 8ffb57f2303a5124d93d405c083b32b419bd7ecb..e857628b0b27e61234102dc843ab0cc84a5f5c42 100644 --- a/net/bluetooth/bnep/sock.c +++ b/net/bluetooth/bnep/sock.c @@ -46,11 +46,6 @@ #include "bnep.h" -#ifndef CONFIG_BT_BNEP_DEBUG -#undef BT_DBG -#define BT_DBG( A... ) -#endif - static int bnep_sock_release(struct socket *sock) { struct sock *sk = sock->sk; diff --git a/net/bluetooth/cmtp/capi.c b/net/bluetooth/cmtp/capi.c index 3e9d5bb3fefb6de364353c62684efd5b7629e9d4..78958c0f9a40a8e7e04e15c41074c1e47e959398 100644 --- a/net/bluetooth/cmtp/capi.c +++ b/net/bluetooth/cmtp/capi.c @@ -42,11 +42,6 @@ #include "cmtp.h" -#ifndef CONFIG_BT_CMTP_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define CAPI_INTEROPERABILITY 0x20 #define CAPI_INTEROPERABILITY_REQ CAPICMD(CAPI_INTEROPERABILITY, CAPI_REQ) diff --git a/net/bluetooth/cmtp/core.c b/net/bluetooth/cmtp/core.c index ca60a4517fd34c86061f99a7a6bde51cfef35b44..c9cac7719efe757ddcbd5567f1d464ee4cf12f47 100644 --- a/net/bluetooth/cmtp/core.c +++ b/net/bluetooth/cmtp/core.c @@ -44,11 +44,6 @@ #include "cmtp.h" -#ifndef CONFIG_BT_CMTP_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "1.0" static DECLARE_RWSEM(cmtp_session_sem); diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c index 8c7f7bc4e0bacbbed7ef05daae6aacb0af34a8e3..16b0fad74f6e82d6a9ec0f5c98725a50fd89757a 100644 --- a/net/bluetooth/cmtp/sock.c +++ b/net/bluetooth/cmtp/sock.c @@ -43,11 +43,6 @@ #include "cmtp.h" -#ifndef CONFIG_BT_CMTP_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - static int cmtp_sock_release(struct socket *sock) { struct sock *sk = sock->sk; diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c index b7002429f1525311053f14171a1d94a25bf1ff04..a4a789f24c8d4668d7b54997654f8a516d62898a 100644 --- a/net/bluetooth/hci_conn.c +++ b/net/bluetooth/hci_conn.c @@ -45,11 +45,6 @@ #include #include -#ifndef CONFIG_BT_HCI_CORE_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - void hci_acl_connect(struct hci_conn *conn) { struct hci_dev *hdev = conn->hdev; diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 278a3ace14f664e019a85109ae6450e9ed13cff6..ba78cc1eb8d9aaa8973c3a2395af86a98e71d4d6 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -48,11 +48,6 @@ #include #include -#ifndef CONFIG_BT_HCI_CORE_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - static void hci_cmd_task(unsigned long arg); static void hci_rx_task(unsigned long arg); static void hci_tx_task(unsigned long arg); @@ -205,7 +200,7 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt) /* Mandatory initialization */ /* Reset */ - if (test_bit(HCI_QUIRK_RESET_ON_INIT, &hdev->quirks)) + if (!test_bit(HCI_QUIRK_NO_RESET, &hdev->quirks)) hci_send_cmd(hdev, HCI_OP_RESET, 0, NULL); /* Read Local Supported Features */ @@ -290,7 +285,7 @@ static void hci_linkpol_req(struct hci_dev *hdev, unsigned long opt) { __le16 policy = cpu_to_le16(opt); - BT_DBG("%s %x", hdev->name, opt); + BT_DBG("%s %x", hdev->name, policy); /* Default link policy */ hci_send_cmd(hdev, HCI_OP_WRITE_DEF_LINK_POLICY, 2, &policy); @@ -756,7 +751,7 @@ int hci_get_dev_list(void __user *arg) size = sizeof(*dl) + dev_num * sizeof(*dr); - if (!(dl = kmalloc(size, GFP_KERNEL))) + if (!(dl = kzalloc(size, GFP_KERNEL))) return -ENOMEM; dr = dl->dev_req; diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c index ad7a553d77131c469bf4c9ebc3bc8bbfe84d1a33..f91ba690f5d29cfc932deb3cf0ae810ce6993ae5 100644 --- a/net/bluetooth/hci_event.c +++ b/net/bluetooth/hci_event.c @@ -45,11 +45,6 @@ #include #include -#ifndef CONFIG_BT_HCI_CORE_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - /* Handle HCI Event packets */ static void hci_cc_inquiry_cancel(struct hci_dev *hdev, struct sk_buff *skb) diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c index d62579b67959cd935f1f20c8c128dcabd9436f37..4f9621f759a010d7e2403660103a780341f77e14 100644 --- a/net/bluetooth/hci_sock.c +++ b/net/bluetooth/hci_sock.c @@ -49,11 +49,6 @@ #include #include -#ifndef CONFIG_BT_HCI_SOCK_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - /* ----- HCI socket interface ----- */ static inline int hci_test_bit(int nr, void *addr) diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c index f4f6615cad9f910c55f1cc70db8e633e010ce6eb..1a1f916be44e258a853fcbf4d60483199c976c32 100644 --- a/net/bluetooth/hci_sysfs.c +++ b/net/bluetooth/hci_sysfs.c @@ -6,11 +6,6 @@ #include #include -#ifndef CONFIG_BT_HCI_CORE_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - struct class *bt_class = NULL; EXPORT_SYMBOL_GPL(bt_class); @@ -113,8 +108,7 @@ void hci_conn_add_sysfs(struct hci_conn *conn) conn->dev.class = bt_class; conn->dev.parent = &hdev->dev; - snprintf(conn->dev.bus_id, BUS_ID_SIZE, "%s:%d", - hdev->name, conn->handle); + dev_set_name(&conn->dev, "%s:%d", hdev->name, conn->handle); dev_set_drvdata(&conn->dev, conn); @@ -132,7 +126,7 @@ void hci_conn_add_sysfs(struct hci_conn *conn) */ static int __match_tty(struct device *dev, void *data) { - return !strncmp(dev->bus_id, "rfcomm", 6); + return !strncmp(dev_name(dev), "rfcomm", 6); } static void del_conn(struct work_struct *work) @@ -421,7 +415,7 @@ int hci_register_sysfs(struct hci_dev *hdev) dev->class = bt_class; dev->parent = hdev->parent; - strlcpy(dev->bus_id, hdev->name, BUS_ID_SIZE); + dev_set_name(dev, "%s", hdev->name); dev_set_drvdata(dev, hdev); diff --git a/net/bluetooth/hidp/core.c b/net/bluetooth/hidp/core.c index acdeab3d980707fbd7740344abd4f7ffe335c75d..b18676870d5500e0fff1ece30654b060f373db2d 100644 --- a/net/bluetooth/hidp/core.c +++ b/net/bluetooth/hidp/core.c @@ -47,11 +47,6 @@ #include "hidp.h" -#ifndef CONFIG_BT_HIDP_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "1.2" static DECLARE_RWSEM(hidp_session_sem); diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c index f4dd02ca9a96d9acd1c73872aac795b6de68575b..37c9d7d2e688ba35279f310707597c04f26d96b9 100644 --- a/net/bluetooth/hidp/sock.c +++ b/net/bluetooth/hidp/sock.c @@ -39,11 +39,6 @@ #include "hidp.h" -#ifndef CONFIG_BT_HIDP_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - static int hidp_sock_release(struct socket *sock) { struct sock *sk = sock->sk; diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c index 9610a9c85b9896e69cd6c62712cb5f8376a33040..b93748e224ff1505bd0f8c2448f1070f3854a796 100644 --- a/net/bluetooth/l2cap.c +++ b/net/bluetooth/l2cap.c @@ -50,11 +50,6 @@ #include #include -#ifndef CONFIG_BT_L2CAP_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "2.11" static u32 l2cap_feat_mask = 0x0000; diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c index ce68e046d963840e4a3822972ed33f2a30a86244..acd84fd524b856c25cf1f7c40560c3a6726d7236 100644 --- a/net/bluetooth/rfcomm/core.c +++ b/net/bluetooth/rfcomm/core.c @@ -46,11 +46,6 @@ #include #include -#ifndef CONFIG_BT_RFCOMM_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "1.10" static int disable_cfc = 0; diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c index 8a972b6ba85fe9190c4bdb82e78d915683376cd5..d3fc6fca38d0892af7fe2e2d0f18328a82b6df2e 100644 --- a/net/bluetooth/rfcomm/sock.c +++ b/net/bluetooth/rfcomm/sock.c @@ -50,11 +50,6 @@ #include #include -#ifndef CONFIG_BT_RFCOMM_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - static const struct proto_ops rfcomm_sock_ops; static struct bt_sock_list rfcomm_sk_list = { @@ -644,7 +639,7 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock, msg->msg_namelen = 0; - BT_DBG("sk %p size %d", sk, size); + BT_DBG("sk %p size %zu", sk, size); lock_sock(sk); @@ -792,7 +787,7 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { - struct sock *sk = sock->sk; + struct sock *sk __maybe_unused = sock->sk; int err; BT_DBG("sk %p cmd %x arg %lx", sk, cmd, arg); diff --git a/net/bluetooth/rfcomm/tty.c b/net/bluetooth/rfcomm/tty.c index d3340dd52bcffd778f6604ed716cebf8f1577a42..d030c69cb5a306ee2cf8c89584e286fc4cf1afb9 100644 --- a/net/bluetooth/rfcomm/tty.c +++ b/net/bluetooth/rfcomm/tty.c @@ -39,11 +39,6 @@ #include #include -#ifndef CONFIG_BT_RFCOMM_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define RFCOMM_TTY_MAGIC 0x6d02 /* magic number for rfcomm struct */ #define RFCOMM_TTY_PORTS RFCOMM_MAX_DEV /* whole lotta rfcomm devices */ #define RFCOMM_TTY_MAJOR 216 /* device node major id of the usb/bluetooth.c driver */ @@ -58,7 +53,7 @@ struct rfcomm_dev { char name[12]; int id; unsigned long flags; - int opened; + atomic_t opened; int err; bdaddr_t src; @@ -261,6 +256,8 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) dev->flags = req->flags & ((1 << RFCOMM_RELEASE_ONHUP) | (1 << RFCOMM_REUSE_DLC)); + atomic_set(&dev->opened, 0); + init_waitqueue_head(&dev->wait); tasklet_init(&dev->wakeup_task, rfcomm_tty_wakeup, (unsigned long) dev); @@ -301,18 +298,15 @@ static int rfcomm_dev_add(struct rfcomm_dev_req *req, struct rfcomm_dlc *dlc) out: write_unlock_bh(&rfcomm_dev_lock); - if (err < 0) { - kfree(dev); - return err; - } + if (err < 0) + goto free; dev->tty_dev = tty_register_device(rfcomm_tty_driver, dev->id, NULL); if (IS_ERR(dev->tty_dev)) { err = PTR_ERR(dev->tty_dev); list_del(&dev->list); - kfree(dev); - return err; + goto free; } dev_set_drvdata(dev->tty_dev, dev); @@ -324,16 +318,20 @@ out: BT_ERR("Failed to create channel attribute"); return dev->id; + +free: + kfree(dev); + return err; } static void rfcomm_dev_del(struct rfcomm_dev *dev) { BT_DBG("dev %p", dev); - if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) - BUG_ON(1); - else - set_bit(RFCOMM_TTY_RELEASED, &dev->flags); + BUG_ON(test_and_set_bit(RFCOMM_TTY_RELEASED, &dev->flags)); + + if (atomic_read(&dev->opened) > 0) + return; write_lock_bh(&rfcomm_dev_lock); list_del_init(&dev->list); @@ -689,9 +687,10 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp) if (!dev) return -ENODEV; - BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), dev->channel, dev->opened); + BT_DBG("dev %p dst %s channel %d opened %d", dev, batostr(&dev->dst), + dev->channel, atomic_read(&dev->opened)); - if (dev->opened++ != 0) + if (atomic_inc_return(&dev->opened) > 1) return 0; dlc = dev->dlc; @@ -747,9 +746,10 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) if (!dev) return; - BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, dev->opened); + BT_DBG("tty %p dev %p dlc %p opened %d", tty, dev, dev->dlc, + atomic_read(&dev->opened)); - if (--dev->opened == 0) { + if (atomic_dec_and_test(&dev->opened)) { if (dev->tty_dev->parent) device_move(dev->tty_dev, NULL); @@ -763,6 +763,14 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp) tty->driver_data = NULL; dev->tty = NULL; rfcomm_dlc_unlock(dev->dlc); + + if (test_bit(RFCOMM_TTY_RELEASED, &dev->flags)) { + write_lock_bh(&rfcomm_dev_lock); + list_del_init(&dev->list); + write_unlock_bh(&rfcomm_dev_lock); + + rfcomm_dev_put(dev); + } } rfcomm_dev_put(dev); diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c index 0cc91e6da76d7f9d16983985f176ab1d7319eaab..46fd8bf9a69056fcf69d2aa6d5f7617768bb8ef1 100644 --- a/net/bluetooth/sco.c +++ b/net/bluetooth/sco.c @@ -48,11 +48,6 @@ #include #include -#ifndef CONFIG_BT_SCO_DEBUG -#undef BT_DBG -#define BT_DBG(D...) -#endif - #define VERSION "0.6" static int disable_esco = 0; diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c index 6c023f0f8252c184d67a8e8d9f3f00e44ef4526f..18538d7460d715144fb4afd824d88d34f8c5c4b9 100644 --- a/net/bridge/br_device.c +++ b/net/bridge/br_device.c @@ -147,7 +147,7 @@ static int br_set_tx_csum(struct net_device *dev, u32 data) return 0; } -static struct ethtool_ops br_ethtool_ops = { +static const struct ethtool_ops br_ethtool_ops = { .get_drvinfo = br_getinfo, .get_link = ethtool_op_get_link, .get_tx_csum = ethtool_op_get_tx_csum, @@ -160,21 +160,25 @@ static struct ethtool_ops br_ethtool_ops = { .get_flags = ethtool_op_get_flags, }; +static const struct net_device_ops br_netdev_ops = { + .ndo_open = br_dev_open, + .ndo_stop = br_dev_stop, + .ndo_start_xmit = br_dev_xmit, + .ndo_set_mac_address = br_set_mac_address, + .ndo_set_multicast_list = br_dev_set_multicast_list, + .ndo_change_mtu = br_change_mtu, + .ndo_do_ioctl = br_dev_ioctl, +}; + void br_dev_setup(struct net_device *dev) { random_ether_addr(dev->dev_addr); ether_setup(dev); - dev->do_ioctl = br_dev_ioctl; - dev->hard_start_xmit = br_dev_xmit; - dev->open = br_dev_open; - dev->set_multicast_list = br_dev_set_multicast_list; - dev->change_mtu = br_change_mtu; + dev->netdev_ops = &br_netdev_ops; dev->destructor = free_netdev; SET_ETHTOOL_OPS(dev, &br_ethtool_ops); - dev->stop = br_dev_stop; dev->tx_queue_len = 0; - dev->set_mac_address = br_set_mac_address; dev->priv_flags = IFF_EBRIDGE; dev->features = NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_HIGHDMA | diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index 0a09ccf68c1c16e6362f895ba389f7287520594e..727c5c510a602573b216ec66fb3ce1dbf274b0d5 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -373,7 +373,7 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) if (dev->flags & IFF_LOOPBACK || dev->type != ARPHRD_ETHER) return -EINVAL; - if (dev->hard_start_xmit == br_dev_xmit) + if (dev->netdev_ops->ndo_start_xmit == br_dev_xmit) return -ELOOP; if (dev->br_port != NULL) @@ -460,7 +460,7 @@ void br_net_exit(struct net *net) restart: for_each_netdev(net, dev) { if (dev->priv_flags & IFF_EBRIDGE) { - del_br(dev->priv); + del_br(netdev_priv(dev)); goto restart; } } diff --git a/net/bridge/br_netfilter.c b/net/bridge/br_netfilter.c index 45f61c348e369c7a78d2fd91d8a14fb1ea75b7e5..a65e43a17fbb2c3ab6334be3ab60f8ffd0e19ced 100644 --- a/net/bridge/br_netfilter.c +++ b/net/bridge/br_netfilter.c @@ -109,7 +109,6 @@ static struct dst_ops fake_dst_ops = { .family = AF_INET, .protocol = __constant_htons(ETH_P_IP), .update_pmtu = fake_update_pmtu, - .entry_size = sizeof(struct rtable), .entries = ATOMIC_INIT(0), }; @@ -370,7 +369,7 @@ static int br_nf_pre_routing_finish(struct sk_buff *skb) if (err != -EHOSTUNREACH || !in_dev || IN_DEV_FORWARD(in_dev)) goto free_skb; - if (!ip_route_output_key(&init_net, &rt, &fl)) { + if (!ip_route_output_key(dev_net(dev), &rt, &fl)) { /* - Bridged-and-DNAT'ed traffic doesn't * require ip_forwarding. */ if (((struct dst_entry *)rt)->dev == dev) { @@ -951,35 +950,35 @@ static ctl_table brnf_table[] = { .data = &brnf_call_arptables, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &brnf_sysctl_call_tables, + .proc_handler = brnf_sysctl_call_tables, }, { .procname = "bridge-nf-call-iptables", .data = &brnf_call_iptables, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &brnf_sysctl_call_tables, + .proc_handler = brnf_sysctl_call_tables, }, { .procname = "bridge-nf-call-ip6tables", .data = &brnf_call_ip6tables, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &brnf_sysctl_call_tables, + .proc_handler = brnf_sysctl_call_tables, }, { .procname = "bridge-nf-filter-vlan-tagged", .data = &brnf_filter_vlan_tagged, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &brnf_sysctl_call_tables, + .proc_handler = brnf_sysctl_call_tables, }, { .procname = "bridge-nf-filter-pppoe-tagged", .data = &brnf_filter_pppoe_tagged, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &brnf_sysctl_call_tables, + .proc_handler = brnf_sysctl_call_tables, }, { .ctl_name = 0 } }; diff --git a/net/bridge/br_sysfs_br.c b/net/bridge/br_sysfs_br.c index 158dee8b4965307c045d6fec2d5a930070a4cd68..603d89248e7148e1a830146953dfbfdcb54491bd 100644 --- a/net/bridge/br_sysfs_br.c +++ b/net/bridge/br_sysfs_br.c @@ -22,7 +22,7 @@ #include "br_private.h" #define to_dev(obj) container_of(obj, struct device, kobj) -#define to_bridge(cd) ((struct net_bridge *)(to_net_dev(cd)->priv)) +#define to_bridge(cd) ((struct net_bridge *)netdev_priv(to_net_dev(cd))) /* * Common code for storing bridge parameters. diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c index 3d33c608906aeadddaa0a0361372d34430121d97..d44cbf8c374af41d54bb0d7cd0727fa06d30052a 100644 --- a/net/bridge/netfilter/ebt_log.c +++ b/net/bridge/netfilter/ebt_log.c @@ -79,7 +79,6 @@ print_ports(const struct sk_buff *skb, uint8_t protocol, int offset) } } -#define myNIPQUAD(a) a[0], a[1], a[2], a[3] static void ebt_log_packet(u_int8_t pf, unsigned int hooknum, const struct sk_buff *skb, const struct net_device *in, @@ -113,9 +112,8 @@ ebt_log_packet(u_int8_t pf, unsigned int hooknum, printk(" INCOMPLETE IP header"); goto out; } - printk(" IP SRC=%u.%u.%u.%u IP DST=%u.%u.%u.%u, IP " - "tos=0x%02X, IP proto=%d", NIPQUAD(ih->saddr), - NIPQUAD(ih->daddr), ih->tos, ih->protocol); + printk(" IP SRC=%pI4 IP DST=%pI4, IP tos=0x%02X, IP proto=%d", + &ih->saddr, &ih->daddr, ih->tos, ih->protocol); print_ports(skb, ih->protocol, ih->ihl*4); goto out; } @@ -133,10 +131,8 @@ ebt_log_packet(u_int8_t pf, unsigned int hooknum, printk(" INCOMPLETE IPv6 header"); goto out; } - printk(" IPv6 SRC=%x:%x:%x:%x:%x:%x:%x:%x " - "IPv6 DST=%x:%x:%x:%x:%x:%x:%x:%x, IPv6 " - "priority=0x%01X, Next Header=%d", NIP6(ih->saddr), - NIP6(ih->daddr), ih->priority, ih->nexthdr); + printk(" IPv6 SRC=%pI6 IPv6 DST=%pI6, IPv6 priority=0x%01X, Next Header=%d", + &ih->saddr, &ih->daddr, ih->priority, ih->nexthdr); nexthdr = ih->nexthdr; offset_ph = ipv6_skip_exthdr(skb, sizeof(_iph), &nexthdr); if (offset_ph == -1) @@ -177,12 +173,10 @@ ebt_log_packet(u_int8_t pf, unsigned int hooknum, } printk(" ARP MAC SRC="); print_MAC(ap->mac_src); - printk(" ARP IP SRC=%u.%u.%u.%u", - myNIPQUAD(ap->ip_src)); + printk(" ARP IP SRC=%pI4", ap->ip_src); printk(" ARP MAC DST="); print_MAC(ap->mac_dst); - printk(" ARP IP DST=%u.%u.%u.%u", - myNIPQUAD(ap->ip_dst)); + printk(" ARP IP DST=%pI4", ap->ip_dst); } } out: diff --git a/net/bridge/netfilter/ebtable_broute.c b/net/bridge/netfilter/ebtable_broute.c index 246626bb0c879db5f62786b53c992d48e939f188..8604dfc1fc3be0f2c36f6b84b3bceecb930cdfba 100644 --- a/net/bridge/netfilter/ebtable_broute.c +++ b/net/bridge/netfilter/ebtable_broute.c @@ -56,29 +56,47 @@ static int ebt_broute(struct sk_buff *skb) int ret; ret = ebt_do_table(NF_BR_BROUTING, skb, skb->dev, NULL, - &broute_table); + dev_net(skb->dev)->xt.broute_table); if (ret == NF_DROP) return 1; /* route it */ return 0; /* bridge it */ } +static int __net_init broute_net_init(struct net *net) +{ + net->xt.broute_table = ebt_register_table(net, &broute_table); + if (IS_ERR(net->xt.broute_table)) + return PTR_ERR(net->xt.broute_table); + return 0; +} + +static void __net_exit broute_net_exit(struct net *net) +{ + ebt_unregister_table(net->xt.broute_table); +} + +static struct pernet_operations broute_net_ops = { + .init = broute_net_init, + .exit = broute_net_exit, +}; + static int __init ebtable_broute_init(void) { int ret; - ret = ebt_register_table(&broute_table); + ret = register_pernet_subsys(&broute_net_ops); if (ret < 0) return ret; /* see br_input.c */ rcu_assign_pointer(br_should_route_hook, ebt_broute); - return ret; + return 0; } static void __exit ebtable_broute_fini(void) { rcu_assign_pointer(br_should_route_hook, NULL); synchronize_net(); - ebt_unregister_table(&broute_table); + unregister_pernet_subsys(&broute_net_ops); } module_init(ebtable_broute_init); diff --git a/net/bridge/netfilter/ebtable_filter.c b/net/bridge/netfilter/ebtable_filter.c index 1a58af51a2e24a374d2d558e65e8206a5c96f329..2b2e8040a9c68c4b55fd1b30850fa9703ba4f7ca 100644 --- a/net/bridge/netfilter/ebtable_filter.c +++ b/net/bridge/netfilter/ebtable_filter.c @@ -61,29 +61,36 @@ static struct ebt_table frame_filter = }; static unsigned int -ebt_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, +ebt_in_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return ebt_do_table(hook, skb, in, out, &frame_filter); + return ebt_do_table(hook, skb, in, out, dev_net(in)->xt.frame_filter); +} + +static unsigned int +ebt_out_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, + const struct net_device *out, int (*okfn)(struct sk_buff *)) +{ + return ebt_do_table(hook, skb, in, out, dev_net(out)->xt.frame_filter); } static struct nf_hook_ops ebt_ops_filter[] __read_mostly = { { - .hook = ebt_hook, + .hook = ebt_in_hook, .owner = THIS_MODULE, .pf = PF_BRIDGE, .hooknum = NF_BR_LOCAL_IN, .priority = NF_BR_PRI_FILTER_BRIDGED, }, { - .hook = ebt_hook, + .hook = ebt_in_hook, .owner = THIS_MODULE, .pf = PF_BRIDGE, .hooknum = NF_BR_FORWARD, .priority = NF_BR_PRI_FILTER_BRIDGED, }, { - .hook = ebt_hook, + .hook = ebt_out_hook, .owner = THIS_MODULE, .pf = PF_BRIDGE, .hooknum = NF_BR_LOCAL_OUT, @@ -91,23 +98,41 @@ static struct nf_hook_ops ebt_ops_filter[] __read_mostly = { }, }; +static int __net_init frame_filter_net_init(struct net *net) +{ + net->xt.frame_filter = ebt_register_table(net, &frame_filter); + if (IS_ERR(net->xt.frame_filter)) + return PTR_ERR(net->xt.frame_filter); + return 0; +} + +static void __net_exit frame_filter_net_exit(struct net *net) +{ + ebt_unregister_table(net->xt.frame_filter); +} + +static struct pernet_operations frame_filter_net_ops = { + .init = frame_filter_net_init, + .exit = frame_filter_net_exit, +}; + static int __init ebtable_filter_init(void) { int ret; - ret = ebt_register_table(&frame_filter); + ret = register_pernet_subsys(&frame_filter_net_ops); if (ret < 0) return ret; ret = nf_register_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter)); if (ret < 0) - ebt_unregister_table(&frame_filter); + unregister_pernet_subsys(&frame_filter_net_ops); return ret; } static void __exit ebtable_filter_fini(void) { nf_unregister_hooks(ebt_ops_filter, ARRAY_SIZE(ebt_ops_filter)); - ebt_unregister_table(&frame_filter); + unregister_pernet_subsys(&frame_filter_net_ops); } module_init(ebtable_filter_init); diff --git a/net/bridge/netfilter/ebtable_nat.c b/net/bridge/netfilter/ebtable_nat.c index f60c1e78e57537541e9e1d2ddbd186ff4e681df5..3fe1ae87e35f912cdb0e255cadff4deb579d121f 100644 --- a/net/bridge/netfilter/ebtable_nat.c +++ b/net/bridge/netfilter/ebtable_nat.c @@ -61,36 +61,36 @@ static struct ebt_table frame_nat = }; static unsigned int -ebt_nat_dst(unsigned int hook, struct sk_buff *skb, const struct net_device *in +ebt_nat_in(unsigned int hook, struct sk_buff *skb, const struct net_device *in , const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return ebt_do_table(hook, skb, in, out, &frame_nat); + return ebt_do_table(hook, skb, in, out, dev_net(in)->xt.frame_nat); } static unsigned int -ebt_nat_src(unsigned int hook, struct sk_buff *skb, const struct net_device *in +ebt_nat_out(unsigned int hook, struct sk_buff *skb, const struct net_device *in , const struct net_device *out, int (*okfn)(struct sk_buff *)) { - return ebt_do_table(hook, skb, in, out, &frame_nat); + return ebt_do_table(hook, skb, in, out, dev_net(out)->xt.frame_nat); } static struct nf_hook_ops ebt_ops_nat[] __read_mostly = { { - .hook = ebt_nat_dst, + .hook = ebt_nat_out, .owner = THIS_MODULE, .pf = PF_BRIDGE, .hooknum = NF_BR_LOCAL_OUT, .priority = NF_BR_PRI_NAT_DST_OTHER, }, { - .hook = ebt_nat_src, + .hook = ebt_nat_out, .owner = THIS_MODULE, .pf = PF_BRIDGE, .hooknum = NF_BR_POST_ROUTING, .priority = NF_BR_PRI_NAT_SRC, }, { - .hook = ebt_nat_dst, + .hook = ebt_nat_in, .owner = THIS_MODULE, .pf = PF_BRIDGE, .hooknum = NF_BR_PRE_ROUTING, @@ -98,23 +98,41 @@ static struct nf_hook_ops ebt_ops_nat[] __read_mostly = { }, }; +static int __net_init frame_nat_net_init(struct net *net) +{ + net->xt.frame_nat = ebt_register_table(net, &frame_nat); + if (IS_ERR(net->xt.frame_nat)) + return PTR_ERR(net->xt.frame_nat); + return 0; +} + +static void __net_exit frame_nat_net_exit(struct net *net) +{ + ebt_unregister_table(net->xt.frame_nat); +} + +static struct pernet_operations frame_nat_net_ops = { + .init = frame_nat_net_init, + .exit = frame_nat_net_exit, +}; + static int __init ebtable_nat_init(void) { int ret; - ret = ebt_register_table(&frame_nat); + ret = register_pernet_subsys(&frame_nat_net_ops); if (ret < 0) return ret; ret = nf_register_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat)); if (ret < 0) - ebt_unregister_table(&frame_nat); + unregister_pernet_subsys(&frame_nat_net_ops); return ret; } static void __exit ebtable_nat_fini(void) { nf_unregister_hooks(ebt_ops_nat, ARRAY_SIZE(ebt_ops_nat)); - ebt_unregister_table(&frame_nat); + unregister_pernet_subsys(&frame_nat_net_ops); } module_init(ebtable_nat_init); diff --git a/net/bridge/netfilter/ebtables.c b/net/bridge/netfilter/ebtables.c index 0fa208e86405ceab189042dd36e03fd3e6b893fd..fa108c46e8510d1cf447cd4501576d2fd9cf4934 100644 --- a/net/bridge/netfilter/ebtables.c +++ b/net/bridge/netfilter/ebtables.c @@ -55,7 +55,6 @@ static DEFINE_MUTEX(ebt_mutex); -static LIST_HEAD(ebt_tables); static struct xt_target ebt_standard_target = { .name = "standard", @@ -315,9 +314,11 @@ find_inlist_lock(struct list_head *head, const char *name, const char *prefix, } static inline struct ebt_table * -find_table_lock(const char *name, int *error, struct mutex *mutex) +find_table_lock(struct net *net, const char *name, int *error, + struct mutex *mutex) { - return find_inlist_lock(&ebt_tables, name, "ebtable_", error, mutex); + return find_inlist_lock(&net->xt.tables[NFPROTO_BRIDGE], name, + "ebtable_", error, mutex); } static inline int @@ -944,7 +945,7 @@ static void get_counters(struct ebt_counter *oldcounters, } /* replace the table */ -static int do_replace(void __user *user, unsigned int len) +static int do_replace(struct net *net, void __user *user, unsigned int len) { int ret, i, countersize; struct ebt_table_info *newinfo; @@ -1016,7 +1017,7 @@ static int do_replace(void __user *user, unsigned int len) if (ret != 0) goto free_counterstmp; - t = find_table_lock(tmp.name, &ret, &ebt_mutex); + t = find_table_lock(net, tmp.name, &ret, &ebt_mutex); if (!t) { ret = -ENOENT; goto free_iterate; @@ -1097,7 +1098,7 @@ free_newinfo: return ret; } -int ebt_register_table(struct ebt_table *table) +struct ebt_table *ebt_register_table(struct net *net, struct ebt_table *table) { struct ebt_table_info *newinfo; struct ebt_table *t; @@ -1109,14 +1110,21 @@ int ebt_register_table(struct ebt_table *table) repl->entries_size == 0 || repl->counters || table->private) { BUGPRINT("Bad table data for ebt_register_table!!!\n"); - return -EINVAL; + return ERR_PTR(-EINVAL); + } + + /* Don't add one table to multiple lists. */ + table = kmemdup(table, sizeof(struct ebt_table), GFP_KERNEL); + if (!table) { + ret = -ENOMEM; + goto out; } countersize = COUNTER_OFFSET(repl->nentries) * nr_cpu_ids; newinfo = vmalloc(sizeof(*newinfo) + countersize); ret = -ENOMEM; if (!newinfo) - return -ENOMEM; + goto free_table; p = vmalloc(repl->entries_size); if (!p) @@ -1148,7 +1156,7 @@ int ebt_register_table(struct ebt_table *table) if (table->check && table->check(newinfo, table->valid_hooks)) { BUGPRINT("The table doesn't like its own initial data, lol\n"); - return -EINVAL; + return ERR_PTR(-EINVAL); } table->private = newinfo; @@ -1157,7 +1165,7 @@ int ebt_register_table(struct ebt_table *table) if (ret != 0) goto free_chainstack; - list_for_each_entry(t, &ebt_tables, list) { + list_for_each_entry(t, &net->xt.tables[NFPROTO_BRIDGE], list) { if (strcmp(t->name, table->name) == 0) { ret = -EEXIST; BUGPRINT("Table name already exists\n"); @@ -1170,9 +1178,9 @@ int ebt_register_table(struct ebt_table *table) ret = -ENOENT; goto free_unlock; } - list_add(&table->list, &ebt_tables); + list_add(&table->list, &net->xt.tables[NFPROTO_BRIDGE]); mutex_unlock(&ebt_mutex); - return 0; + return table; free_unlock: mutex_unlock(&ebt_mutex); free_chainstack: @@ -1184,7 +1192,10 @@ free_chainstack: vfree(newinfo->entries); free_newinfo: vfree(newinfo); - return ret; +free_table: + kfree(table); +out: + return ERR_PTR(ret); } void ebt_unregister_table(struct ebt_table *table) @@ -1198,6 +1209,10 @@ void ebt_unregister_table(struct ebt_table *table) mutex_lock(&ebt_mutex); list_del(&table->list); mutex_unlock(&ebt_mutex); + EBT_ENTRY_ITERATE(table->private->entries, table->private->entries_size, + ebt_cleanup_entry, NULL); + if (table->private->nentries) + module_put(table->me); vfree(table->private->entries); if (table->private->chainstack) { for_each_possible_cpu(i) @@ -1205,10 +1220,11 @@ void ebt_unregister_table(struct ebt_table *table) vfree(table->private->chainstack); } vfree(table->private); + kfree(table); } /* userspace just supplied us with counters */ -static int update_counters(void __user *user, unsigned int len) +static int update_counters(struct net *net, void __user *user, unsigned int len) { int i, ret; struct ebt_counter *tmp; @@ -1228,7 +1244,7 @@ static int update_counters(void __user *user, unsigned int len) return -ENOMEM; } - t = find_table_lock(hlp.name, &ret, &ebt_mutex); + t = find_table_lock(net, hlp.name, &ret, &ebt_mutex); if (!t) goto free_tmp; @@ -1386,10 +1402,10 @@ static int do_ebt_set_ctl(struct sock *sk, switch(cmd) { case EBT_SO_SET_ENTRIES: - ret = do_replace(user, len); + ret = do_replace(sock_net(sk), user, len); break; case EBT_SO_SET_COUNTERS: - ret = update_counters(user, len); + ret = update_counters(sock_net(sk), user, len); break; default: ret = -EINVAL; @@ -1406,7 +1422,7 @@ static int do_ebt_get_ctl(struct sock *sk, int cmd, void __user *user, int *len) if (copy_from_user(&tmp, user, sizeof(tmp))) return -EFAULT; - t = find_table_lock(tmp.name, &ret, &ebt_mutex); + t = find_table_lock(sock_net(sk), tmp.name, &ret, &ebt_mutex); if (!t) return ret; diff --git a/net/can/raw.c b/net/can/raw.c index 6e0663faaf9fcdea78d0f57947489e429d764cdd..27aab63df467cce099bc05ce8e1da51ef48ef666 100644 --- a/net/can/raw.c +++ b/net/can/raw.c @@ -641,17 +641,12 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err); - if (!skb) { - dev_put(dev); - return err; - } + if (!skb) + goto put_dev; err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); - if (err < 0) { - kfree_skb(skb); - dev_put(dev); - return err; - } + if (err < 0) + goto free_skb; skb->dev = dev; skb->sk = sk; @@ -660,9 +655,16 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock, dev_put(dev); if (err) - return err; + goto send_failed; return size; + +free_skb: + kfree_skb(skb); +put_dev: + dev_put(dev); +send_failed: + return err; } static int raw_recvmsg(struct kiocb *iocb, struct socket *sock, diff --git a/net/core/datagram.c b/net/core/datagram.c index ee631843c2f533de37101e92d05d447f85cf4d1f..5e2ac0c4b07cfdab7b2a5a2c74e2c2ddcd337328 100644 --- a/net/core/datagram.c +++ b/net/core/datagram.c @@ -209,7 +209,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, void skb_free_datagram(struct sock *sk, struct sk_buff *skb) { kfree_skb(skb); - sk_mem_reclaim(sk); + sk_mem_reclaim_partial(sk); } /** @@ -248,8 +248,7 @@ int skb_kill_datagram(struct sock *sk, struct sk_buff *skb, unsigned int flags) spin_unlock_bh(&sk->sk_receive_queue.lock); } - kfree_skb(skb); - sk_mem_reclaim(sk); + skb_free_datagram(sk, skb); return err; } diff --git a/net/core/dev.c b/net/core/dev.c index 89912ae6de651f5931cd76fe79b278e20addf4ad..446424027d245d6a9583e0da918e09e3d3241d3a 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -108,7 +108,6 @@ #include #include #include -#include #include #include #include @@ -130,6 +129,9 @@ #include "net-sysfs.h" +/* Instead of increasing this, you should create a hash table. */ +#define MAX_GRO_SKBS 8 + /* * The list of packet types we will receive (as opposed to discard) * and the routines to invoke. @@ -281,8 +283,8 @@ static const unsigned short netdev_lock_type[] = ARPHRD_PIMREG, ARPHRD_HIPPI, ARPHRD_ASH, ARPHRD_ECONET, ARPHRD_IRDA, ARPHRD_FCPP, ARPHRD_FCAL, ARPHRD_FCPL, ARPHRD_FCFABRIC, ARPHRD_IEEE802_TR, ARPHRD_IEEE80211, - ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_VOID, - ARPHRD_NONE}; + ARPHRD_IEEE80211_PRISM, ARPHRD_IEEE80211_RADIOTAP, ARPHRD_PHONET, + ARPHRD_PHONET_PIPE, ARPHRD_VOID, ARPHRD_NONE}; static const char *netdev_lock_name[] = {"_xmit_NETROM", "_xmit_ETHER", "_xmit_EETHER", "_xmit_AX25", @@ -298,8 +300,8 @@ static const char *netdev_lock_name[] = "_xmit_PIMREG", "_xmit_HIPPI", "_xmit_ASH", "_xmit_ECONET", "_xmit_IRDA", "_xmit_FCPP", "_xmit_FCAL", "_xmit_FCPL", "_xmit_FCFABRIC", "_xmit_IEEE802_TR", "_xmit_IEEE80211", - "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_VOID", - "_xmit_NONE"}; + "_xmit_IEEE80211_PRISM", "_xmit_IEEE80211_RADIOTAP", "_xmit_PHONET", + "_xmit_PHONET_PIPE", "_xmit_VOID", "_xmit_NONE"}; static struct lock_class_key netdev_xmit_lock_key[ARRAY_SIZE(netdev_lock_type)]; static struct lock_class_key netdev_addr_lock_key[ARRAY_SIZE(netdev_lock_type)]; @@ -924,10 +926,15 @@ int dev_change_name(struct net_device *dev, const char *newname) strlcpy(dev->name, newname, IFNAMSIZ); rollback: - ret = device_rename(&dev->dev, dev->name); - if (ret) { - memcpy(dev->name, oldname, IFNAMSIZ); - return ret; + /* For now only devices in the initial network namespace + * are in sysfs. + */ + if (net == &init_net) { + ret = device_rename(&dev->dev, dev->name); + if (ret) { + memcpy(dev->name, oldname, IFNAMSIZ); + return ret; + } } write_lock_bh(&dev_base_lock); @@ -1055,6 +1062,7 @@ void dev_load(struct net *net, const char *name) */ int dev_open(struct net_device *dev) { + const struct net_device_ops *ops = dev->netdev_ops; int ret = 0; ASSERT_RTNL(); @@ -1077,11 +1085,11 @@ int dev_open(struct net_device *dev) */ set_bit(__LINK_STATE_START, &dev->state); - if (dev->validate_addr) - ret = dev->validate_addr(dev); + if (ops->ndo_validate_addr) + ret = ops->ndo_validate_addr(dev); - if (!ret && dev->open) - ret = dev->open(dev); + if (!ret && ops->ndo_open) + ret = ops->ndo_open(dev); /* * If it went open OK then: @@ -1125,6 +1133,7 @@ int dev_open(struct net_device *dev) */ int dev_close(struct net_device *dev) { + const struct net_device_ops *ops = dev->netdev_ops; ASSERT_RTNL(); might_sleep(); @@ -1157,8 +1166,8 @@ int dev_close(struct net_device *dev) * We allow it to be called even after a DETACH hot-plug * event. */ - if (dev->stop) - dev->stop(dev); + if (ops->ndo_stop) + ops->ndo_stop(dev); /* * Device is now down. @@ -1527,8 +1536,6 @@ struct sk_buff *skb_gso_segment(struct sk_buff *skb, int features) __be16 type = skb->protocol; int err; - BUG_ON(skb_shinfo(skb)->frag_list); - skb_reset_mac_header(skb); skb->mac_len = skb->network_header - skb->mac_header; __skb_pull(skb, skb->mac_len); @@ -1654,6 +1661,9 @@ static int dev_gso_segment(struct sk_buff *skb) int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq) { + const struct net_device_ops *ops = dev->netdev_ops; + + prefetch(&dev->netdev_ops->ndo_start_xmit); if (likely(!skb->next)) { if (!list_empty(&ptype_all)) dev_queue_xmit_nit(skb, dev); @@ -1665,7 +1675,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, goto gso; } - return dev->hard_start_xmit(skb, dev); + return ops->ndo_start_xmit(skb, dev); } gso: @@ -1675,7 +1685,7 @@ gso: skb->next = nskb->next; nskb->next = NULL; - rc = dev->hard_start_xmit(nskb, dev); + rc = ops->ndo_start_xmit(nskb, dev); if (unlikely(rc)) { nskb->next = skb->next; skb->next = nskb; @@ -1749,10 +1759,11 @@ static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb) static struct netdev_queue *dev_pick_tx(struct net_device *dev, struct sk_buff *skb) { + const struct net_device_ops *ops = dev->netdev_ops; u16 queue_index = 0; - if (dev->select_queue) - queue_index = dev->select_queue(dev, skb); + if (ops->ndo_select_queue) + queue_index = ops->ndo_select_queue(dev, skb); else if (dev->real_num_tx_queues > 1) queue_index = simple_tx_hash(dev, skb); @@ -2251,8 +2262,10 @@ int netif_receive_skb(struct sk_buff *skb) rcu_read_lock(); /* Don't receive packets in an exiting network namespace */ - if (!net_alive(dev_net(skb->dev))) + if (!net_alive(dev_net(skb->dev))) { + kfree_skb(skb); goto out; + } #ifdef CONFIG_NET_CLS_ACT if (skb->tc_verd & TC_NCLS) { @@ -2325,6 +2338,125 @@ static void flush_backlog(void *arg) } } +static int napi_gro_complete(struct sk_buff *skb) +{ + struct packet_type *ptype; + __be16 type = skb->protocol; + struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK]; + int err = -ENOENT; + + if (!skb_shinfo(skb)->frag_list) + goto out; + + rcu_read_lock(); + list_for_each_entry_rcu(ptype, head, list) { + if (ptype->type != type || ptype->dev || !ptype->gro_complete) + continue; + + err = ptype->gro_complete(skb); + break; + } + rcu_read_unlock(); + + if (err) { + WARN_ON(&ptype->list == head); + kfree_skb(skb); + return NET_RX_SUCCESS; + } + +out: + __skb_push(skb, -skb_network_offset(skb)); + return netif_receive_skb(skb); +} + +void napi_gro_flush(struct napi_struct *napi) +{ + struct sk_buff *skb, *next; + + for (skb = napi->gro_list; skb; skb = next) { + next = skb->next; + skb->next = NULL; + napi_gro_complete(skb); + } + + napi->gro_list = NULL; +} +EXPORT_SYMBOL(napi_gro_flush); + +int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb) +{ + struct sk_buff **pp = NULL; + struct packet_type *ptype; + __be16 type = skb->protocol; + struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK]; + int count = 0; + int same_flow; + int mac_len; + + if (!(skb->dev->features & NETIF_F_GRO)) + goto normal; + + rcu_read_lock(); + list_for_each_entry_rcu(ptype, head, list) { + struct sk_buff *p; + + if (ptype->type != type || ptype->dev || !ptype->gro_receive) + continue; + + skb_reset_network_header(skb); + mac_len = skb->network_header - skb->mac_header; + skb->mac_len = mac_len; + NAPI_GRO_CB(skb)->same_flow = 0; + NAPI_GRO_CB(skb)->flush = 0; + + for (p = napi->gro_list; p; p = p->next) { + count++; + NAPI_GRO_CB(p)->same_flow = + p->mac_len == mac_len && + !memcmp(skb_mac_header(p), skb_mac_header(skb), + mac_len); + NAPI_GRO_CB(p)->flush = 0; + } + + pp = ptype->gro_receive(&napi->gro_list, skb); + break; + } + rcu_read_unlock(); + + if (&ptype->list == head) + goto normal; + + same_flow = NAPI_GRO_CB(skb)->same_flow; + + if (pp) { + struct sk_buff *nskb = *pp; + + *pp = nskb->next; + nskb->next = NULL; + napi_gro_complete(nskb); + count--; + } + + if (same_flow) + goto ok; + + if (NAPI_GRO_CB(skb)->flush || count >= MAX_GRO_SKBS) { + __skb_push(skb, -skb_network_offset(skb)); + goto normal; + } + + NAPI_GRO_CB(skb)->count = 1; + skb->next = napi->gro_list; + napi->gro_list = skb; + +ok: + return NET_RX_SUCCESS; + +normal: + return netif_receive_skb(skb); +} +EXPORT_SYMBOL(napi_gro_receive); + static int process_backlog(struct napi_struct *napi, int quota) { int work = 0; @@ -2344,9 +2476,11 @@ static int process_backlog(struct napi_struct *napi, int quota) } local_irq_enable(); - netif_receive_skb(skb); + napi_gro_receive(napi, skb); } while (++work < quota && jiffies == start_time); + napi_gro_flush(napi); + return work; } @@ -2367,11 +2501,73 @@ void __napi_schedule(struct napi_struct *n) } EXPORT_SYMBOL(__napi_schedule); +void __napi_complete(struct napi_struct *n) +{ + BUG_ON(!test_bit(NAPI_STATE_SCHED, &n->state)); + BUG_ON(n->gro_list); + + list_del(&n->poll_list); + smp_mb__before_clear_bit(); + clear_bit(NAPI_STATE_SCHED, &n->state); +} +EXPORT_SYMBOL(__napi_complete); + +void napi_complete(struct napi_struct *n) +{ + unsigned long flags; + + /* + * don't let napi dequeue from the cpu poll list + * just in case its running on a different cpu + */ + if (unlikely(test_bit(NAPI_STATE_NPSVC, &n->state))) + return; + + napi_gro_flush(n); + local_irq_save(flags); + __napi_complete(n); + local_irq_restore(flags); +} +EXPORT_SYMBOL(napi_complete); + +void netif_napi_add(struct net_device *dev, struct napi_struct *napi, + int (*poll)(struct napi_struct *, int), int weight) +{ + INIT_LIST_HEAD(&napi->poll_list); + napi->gro_list = NULL; + napi->poll = poll; + napi->weight = weight; + list_add(&napi->dev_list, &dev->napi_list); +#ifdef CONFIG_NETPOLL + napi->dev = dev; + spin_lock_init(&napi->poll_lock); + napi->poll_owner = -1; +#endif + set_bit(NAPI_STATE_SCHED, &napi->state); +} +EXPORT_SYMBOL(netif_napi_add); + +void netif_napi_del(struct napi_struct *napi) +{ + struct sk_buff *skb, *next; + + list_del_init(&napi->dev_list); + + for (skb = napi->gro_list; skb; skb = next) { + next = skb->next; + skb->next = NULL; + kfree_skb(skb); + } + + napi->gro_list = NULL; +} +EXPORT_SYMBOL(netif_napi_del); + static void net_rx_action(struct softirq_action *h) { struct list_head *list = &__get_cpu_var(softnet_data).poll_list; - unsigned long start_time = jiffies; + unsigned long time_limit = jiffies + 2; int budget = netdev_budget; void *have; @@ -2382,13 +2578,10 @@ static void net_rx_action(struct softirq_action *h) int work, weight; /* If softirq window is exhuasted then punt. - * - * Note that this is a slight policy change from the - * previous NAPI code, which would allow up to 2 - * jiffies to pass before breaking out. The test - * used to be "jiffies - start_time > 1". + * Allow this to run for 2 jiffies since which will allow + * an average latency of 1.5/HZ. */ - if (unlikely(budget <= 0 || jiffies != start_time)) + if (unlikely(budget <= 0 || time_after(jiffies, time_limit))) goto softnet_break; local_irq_enable(); @@ -2615,7 +2808,7 @@ void dev_seq_stop(struct seq_file *seq, void *v) static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev) { - struct net_device_stats *stats = dev->get_stats(dev); + const struct net_device_stats *stats = dev_get_stats(dev); seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", @@ -2797,31 +2990,6 @@ static void ptype_seq_stop(struct seq_file *seq, void *v) rcu_read_unlock(); } -static void ptype_seq_decode(struct seq_file *seq, void *sym) -{ -#ifdef CONFIG_KALLSYMS - unsigned long offset = 0, symsize; - const char *symname; - char *modname; - char namebuf[128]; - - symname = kallsyms_lookup((unsigned long)sym, &symsize, &offset, - &modname, namebuf); - - if (symname) { - char *delim = ":"; - - if (!modname) - modname = delim = ""; - seq_printf(seq, "%s%s%s%s+0x%lx", delim, modname, delim, - symname, offset); - return; - } -#endif - - seq_printf(seq, "[%p]", sym); -} - static int ptype_seq_show(struct seq_file *seq, void *v) { struct packet_type *pt = v; @@ -2834,10 +3002,8 @@ static int ptype_seq_show(struct seq_file *seq, void *v) else seq_printf(seq, "%04x", ntohs(pt->type)); - seq_printf(seq, " %-8s ", - pt->dev ? pt->dev->name : ""); - ptype_seq_decode(seq, pt->func); - seq_putc(seq, '\n'); + seq_printf(seq, " %-8s %pF\n", + pt->dev ? pt->dev->name : "", pt->func); } return 0; @@ -2954,8 +3120,10 @@ int netdev_set_master(struct net_device *slave, struct net_device *master) static void dev_change_rx_flags(struct net_device *dev, int flags) { - if (dev->flags & IFF_UP && dev->change_rx_flags) - dev->change_rx_flags(dev, flags); + const struct net_device_ops *ops = dev->netdev_ops; + + if ((dev->flags & IFF_UP) && ops->ndo_change_rx_flags) + ops->ndo_change_rx_flags(dev, flags); } static int __dev_set_promiscuity(struct net_device *dev, int inc) @@ -3079,6 +3247,8 @@ int dev_set_allmulti(struct net_device *dev, int inc) */ void __dev_set_rx_mode(struct net_device *dev) { + const struct net_device_ops *ops = dev->netdev_ops; + /* dev_open will call this function so the list will stay sane. */ if (!(dev->flags&IFF_UP)) return; @@ -3086,8 +3256,8 @@ void __dev_set_rx_mode(struct net_device *dev) if (!netif_device_present(dev)) return; - if (dev->set_rx_mode) - dev->set_rx_mode(dev); + if (ops->ndo_set_rx_mode) + ops->ndo_set_rx_mode(dev); else { /* Unicast addresses changes may only happen under the rtnl, * therefore calling __dev_set_promiscuity here is safe. @@ -3100,8 +3270,8 @@ void __dev_set_rx_mode(struct net_device *dev) dev->uc_promisc = 0; } - if (dev->set_multicast_list) - dev->set_multicast_list(dev); + if (ops->ndo_set_multicast_list) + ops->ndo_set_multicast_list(dev); } } @@ -3460,6 +3630,7 @@ int dev_change_flags(struct net_device *dev, unsigned flags) */ int dev_set_mtu(struct net_device *dev, int new_mtu) { + const struct net_device_ops *ops = dev->netdev_ops; int err; if (new_mtu == dev->mtu) @@ -3473,10 +3644,11 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) return -ENODEV; err = 0; - if (dev->change_mtu) - err = dev->change_mtu(dev, new_mtu); + if (ops->ndo_change_mtu) + err = ops->ndo_change_mtu(dev, new_mtu); else dev->mtu = new_mtu; + if (!err && dev->flags & IFF_UP) call_netdevice_notifiers(NETDEV_CHANGEMTU, dev); return err; @@ -3491,15 +3663,16 @@ int dev_set_mtu(struct net_device *dev, int new_mtu) */ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa) { + const struct net_device_ops *ops = dev->netdev_ops; int err; - if (!dev->set_mac_address) + if (!ops->ndo_set_mac_address) return -EOPNOTSUPP; if (sa->sa_family != dev->type) return -EINVAL; if (!netif_device_present(dev)) return -ENODEV; - err = dev->set_mac_address(dev, sa); + err = ops->ndo_set_mac_address(dev, sa); if (!err) call_netdevice_notifiers(NETDEV_CHANGEADDR, dev); return err; @@ -3579,10 +3752,13 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) { int err; struct net_device *dev = __dev_get_by_name(net, ifr->ifr_name); + const struct net_device_ops *ops; if (!dev) return -ENODEV; + ops = dev->netdev_ops; + switch (cmd) { case SIOCSIFFLAGS: /* Set interface flags */ return dev_change_flags(dev, ifr->ifr_flags); @@ -3606,15 +3782,15 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) return 0; case SIOCSIFMAP: - if (dev->set_config) { + if (ops->ndo_set_config) { if (!netif_device_present(dev)) return -ENODEV; - return dev->set_config(dev, &ifr->ifr_map); + return ops->ndo_set_config(dev, &ifr->ifr_map); } return -EOPNOTSUPP; case SIOCADDMULTI: - if ((!dev->set_multicast_list && !dev->set_rx_mode) || + if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) || ifr->ifr_hwaddr.sa_family != AF_UNSPEC) return -EINVAL; if (!netif_device_present(dev)) @@ -3623,7 +3799,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) dev->addr_len, 1); case SIOCDELMULTI: - if ((!dev->set_multicast_list && !dev->set_rx_mode) || + if ((!ops->ndo_set_multicast_list && !ops->ndo_set_rx_mode) || ifr->ifr_hwaddr.sa_family != AF_UNSPEC) return -EINVAL; if (!netif_device_present(dev)) @@ -3661,10 +3837,9 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd) cmd == SIOCBRDELIF || cmd == SIOCWANDEV) { err = -EOPNOTSUPP; - if (dev->do_ioctl) { + if (ops->ndo_do_ioctl) { if (netif_device_present(dev)) - err = dev->do_ioctl(dev, ifr, - cmd); + err = ops->ndo_do_ioctl(dev, ifr, cmd); else err = -ENODEV; } @@ -3925,8 +4100,8 @@ static void rollback_registered(struct net_device *dev) */ dev_addr_discard(dev); - if (dev->uninit) - dev->uninit(dev); + if (dev->netdev_ops->ndo_uninit) + dev->netdev_ops->ndo_uninit(dev); /* Notifier chain MUST detach us from master device. */ WARN_ON(dev->master); @@ -4016,7 +4191,7 @@ int register_netdevice(struct net_device *dev) struct hlist_head *head; struct hlist_node *p; int ret; - struct net *net; + struct net *net = dev_net(dev); BUG_ON(dev_boot_phase); ASSERT_RTNL(); @@ -4025,8 +4200,7 @@ int register_netdevice(struct net_device *dev) /* When net_device's are persistent, this will be fatal. */ BUG_ON(dev->reg_state != NETREG_UNINITIALIZED); - BUG_ON(!dev_net(dev)); - net = dev_net(dev); + BUG_ON(!net); spin_lock_init(&dev->addr_list_lock); netdev_set_addr_lockdep_class(dev); @@ -4034,9 +4208,46 @@ int register_netdevice(struct net_device *dev) dev->iflink = -1; +#ifdef CONFIG_COMPAT_NET_DEV_OPS + /* Netdevice_ops API compatiability support. + * This is temporary until all network devices are converted. + */ + if (dev->netdev_ops) { + const struct net_device_ops *ops = dev->netdev_ops; + + dev->init = ops->ndo_init; + dev->uninit = ops->ndo_uninit; + dev->open = ops->ndo_open; + dev->change_rx_flags = ops->ndo_change_rx_flags; + dev->set_rx_mode = ops->ndo_set_rx_mode; + dev->set_multicast_list = ops->ndo_set_multicast_list; + dev->set_mac_address = ops->ndo_set_mac_address; + dev->validate_addr = ops->ndo_validate_addr; + dev->do_ioctl = ops->ndo_do_ioctl; + dev->set_config = ops->ndo_set_config; + dev->change_mtu = ops->ndo_change_mtu; + dev->tx_timeout = ops->ndo_tx_timeout; + dev->get_stats = ops->ndo_get_stats; + dev->vlan_rx_register = ops->ndo_vlan_rx_register; + dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid; + dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = ops->ndo_poll_controller; +#endif + } else { + char drivername[64]; + pr_info("%s (%s): not using net_device_ops yet\n", + dev->name, netdev_drivername(dev, drivername, 64)); + + /* This works only because net_device_ops and the + compatiablity structure are the same. */ + dev->netdev_ops = (void *) &(dev->init); + } +#endif + /* Init, if this function is available */ - if (dev->init) { - ret = dev->init(dev); + if (dev->netdev_ops->ndo_init) { + ret = dev->netdev_ops->ndo_init(dev); if (ret) { if (ret > 0) ret = -EIO; @@ -4114,8 +4325,8 @@ out: return ret; err_uninit: - if (dev->uninit) - dev->uninit(dev); + if (dev->netdev_ops->ndo_uninit) + dev->netdev_ops->ndo_uninit(dev); goto out; } @@ -4271,10 +4482,24 @@ void netdev_run_todo(void) } } -static struct net_device_stats *internal_stats(struct net_device *dev) -{ - return &dev->stats; +/** + * dev_get_stats - get network device statistics + * @dev: device to get statistics from + * + * Get network statistics from device. The device driver may provide + * its own method by setting dev->netdev_ops->get_stats; otherwise + * the internal statistics structure is used. + */ +const struct net_device_stats *dev_get_stats(struct net_device *dev) + { + const struct net_device_ops *ops = dev->netdev_ops; + + if (ops->ndo_get_stats) + return ops->ndo_get_stats(dev); + else + return &dev->stats; } +EXPORT_SYMBOL(dev_get_stats); static void netdev_init_one_queue(struct net_device *dev, struct netdev_queue *queue, @@ -4343,18 +4568,11 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name, dev->num_tx_queues = queue_count; dev->real_num_tx_queues = queue_count; - if (sizeof_priv) { - dev->priv = ((char *)dev + - ((sizeof(struct net_device) + NETDEV_ALIGN_CONST) - & ~NETDEV_ALIGN_CONST)); - } - dev->gso_max_size = GSO_MAX_SIZE; netdev_init_queues(dev); - dev->get_stats = internal_stats; - netpoll_netdev_init(dev); + INIT_LIST_HEAD(&dev->napi_list); setup(dev); strcpy(dev->name, name); return dev; @@ -4371,10 +4589,15 @@ EXPORT_SYMBOL(alloc_netdev_mq); */ void free_netdev(struct net_device *dev) { + struct napi_struct *p, *n; + release_net(dev_net(dev)); kfree(dev->_tx); + list_for_each_entry_safe(p, n, &dev->napi_list, dev_list) + netif_napi_del(p); + /* Compatibility with error handling in drivers */ if (dev->reg_state == NETREG_UNINITIALIZED) { kfree((char *)dev - dev->padded); @@ -4467,6 +4690,15 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char if (dev->features & NETIF_F_NETNS_LOCAL) goto out; +#ifdef CONFIG_SYSFS + /* Don't allow real devices to be moved when sysfs + * is enabled. + */ + err = -EINVAL; + if (dev->dev.parent) + goto out; +#endif + /* Ensure the device has been registrered */ err = -EINVAL; if (dev->reg_state != NETREG_REGISTERED) @@ -4524,6 +4756,8 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char */ dev_addr_discard(dev); + netdev_unregister_kobject(dev); + /* Actually switch the network namespace */ dev_net_set(dev, net); @@ -4540,7 +4774,6 @@ int dev_change_net_namespace(struct net_device *dev, struct net *net, const char } /* Fixup kobjects */ - netdev_unregister_kobject(dev); err = netdev_register_kobject(dev); WARN_ON(err); @@ -4847,6 +5080,12 @@ static void __net_exit default_device_exit(struct net *net) if (dev->features & NETIF_F_NETNS_LOCAL) continue; + /* Delete virtual devices */ + if (dev->rtnl_link_ops && dev->rtnl_link_ops->dellink) { + dev->rtnl_link_ops->dellink(dev); + continue; + } + /* Push remaing network devices to init_net */ snprintf(fb_name, IFNAMSIZ, "dev%d", dev->ifindex); err = dev_change_net_namespace(dev, &init_net, fb_name); @@ -4893,9 +5132,6 @@ static int __init net_dev_init(void) if (register_pernet_subsys(&netdev_net_ops)) goto out; - if (register_pernet_device(&default_device_ops)) - goto out; - /* * Initialise the packet receive queues. */ @@ -4910,12 +5146,28 @@ static int __init net_dev_init(void) queue->backlog.poll = process_backlog; queue->backlog.weight = weight_p; + queue->backlog.gro_list = NULL; } - netdev_dma_register(); - dev_boot_phase = 0; + /* The loopback device is special if any other network devices + * is present in a network namespace the loopback device must + * be present. Since we now dynamically allocate and free the + * loopback device ensure this invariant is maintained by + * keeping the loopback device as the first device on the + * list of network devices. Ensuring the loopback devices + * is the first device that appears and the last network device + * that disappears. + */ + if (register_pernet_device(&loopback_net_ops)) + goto out; + + if (register_pernet_device(&default_device_ops)) + goto out; + + netdev_dma_register(); + open_softirq(NET_TX_SOFTIRQ, net_tx_action); open_softirq(NET_RX_SOFTIRQ, net_rx_action); diff --git a/net/core/dst.c b/net/core/dst.c index 09c1530f46814d287929a37ce948885d44f8bb03..57bc4d5b8d084c053cded6ebddfe66bf6255d9f5 100644 --- a/net/core/dst.c +++ b/net/core/dst.c @@ -263,9 +263,11 @@ again: void dst_release(struct dst_entry *dst) { if (dst) { - WARN_ON(atomic_read(&dst->__refcnt) < 1); + int newrefcnt; + smp_mb__before_atomic_dec(); - atomic_dec(&dst->__refcnt); + newrefcnt = atomic_dec_return(&dst->__refcnt); + WARN_ON(newrefcnt < 0); } } EXPORT_SYMBOL(dst_release); diff --git a/net/core/ethtool.c b/net/core/ethtool.c index 14ada537f895c10f86006b63b4ba4f312eb610d3..947710a36ced534e0599a59dbd7860600e833376 100644 --- a/net/core/ethtool.c +++ b/net/core/ethtool.c @@ -528,6 +528,22 @@ static int ethtool_set_tx_csum(struct net_device *dev, char __user *useraddr) return dev->ethtool_ops->set_tx_csum(dev, edata.data); } +static int ethtool_set_rx_csum(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata; + + if (!dev->ethtool_ops->set_rx_csum) + return -EOPNOTSUPP; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + if (!edata.data && dev->ethtool_ops->set_sg) + dev->features &= ~NETIF_F_GRO; + + return dev->ethtool_ops->set_rx_csum(dev, edata.data); +} + static int ethtool_set_sg(struct net_device *dev, char __user *useraddr) { struct ethtool_value edata; @@ -599,6 +615,34 @@ static int ethtool_set_gso(struct net_device *dev, char __user *useraddr) return 0; } +static int ethtool_get_gro(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata = { ETHTOOL_GGRO }; + + edata.data = dev->features & NETIF_F_GRO; + if (copy_to_user(useraddr, &edata, sizeof(edata))) + return -EFAULT; + return 0; +} + +static int ethtool_set_gro(struct net_device *dev, char __user *useraddr) +{ + struct ethtool_value edata; + + if (copy_from_user(&edata, useraddr, sizeof(edata))) + return -EFAULT; + + if (edata.data) { + if (!dev->ethtool_ops->get_rx_csum || + !dev->ethtool_ops->get_rx_csum(dev)) + return -EINVAL; + dev->features |= NETIF_F_GRO; + } else + dev->features &= ~NETIF_F_GRO; + + return 0; +} + static int ethtool_self_test(struct net_device *dev, char __user *useraddr) { struct ethtool_test test; @@ -932,8 +976,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) dev->ethtool_ops->get_rx_csum); break; case ETHTOOL_SRXCSUM: - rc = ethtool_set_value(dev, useraddr, - dev->ethtool_ops->set_rx_csum); + rc = ethtool_set_rx_csum(dev, useraddr); break; case ETHTOOL_GTXCSUM: rc = ethtool_get_value(dev, useraddr, ethcmd, @@ -1014,6 +1057,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr) case ETHTOOL_SRXFH: rc = ethtool_set_rxhash(dev, useraddr); break; + case ETHTOOL_GGRO: + rc = ethtool_get_gro(dev, useraddr); + break; + case ETHTOOL_SGRO: + rc = ethtool_set_gro(dev, useraddr); + break; default: rc = -EOPNOTSUPP; } diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c index 79de3b14a8d13256f54aaea43d1e3c6c9092833c..32b3a0152d7adba2079e5a1bc5f5ba9001037996 100644 --- a/net/core/fib_rules.c +++ b/net/core/fib_rules.c @@ -664,17 +664,18 @@ static int __init fib_rules_init(void) rtnl_register(PF_UNSPEC, RTM_DELRULE, fib_nl_delrule, NULL); rtnl_register(PF_UNSPEC, RTM_GETRULE, NULL, fib_nl_dumprule); - err = register_netdevice_notifier(&fib_rules_notifier); + err = register_pernet_subsys(&fib_rules_net_ops); if (err < 0) goto fail; - err = register_pernet_subsys(&fib_rules_net_ops); + err = register_netdevice_notifier(&fib_rules_notifier); if (err < 0) goto fail_unregister; + return 0; fail_unregister: - unregister_netdevice_notifier(&fib_rules_notifier); + unregister_pernet_subsys(&fib_rules_net_ops); fail: rtnl_unregister(PF_UNSPEC, RTM_NEWRULE); rtnl_unregister(PF_UNSPEC, RTM_DELRULE); diff --git a/net/core/filter.c b/net/core/filter.c index df37443558395a01780f725e744a920fb1664872..d1d779ca096d6c70c3d556a8ae68a9255785cca0 100644 --- a/net/core/filter.c +++ b/net/core/filter.c @@ -319,6 +319,25 @@ load_b: A = 0; continue; } + case SKF_AD_NLATTR_NEST: { + struct nlattr *nla; + + if (skb_is_nonlinear(skb)) + return 0; + if (A > skb->len - sizeof(struct nlattr)) + return 0; + + nla = (struct nlattr *)&skb->data[A]; + if (nla->nla_len > A - skb->len) + return 0; + + nla = nla_find_nested(nla, X); + if (nla) + A = (void *)nla - (void *)skb->data; + else + A = 0; + continue; + } default: return 0; } diff --git a/net/core/flow.c b/net/core/flow.c index 5cf81052d044ef91710d51ff7ab2ec162bdd3be6..96015871eceadeacc65d8b572fdcf0d757ecccca 100644 --- a/net/core/flow.c +++ b/net/core/flow.c @@ -165,7 +165,7 @@ static int flow_key_compare(struct flowi *key1, struct flowi *key2) return 0; } -void *flow_cache_lookup(struct flowi *key, u16 family, u8 dir, +void *flow_cache_lookup(struct net *net, struct flowi *key, u16 family, u8 dir, flow_resolve_t resolver) { struct flow_cache_entry *fle, **head; @@ -225,7 +225,7 @@ nocache: void *obj; atomic_t *obj_ref; - err = resolver(key, family, dir, &obj, &obj_ref); + err = resolver(net, key, family, dir, &obj, &obj_ref); if (fle && !err) { fle->genid = atomic_read(&flow_cache_genid); @@ -307,7 +307,7 @@ void flow_cache_flush(void) put_online_cpus(); } -static void __devinit flow_cache_cpu_prepare(int cpu) +static void __init flow_cache_cpu_prepare(int cpu) { struct tasklet_struct *tasklet; unsigned long order; diff --git a/net/core/gen_estimator.c b/net/core/gen_estimator.c index 57abe8266be198dd483c71ce07cf3ce0757ced0e..9cc9f95b109e72abaa5135d99cd0665d889415fa 100644 --- a/net/core/gen_estimator.c +++ b/net/core/gen_estimator.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -89,6 +90,7 @@ struct gen_estimator u32 avpps; u32 avbps; struct rcu_head e_rcu; + struct rb_node node; }; struct gen_estimator_head @@ -102,6 +104,9 @@ static struct gen_estimator_head elist[EST_MAX_INTERVAL+1]; /* Protects against NULL dereference */ static DEFINE_RWLOCK(est_lock); +/* Protects against soft lockup during large deletion */ +static struct rb_root est_root = RB_ROOT; + static void est_timer(unsigned long arg) { int idx = (int)arg; @@ -139,6 +144,46 @@ skip: rcu_read_unlock(); } +static void gen_add_node(struct gen_estimator *est) +{ + struct rb_node **p = &est_root.rb_node, *parent = NULL; + + while (*p) { + struct gen_estimator *e; + + parent = *p; + e = rb_entry(parent, struct gen_estimator, node); + + if (est->bstats > e->bstats) + p = &parent->rb_right; + else + p = &parent->rb_left; + } + rb_link_node(&est->node, parent, p); + rb_insert_color(&est->node, &est_root); +} + +static +struct gen_estimator *gen_find_node(const struct gnet_stats_basic *bstats, + const struct gnet_stats_rate_est *rate_est) +{ + struct rb_node *p = est_root.rb_node; + + while (p) { + struct gen_estimator *e; + + e = rb_entry(p, struct gen_estimator, node); + + if (bstats > e->bstats) + p = p->rb_right; + else if (bstats < e->bstats || rate_est != e->rate_est) + p = p->rb_left; + else + return e; + } + return NULL; +} + /** * gen_new_estimator - create a new rate estimator * @bstats: basic statistics @@ -194,8 +239,11 @@ int gen_new_estimator(struct gnet_stats_basic *bstats, mod_timer(&elist[idx].timer, jiffies + ((HZ/4) << idx)); list_add_rcu(&est->list, &elist[idx].list); + gen_add_node(est); + return 0; } +EXPORT_SYMBOL(gen_new_estimator); static void __gen_kill_estimator(struct rcu_head *head) { @@ -209,36 +257,27 @@ static void __gen_kill_estimator(struct rcu_head *head) * @bstats: basic statistics * @rate_est: rate estimator statistics * - * Removes the rate estimator specified by &bstats and &rate_est - * and deletes the timer. + * Removes the rate estimator specified by &bstats and &rate_est. * * NOTE: Called under rtnl_mutex */ void gen_kill_estimator(struct gnet_stats_basic *bstats, - struct gnet_stats_rate_est *rate_est) + struct gnet_stats_rate_est *rate_est) { - int idx; - struct gen_estimator *e, *n; - - for (idx=0; idx <= EST_MAX_INTERVAL; idx++) { - - /* Skip non initialized indexes */ - if (!elist[idx].timer.function) - continue; + struct gen_estimator *e; - list_for_each_entry_safe(e, n, &elist[idx].list, list) { - if (e->rate_est != rate_est || e->bstats != bstats) - continue; + while ((e = gen_find_node(bstats, rate_est))) { + rb_erase(&e->node, &est_root); - write_lock_bh(&est_lock); - e->bstats = NULL; - write_unlock_bh(&est_lock); + write_lock_bh(&est_lock); + e->bstats = NULL; + write_unlock_bh(&est_lock); - list_del_rcu(&e->list); - call_rcu(&e->e_rcu, __gen_kill_estimator); - } + list_del_rcu(&e->list); + call_rcu(&e->e_rcu, __gen_kill_estimator); } } +EXPORT_SYMBOL(gen_kill_estimator); /** * gen_replace_estimator - replace rate estimator configuration @@ -259,8 +298,20 @@ int gen_replace_estimator(struct gnet_stats_basic *bstats, gen_kill_estimator(bstats, rate_est); return gen_new_estimator(bstats, rate_est, stats_lock, opt); } +EXPORT_SYMBOL(gen_replace_estimator); +/** + * gen_estimator_active - test if estimator is currently in use + * @bstats: basic statistics + * @rate_est: rate estimator statistics + * + * Returns true if estimator is active, and false if not. + */ +bool gen_estimator_active(const struct gnet_stats_basic *bstats, + const struct gnet_stats_rate_est *rate_est) +{ + ASSERT_RTNL(); -EXPORT_SYMBOL(gen_kill_estimator); -EXPORT_SYMBOL(gen_new_estimator); -EXPORT_SYMBOL(gen_replace_estimator); + return gen_find_node(bstats, rate_est) != NULL; +} +EXPORT_SYMBOL(gen_estimator_active); diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 1dc728b38589699d4b85b215208bf6f0bde154f9..9c3717a23cf76648bd17452bb422f32b91b26ce1 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -531,9 +531,7 @@ struct pneigh_entry * pneigh_lookup(struct neigh_table *tbl, if (!n) goto out; -#ifdef CONFIG_NET_NS - n->net = hold_net(net); -#endif + write_pnet(&n->net, hold_net(net)); memcpy(n->key, pkey, key_len); n->dev = dev; if (dev) @@ -1329,9 +1327,9 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, struct neigh_table *tbl) { struct neigh_parms *p, *ref; - struct net *net; + struct net *net = dev_net(dev); + const struct net_device_ops *ops = dev->netdev_ops; - net = dev_net(dev); ref = lookup_neigh_params(tbl, net, 0); if (!ref) return NULL; @@ -1340,20 +1338,17 @@ struct neigh_parms *neigh_parms_alloc(struct net_device *dev, if (p) { p->tbl = tbl; atomic_set(&p->refcnt, 1); - INIT_RCU_HEAD(&p->rcu_head); p->reachable_time = neigh_rand_reach_time(p->base_reachable_time); - if (dev->neigh_setup && dev->neigh_setup(dev, p)) { + if (ops->ndo_neigh_setup && ops->ndo_neigh_setup(dev, p)) { kfree(p); return NULL; } dev_hold(dev); p->dev = dev; -#ifdef CONFIG_NET_NS - p->net = hold_net(net); -#endif + write_pnet(&p->net, hold_net(net)); p->sysctl_table = NULL; write_lock_bh(&tbl->lock); p->next = tbl->parms.next; @@ -1408,11 +1403,8 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) unsigned long now = jiffies; unsigned long phsize; -#ifdef CONFIG_NET_NS - tbl->parms.net = &init_net; -#endif + write_pnet(&tbl->parms.net, &init_net); atomic_set(&tbl->parms.refcnt, 1); - INIT_RCU_HEAD(&tbl->parms.rcu_head); tbl->parms.reachable_time = neigh_rand_reach_time(tbl->parms.base_reachable_time); @@ -1426,9 +1418,8 @@ void neigh_table_init_no_netlink(struct neigh_table *tbl) panic("cannot create neighbour cache statistics"); #ifdef CONFIG_PROC_FS - tbl->pde = proc_create_data(tbl->id, 0, init_net.proc_net_stat, - &neigh_stat_seq_fops, tbl); - if (!tbl->pde) + if (!proc_create_data(tbl->id, 0, init_net.proc_net_stat, + &neigh_stat_seq_fops, tbl)) panic("cannot create neighbour proc dir entry"); #endif @@ -2568,128 +2559,128 @@ static struct neigh_sysctl_table { .procname = "mcast_solicit", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NEIGH_UCAST_SOLICIT, .procname = "ucast_solicit", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NEIGH_APP_SOLICIT, .procname = "app_solicit", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .procname = "retrans_time", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_userhz_jiffies, + .proc_handler = proc_dointvec_userhz_jiffies, }, { .ctl_name = NET_NEIGH_REACHABLE_TIME, .procname = "base_reachable_time", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_NEIGH_DELAY_PROBE_TIME, .procname = "delay_first_probe_time", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_NEIGH_GC_STALE_TIME, .procname = "gc_stale_time", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_NEIGH_UNRES_QLEN, .procname = "unres_qlen", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NEIGH_PROXY_QLEN, .procname = "proxy_qlen", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .procname = "anycast_delay", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_userhz_jiffies, + .proc_handler = proc_dointvec_userhz_jiffies, }, { .procname = "proxy_delay", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_userhz_jiffies, + .proc_handler = proc_dointvec_userhz_jiffies, }, { .procname = "locktime", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_userhz_jiffies, + .proc_handler = proc_dointvec_userhz_jiffies, }, { .ctl_name = NET_NEIGH_RETRANS_TIME_MS, .procname = "retrans_time_ms", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_ms_jiffies, - .strategy = &sysctl_ms_jiffies, + .proc_handler = proc_dointvec_ms_jiffies, + .strategy = sysctl_ms_jiffies, }, { .ctl_name = NET_NEIGH_REACHABLE_TIME_MS, .procname = "base_reachable_time_ms", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_ms_jiffies, - .strategy = &sysctl_ms_jiffies, + .proc_handler = proc_dointvec_ms_jiffies, + .strategy = sysctl_ms_jiffies, }, { .ctl_name = NET_NEIGH_GC_INTERVAL, .procname = "gc_interval", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_NEIGH_GC_THRESH1, .procname = "gc_thresh1", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NEIGH_GC_THRESH2, .procname = "gc_thresh2", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NEIGH_GC_THRESH3, .procname = "gc_thresh3", .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, {}, }, diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index 92d6b946731430ddb9b5533498bc6e04c104c3c0..6ac29a46e23e188be0c3f246c7ff77e538d04ab1 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -270,7 +270,6 @@ static ssize_t netstat_show(const struct device *d, unsigned long offset) { struct net_device *dev = to_net_dev(d); - struct net_device_stats *stats; ssize_t ret = -EINVAL; WARN_ON(offset > sizeof(struct net_device_stats) || @@ -278,7 +277,7 @@ static ssize_t netstat_show(const struct device *d, read_lock(&dev_base_lock); if (dev_isalive(dev)) { - stats = dev->get_stats(dev); + const struct net_device_stats *stats = dev_get_stats(dev); ret = sprintf(buf, fmt_ulong, *(unsigned long *)(((u8 *) stats) + offset)); } @@ -428,6 +427,9 @@ static int netdev_uevent(struct device *d, struct kobj_uevent_env *env) struct net_device *dev = to_net_dev(d); int retval; + if (!net_eq(dev_net(dev), &init_net)) + return 0; + /* pass interface to uevent. */ retval = add_uevent_var(env, "INTERFACE=%s", dev->name); if (retval) @@ -476,6 +478,10 @@ void netdev_unregister_kobject(struct net_device * net) struct device *dev = &(net->dev); kobject_get(&dev->kobj); + + if (dev_net(net) != &init_net) + return; + device_del(dev); } @@ -490,7 +496,7 @@ int netdev_register_kobject(struct net_device *net) dev->groups = groups; BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ); - strlcpy(dev->bus_id, net->name, BUS_ID_SIZE); + dev_set_name(dev, net->name); #ifdef CONFIG_SYSFS *groups++ = &netstat_group; @@ -501,6 +507,9 @@ int netdev_register_kobject(struct net_device *net) #endif #endif /* CONFIG_SYSFS */ + if (dev_net(net) != &init_net) + return 0; + return device_add(dev); } diff --git a/net/core/net_namespace.c b/net/core/net_namespace.c index 1895a4ca9c4f7878467afee19ab714f072c76d57..55cffad2f328349f8c5363a89a55f0e503beba85 100644 --- a/net/core/net_namespace.c +++ b/net/core/net_namespace.c @@ -47,7 +47,6 @@ static __net_init int setup_net(struct net *net) goto out; ng->len = INITIAL_NET_GEN_PTRS; - INIT_RCU_HEAD(&ng->rcu); rcu_assign_pointer(net->gen, ng); error = 0; @@ -478,7 +477,6 @@ int net_assign_generic(struct net *net, int id, void *data) */ ng->len = id; - INIT_RCU_HEAD(&ng->rcu); memcpy(&ng->ptr, &old_ng->ptr, old_ng->len); rcu_assign_pointer(net->gen, ng); diff --git a/net/core/netpoll.c b/net/core/netpoll.c index dadac6281f20392d0431d80a9001a6169ab94ca7..755414cd49d10c8d65c6366bceb2618edf261f75 100644 --- a/net/core/netpoll.c +++ b/net/core/netpoll.c @@ -58,6 +58,7 @@ static void queue_process(struct work_struct *work) while ((skb = skb_dequeue(&npinfo->txq))) { struct net_device *dev = skb->dev; + const struct net_device_ops *ops = dev->netdev_ops; struct netdev_queue *txq; if (!netif_device_present(dev) || !netif_running(dev)) { @@ -71,7 +72,7 @@ static void queue_process(struct work_struct *work) __netif_tx_lock(txq, smp_processor_id()); if (netif_tx_queue_stopped(txq) || netif_tx_queue_frozen(txq) || - dev->hard_start_xmit(skb, dev) != NETDEV_TX_OK) { + ops->ndo_start_xmit(skb, dev) != NETDEV_TX_OK) { skb_queue_head(&npinfo->txq, skb); __netif_tx_unlock(txq); local_irq_restore(flags); @@ -174,12 +175,13 @@ static void service_arp_queue(struct netpoll_info *npi) void netpoll_poll(struct netpoll *np) { struct net_device *dev = np->dev; + const struct net_device_ops *ops = dev->netdev_ops; - if (!dev || !netif_running(dev) || !dev->poll_controller) + if (!dev || !netif_running(dev) || !ops->ndo_poll_controller) return; /* Process pending work on NIC */ - dev->poll_controller(dev); + ops->ndo_poll_controller(dev); poll_napi(dev); @@ -274,6 +276,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) int status = NETDEV_TX_BUSY; unsigned long tries; struct net_device *dev = np->dev; + const struct net_device_ops *ops = dev->netdev_ops; struct netpoll_info *npinfo = np->dev->npinfo; if (!npinfo || !netif_running(dev) || !netif_device_present(dev)) { @@ -294,7 +297,7 @@ static void netpoll_send_skb(struct netpoll *np, struct sk_buff *skb) tries > 0; --tries) { if (__netif_tx_trylock(txq)) { if (!netif_tx_queue_stopped(txq)) - status = dev->hard_start_xmit(skb, dev); + status = ops->ndo_start_xmit(skb, dev); __netif_tx_unlock(txq); if (status == NETDEV_TX_OK) @@ -345,7 +348,7 @@ void netpoll_send_udp(struct netpoll *np, const char *msg, int len) udph->check = csum_tcpudp_magic(htonl(np->local_ip), htonl(np->remote_ip), udp_len, IPPROTO_UDP, - csum_partial((unsigned char *)udph, udp_len, 0)); + csum_partial(udph, udp_len, 0)); if (udph->check == 0) udph->check = CSUM_MANGLED_0; @@ -555,7 +558,6 @@ out: void netpoll_print_options(struct netpoll *np) { - DECLARE_MAC_BUF(mac); printk(KERN_INFO "%s: local port %d\n", np->name, np->local_port); printk(KERN_INFO "%s: local IP %d.%d.%d.%d\n", @@ -566,8 +568,8 @@ void netpoll_print_options(struct netpoll *np) np->name, np->remote_port); printk(KERN_INFO "%s: remote IP %d.%d.%d.%d\n", np->name, HIPQUAD(np->remote_ip)); - printk(KERN_INFO "%s: remote ethernet address %s\n", - np->name, print_mac(mac, np->remote_mac)); + printk(KERN_INFO "%s: remote ethernet address %pM\n", + np->name, np->remote_mac); } int netpoll_parse_options(struct netpoll *np, char *opt) @@ -697,7 +699,7 @@ int netpoll_setup(struct netpoll *np) atomic_inc(&npinfo->refcnt); } - if (!ndev->poll_controller) { + if (!ndev->netdev_ops->ndo_poll_controller) { printk(KERN_ERR "%s: %s doesn't support polling, aborting.\n", np->name, np->dev_name); err = -ENOTSUPP; diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 8997e912aaaf4854b4f3e027e3b2ea496b9d1de3..65498483325aa09dc1507284fee54759da6e8c66 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -422,6 +422,7 @@ static struct pktgen_dev *pktgen_find_dev(struct pktgen_thread *t, const char *ifname); static int pktgen_device_event(struct notifier_block *, unsigned long, void *); static void pktgen_run_all_threads(void); +static void pktgen_reset_all_threads(void); static void pktgen_stop_all_threads_ifs(void); static int pktgen_stop_device(struct pktgen_dev *pkt_dev); static void pktgen_stop(struct pktgen_thread *t); @@ -480,6 +481,9 @@ static ssize_t pgctrl_write(struct file *file, const char __user * buf, else if (!strcmp(data, "start")) pktgen_run_all_threads(); + else if (!strcmp(data, "reset")) + pktgen_reset_all_threads(); + else printk(KERN_WARNING "pktgen: Unknown command: %s\n", data); @@ -509,7 +513,6 @@ static int pktgen_if_show(struct seq_file *seq, void *v) __u64 sa; __u64 stopped; __u64 now = getCurUs(); - DECLARE_MAC_BUF(mac); seq_printf(seq, "Params: count %llu min_pkt_size: %u max_pkt_size: %u\n", @@ -554,12 +557,12 @@ static int pktgen_if_show(struct seq_file *seq, void *v) seq_puts(seq, " src_mac: "); - seq_printf(seq, "%s ", - print_mac(mac, is_zero_ether_addr(pkt_dev->src_mac) ? - pkt_dev->odev->dev_addr : pkt_dev->src_mac)); + seq_printf(seq, "%pM ", + is_zero_ether_addr(pkt_dev->src_mac) ? + pkt_dev->odev->dev_addr : pkt_dev->src_mac); seq_printf(seq, "dst_mac: "); - seq_printf(seq, "%s\n", print_mac(mac, pkt_dev->dst_mac)); + seq_printf(seq, "%pM\n", pkt_dev->dst_mac); seq_printf(seq, " udp_src_min: %d udp_src_max: %d udp_dst_min: %d udp_dst_max: %d\n", @@ -2162,7 +2165,8 @@ static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow) struct xfrm_state *x = pkt_dev->flows[flow].x; if (!x) { /*slow path: we dont already have xfrm_state*/ - x = xfrm_stateonly_find((xfrm_address_t *)&pkt_dev->cur_daddr, + x = xfrm_stateonly_find(&init_net, + (xfrm_address_t *)&pkt_dev->cur_daddr, (xfrm_address_t *)&pkt_dev->cur_saddr, AF_INET, pkt_dev->ipsmode, @@ -3169,6 +3173,24 @@ static void pktgen_run_all_threads(void) pktgen_wait_all_threads_run(); } +static void pktgen_reset_all_threads(void) +{ + struct pktgen_thread *t; + + pr_debug("pktgen: entering pktgen_reset_all_threads.\n"); + + mutex_lock(&pktgen_thread_lock); + + list_for_each_entry(t, &pktgen_threads, th_list) + t->control |= (T_REMDEVALL); + + mutex_unlock(&pktgen_thread_lock); + + schedule_timeout_interruptible(msecs_to_jiffies(125)); /* Propagate thread->control */ + + pktgen_wait_all_threads_run(); +} + static void show_results(struct pktgen_dev *pkt_dev, int nr_frags) { __u64 total_us, bps, mbps, pps, idle; @@ -3331,14 +3353,14 @@ static void pktgen_rem_thread(struct pktgen_thread *t) static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) { - struct net_device *odev = NULL; + struct net_device *odev = pkt_dev->odev; + int (*xmit)(struct sk_buff *, struct net_device *) + = odev->netdev_ops->ndo_start_xmit; struct netdev_queue *txq; __u64 idle_start = 0; u16 queue_map; int ret; - odev = pkt_dev->odev; - if (pkt_dev->delay_us || pkt_dev->delay_ns) { u64 now; @@ -3419,7 +3441,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev) atomic_inc(&(pkt_dev->skb->users)); retry_now: - ret = odev->hard_start_xmit(pkt_dev->skb, odev); + ret = (*xmit)(pkt_dev->skb, odev); if (likely(ret == NETDEV_TX_OK)) { pkt_dev->last_ok = 1; pkt_dev->sofar++; diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 4dfb6b4d4559c9e52addf1c247028061af0bbdd5..790dd205bb5d9b9a9704734934b74db6029a44c0 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c @@ -551,7 +551,7 @@ static void set_operstate(struct net_device *dev, unsigned char transition) } static void copy_rtnl_link_stats(struct rtnl_link_stats *a, - struct net_device_stats *b) + const struct net_device_stats *b) { a->rx_packets = b->rx_packets; a->tx_packets = b->tx_packets; @@ -609,7 +609,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, struct netdev_queue *txq; struct ifinfomsg *ifm; struct nlmsghdr *nlh; - struct net_device_stats *stats; + const struct net_device_stats *stats; struct nlattr *attr; nlh = nlmsg_put(skb, pid, seq, type, sizeof(*ifm), flags); @@ -666,7 +666,7 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, if (attr == NULL) goto nla_put_failure; - stats = dev->get_stats(dev); + stats = dev_get_stats(dev); copy_rtnl_link_stats(nla_data(attr), stats); if (dev->rtnl_link_ops) { @@ -762,6 +762,7 @@ static int validate_linkmsg(struct net_device *dev, struct nlattr *tb[]) static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, struct nlattr **tb, char *ifname, int modified) { + const struct net_device_ops *ops = dev->netdev_ops; int send_addr_notify = 0; int err; @@ -783,7 +784,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, struct rtnl_link_ifmap *u_map; struct ifmap k_map; - if (!dev->set_config) { + if (!ops->ndo_set_config) { err = -EOPNOTSUPP; goto errout; } @@ -801,7 +802,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, k_map.dma = (unsigned char) u_map->dma; k_map.port = (unsigned char) u_map->port; - err = dev->set_config(dev, &k_map); + err = ops->ndo_set_config(dev, &k_map); if (err < 0) goto errout; @@ -812,7 +813,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, struct sockaddr *sa; int len; - if (!dev->set_mac_address) { + if (!ops->ndo_set_mac_address) { err = -EOPNOTSUPP; goto errout; } @@ -831,7 +832,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm, sa->sa_family = dev->type; memcpy(sa->sa_data, nla_data(tb[IFLA_ADDRESS]), dev->addr_len); - err = dev->set_mac_address(dev, sa); + err = ops->ndo_set_mac_address(dev, sa); kfree(sa); if (err) goto errout; diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 65f7757465bd2ed8b99c2a0934c8e5dc32c73b00..b8d0abb264334d6d5589d107c8cf4007e393ffd4 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -501,7 +501,7 @@ static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old) new->network_header = old->network_header; new->mac_header = old->mac_header; new->dst = dst_clone(old->dst); -#ifdef CONFIG_INET +#ifdef CONFIG_XFRM new->sp = secpath_get(old->sp); #endif memcpy(new->cb, old->cb, sizeof(old->cb)); @@ -556,6 +556,7 @@ static struct sk_buff *__skb_clone(struct sk_buff *n, struct sk_buff *skb) C(truesize); #if defined(CONFIG_MAC80211) || defined(CONFIG_MAC80211_MODULE) C(do_not_encrypt); + C(requeue); #endif atomic_set(&n->users, 1); @@ -2017,6 +2018,148 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len) skb_split_no_header(skb, skb1, len, pos); } +/* Shifting from/to a cloned skb is a no-go. + * + * Caller cannot keep skb_shinfo related pointers past calling here! + */ +static int skb_prepare_for_shift(struct sk_buff *skb) +{ + return skb_cloned(skb) && pskb_expand_head(skb, 0, 0, GFP_ATOMIC); +} + +/** + * skb_shift - Shifts paged data partially from skb to another + * @tgt: buffer into which tail data gets added + * @skb: buffer from which the paged data comes from + * @shiftlen: shift up to this many bytes + * + * Attempts to shift up to shiftlen worth of bytes, which may be less than + * the length of the skb, from tgt to skb. Returns number bytes shifted. + * It's up to caller to free skb if everything was shifted. + * + * If @tgt runs out of frags, the whole operation is aborted. + * + * Skb cannot include anything else but paged data while tgt is allowed + * to have non-paged data as well. + * + * TODO: full sized shift could be optimized but that would need + * specialized skb free'er to handle frags without up-to-date nr_frags. + */ +int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen) +{ + int from, to, merge, todo; + struct skb_frag_struct *fragfrom, *fragto; + + BUG_ON(shiftlen > skb->len); + BUG_ON(skb_headlen(skb)); /* Would corrupt stream */ + + todo = shiftlen; + from = 0; + to = skb_shinfo(tgt)->nr_frags; + fragfrom = &skb_shinfo(skb)->frags[from]; + + /* Actual merge is delayed until the point when we know we can + * commit all, so that we don't have to undo partial changes + */ + if (!to || + !skb_can_coalesce(tgt, to, fragfrom->page, fragfrom->page_offset)) { + merge = -1; + } else { + merge = to - 1; + + todo -= fragfrom->size; + if (todo < 0) { + if (skb_prepare_for_shift(skb) || + skb_prepare_for_shift(tgt)) + return 0; + + /* All previous frag pointers might be stale! */ + fragfrom = &skb_shinfo(skb)->frags[from]; + fragto = &skb_shinfo(tgt)->frags[merge]; + + fragto->size += shiftlen; + fragfrom->size -= shiftlen; + fragfrom->page_offset += shiftlen; + + goto onlymerged; + } + + from++; + } + + /* Skip full, not-fitting skb to avoid expensive operations */ + if ((shiftlen == skb->len) && + (skb_shinfo(skb)->nr_frags - from) > (MAX_SKB_FRAGS - to)) + return 0; + + if (skb_prepare_for_shift(skb) || skb_prepare_for_shift(tgt)) + return 0; + + while ((todo > 0) && (from < skb_shinfo(skb)->nr_frags)) { + if (to == MAX_SKB_FRAGS) + return 0; + + fragfrom = &skb_shinfo(skb)->frags[from]; + fragto = &skb_shinfo(tgt)->frags[to]; + + if (todo >= fragfrom->size) { + *fragto = *fragfrom; + todo -= fragfrom->size; + from++; + to++; + + } else { + get_page(fragfrom->page); + fragto->page = fragfrom->page; + fragto->page_offset = fragfrom->page_offset; + fragto->size = todo; + + fragfrom->page_offset += todo; + fragfrom->size -= todo; + todo = 0; + + to++; + break; + } + } + + /* Ready to "commit" this state change to tgt */ + skb_shinfo(tgt)->nr_frags = to; + + if (merge >= 0) { + fragfrom = &skb_shinfo(skb)->frags[0]; + fragto = &skb_shinfo(tgt)->frags[merge]; + + fragto->size += fragfrom->size; + put_page(fragfrom->page); + } + + /* Reposition in the original skb */ + to = 0; + while (from < skb_shinfo(skb)->nr_frags) + skb_shinfo(skb)->frags[to++] = skb_shinfo(skb)->frags[from++]; + skb_shinfo(skb)->nr_frags = to; + + BUG_ON(todo > 0 && !skb_shinfo(skb)->nr_frags); + +onlymerged: + /* Most likely the tgt won't ever need its checksum anymore, skb on + * the other hand might need it if it needs to be resent + */ + tgt->ip_summed = CHECKSUM_PARTIAL; + skb->ip_summed = CHECKSUM_PARTIAL; + + /* Yak, is it really working this way? Some helper please? */ + skb->len -= shiftlen; + skb->data_len -= shiftlen; + skb->truesize -= shiftlen; + tgt->len += shiftlen; + tgt->data_len += shiftlen; + tgt->truesize += shiftlen; + + return shiftlen; +} + /** * skb_prepare_seq_read - Prepare a sequential read of skb data * @skb: the buffer to read @@ -2285,6 +2428,7 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) { struct sk_buff *segs = NULL; struct sk_buff *tail = NULL; + struct sk_buff *fskb = skb_shinfo(skb)->frag_list; unsigned int mss = skb_shinfo(skb)->gso_size; unsigned int doffset = skb->data - skb_mac_header(skb); unsigned int offset = doffset; @@ -2304,7 +2448,6 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) struct sk_buff *nskb; skb_frag_t *frag; int hsize; - int k; int size; len = skb->len - offset; @@ -2317,9 +2460,36 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) if (hsize > len || !sg) hsize = len; - nskb = alloc_skb(hsize + doffset + headroom, GFP_ATOMIC); - if (unlikely(!nskb)) - goto err; + if (!hsize && i >= nfrags) { + BUG_ON(fskb->len != len); + + pos += len; + nskb = skb_clone(fskb, GFP_ATOMIC); + fskb = fskb->next; + + if (unlikely(!nskb)) + goto err; + + hsize = skb_end_pointer(nskb) - nskb->head; + if (skb_cow_head(nskb, doffset + headroom)) { + kfree_skb(nskb); + goto err; + } + + nskb->truesize += skb_end_pointer(nskb) - nskb->head - + hsize; + skb_release_head_state(nskb); + __skb_push(nskb, doffset); + } else { + nskb = alloc_skb(hsize + doffset + headroom, + GFP_ATOMIC); + + if (unlikely(!nskb)) + goto err; + + skb_reserve(nskb, headroom); + __skb_put(nskb, doffset); + } if (segs) tail->next = nskb; @@ -2330,13 +2500,15 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) __copy_skb_header(nskb, skb); nskb->mac_len = skb->mac_len; - skb_reserve(nskb, headroom); skb_reset_mac_header(nskb); skb_set_network_header(nskb, skb->mac_len); nskb->transport_header = (nskb->network_header + skb_network_header_len(skb)); - skb_copy_from_linear_data(skb, skb_put(nskb, doffset), - doffset); + skb_copy_from_linear_data(skb, nskb->data, doffset); + + if (pos >= offset + len) + continue; + if (!sg) { nskb->ip_summed = CHECKSUM_NONE; nskb->csum = skb_copy_and_csum_bits(skb, offset, @@ -2346,14 +2518,11 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) } frag = skb_shinfo(nskb)->frags; - k = 0; skb_copy_from_linear_data_offset(skb, offset, skb_put(nskb, hsize), hsize); - while (pos < offset + len) { - BUG_ON(i >= nfrags); - + while (pos < offset + len && i < nfrags) { *frag = skb_shinfo(skb)->frags[i]; get_page(frag->page); size = frag->size; @@ -2363,20 +2532,39 @@ struct sk_buff *skb_segment(struct sk_buff *skb, int features) frag->size -= offset - pos; } - k++; + skb_shinfo(nskb)->nr_frags++; if (pos + size <= offset + len) { i++; pos += size; } else { frag->size -= pos + size - (offset + len); - break; + goto skip_fraglist; } frag++; } - skb_shinfo(nskb)->nr_frags = k; + if (pos < offset + len) { + struct sk_buff *fskb2 = fskb; + + BUG_ON(pos + fskb->len != offset + len); + + pos += fskb->len; + fskb = fskb->next; + + if (fskb2->next) { + fskb2 = skb_clone(fskb2, GFP_ATOMIC); + if (!fskb2) + goto err; + } else + skb_get(fskb2); + + BUG_ON(skb_shinfo(nskb)->frag_list); + skb_shinfo(nskb)->frag_list = fskb2; + } + +skip_fraglist: nskb->data_len = len - hsize; nskb->len += nskb->data_len; nskb->truesize += nskb->data_len; @@ -2394,6 +2582,65 @@ err: EXPORT_SYMBOL_GPL(skb_segment); +int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb) +{ + struct sk_buff *p = *head; + struct sk_buff *nskb; + unsigned int headroom; + unsigned int hlen = p->data - skb_mac_header(p); + + if (hlen + p->len + skb->len >= 65536) + return -E2BIG; + + if (skb_shinfo(p)->frag_list) + goto merge; + + headroom = skb_headroom(p); + nskb = netdev_alloc_skb(p->dev, headroom); + if (unlikely(!nskb)) + return -ENOMEM; + + __copy_skb_header(nskb, p); + nskb->mac_len = p->mac_len; + + skb_reserve(nskb, headroom); + + skb_set_mac_header(nskb, -hlen); + skb_set_network_header(nskb, skb_network_offset(p)); + skb_set_transport_header(nskb, skb_transport_offset(p)); + + memcpy(skb_mac_header(nskb), skb_mac_header(p), hlen); + + *NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p); + skb_shinfo(nskb)->frag_list = p; + skb_header_release(p); + nskb->prev = p; + + nskb->data_len += p->len; + nskb->truesize += p->len; + nskb->len += p->len; + + *head = nskb; + nskb->next = p->next; + p->next = NULL; + + p = nskb; + +merge: + NAPI_GRO_CB(p)->count++; + p->prev->next = skb; + p->prev = skb; + skb_header_release(skb); + + p->data_len += skb->len; + p->truesize += skb->len; + p->len += skb->len; + + NAPI_GRO_CB(skb)->same_flow = 1; + return 0; +} +EXPORT_SYMBOL_GPL(skb_gro_receive); + void __init skb_init(void) { skbuff_head_cache = kmem_cache_create("skbuff_head_cache", diff --git a/net/core/sock.c b/net/core/sock.c index edf7220889a4b75f1e1671c39aeef8c31351387b..f3a0d08cbb48389c67d36bafcf49fce1c0ace1ab 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -1071,7 +1071,7 @@ struct sock *sk_clone(const struct sock *sk, const gfp_t priority) newsk->sk_sleep = NULL; if (newsk->sk_prot->sockets_allocated) - atomic_inc(newsk->sk_prot->sockets_allocated); + percpu_counter_inc(newsk->sk_prot->sockets_allocated); } out: return newsk; @@ -1463,8 +1463,12 @@ int __sk_mem_schedule(struct sock *sk, int size, int kind) } if (prot->memory_pressure) { - if (!*prot->memory_pressure || - prot->sysctl_mem[2] > atomic_read(prot->sockets_allocated) * + int alloc; + + if (!*prot->memory_pressure) + return 1; + alloc = percpu_counter_read_positive(prot->sockets_allocated); + if (prot->sysctl_mem[2] > alloc * sk_mem_pages(sk->sk_wmem_queued + atomic_read(&sk->sk_rmem_alloc) + sk->sk_forward_alloc)) @@ -2037,7 +2041,8 @@ int proto_register(struct proto *prot, int alloc_slab) { if (alloc_slab) { prot->slab = kmem_cache_create(prot->name, prot->obj_size, 0, - SLAB_HWCACHE_ALIGN, NULL); + SLAB_HWCACHE_ALIGN | prot->slab_flags, + NULL); if (prot->slab == NULL) { printk(KERN_CRIT "%s: Can't create sock SLAB cache!\n", @@ -2076,7 +2081,9 @@ int proto_register(struct proto *prot, int alloc_slab) prot->twsk_prot->twsk_slab = kmem_cache_create(prot->twsk_prot->twsk_slab_name, prot->twsk_prot->twsk_obj_size, - 0, SLAB_HWCACHE_ALIGN, + 0, + SLAB_HWCACHE_ALIGN | + prot->slab_flags, NULL); if (prot->twsk_prot->twsk_slab == NULL) goto out_free_timewait_sock_slab_name; @@ -2164,7 +2171,7 @@ static void proto_seq_printf(struct seq_file *seq, struct proto *proto) "%2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c %2c\n", proto->name, proto->obj_size, - proto->sockets_allocated != NULL ? atomic_read(proto->sockets_allocated) : -1, + sock_prot_inuse_get(seq_file_net(seq), proto), proto->memory_allocated != NULL ? atomic_read(proto->memory_allocated) : -1, proto->memory_pressure != NULL ? *proto->memory_pressure ? "yes" : "no" : "NI", proto->max_header, @@ -2218,7 +2225,8 @@ static const struct seq_operations proto_seq_ops = { static int proto_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &proto_seq_ops); + return seq_open_net(inode, file, &proto_seq_ops, + sizeof(struct seq_net_private)); } static const struct file_operations proto_seq_fops = { @@ -2226,13 +2234,31 @@ static const struct file_operations proto_seq_fops = { .open = proto_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_net, +}; + +static __net_init int proto_init_net(struct net *net) +{ + if (!proc_net_fops_create(net, "protocols", S_IRUGO, &proto_seq_fops)) + return -ENOMEM; + + return 0; +} + +static __net_exit void proto_exit_net(struct net *net) +{ + proc_net_remove(net, "protocols"); +} + + +static __net_initdata struct pernet_operations proto_net_ops = { + .init = proto_init_net, + .exit = proto_exit_net, }; static int __init proto_init(void) { - /* register /proc/net/protocols */ - return proc_net_fops_create(&init_net, "protocols", S_IRUGO, &proto_seq_fops) == NULL ? -ENOBUFS : 0; + return register_pernet_subsys(&proto_net_ops); } subsys_initcall(proto_init); diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index f686467ff12ba085f12b140f340a639699a7e049..83d3398559ea80d3823140856b375dd5c2419927 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -12,7 +12,6 @@ #include #include #include -#include static struct ctl_table net_core_table[] = { #ifdef CONFIG_NET @@ -22,7 +21,7 @@ static struct ctl_table net_core_table[] = { .data = &sysctl_wmem_max, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_CORE_RMEM_MAX, @@ -30,7 +29,7 @@ static struct ctl_table net_core_table[] = { .data = &sysctl_rmem_max, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_CORE_WMEM_DEFAULT, @@ -38,7 +37,7 @@ static struct ctl_table net_core_table[] = { .data = &sysctl_wmem_default, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_CORE_RMEM_DEFAULT, @@ -46,7 +45,7 @@ static struct ctl_table net_core_table[] = { .data = &sysctl_rmem_default, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_CORE_DEV_WEIGHT, @@ -54,7 +53,7 @@ static struct ctl_table net_core_table[] = { .data = &weight_p, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_CORE_MAX_BACKLOG, @@ -62,7 +61,7 @@ static struct ctl_table net_core_table[] = { .data = &netdev_max_backlog, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_CORE_MSG_COST, @@ -70,8 +69,8 @@ static struct ctl_table net_core_table[] = { .data = &net_ratelimit_state.interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_CORE_MSG_BURST, @@ -79,7 +78,7 @@ static struct ctl_table net_core_table[] = { .data = &net_ratelimit_state.burst, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_CORE_OPTMEM_MAX, @@ -87,42 +86,8 @@ static struct ctl_table net_core_table[] = { .data = &sysctl_optmem_max, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, -#ifdef CONFIG_XFRM - { - .ctl_name = NET_CORE_AEVENT_ETIME, - .procname = "xfrm_aevent_etime", - .data = &sysctl_xfrm_aevent_etime, - .maxlen = sizeof(u32), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = NET_CORE_AEVENT_RSEQTH, - .procname = "xfrm_aevent_rseqth", - .data = &sysctl_xfrm_aevent_rseqth, - .maxlen = sizeof(u32), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = CTL_UNNUMBERED, - .procname = "xfrm_larval_drop", - .data = &sysctl_xfrm_larval_drop, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, - { - .ctl_name = CTL_UNNUMBERED, - .procname = "xfrm_acq_expires", - .data = &sysctl_xfrm_acq_expires, - .maxlen = sizeof(int), - .mode = 0644, - .proc_handler = &proc_dointvec - }, -#endif /* CONFIG_XFRM */ #endif /* CONFIG_NET */ { .ctl_name = NET_CORE_BUDGET, @@ -130,7 +95,7 @@ static struct ctl_table net_core_table[] = { .data = &netdev_budget, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_CORE_WARNINGS, @@ -138,7 +103,7 @@ static struct ctl_table net_core_table[] = { .data = &net_msg_warn, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = 0 } }; @@ -150,12 +115,12 @@ static struct ctl_table netns_core_table[] = { .data = &init_net.core.sysctl_somaxconn, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = 0 } }; -static __net_initdata struct ctl_path net_core_path[] = { +__net_initdata struct ctl_path net_core_path[] = { { .procname = "net", .ctl_name = CTL_NET, }, { .procname = "core", .ctl_name = NET_CORE, }, { }, @@ -207,8 +172,11 @@ static __net_initdata struct pernet_operations sysctl_core_ops = { static __init int sysctl_core_init(void) { + static struct ctl_table empty[1]; + + register_sysctl_paths(net_core_path, empty); register_net_sysctl_rotable(net_core_path, net_core_table); return register_pernet_subsys(&sysctl_core_ops); } -__initcall(sysctl_core_init); +fs_initcall(sysctl_core_init); diff --git a/net/dcb/Kconfig b/net/dcb/Kconfig new file mode 100644 index 0000000000000000000000000000000000000000..4066d59c8de5e0c4a3308a9a0a00f30519b00be8 --- /dev/null +++ b/net/dcb/Kconfig @@ -0,0 +1,22 @@ +config DCB + bool "Data Center Bridging support" + default n + ---help--- + This enables support for configuring Data Center Bridging (DCB) + features on DCB capable Ethernet adapters via rtnetlink. Say 'Y' + if you have a DCB capable Ethernet adapter which supports this + interface and you are connected to a DCB capable switch. + + DCB is a collection of Ethernet enhancements which allow DCB capable + NICs and switches to support network traffic with differing + requirements (highly reliable, no drops vs. best effort vs. low + latency) to co-exist on Ethernet. + + DCB features include: + Enhanced Transmission Selection (aka Priority Grouping) - provides a + framework for assigning bandwidth guarantees to traffic classes. + Priority-based Flow Control (PFC) - a MAC control pause frame which + works at the granularity of the 802.1p priority instead of the + link (802.3x). + + If unsure, say N. diff --git a/net/dcb/Makefile b/net/dcb/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..9930f4cde81816bbed28b0b1b4fe6de596e5f4f1 --- /dev/null +++ b/net/dcb/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_DCB) += dcbnl.o diff --git a/net/dcb/dcbnl.c b/net/dcb/dcbnl.c new file mode 100644 index 0000000000000000000000000000000000000000..5dbfe5fdc0d63970071945a1059d5032281071ed --- /dev/null +++ b/net/dcb/dcbnl.c @@ -0,0 +1,1122 @@ +/* + * Copyright (c) 2008, Intel Corporation. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope 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. + * + * Author: Lucy Liu + */ + +#include +#include +#include +#include +#include +#include +#include + +/** + * Data Center Bridging (DCB) is a collection of Ethernet enhancements + * intended to allow network traffic with differing requirements + * (highly reliable, no drops vs. best effort vs. low latency) to operate + * and co-exist on Ethernet. Current DCB features are: + * + * Enhanced Transmission Selection (aka Priority Grouping [PG]) - provides a + * framework for assigning bandwidth guarantees to traffic classes. + * + * Priority-based Flow Control (PFC) - provides a flow control mechanism which + * can work independently for each 802.1p priority. + * + * Congestion Notification - provides a mechanism for end-to-end congestion + * control for protocols which do not have built-in congestion management. + * + * More information about the emerging standards for these Ethernet features + * can be found at: http://www.ieee802.org/1/pages/dcbridges.html + * + * This file implements an rtnetlink interface to allow configuration of DCB + * features for capable devices. + */ + +MODULE_AUTHOR("Lucy Liu, "); +MODULE_DESCRIPTION("Data Center Bridging netlink interface"); +MODULE_LICENSE("GPL"); + +/**************** DCB attribute policies *************************************/ + +/* DCB netlink attributes policy */ +static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = { + [DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1}, + [DCB_ATTR_STATE] = {.type = NLA_U8}, + [DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED}, + [DCB_ATTR_PG_CFG] = {.type = NLA_NESTED}, + [DCB_ATTR_SET_ALL] = {.type = NLA_U8}, + [DCB_ATTR_PERM_HWADDR] = {.type = NLA_FLAG}, + [DCB_ATTR_CAP] = {.type = NLA_NESTED}, + [DCB_ATTR_PFC_STATE] = {.type = NLA_U8}, + [DCB_ATTR_BCN] = {.type = NLA_NESTED}, +}; + +/* DCB priority flow control to User Priority nested attributes */ +static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = { + [DCB_PFC_UP_ATTR_0] = {.type = NLA_U8}, + [DCB_PFC_UP_ATTR_1] = {.type = NLA_U8}, + [DCB_PFC_UP_ATTR_2] = {.type = NLA_U8}, + [DCB_PFC_UP_ATTR_3] = {.type = NLA_U8}, + [DCB_PFC_UP_ATTR_4] = {.type = NLA_U8}, + [DCB_PFC_UP_ATTR_5] = {.type = NLA_U8}, + [DCB_PFC_UP_ATTR_6] = {.type = NLA_U8}, + [DCB_PFC_UP_ATTR_7] = {.type = NLA_U8}, + [DCB_PFC_UP_ATTR_ALL] = {.type = NLA_FLAG}, +}; + +/* DCB priority grouping nested attributes */ +static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = { + [DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED}, + [DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED}, + [DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED}, + [DCB_PG_ATTR_TC_3] = {.type = NLA_NESTED}, + [DCB_PG_ATTR_TC_4] = {.type = NLA_NESTED}, + [DCB_PG_ATTR_TC_5] = {.type = NLA_NESTED}, + [DCB_PG_ATTR_TC_6] = {.type = NLA_NESTED}, + [DCB_PG_ATTR_TC_7] = {.type = NLA_NESTED}, + [DCB_PG_ATTR_TC_ALL] = {.type = NLA_NESTED}, + [DCB_PG_ATTR_BW_ID_0] = {.type = NLA_U8}, + [DCB_PG_ATTR_BW_ID_1] = {.type = NLA_U8}, + [DCB_PG_ATTR_BW_ID_2] = {.type = NLA_U8}, + [DCB_PG_ATTR_BW_ID_3] = {.type = NLA_U8}, + [DCB_PG_ATTR_BW_ID_4] = {.type = NLA_U8}, + [DCB_PG_ATTR_BW_ID_5] = {.type = NLA_U8}, + [DCB_PG_ATTR_BW_ID_6] = {.type = NLA_U8}, + [DCB_PG_ATTR_BW_ID_7] = {.type = NLA_U8}, + [DCB_PG_ATTR_BW_ID_ALL] = {.type = NLA_FLAG}, +}; + +/* DCB traffic class nested attributes. */ +static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = { + [DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8}, + [DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8}, + [DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8}, + [DCB_TC_ATTR_PARAM_BW_PCT] = {.type = NLA_U8}, + [DCB_TC_ATTR_PARAM_ALL] = {.type = NLA_FLAG}, +}; + +/* DCB capabilities nested attributes. */ +static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = { + [DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG}, + [DCB_CAP_ATTR_PG] = {.type = NLA_U8}, + [DCB_CAP_ATTR_PFC] = {.type = NLA_U8}, + [DCB_CAP_ATTR_UP2TC] = {.type = NLA_U8}, + [DCB_CAP_ATTR_PG_TCS] = {.type = NLA_U8}, + [DCB_CAP_ATTR_PFC_TCS] = {.type = NLA_U8}, + [DCB_CAP_ATTR_GSP] = {.type = NLA_U8}, + [DCB_CAP_ATTR_BCN] = {.type = NLA_U8}, +}; + +/* DCB capabilities nested attributes. */ +static struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = { + [DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG}, + [DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8}, + [DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8}, +}; + +/* DCB BCN nested attributes. */ +static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = { + [DCB_BCN_ATTR_RP_0] = {.type = NLA_U8}, + [DCB_BCN_ATTR_RP_1] = {.type = NLA_U8}, + [DCB_BCN_ATTR_RP_2] = {.type = NLA_U8}, + [DCB_BCN_ATTR_RP_3] = {.type = NLA_U8}, + [DCB_BCN_ATTR_RP_4] = {.type = NLA_U8}, + [DCB_BCN_ATTR_RP_5] = {.type = NLA_U8}, + [DCB_BCN_ATTR_RP_6] = {.type = NLA_U8}, + [DCB_BCN_ATTR_RP_7] = {.type = NLA_U8}, + [DCB_BCN_ATTR_RP_ALL] = {.type = NLA_FLAG}, + [DCB_BCN_ATTR_BCNA_0] = {.type = NLA_U32}, + [DCB_BCN_ATTR_BCNA_1] = {.type = NLA_U32}, + [DCB_BCN_ATTR_ALPHA] = {.type = NLA_U32}, + [DCB_BCN_ATTR_BETA] = {.type = NLA_U32}, + [DCB_BCN_ATTR_GD] = {.type = NLA_U32}, + [DCB_BCN_ATTR_GI] = {.type = NLA_U32}, + [DCB_BCN_ATTR_TMAX] = {.type = NLA_U32}, + [DCB_BCN_ATTR_TD] = {.type = NLA_U32}, + [DCB_BCN_ATTR_RMIN] = {.type = NLA_U32}, + [DCB_BCN_ATTR_W] = {.type = NLA_U32}, + [DCB_BCN_ATTR_RD] = {.type = NLA_U32}, + [DCB_BCN_ATTR_RU] = {.type = NLA_U32}, + [DCB_BCN_ATTR_WRTT] = {.type = NLA_U32}, + [DCB_BCN_ATTR_RI] = {.type = NLA_U32}, + [DCB_BCN_ATTR_C] = {.type = NLA_U32}, + [DCB_BCN_ATTR_ALL] = {.type = NLA_FLAG}, +}; + +/* standard netlink reply call */ +static int dcbnl_reply(u8 value, u8 event, u8 cmd, u8 attr, u32 pid, + u32 seq, u16 flags) +{ + struct sk_buff *dcbnl_skb; + struct dcbmsg *dcb; + struct nlmsghdr *nlh; + int ret = -EINVAL; + + dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!dcbnl_skb) + return ret; + + nlh = NLMSG_NEW(dcbnl_skb, pid, seq, event, sizeof(*dcb), flags); + + dcb = NLMSG_DATA(nlh); + dcb->dcb_family = AF_UNSPEC; + dcb->cmd = cmd; + dcb->dcb_pad = 0; + + ret = nla_put_u8(dcbnl_skb, attr, value); + if (ret) + goto err; + + /* end the message, assign the nlmsg_len. */ + nlmsg_end(dcbnl_skb, nlh); + ret = rtnl_unicast(dcbnl_skb, &init_net, pid); + if (ret) + goto err; + + return 0; +nlmsg_failure: +err: + kfree(dcbnl_skb); + return ret; +} + +static int dcbnl_getstate(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + int ret = -EINVAL; + + /* if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->getstate) */ + if (!netdev->dcbnl_ops->getstate) + return ret; + + ret = dcbnl_reply(netdev->dcbnl_ops->getstate(netdev), RTM_GETDCB, + DCB_CMD_GSTATE, DCB_ATTR_STATE, pid, seq, flags); + + return ret; +} + +static int dcbnl_getpfccfg(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + struct sk_buff *dcbnl_skb; + struct nlmsghdr *nlh; + struct dcbmsg *dcb; + struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1], *nest; + u8 value; + int ret = -EINVAL; + int i; + int getall = 0; + + if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->getpfccfg) + return ret; + + ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, + tb[DCB_ATTR_PFC_CFG], + dcbnl_pfc_up_nest); + if (ret) + goto err_out; + + dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!dcbnl_skb) + goto err_out; + + nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); + + dcb = NLMSG_DATA(nlh); + dcb->dcb_family = AF_UNSPEC; + dcb->cmd = DCB_CMD_PFC_GCFG; + + nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PFC_CFG); + if (!nest) + goto err; + + if (data[DCB_PFC_UP_ATTR_ALL]) + getall = 1; + + for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { + if (!getall && !data[i]) + continue; + + netdev->dcbnl_ops->getpfccfg(netdev, i - DCB_PFC_UP_ATTR_0, + &value); + ret = nla_put_u8(dcbnl_skb, i, value); + + if (ret) { + nla_nest_cancel(dcbnl_skb, nest); + goto err; + } + } + nla_nest_end(dcbnl_skb, nest); + + nlmsg_end(dcbnl_skb, nlh); + + ret = rtnl_unicast(dcbnl_skb, &init_net, pid); + if (ret) + goto err; + + return 0; +nlmsg_failure: +err: + kfree(dcbnl_skb); +err_out: + return -EINVAL; +} + +static int dcbnl_getperm_hwaddr(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + struct sk_buff *dcbnl_skb; + struct nlmsghdr *nlh; + struct dcbmsg *dcb; + u8 perm_addr[MAX_ADDR_LEN]; + int ret = -EINVAL; + + if (!netdev->dcbnl_ops->getpermhwaddr) + return ret; + + dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!dcbnl_skb) + goto err_out; + + nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); + + dcb = NLMSG_DATA(nlh); + dcb->dcb_family = AF_UNSPEC; + dcb->cmd = DCB_CMD_GPERM_HWADDR; + + netdev->dcbnl_ops->getpermhwaddr(netdev, perm_addr); + + ret = nla_put(dcbnl_skb, DCB_ATTR_PERM_HWADDR, sizeof(perm_addr), + perm_addr); + + nlmsg_end(dcbnl_skb, nlh); + + ret = rtnl_unicast(dcbnl_skb, &init_net, pid); + if (ret) + goto err; + + return 0; + +nlmsg_failure: +err: + kfree(dcbnl_skb); +err_out: + return -EINVAL; +} + +static int dcbnl_getcap(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + struct sk_buff *dcbnl_skb; + struct nlmsghdr *nlh; + struct dcbmsg *dcb; + struct nlattr *data[DCB_CAP_ATTR_MAX + 1], *nest; + u8 value; + int ret = -EINVAL; + int i; + int getall = 0; + + if (!tb[DCB_ATTR_CAP] || !netdev->dcbnl_ops->getcap) + return ret; + + ret = nla_parse_nested(data, DCB_CAP_ATTR_MAX, tb[DCB_ATTR_CAP], + dcbnl_cap_nest); + if (ret) + goto err_out; + + dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!dcbnl_skb) + goto err_out; + + nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); + + dcb = NLMSG_DATA(nlh); + dcb->dcb_family = AF_UNSPEC; + dcb->cmd = DCB_CMD_GCAP; + + nest = nla_nest_start(dcbnl_skb, DCB_ATTR_CAP); + if (!nest) + goto err; + + if (data[DCB_CAP_ATTR_ALL]) + getall = 1; + + for (i = DCB_CAP_ATTR_ALL+1; i <= DCB_CAP_ATTR_MAX; i++) { + if (!getall && !data[i]) + continue; + + if (!netdev->dcbnl_ops->getcap(netdev, i, &value)) { + ret = nla_put_u8(dcbnl_skb, i, value); + + if (ret) { + nla_nest_cancel(dcbnl_skb, nest); + goto err; + } + } + } + nla_nest_end(dcbnl_skb, nest); + + nlmsg_end(dcbnl_skb, nlh); + + ret = rtnl_unicast(dcbnl_skb, &init_net, pid); + if (ret) + goto err; + + return 0; +nlmsg_failure: +err: + kfree(dcbnl_skb); +err_out: + return -EINVAL; +} + +static int dcbnl_getnumtcs(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + struct sk_buff *dcbnl_skb; + struct nlmsghdr *nlh; + struct dcbmsg *dcb; + struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1], *nest; + u8 value; + int ret = -EINVAL; + int i; + int getall = 0; + + if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->getnumtcs) + return ret; + + ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], + dcbnl_numtcs_nest); + if (ret) { + ret = -EINVAL; + goto err_out; + } + + dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!dcbnl_skb) { + ret = -EINVAL; + goto err_out; + } + + nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); + + dcb = NLMSG_DATA(nlh); + dcb->dcb_family = AF_UNSPEC; + dcb->cmd = DCB_CMD_GNUMTCS; + + nest = nla_nest_start(dcbnl_skb, DCB_ATTR_NUMTCS); + if (!nest) { + ret = -EINVAL; + goto err; + } + + if (data[DCB_NUMTCS_ATTR_ALL]) + getall = 1; + + for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { + if (!getall && !data[i]) + continue; + + ret = netdev->dcbnl_ops->getnumtcs(netdev, i, &value); + if (!ret) { + ret = nla_put_u8(dcbnl_skb, i, value); + + if (ret) { + nla_nest_cancel(dcbnl_skb, nest); + ret = -EINVAL; + goto err; + } + } else { + goto err; + } + } + nla_nest_end(dcbnl_skb, nest); + + nlmsg_end(dcbnl_skb, nlh); + + ret = rtnl_unicast(dcbnl_skb, &init_net, pid); + if (ret) { + ret = -EINVAL; + goto err; + } + + return 0; +nlmsg_failure: +err: + kfree(dcbnl_skb); +err_out: + return ret; +} + +static int dcbnl_setnumtcs(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + struct nlattr *data[DCB_NUMTCS_ATTR_MAX + 1]; + int ret = -EINVAL; + u8 value; + int i; + + if (!tb[DCB_ATTR_NUMTCS] || !netdev->dcbnl_ops->setnumtcs) + return ret; + + ret = nla_parse_nested(data, DCB_NUMTCS_ATTR_MAX, tb[DCB_ATTR_NUMTCS], + dcbnl_numtcs_nest); + + if (ret) { + ret = -EINVAL; + goto err; + } + + for (i = DCB_NUMTCS_ATTR_ALL+1; i <= DCB_NUMTCS_ATTR_MAX; i++) { + if (data[i] == NULL) + continue; + + value = nla_get_u8(data[i]); + + ret = netdev->dcbnl_ops->setnumtcs(netdev, i, value); + + if (ret) + goto operr; + } + +operr: + ret = dcbnl_reply(!!ret, RTM_SETDCB, DCB_CMD_SNUMTCS, + DCB_ATTR_NUMTCS, pid, seq, flags); + +err: + return ret; +} + +static int dcbnl_getpfcstate(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + int ret = -EINVAL; + + if (!netdev->dcbnl_ops->getpfcstate) + return ret; + + ret = dcbnl_reply(netdev->dcbnl_ops->getpfcstate(netdev), RTM_GETDCB, + DCB_CMD_PFC_GSTATE, DCB_ATTR_PFC_STATE, + pid, seq, flags); + + return ret; +} + +static int dcbnl_setpfcstate(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + int ret = -EINVAL; + u8 value; + + if (!tb[DCB_ATTR_PFC_STATE] || !netdev->dcbnl_ops->setpfcstate) + return ret; + + value = nla_get_u8(tb[DCB_ATTR_PFC_STATE]); + + netdev->dcbnl_ops->setpfcstate(netdev, value); + + ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SSTATE, DCB_ATTR_PFC_STATE, + pid, seq, flags); + + return ret; +} + +static int __dcbnl_pg_getcfg(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags, int dir) +{ + struct sk_buff *dcbnl_skb; + struct nlmsghdr *nlh; + struct dcbmsg *dcb; + struct nlattr *pg_nest, *param_nest, *data; + struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; + struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; + u8 prio, pgid, tc_pct, up_map; + int ret = -EINVAL; + int getall = 0; + int i; + + if (!tb[DCB_ATTR_PG_CFG] || + !netdev->dcbnl_ops->getpgtccfgtx || + !netdev->dcbnl_ops->getpgtccfgrx || + !netdev->dcbnl_ops->getpgbwgcfgtx || + !netdev->dcbnl_ops->getpgbwgcfgrx) + return ret; + + ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, + tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); + + if (ret) + goto err_out; + + dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!dcbnl_skb) + goto err_out; + + nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); + + dcb = NLMSG_DATA(nlh); + dcb->dcb_family = AF_UNSPEC; + dcb->cmd = (dir) ? DCB_CMD_PGRX_GCFG : DCB_CMD_PGTX_GCFG; + + pg_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_PG_CFG); + if (!pg_nest) + goto err; + + if (pg_tb[DCB_PG_ATTR_TC_ALL]) + getall = 1; + + for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { + if (!getall && !pg_tb[i]) + continue; + + if (pg_tb[DCB_PG_ATTR_TC_ALL]) + data = pg_tb[DCB_PG_ATTR_TC_ALL]; + else + data = pg_tb[i]; + ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, + data, dcbnl_tc_param_nest); + if (ret) + goto err_pg; + + param_nest = nla_nest_start(dcbnl_skb, i); + if (!param_nest) + goto err_pg; + + pgid = DCB_ATTR_VALUE_UNDEFINED; + prio = DCB_ATTR_VALUE_UNDEFINED; + tc_pct = DCB_ATTR_VALUE_UNDEFINED; + up_map = DCB_ATTR_VALUE_UNDEFINED; + + if (dir) { + /* Rx */ + netdev->dcbnl_ops->getpgtccfgrx(netdev, + i - DCB_PG_ATTR_TC_0, &prio, + &pgid, &tc_pct, &up_map); + } else { + /* Tx */ + netdev->dcbnl_ops->getpgtccfgtx(netdev, + i - DCB_PG_ATTR_TC_0, &prio, + &pgid, &tc_pct, &up_map); + } + + if (param_tb[DCB_TC_ATTR_PARAM_PGID] || + param_tb[DCB_TC_ATTR_PARAM_ALL]) { + ret = nla_put_u8(dcbnl_skb, + DCB_TC_ATTR_PARAM_PGID, pgid); + if (ret) + goto err_param; + } + if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING] || + param_tb[DCB_TC_ATTR_PARAM_ALL]) { + ret = nla_put_u8(dcbnl_skb, + DCB_TC_ATTR_PARAM_UP_MAPPING, up_map); + if (ret) + goto err_param; + } + if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO] || + param_tb[DCB_TC_ATTR_PARAM_ALL]) { + ret = nla_put_u8(dcbnl_skb, + DCB_TC_ATTR_PARAM_STRICT_PRIO, prio); + if (ret) + goto err_param; + } + if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT] || + param_tb[DCB_TC_ATTR_PARAM_ALL]) { + ret = nla_put_u8(dcbnl_skb, DCB_TC_ATTR_PARAM_BW_PCT, + tc_pct); + if (ret) + goto err_param; + } + nla_nest_end(dcbnl_skb, param_nest); + } + + if (pg_tb[DCB_PG_ATTR_BW_ID_ALL]) + getall = 1; + else + getall = 0; + + for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { + if (!getall && !pg_tb[i]) + continue; + + tc_pct = DCB_ATTR_VALUE_UNDEFINED; + + if (dir) { + /* Rx */ + netdev->dcbnl_ops->getpgbwgcfgrx(netdev, + i - DCB_PG_ATTR_BW_ID_0, &tc_pct); + } else { + /* Tx */ + netdev->dcbnl_ops->getpgbwgcfgtx(netdev, + i - DCB_PG_ATTR_BW_ID_0, &tc_pct); + } + ret = nla_put_u8(dcbnl_skb, i, tc_pct); + + if (ret) + goto err_pg; + } + + nla_nest_end(dcbnl_skb, pg_nest); + + nlmsg_end(dcbnl_skb, nlh); + + ret = rtnl_unicast(dcbnl_skb, &init_net, pid); + if (ret) + goto err; + + return 0; + +err_param: + nla_nest_cancel(dcbnl_skb, param_nest); +err_pg: + nla_nest_cancel(dcbnl_skb, pg_nest); +nlmsg_failure: +err: + kfree(dcbnl_skb); +err_out: + ret = -EINVAL; + return ret; +} + +static int dcbnl_pgtx_getcfg(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 0); +} + +static int dcbnl_pgrx_getcfg(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + return __dcbnl_pg_getcfg(netdev, tb, pid, seq, flags, 1); +} + +static int dcbnl_setstate(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + int ret = -EINVAL; + u8 value; + + if (!tb[DCB_ATTR_STATE] || !netdev->dcbnl_ops->setstate) + return ret; + + value = nla_get_u8(tb[DCB_ATTR_STATE]); + + ret = dcbnl_reply(netdev->dcbnl_ops->setstate(netdev, value), + RTM_SETDCB, DCB_CMD_SSTATE, DCB_ATTR_STATE, + pid, seq, flags); + + return ret; +} + +static int dcbnl_setpfccfg(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + struct nlattr *data[DCB_PFC_UP_ATTR_MAX + 1]; + int i; + int ret = -EINVAL; + u8 value; + + if (!tb[DCB_ATTR_PFC_CFG] || !netdev->dcbnl_ops->setpfccfg) + return ret; + + ret = nla_parse_nested(data, DCB_PFC_UP_ATTR_MAX, + tb[DCB_ATTR_PFC_CFG], + dcbnl_pfc_up_nest); + if (ret) + goto err; + + for (i = DCB_PFC_UP_ATTR_0; i <= DCB_PFC_UP_ATTR_7; i++) { + if (data[i] == NULL) + continue; + value = nla_get_u8(data[i]); + netdev->dcbnl_ops->setpfccfg(netdev, + data[i]->nla_type - DCB_PFC_UP_ATTR_0, value); + } + + ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_PFC_SCFG, DCB_ATTR_PFC_CFG, + pid, seq, flags); +err: + return ret; +} + +static int dcbnl_setall(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + int ret = -EINVAL; + + if (!tb[DCB_ATTR_SET_ALL] || !netdev->dcbnl_ops->setall) + return ret; + + ret = dcbnl_reply(netdev->dcbnl_ops->setall(netdev), RTM_SETDCB, + DCB_CMD_SET_ALL, DCB_ATTR_SET_ALL, pid, seq, flags); + + return ret; +} + +static int __dcbnl_pg_setcfg(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags, int dir) +{ + struct nlattr *pg_tb[DCB_PG_ATTR_MAX + 1]; + struct nlattr *param_tb[DCB_TC_ATTR_PARAM_MAX + 1]; + int ret = -EINVAL; + int i; + u8 pgid; + u8 up_map; + u8 prio; + u8 tc_pct; + + if (!tb[DCB_ATTR_PG_CFG] || + !netdev->dcbnl_ops->setpgtccfgtx || + !netdev->dcbnl_ops->setpgtccfgrx || + !netdev->dcbnl_ops->setpgbwgcfgtx || + !netdev->dcbnl_ops->setpgbwgcfgrx) + return ret; + + ret = nla_parse_nested(pg_tb, DCB_PG_ATTR_MAX, + tb[DCB_ATTR_PG_CFG], dcbnl_pg_nest); + if (ret) + goto err; + + for (i = DCB_PG_ATTR_TC_0; i <= DCB_PG_ATTR_TC_7; i++) { + if (!pg_tb[i]) + continue; + + ret = nla_parse_nested(param_tb, DCB_TC_ATTR_PARAM_MAX, + pg_tb[i], dcbnl_tc_param_nest); + if (ret) + goto err; + + pgid = DCB_ATTR_VALUE_UNDEFINED; + prio = DCB_ATTR_VALUE_UNDEFINED; + tc_pct = DCB_ATTR_VALUE_UNDEFINED; + up_map = DCB_ATTR_VALUE_UNDEFINED; + + if (param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]) + prio = + nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_STRICT_PRIO]); + + if (param_tb[DCB_TC_ATTR_PARAM_PGID]) + pgid = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_PGID]); + + if (param_tb[DCB_TC_ATTR_PARAM_BW_PCT]) + tc_pct = nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_BW_PCT]); + + if (param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]) + up_map = + nla_get_u8(param_tb[DCB_TC_ATTR_PARAM_UP_MAPPING]); + + /* dir: Tx = 0, Rx = 1 */ + if (dir) { + /* Rx */ + netdev->dcbnl_ops->setpgtccfgrx(netdev, + i - DCB_PG_ATTR_TC_0, + prio, pgid, tc_pct, up_map); + } else { + /* Tx */ + netdev->dcbnl_ops->setpgtccfgtx(netdev, + i - DCB_PG_ATTR_TC_0, + prio, pgid, tc_pct, up_map); + } + } + + for (i = DCB_PG_ATTR_BW_ID_0; i <= DCB_PG_ATTR_BW_ID_7; i++) { + if (!pg_tb[i]) + continue; + + tc_pct = nla_get_u8(pg_tb[i]); + + /* dir: Tx = 0, Rx = 1 */ + if (dir) { + /* Rx */ + netdev->dcbnl_ops->setpgbwgcfgrx(netdev, + i - DCB_PG_ATTR_BW_ID_0, tc_pct); + } else { + /* Tx */ + netdev->dcbnl_ops->setpgbwgcfgtx(netdev, + i - DCB_PG_ATTR_BW_ID_0, tc_pct); + } + } + + ret = dcbnl_reply(0, RTM_SETDCB, + (dir ? DCB_CMD_PGRX_SCFG : DCB_CMD_PGTX_SCFG), + DCB_ATTR_PG_CFG, pid, seq, flags); + +err: + return ret; +} + +static int dcbnl_pgtx_setcfg(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 0); +} + +static int dcbnl_pgrx_setcfg(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + return __dcbnl_pg_setcfg(netdev, tb, pid, seq, flags, 1); +} + +static int dcbnl_bcn_getcfg(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + struct sk_buff *dcbnl_skb; + struct nlmsghdr *nlh; + struct dcbmsg *dcb; + struct nlattr *bcn_nest; + struct nlattr *bcn_tb[DCB_BCN_ATTR_MAX + 1]; + u8 value_byte; + u32 value_integer; + int ret = -EINVAL; + bool getall = false; + int i; + + if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->getbcnrp || + !netdev->dcbnl_ops->getbcncfg) + return ret; + + ret = nla_parse_nested(bcn_tb, DCB_BCN_ATTR_MAX, + tb[DCB_ATTR_BCN], dcbnl_bcn_nest); + + if (ret) + goto err_out; + + dcbnl_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); + if (!dcbnl_skb) + goto err_out; + + nlh = NLMSG_NEW(dcbnl_skb, pid, seq, RTM_GETDCB, sizeof(*dcb), flags); + + dcb = NLMSG_DATA(nlh); + dcb->dcb_family = AF_UNSPEC; + dcb->cmd = DCB_CMD_BCN_GCFG; + + bcn_nest = nla_nest_start(dcbnl_skb, DCB_ATTR_BCN); + if (!bcn_nest) + goto err; + + if (bcn_tb[DCB_BCN_ATTR_ALL]) + getall = true; + + for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { + if (!getall && !bcn_tb[i]) + continue; + + netdev->dcbnl_ops->getbcnrp(netdev, i - DCB_BCN_ATTR_RP_0, + &value_byte); + ret = nla_put_u8(dcbnl_skb, i, value_byte); + if (ret) + goto err_bcn; + } + + for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { + if (!getall && !bcn_tb[i]) + continue; + + netdev->dcbnl_ops->getbcncfg(netdev, i, + &value_integer); + ret = nla_put_u32(dcbnl_skb, i, value_integer); + if (ret) + goto err_bcn; + } + + nla_nest_end(dcbnl_skb, bcn_nest); + + nlmsg_end(dcbnl_skb, nlh); + + ret = rtnl_unicast(dcbnl_skb, &init_net, pid); + if (ret) + goto err; + + return 0; + +err_bcn: + nla_nest_cancel(dcbnl_skb, bcn_nest); +nlmsg_failure: +err: + kfree(dcbnl_skb); +err_out: + ret = -EINVAL; + return ret; +} + +static int dcbnl_bcn_setcfg(struct net_device *netdev, struct nlattr **tb, + u32 pid, u32 seq, u16 flags) +{ + struct nlattr *data[DCB_BCN_ATTR_MAX + 1]; + int i; + int ret = -EINVAL; + u8 value_byte; + u32 value_int; + + if (!tb[DCB_ATTR_BCN] || !netdev->dcbnl_ops->setbcncfg + || !netdev->dcbnl_ops->setbcnrp) + return ret; + + ret = nla_parse_nested(data, DCB_BCN_ATTR_MAX, + tb[DCB_ATTR_BCN], + dcbnl_pfc_up_nest); + if (ret) + goto err; + + for (i = DCB_BCN_ATTR_RP_0; i <= DCB_BCN_ATTR_RP_7; i++) { + if (data[i] == NULL) + continue; + value_byte = nla_get_u8(data[i]); + netdev->dcbnl_ops->setbcnrp(netdev, + data[i]->nla_type - DCB_BCN_ATTR_RP_0, value_byte); + } + + for (i = DCB_BCN_ATTR_BCNA_0; i <= DCB_BCN_ATTR_RI; i++) { + if (data[i] == NULL) + continue; + value_int = nla_get_u32(data[i]); + netdev->dcbnl_ops->setbcncfg(netdev, + i, value_int); + } + + ret = dcbnl_reply(0, RTM_SETDCB, DCB_CMD_BCN_SCFG, DCB_ATTR_BCN, + pid, seq, flags); +err: + return ret; +} + +static int dcb_doit(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) +{ + struct net *net = sock_net(skb->sk); + struct net_device *netdev; + struct dcbmsg *dcb = (struct dcbmsg *)NLMSG_DATA(nlh); + struct nlattr *tb[DCB_ATTR_MAX + 1]; + u32 pid = skb ? NETLINK_CB(skb).pid : 0; + int ret = -EINVAL; + + if (net != &init_net) + return -EINVAL; + + ret = nlmsg_parse(nlh, sizeof(*dcb), tb, DCB_ATTR_MAX, + dcbnl_rtnl_policy); + if (ret < 0) + return ret; + + if (!tb[DCB_ATTR_IFNAME]) + return -EINVAL; + + netdev = dev_get_by_name(&init_net, nla_data(tb[DCB_ATTR_IFNAME])); + if (!netdev) + return -EINVAL; + + if (!netdev->dcbnl_ops) + goto errout; + + switch (dcb->cmd) { + case DCB_CMD_GSTATE: + ret = dcbnl_getstate(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_PFC_GCFG: + ret = dcbnl_getpfccfg(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_GPERM_HWADDR: + ret = dcbnl_getperm_hwaddr(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_PGTX_GCFG: + ret = dcbnl_pgtx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_PGRX_GCFG: + ret = dcbnl_pgrx_getcfg(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_BCN_GCFG: + ret = dcbnl_bcn_getcfg(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_SSTATE: + ret = dcbnl_setstate(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_PFC_SCFG: + ret = dcbnl_setpfccfg(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + + case DCB_CMD_SET_ALL: + ret = dcbnl_setall(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_PGTX_SCFG: + ret = dcbnl_pgtx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_PGRX_SCFG: + ret = dcbnl_pgrx_setcfg(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_GCAP: + ret = dcbnl_getcap(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_GNUMTCS: + ret = dcbnl_getnumtcs(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_SNUMTCS: + ret = dcbnl_setnumtcs(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_PFC_GSTATE: + ret = dcbnl_getpfcstate(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_PFC_SSTATE: + ret = dcbnl_setpfcstate(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + case DCB_CMD_BCN_SCFG: + ret = dcbnl_bcn_setcfg(netdev, tb, pid, nlh->nlmsg_seq, + nlh->nlmsg_flags); + goto out; + default: + goto errout; + } +errout: + ret = -EINVAL; +out: + dev_put(netdev); + return ret; +} + +static int __init dcbnl_init(void) +{ + rtnl_register(PF_UNSPEC, RTM_GETDCB, dcb_doit, NULL); + rtnl_register(PF_UNSPEC, RTM_SETDCB, dcb_doit, NULL); + + return 0; +} +module_init(dcbnl_init); + +static void __exit dcbnl_exit(void) +{ + rtnl_unregister(PF_UNSPEC, RTM_GETDCB); + rtnl_unregister(PF_UNSPEC, RTM_SETDCB); +} +module_exit(dcbnl_exit); + + diff --git a/net/dccp/ackvec.c b/net/dccp/ackvec.c index 1e8be246ad159fe920869d90bfd9ea846efdb22f..01e4d39fa23274a3fe57c49342ab10db7af7a1f5 100644 --- a/net/dccp/ackvec.c +++ b/net/dccp/ackvec.c @@ -12,7 +12,6 @@ #include "ackvec.h" #include "dccp.h" -#include #include #include #include @@ -68,7 +67,7 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) struct dccp_sock *dp = dccp_sk(sk); struct dccp_ackvec *av = dp->dccps_hc_rx_ackvec; /* Figure out how many options do we need to represent the ackvec */ - const u16 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_MAX_ACKVEC_OPT_LEN); + const u8 nr_opts = DIV_ROUND_UP(av->av_vec_len, DCCP_SINGLE_OPT_MAXLEN); u16 len = av->av_vec_len + 2 * nr_opts, i; u32 elapsed_time; const unsigned char *tail, *from; @@ -100,8 +99,8 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb) for (i = 0; i < nr_opts; ++i) { int copylen = len; - if (len > DCCP_MAX_ACKVEC_OPT_LEN) - copylen = DCCP_MAX_ACKVEC_OPT_LEN; + if (len > DCCP_SINGLE_OPT_MAXLEN) + copylen = DCCP_SINGLE_OPT_MAXLEN; *to++ = DCCPO_ACK_VECTOR_0; *to++ = copylen + 2; @@ -432,7 +431,7 @@ found: int dccp_ackvec_parse(struct sock *sk, const struct sk_buff *skb, u64 *ackno, const u8 opt, const u8 *value, const u8 len) { - if (len > DCCP_MAX_ACKVEC_OPT_LEN) + if (len > DCCP_SINGLE_OPT_MAXLEN) return -1; /* dccp_ackvector_print(DCCP_SKB_CB(skb)->dccpd_ack_seq, value, len); */ diff --git a/net/dccp/ackvec.h b/net/dccp/ackvec.h index bcb64fb4acefd5ef96d31637d5d5ff80b439bd87..4ccee030524e403abac5cec98e340307937021b1 100644 --- a/net/dccp/ackvec.h +++ b/net/dccp/ackvec.h @@ -11,15 +11,14 @@ * published by the Free Software Foundation. */ +#include #include #include #include #include -/* Read about the ECN nonce to see why it is 253 */ -#define DCCP_MAX_ACKVEC_OPT_LEN 253 /* We can spread an ack vector across multiple options */ -#define DCCP_MAX_ACKVEC_LEN (DCCP_MAX_ACKVEC_OPT_LEN * 2) +#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2) #define DCCP_ACKVEC_STATE_RECEIVED 0 #define DCCP_ACKVEC_STATE_ECN_MARKED (1 << 6) diff --git a/net/dccp/ccid.c b/net/dccp/ccid.c index 8fe931a3d7a1b1b7240a3421b7af0c404afae375..bcc643f992aeb6c70ed218ebb7248e9a072ea758 100644 --- a/net/dccp/ccid.c +++ b/net/dccp/ccid.c @@ -13,6 +13,13 @@ #include "ccid.h" +static u8 builtin_ccids[] = { + DCCPC_CCID2, /* CCID2 is supported by default */ +#if defined(CONFIG_IP_DCCP_CCID3) || defined(CONFIG_IP_DCCP_CCID3_MODULE) + DCCPC_CCID3, +#endif +}; + static struct ccid_operations *ccids[CCID_MAX]; #if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT) static atomic_t ccids_lockct = ATOMIC_INIT(0); @@ -86,6 +93,47 @@ static void ccid_kmem_cache_destroy(struct kmem_cache *slab) } } +/* check that up to @array_len members in @ccid_array are supported */ +bool ccid_support_check(u8 const *ccid_array, u8 array_len) +{ + u8 i, j, found; + + for (i = 0, found = 0; i < array_len; i++, found = 0) { + for (j = 0; !found && j < ARRAY_SIZE(builtin_ccids); j++) + found = (ccid_array[i] == builtin_ccids[j]); + if (!found) + return false; + } + return true; +} + +/** + * ccid_get_builtin_ccids - Provide copy of `builtin' CCID array + * @ccid_array: pointer to copy into + * @array_len: value to return length into + * This function allocates memory - caller must see that it is freed after use. + */ +int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len) +{ + *ccid_array = kmemdup(builtin_ccids, sizeof(builtin_ccids), gfp_any()); + if (*ccid_array == NULL) + return -ENOBUFS; + *array_len = ARRAY_SIZE(builtin_ccids); + return 0; +} + +int ccid_getsockopt_builtin_ccids(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + if (len < sizeof(builtin_ccids)) + return -EINVAL; + + if (put_user(sizeof(builtin_ccids), optlen) || + copy_to_user(optval, builtin_ccids, sizeof(builtin_ccids))) + return -EFAULT; + return 0; +} + int ccid_register(struct ccid_operations *ccid_ops) { int err = -ENOBUFS; @@ -205,20 +253,6 @@ out_module_put: EXPORT_SYMBOL_GPL(ccid_new); -struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, gfp_t gfp) -{ - return ccid_new(id, sk, 1, gfp); -} - -EXPORT_SYMBOL_GPL(ccid_hc_rx_new); - -struct ccid *ccid_hc_tx_new(unsigned char id,struct sock *sk, gfp_t gfp) -{ - return ccid_new(id, sk, 0, gfp); -} - -EXPORT_SYMBOL_GPL(ccid_hc_tx_new); - static void ccid_delete(struct ccid *ccid, struct sock *sk, int rx) { struct ccid_operations *ccid_ops; diff --git a/net/dccp/ccid.h b/net/dccp/ccid.h index fdeae7b5731950ed3caa776cf82a0d35f2771012..18f69423a7084fc929c359a5168d4250c5beb208 100644 --- a/net/dccp/ccid.h +++ b/net/dccp/ccid.h @@ -103,13 +103,31 @@ static inline void *ccid_priv(const struct ccid *ccid) return (void *)ccid->ccid_priv; } +extern bool ccid_support_check(u8 const *ccid_array, u8 array_len); +extern int ccid_get_builtin_ccids(u8 **ccid_array, u8 *array_len); +extern int ccid_getsockopt_builtin_ccids(struct sock *sk, int len, + char __user *, int __user *); + extern struct ccid *ccid_new(unsigned char id, struct sock *sk, int rx, gfp_t gfp); -extern struct ccid *ccid_hc_rx_new(unsigned char id, struct sock *sk, - gfp_t gfp); -extern struct ccid *ccid_hc_tx_new(unsigned char id, struct sock *sk, - gfp_t gfp); +static inline int ccid_get_current_rx_ccid(struct dccp_sock *dp) +{ + struct ccid *ccid = dp->dccps_hc_rx_ccid; + + if (ccid == NULL || ccid->ccid_ops == NULL) + return -1; + return ccid->ccid_ops->ccid_id; +} + +static inline int ccid_get_current_tx_ccid(struct dccp_sock *dp) +{ + struct ccid *ccid = dp->dccps_hc_tx_ccid; + + if (ccid == NULL || ccid->ccid_ops == NULL) + return -1; + return ccid->ccid_ops->ccid_id; +} extern void ccid_hc_rx_delete(struct ccid *ccid, struct sock *sk); extern void ccid_hc_tx_delete(struct ccid *ccid, struct sock *sk); diff --git a/net/dccp/ccids/ccid2.c b/net/dccp/ccids/ccid2.c index 9a430734530c6d8bd2079ca7c1662d03b221ad73..c9ea19a4d85e10b0ba8c5a2a4d8c27b2496bc79b 100644 --- a/net/dccp/ccids/ccid2.c +++ b/net/dccp/ccids/ccid2.c @@ -25,7 +25,7 @@ /* * This implementation should follow RFC 4341 */ - +#include "../feat.h" #include "../ccid.h" #include "../dccp.h" #include "ccid2.h" @@ -147,8 +147,8 @@ static void ccid2_change_l_ack_ratio(struct sock *sk, u32 val) DCCP_WARN("Limiting Ack Ratio (%u) to %u\n", val, max_ratio); val = max_ratio; } - if (val > 0xFFFF) /* RFC 4340, 11.3 */ - val = 0xFFFF; + if (val > DCCPF_ACK_RATIO_MAX) + val = DCCPF_ACK_RATIO_MAX; if (val == dp->dccps_l_ack_ratio) return; diff --git a/net/dccp/dccp.h b/net/dccp/dccp.h index b4bc6e095a0e5b367275582ce4ab4e78823e3a84..0bc4c9a02e1964d3f6e0c5431b0a4d968115739a 100644 --- a/net/dccp/dccp.h +++ b/net/dccp/dccp.h @@ -49,7 +49,7 @@ extern int dccp_debug; extern struct inet_hashinfo dccp_hashinfo; -extern atomic_t dccp_orphan_count; +extern struct percpu_counter dccp_orphan_count; extern void dccp_time_wait(struct sock *sk, int state, int timeo); @@ -98,9 +98,6 @@ extern int sysctl_dccp_retries2; extern int sysctl_dccp_feat_sequence_window; extern int sysctl_dccp_feat_rx_ccid; extern int sysctl_dccp_feat_tx_ccid; -extern int sysctl_dccp_feat_ack_ratio; -extern int sysctl_dccp_feat_send_ack_vector; -extern int sysctl_dccp_feat_send_ndp_count; extern int sysctl_dccp_tx_qlen; extern int sysctl_dccp_sync_ratelimit; @@ -252,7 +249,8 @@ extern const char *dccp_state_name(const int state); extern void dccp_set_state(struct sock *sk, const int state); extern void dccp_done(struct sock *sk); -extern void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb); +extern int dccp_reqsk_init(struct request_sock *rq, struct dccp_sock const *dp, + struct sk_buff const *skb); extern int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb); @@ -435,12 +433,19 @@ static inline int dccp_ack_pending(const struct sock *sk) const struct dccp_sock *dp = dccp_sk(sk); return dp->dccps_timestamp_echo != 0 || #ifdef CONFIG_IP_DCCP_ACKVEC - (dccp_msk(sk)->dccpms_send_ack_vector && + (dp->dccps_hc_rx_ackvec != NULL && dccp_ackvec_pending(dp->dccps_hc_rx_ackvec)) || #endif inet_csk_ack_scheduled(sk); } +extern int dccp_feat_finalise_settings(struct dccp_sock *dp); +extern int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq); +extern int dccp_feat_insert_opts(struct dccp_sock*, struct dccp_request_sock*, + struct sk_buff *skb); +extern int dccp_feat_activate_values(struct sock *sk, struct list_head *fn); +extern void dccp_feat_list_purge(struct list_head *fn_list); + extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb); extern int dccp_insert_options_rsk(struct dccp_request_sock*, struct sk_buff*); extern int dccp_insert_option_elapsed_time(struct sock *sk, diff --git a/net/dccp/diag.c b/net/dccp/diag.c index d8a3509b26f68812c194f852eb5a0e017f0920e2..b21f261da75ee2572e40ce44f44746c3ee899e7a 100644 --- a/net/dccp/diag.c +++ b/net/dccp/diag.c @@ -29,11 +29,14 @@ static void dccp_get_info(struct sock *sk, struct tcp_info *info) info->tcpi_backoff = icsk->icsk_backoff; info->tcpi_pmtu = icsk->icsk_pmtu_cookie; - if (dccp_msk(sk)->dccpms_send_ack_vector) + if (dp->dccps_hc_rx_ackvec != NULL) info->tcpi_options |= TCPI_OPT_SACK; - ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info); - ccid_hc_tx_get_info(dp->dccps_hc_tx_ccid, sk, info); + if (dp->dccps_hc_rx_ccid != NULL) + ccid_hc_rx_get_info(dp->dccps_hc_rx_ccid, sk, info); + + if (dp->dccps_hc_tx_ccid != NULL) + ccid_hc_tx_get_info(dp->dccps_hc_tx_ccid, sk, info); } static void dccp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, @@ -45,7 +48,7 @@ static void dccp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, dccp_get_info(sk, _info); } -static struct inet_diag_handler dccp_diag_handler = { +static const struct inet_diag_handler dccp_diag_handler = { .idiag_hashinfo = &dccp_hashinfo, .idiag_get_info = dccp_diag_get_info, .idiag_type = DCCPDIAG_GETSOCK, diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 933a0ecf8d463b0649fd69f78335533d86950517..30f9fb76b921f3ffe19690d9732239b869c6f6fe 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c @@ -1,11 +1,17 @@ /* * net/dccp/feat.c * - * An implementation of the DCCP protocol - * Andrea Bittau + * Feature negotiation for the DCCP protocol (RFC 4340, section 6) + * + * Copyright (c) 2008 Gerrit Renker + * Rewrote from scratch, some bits from earlier code by + * Copyright (c) 2005 Andrea Bittau + * * * ASSUMPTIONS * ----------- + * o Feature negotiation is coordinated with connection setup (as in TCP), wild + * changes of parameters of an established connection are not supported. * o All currently known SP features have 1-byte quantities. If in the future * extensions of RFCs 4340..42 define features with item lengths larger than * one byte, a feature-specific extension of the code will be required. @@ -15,597 +21,1185 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ - #include - #include "ccid.h" #include "feat.h" -#define DCCP_FEAT_SP_NOAGREE (-123) - -int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, - u8 *val, u8 len, gfp_t gfp) -{ - struct dccp_opt_pend *opt; - - dccp_feat_debug(type, feature, *val); - - if (len > 3) { - DCCP_WARN("invalid length %d\n", len); - return -EINVAL; - } - /* XXX add further sanity checks */ - - /* check if that feature is already being negotiated */ - list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { - /* ok we found a negotiation for this option already */ - if (opt->dccpop_feat == feature && opt->dccpop_type == type) { - dccp_pr_debug("Replacing old\n"); - /* replace */ - BUG_ON(opt->dccpop_val == NULL); - kfree(opt->dccpop_val); - opt->dccpop_val = val; - opt->dccpop_len = len; - opt->dccpop_conf = 0; - return 0; - } - } - - /* negotiation for a new feature */ - opt = kmalloc(sizeof(*opt), gfp); - if (opt == NULL) - return -ENOMEM; - - opt->dccpop_type = type; - opt->dccpop_feat = feature; - opt->dccpop_len = len; - opt->dccpop_val = val; - opt->dccpop_conf = 0; - opt->dccpop_sc = NULL; - - BUG_ON(opt->dccpop_val == NULL); - - list_add_tail(&opt->dccpop_node, &dmsk->dccpms_pending); - return 0; -} - -EXPORT_SYMBOL_GPL(dccp_feat_change); - -static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr) +/* + * Feature activation handlers. + * + * These all use an u64 argument, to provide enough room for NN/SP features. At + * this stage the negotiated values have been checked to be within their range. + */ +static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx) { struct dccp_sock *dp = dccp_sk(sk); - struct dccp_minisock *dmsk = dccp_msk(sk); - /* figure out if we are changing our CCID or the peer's */ - const int rx = type == DCCPO_CHANGE_R; - const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid; - struct ccid *new_ccid; + struct ccid *new_ccid = ccid_new(ccid, sk, rx, gfp_any()); - /* Check if nothing is being changed. */ - if (ccid_nr == new_ccid_nr) - return 0; - - new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC); if (new_ccid == NULL) return -ENOMEM; if (rx) { ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); dp->dccps_hc_rx_ccid = new_ccid; - dmsk->dccpms_rx_ccid = new_ccid_nr; } else { ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); dp->dccps_hc_tx_ccid = new_ccid; - dmsk->dccpms_tx_ccid = new_ccid_nr; } + return 0; +} +static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx) +{ + if (!rx) + dccp_msk(sk)->dccpms_sequence_window = seq_win; return 0; } -static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val) +static int dccp_hdlr_ack_ratio(struct sock *sk, u64 ratio, bool rx) { - dccp_feat_debug(type, feat, val); + if (rx) + dccp_sk(sk)->dccps_r_ack_ratio = ratio; + else + dccp_sk(sk)->dccps_l_ack_ratio = ratio; + return 0; +} - switch (feat) { - case DCCPF_CCID: - return dccp_feat_update_ccid(sk, type, val); - default: - dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n", - dccp_feat_typename(type), feat); - break; +static int dccp_hdlr_ackvec(struct sock *sk, u64 enable, bool rx) +{ + struct dccp_sock *dp = dccp_sk(sk); + + if (rx) { + if (enable && dp->dccps_hc_rx_ackvec == NULL) { + dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(gfp_any()); + if (dp->dccps_hc_rx_ackvec == NULL) + return -ENOMEM; + } else if (!enable) { + dccp_ackvec_free(dp->dccps_hc_rx_ackvec); + dp->dccps_hc_rx_ackvec = NULL; + } } return 0; } -static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt, - u8 *rpref, u8 rlen) +static int dccp_hdlr_ndp(struct sock *sk, u64 enable, bool rx) { - struct dccp_sock *dp = dccp_sk(sk); - u8 *spref, slen, *res = NULL; - int i, j, rc, agree = 1; + if (!rx) + dccp_sk(sk)->dccps_send_ndp_count = (enable > 0); + return 0; +} - BUG_ON(rpref == NULL); +/* + * Minimum Checksum Coverage is located at the RX side (9.2.1). This means that + * `rx' holds when the sending peer informs about his partial coverage via a + * ChangeR() option. In the other case, we are the sender and the receiver + * announces its coverage via ChangeL() options. The policy here is to honour + * such communication by enabling the corresponding partial coverage - but only + * if it has not been set manually before; the warning here means that all + * packets will be dropped. + */ +static int dccp_hdlr_min_cscov(struct sock *sk, u64 cscov, bool rx) +{ + struct dccp_sock *dp = dccp_sk(sk); - /* check if we are the black sheep */ - if (dp->dccps_role == DCCP_ROLE_CLIENT) { - spref = rpref; - slen = rlen; - rpref = opt->dccpop_val; - rlen = opt->dccpop_len; - } else { - spref = opt->dccpop_val; - slen = opt->dccpop_len; + if (rx) + dp->dccps_pcrlen = cscov; + else { + if (dp->dccps_pcslen == 0) + dp->dccps_pcslen = cscov; + else if (cscov > dp->dccps_pcslen) + DCCP_WARN("CsCov %u too small, peer requires >= %u\n", + dp->dccps_pcslen, (u8)cscov); } - /* - * Now we have server preference list in spref and client preference in - * rpref - */ - BUG_ON(spref == NULL); - BUG_ON(rpref == NULL); + return 0; +} - /* FIXME sanity check vals */ +static const struct { + u8 feat_num; /* DCCPF_xxx */ + enum dccp_feat_type rxtx; /* RX or TX */ + enum dccp_feat_type reconciliation; /* SP or NN */ + u8 default_value; /* as in 6.4 */ + int (*activation_hdlr)(struct sock *sk, u64 val, bool rx); +/* + * Lookup table for location and type of features (from RFC 4340/4342) + * +--------------------------+----+-----+----+----+---------+-----------+ + * | Feature | Location | Reconc. | Initial | Section | + * | | RX | TX | SP | NN | Value | Reference | + * +--------------------------+----+-----+----+----+---------+-----------+ + * | DCCPF_CCID | | X | X | | 2 | 10 | + * | DCCPF_SHORT_SEQNOS | | X | X | | 0 | 7.6.1 | + * | DCCPF_SEQUENCE_WINDOW | | X | | X | 100 | 7.5.2 | + * | DCCPF_ECN_INCAPABLE | X | | X | | 0 | 12.1 | + * | DCCPF_ACK_RATIO | | X | | X | 2 | 11.3 | + * | DCCPF_SEND_ACK_VECTOR | X | | X | | 0 | 11.5 | + * | DCCPF_SEND_NDP_COUNT | | X | X | | 0 | 7.7.2 | + * | DCCPF_MIN_CSUM_COVER | X | | X | | 0 | 9.2.1 | + * | DCCPF_DATA_CHECKSUM | X | | X | | 0 | 9.3.1 | + * | DCCPF_SEND_LEV_RATE | X | | X | | 0 | 4342/8.4 | + * +--------------------------+----+-----+----+----+---------+-----------+ + */ +} dccp_feat_table[] = { + { DCCPF_CCID, FEAT_AT_TX, FEAT_SP, 2, dccp_hdlr_ccid }, + { DCCPF_SHORT_SEQNOS, FEAT_AT_TX, FEAT_SP, 0, NULL }, + { DCCPF_SEQUENCE_WINDOW, FEAT_AT_TX, FEAT_NN, 100, dccp_hdlr_seq_win }, + { DCCPF_ECN_INCAPABLE, FEAT_AT_RX, FEAT_SP, 0, NULL }, + { DCCPF_ACK_RATIO, FEAT_AT_TX, FEAT_NN, 2, dccp_hdlr_ack_ratio}, + { DCCPF_SEND_ACK_VECTOR, FEAT_AT_RX, FEAT_SP, 0, dccp_hdlr_ackvec }, + { DCCPF_SEND_NDP_COUNT, FEAT_AT_TX, FEAT_SP, 0, dccp_hdlr_ndp }, + { DCCPF_MIN_CSUM_COVER, FEAT_AT_RX, FEAT_SP, 0, dccp_hdlr_min_cscov}, + { DCCPF_DATA_CHECKSUM, FEAT_AT_RX, FEAT_SP, 0, NULL }, + { DCCPF_SEND_LEV_RATE, FEAT_AT_RX, FEAT_SP, 0, NULL }, +}; +#define DCCP_FEAT_SUPPORTED_MAX ARRAY_SIZE(dccp_feat_table) + +/** + * dccp_feat_index - Hash function to map feature number into array position + * Returns consecutive array index or -1 if the feature is not understood. + */ +static int dccp_feat_index(u8 feat_num) +{ + /* The first 9 entries are occupied by the types from RFC 4340, 6.4 */ + if (feat_num > DCCPF_RESERVED && feat_num <= DCCPF_DATA_CHECKSUM) + return feat_num - 1; - /* Are values in any order? XXX Lame "algorithm" here */ - for (i = 0; i < slen; i++) { - for (j = 0; j < rlen; j++) { - if (spref[i] == rpref[j]) { - res = &spref[i]; - break; - } - } - if (res) - break; + /* + * Other features: add cases for new feature types here after adding + * them to the above table. + */ + switch (feat_num) { + case DCCPF_SEND_LEV_RATE: + return DCCP_FEAT_SUPPORTED_MAX - 1; } + return -1; +} - /* we didn't agree on anything */ - if (res == NULL) { - /* confirm previous value */ - switch (opt->dccpop_feat) { - case DCCPF_CCID: - /* XXX did i get this right? =P */ - if (opt->dccpop_type == DCCPO_CHANGE_L) - res = &dccp_msk(sk)->dccpms_tx_ccid; - else - res = &dccp_msk(sk)->dccpms_rx_ccid; - break; +static u8 dccp_feat_type(u8 feat_num) +{ + int idx = dccp_feat_index(feat_num); - default: - DCCP_BUG("Fell through, feat=%d", opt->dccpop_feat); - /* XXX implement res */ - return -EFAULT; - } + if (idx < 0) + return FEAT_UNKNOWN; + return dccp_feat_table[idx].reconciliation; +} - dccp_pr_debug("Don't agree... reconfirming %d\n", *res); - agree = 0; /* this is used for mandatory options... */ - } +static int dccp_feat_default_value(u8 feat_num) +{ + int idx = dccp_feat_index(feat_num); + /* + * There are no default values for unknown features, so encountering a + * negative index here indicates a serious problem somewhere else. + */ + DCCP_BUG_ON(idx < 0); - /* need to put result and our preference list */ - rlen = 1 + opt->dccpop_len; - rpref = kmalloc(rlen, GFP_ATOMIC); - if (rpref == NULL) - return -ENOMEM; + return idx < 0 ? 0 : dccp_feat_table[idx].default_value; +} - *rpref = *res; - memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len); +static int __dccp_feat_activate(struct sock *sk, const int idx, + const bool is_local, dccp_feat_val const *fval) +{ + bool rx; + u64 val; - /* put it in the "confirm queue" */ - if (opt->dccpop_sc == NULL) { - opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC); - if (opt->dccpop_sc == NULL) { - kfree(rpref); - return -ENOMEM; + if (idx < 0 || idx >= DCCP_FEAT_SUPPORTED_MAX) + return -1; + if (dccp_feat_table[idx].activation_hdlr == NULL) + return 0; + + if (fval == NULL) { + val = dccp_feat_table[idx].default_value; + } else if (dccp_feat_table[idx].reconciliation == FEAT_SP) { + if (fval->sp.vec == NULL) { + /* + * This can happen when an empty Confirm is sent + * for an SP (i.e. known) feature. In this case + * we would be using the default anyway. + */ + DCCP_CRIT("Feature #%d undefined: using default", idx); + val = dccp_feat_table[idx].default_value; + } else { + val = fval->sp.vec[0]; } } else { - /* recycle the confirm slot */ - BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); - kfree(opt->dccpop_sc->dccpoc_val); - dccp_pr_debug("recycling confirm slot\n"); + val = fval->nn; } - memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc)); - opt->dccpop_sc->dccpoc_val = rpref; - opt->dccpop_sc->dccpoc_len = rlen; + /* Location is RX if this is a local-RX or remote-TX feature */ + rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX)); - /* update the option on our side [we are about to send the confirm] */ - rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res); - if (rc) { - kfree(opt->dccpop_sc->dccpoc_val); - kfree(opt->dccpop_sc); - opt->dccpop_sc = NULL; - return rc; - } + return dccp_feat_table[idx].activation_hdlr(sk, val, rx); +} - dccp_pr_debug("Will confirm %d\n", *rpref); +/* Test for "Req'd" feature (RFC 4340, 6.4) */ +static inline int dccp_feat_must_be_understood(u8 feat_num) +{ + return feat_num == DCCPF_CCID || feat_num == DCCPF_SHORT_SEQNOS || + feat_num == DCCPF_SEQUENCE_WINDOW; +} - /* say we want to change to X but we just got a confirm X, suppress our - * change - */ - if (!opt->dccpop_conf) { - if (*opt->dccpop_val == *res) - opt->dccpop_conf = 1; - dccp_pr_debug("won't ask for change of same feature\n"); +/* copy constructor, fval must not already contain allocated memory */ +static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len) +{ + fval->sp.len = len; + if (fval->sp.len > 0) { + fval->sp.vec = kmemdup(val, len, gfp_any()); + if (fval->sp.vec == NULL) { + fval->sp.len = 0; + return -ENOBUFS; + } } + return 0; +} - return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */ +static void dccp_feat_val_destructor(u8 feat_num, dccp_feat_val *val) +{ + if (unlikely(val == NULL)) + return; + if (dccp_feat_type(feat_num) == FEAT_SP) + kfree(val->sp.vec); + memset(val, 0, sizeof(*val)); } -static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) +static struct dccp_feat_entry * + dccp_feat_clone_entry(struct dccp_feat_entry const *original) { - struct dccp_minisock *dmsk = dccp_msk(sk); - struct dccp_opt_pend *opt; - int rc = 1; - u8 t; + struct dccp_feat_entry *new; + u8 type = dccp_feat_type(original->feat_num); - /* - * We received a CHANGE. We gotta match it against our own preference - * list. If we got a CHANGE_R it means it's a change for us, so we need - * to compare our CHANGE_L list. - */ - if (type == DCCPO_CHANGE_L) - t = DCCPO_CHANGE_R; - else - t = DCCPO_CHANGE_L; + if (type == FEAT_UNKNOWN) + return NULL; - /* find our preference list for this feature */ - list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { - if (opt->dccpop_type != t || opt->dccpop_feat != feature) - continue; + new = kmemdup(original, sizeof(struct dccp_feat_entry), gfp_any()); + if (new == NULL) + return NULL; - /* find the winner from the two preference lists */ - rc = dccp_feat_reconcile(sk, opt, val, len); - break; + if (type == FEAT_SP && dccp_feat_clone_sp_val(&new->val, + original->val.sp.vec, + original->val.sp.len)) { + kfree(new); + return NULL; } + return new; +} - /* We didn't deal with the change. This can happen if we have no - * preference list for the feature. In fact, it just shouldn't - * happen---if we understand a feature, we should have a preference list - * with at least the default value. - */ - BUG_ON(rc == 1); +static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry) +{ + if (entry != NULL) { + dccp_feat_val_destructor(entry->feat_num, &entry->val); + kfree(entry); + } +} - return rc; +/* + * List management functions + * + * Feature negotiation lists rely on and maintain the following invariants: + * - each feat_num in the list is known, i.e. we know its type and default value + * - each feat_num/is_local combination is unique (old entries are overwritten) + * - SP values are always freshly allocated + * - list is sorted in increasing order of feature number (faster lookup) + */ +static struct dccp_feat_entry *dccp_feat_list_lookup(struct list_head *fn_list, + u8 feat_num, bool is_local) +{ + struct dccp_feat_entry *entry; + + list_for_each_entry(entry, fn_list, node) { + if (entry->feat_num == feat_num && entry->is_local == is_local) + return entry; + else if (entry->feat_num > feat_num) + break; + } + return NULL; } -static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) +/** + * dccp_feat_entry_new - Central list update routine (called by all others) + * @head: list to add to + * @feat: feature number + * @local: whether the local (1) or remote feature with number @feat is meant + * This is the only constructor and serves to ensure the above invariants. + */ +static struct dccp_feat_entry * + dccp_feat_entry_new(struct list_head *head, u8 feat, bool local) { - struct dccp_opt_pend *opt; - struct dccp_minisock *dmsk = dccp_msk(sk); - u8 *copy; - int rc; + struct dccp_feat_entry *entry; + + list_for_each_entry(entry, head, node) + if (entry->feat_num == feat && entry->is_local == local) { + dccp_feat_val_destructor(entry->feat_num, &entry->val); + return entry; + } else if (entry->feat_num > feat) { + head = &entry->node; + break; + } - /* NN features must be Change L (sec. 6.3.2) */ - if (type != DCCPO_CHANGE_L) { - dccp_pr_debug("received %s for NN feature %d\n", - dccp_feat_typename(type), feature); - return -EFAULT; + entry = kmalloc(sizeof(*entry), gfp_any()); + if (entry != NULL) { + entry->feat_num = feat; + entry->is_local = local; + list_add_tail(&entry->node, head); } + return entry; +} - /* XXX sanity check opt val */ +/** + * dccp_feat_push_change - Add/overwrite a Change option in the list + * @fn_list: feature-negotiation list to update + * @feat: one of %dccp_feature_numbers + * @local: whether local (1) or remote (0) @feat_num is meant + * @needs_mandatory: whether to use Mandatory feature negotiation options + * @fval: pointer to NN/SP value to be inserted (will be copied) + */ +static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local, + u8 mandatory, dccp_feat_val *fval) +{ + struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local); - /* copy option so we can confirm it */ - opt = kzalloc(sizeof(*opt), GFP_ATOMIC); - if (opt == NULL) + if (new == NULL) return -ENOMEM; - copy = kmemdup(val, len, GFP_ATOMIC); - if (copy == NULL) { - kfree(opt); - return -ENOMEM; - } + new->feat_num = feat; + new->is_local = local; + new->state = FEAT_INITIALISING; + new->needs_confirm = 0; + new->empty_confirm = 0; + new->val = *fval; + new->needs_mandatory = mandatory; - opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */ - opt->dccpop_feat = feature; - opt->dccpop_val = copy; - opt->dccpop_len = len; + return 0; +} - /* change feature */ - rc = dccp_feat_update(sk, type, feature, *val); - if (rc) { - kfree(opt->dccpop_val); - kfree(opt); - return rc; - } +/** + * dccp_feat_push_confirm - Add a Confirm entry to the FN list + * @fn_list: feature-negotiation list to add to + * @feat: one of %dccp_feature_numbers + * @local: whether local (1) or remote (0) @feat_num is being confirmed + * @fval: pointer to NN/SP value to be inserted or NULL + * Returns 0 on success, a Reset code for further processing otherwise. + */ +static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local, + dccp_feat_val *fval) +{ + struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local); - dccp_feat_debug(type, feature, *copy); + if (new == NULL) + return DCCP_RESET_CODE_TOO_BUSY; - list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); + new->feat_num = feat; + new->is_local = local; + new->state = FEAT_STABLE; /* transition in 6.6.2 */ + new->needs_confirm = 1; + new->empty_confirm = (fval == NULL); + new->val.nn = 0; /* zeroes the whole structure */ + if (!new->empty_confirm) + new->val = *fval; + new->needs_mandatory = 0; return 0; } -static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, - u8 type, u8 feature) +static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local) { - /* XXX check if other confirms for that are queued and recycle slot */ - struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC); + return dccp_feat_push_confirm(fn_list, feat, local, NULL); +} - if (opt == NULL) { - /* XXX what do we do? Ignoring should be fine. It's a change - * after all =P - */ - return; - } +static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry) +{ + list_del(&entry->node); + dccp_feat_entry_destructor(entry); +} - switch (type) { - case DCCPO_CHANGE_L: - opt->dccpop_type = DCCPO_CONFIRM_R; - break; - case DCCPO_CHANGE_R: - opt->dccpop_type = DCCPO_CONFIRM_L; - break; - default: - DCCP_WARN("invalid type %d\n", type); - kfree(opt); - return; +void dccp_feat_list_purge(struct list_head *fn_list) +{ + struct dccp_feat_entry *entry, *next; + + list_for_each_entry_safe(entry, next, fn_list, node) + dccp_feat_entry_destructor(entry); + INIT_LIST_HEAD(fn_list); +} +EXPORT_SYMBOL_GPL(dccp_feat_list_purge); + +/* generate @to as full clone of @from - @to must not contain any nodes */ +int dccp_feat_clone_list(struct list_head const *from, struct list_head *to) +{ + struct dccp_feat_entry *entry, *new; + + INIT_LIST_HEAD(to); + list_for_each_entry(entry, from, node) { + new = dccp_feat_clone_entry(entry); + if (new == NULL) + goto cloning_failed; + list_add_tail(&new->node, to); } - opt->dccpop_feat = feature; - opt->dccpop_val = NULL; - opt->dccpop_len = 0; + return 0; + +cloning_failed: + dccp_feat_list_purge(to); + return -ENOMEM; +} - /* change feature */ - dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature); +/** + * dccp_feat_valid_nn_length - Enforce length constraints on NN options + * Length is between 0 and %DCCP_OPTVAL_MAXLEN. Used for outgoing packets only, + * incoming options are accepted as long as their values are valid. + */ +static u8 dccp_feat_valid_nn_length(u8 feat_num) +{ + if (feat_num == DCCPF_ACK_RATIO) /* RFC 4340, 11.3 and 6.6.8 */ + return 2; + if (feat_num == DCCPF_SEQUENCE_WINDOW) /* RFC 4340, 7.5.2 and 6.5 */ + return 6; + return 0; +} - list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf); +static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val) +{ + switch (feat_num) { + case DCCPF_ACK_RATIO: + return val <= DCCPF_ACK_RATIO_MAX; + case DCCPF_SEQUENCE_WINDOW: + return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX; + } + return 0; /* feature unknown - so we can't tell */ } -static void dccp_feat_flush_confirm(struct sock *sk) +/* check that SP values are within the ranges defined in RFC 4340 */ +static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val) { - struct dccp_minisock *dmsk = dccp_msk(sk); - /* Check if there is anything to confirm in the first place */ - int yes = !list_empty(&dmsk->dccpms_conf); + switch (feat_num) { + case DCCPF_CCID: + return val == DCCPC_CCID2 || val == DCCPC_CCID3; + /* Type-check Boolean feature values: */ + case DCCPF_SHORT_SEQNOS: + case DCCPF_ECN_INCAPABLE: + case DCCPF_SEND_ACK_VECTOR: + case DCCPF_SEND_NDP_COUNT: + case DCCPF_DATA_CHECKSUM: + case DCCPF_SEND_LEV_RATE: + return val < 2; + case DCCPF_MIN_CSUM_COVER: + return val < 16; + } + return 0; /* feature unknown */ +} - if (!yes) { - struct dccp_opt_pend *opt; +static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len) +{ + if (sp_list == NULL || sp_len < 1) + return 0; + while (sp_len--) + if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++)) + return 0; + return 1; +} - list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { - if (opt->dccpop_conf) { - yes = 1; - break; +/** + * dccp_feat_insert_opts - Generate FN options from current list state + * @skb: next sk_buff to be sent to the peer + * @dp: for client during handshake and general negotiation + * @dreq: used by the server only (all Changes/Confirms in LISTEN/RESPOND) + */ +int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq, + struct sk_buff *skb) +{ + struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg; + struct dccp_feat_entry *pos, *next; + u8 opt, type, len, *ptr, nn_in_nbo[DCCP_OPTVAL_MAXLEN]; + bool rpt; + + /* put entries into @skb in the order they appear in the list */ + list_for_each_entry_safe_reverse(pos, next, fn, node) { + opt = dccp_feat_genopt(pos); + type = dccp_feat_type(pos->feat_num); + rpt = false; + + if (pos->empty_confirm) { + len = 0; + ptr = NULL; + } else { + if (type == FEAT_SP) { + len = pos->val.sp.len; + ptr = pos->val.sp.vec; + rpt = pos->needs_confirm; + } else if (type == FEAT_NN) { + len = dccp_feat_valid_nn_length(pos->feat_num); + ptr = nn_in_nbo; + dccp_encode_value_var(pos->val.nn, ptr, len); + } else { + DCCP_BUG("unknown feature %u", pos->feat_num); + return -1; } } + + if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt)) + return -1; + if (pos->needs_mandatory && dccp_insert_option_mandatory(skb)) + return -1; + /* + * Enter CHANGING after transmitting the Change option (6.6.2). + */ + if (pos->state == FEAT_INITIALISING) + pos->state = FEAT_CHANGING; } + return 0; +} - if (!yes) - return; +/** + * __feat_register_nn - Register new NN value on socket + * @fn: feature-negotiation list to register with + * @feat: an NN feature from %dccp_feature_numbers + * @mandatory: use Mandatory option if 1 + * @nn_val: value to register (restricted to 4 bytes) + * Note that NN features are local by definition (RFC 4340, 6.3.2). + */ +static int __feat_register_nn(struct list_head *fn, u8 feat, + u8 mandatory, u64 nn_val) +{ + dccp_feat_val fval = { .nn = nn_val }; - /* OK there is something to confirm... */ - /* XXX check if packet is in flight? Send delayed ack?? */ - if (sk->sk_state == DCCP_OPEN) - dccp_send_ack(sk); + if (dccp_feat_type(feat) != FEAT_NN || + !dccp_feat_is_valid_nn_val(feat, nn_val)) + return -EINVAL; + + /* Don't bother with default values, they will be activated anyway. */ + if (nn_val - (u64)dccp_feat_default_value(feat) == 0) + return 0; + + return dccp_feat_push_change(fn, feat, 1, mandatory, &fval); } -int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len) +/** + * __feat_register_sp - Register new SP value/list on socket + * @fn: feature-negotiation list to register with + * @feat: an SP feature from %dccp_feature_numbers + * @is_local: whether the local (1) or the remote (0) @feat is meant + * @mandatory: use Mandatory option if 1 + * @sp_val: SP value followed by optional preference list + * @sp_len: length of @sp_val in bytes + */ +static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local, + u8 mandatory, u8 const *sp_val, u8 sp_len) { - int rc; + dccp_feat_val fval; - dccp_feat_debug(type, feature, *val); + if (dccp_feat_type(feat) != FEAT_SP || + !dccp_feat_sp_list_ok(feat, sp_val, sp_len)) + return -EINVAL; - /* figure out if it's SP or NN feature */ - switch (feature) { - /* deal with SP features */ - case DCCPF_CCID: - rc = dccp_feat_sp(sk, type, feature, val, len); - break; + /* Avoid negotiating alien CCIDs by only advertising supported ones */ + if (feat == DCCPF_CCID && !ccid_support_check(sp_val, sp_len)) + return -EOPNOTSUPP; - /* deal with NN features */ - case DCCPF_ACK_RATIO: - rc = dccp_feat_nn(sk, type, feature, val, len); - break; + if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len)) + return -ENOMEM; - /* XXX implement other features */ - default: - dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n", - dccp_feat_typename(type), feature); - rc = -EFAULT; - break; - } + return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval); +} - /* check if there were problems changing features */ - if (rc) { - /* If we don't agree on SP, we sent a confirm for old value. - * However we propagate rc to caller in case option was - * mandatory +/** + * dccp_feat_register_sp - Register requests to change SP feature values + * @sk: client or listening socket + * @feat: one of %dccp_feature_numbers + * @is_local: whether the local (1) or remote (0) @feat is meant + * @list: array of preferred values, in descending order of preference + * @len: length of @list in bytes + */ +int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, + u8 const *list, u8 len) +{ /* any changes must be registered before establishing the connection */ + if (sk->sk_state != DCCP_CLOSED) + return -EISCONN; + if (dccp_feat_type(feat) != FEAT_SP) + return -EINVAL; + return __feat_register_sp(&dccp_sk(sk)->dccps_featneg, feat, is_local, + 0, list, len); +} + +/* Analogous to dccp_feat_register_sp(), but for non-negotiable values */ +int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val) +{ + /* any changes must be registered before establishing the connection */ + if (sk->sk_state != DCCP_CLOSED) + return -EISCONN; + if (dccp_feat_type(feat) != FEAT_NN) + return -EINVAL; + return __feat_register_nn(&dccp_sk(sk)->dccps_featneg, feat, 0, val); +} + +/* + * Tracking features whose value depend on the choice of CCID + * + * This is designed with an extension in mind so that a list walk could be done + * before activating any features. However, the existing framework was found to + * work satisfactorily up until now, the automatic verification is left open. + * When adding new CCIDs, add a corresponding dependency table here. + */ +static const struct ccid_dependency *dccp_feat_ccid_deps(u8 ccid, bool is_local) +{ + static const struct ccid_dependency ccid2_dependencies[2][2] = { + /* + * CCID2 mandates Ack Vectors (RFC 4341, 4.): as CCID is a TX + * feature and Send Ack Vector is an RX feature, `is_local' + * needs to be reversed. */ - if (rc != DCCP_FEAT_SP_NOAGREE) - dccp_feat_empty_confirm(dccp_msk(sk), type, feature); + { /* Dependencies of the receiver-side (remote) CCID2 */ + { + .dependent_feat = DCCPF_SEND_ACK_VECTOR, + .is_local = true, + .is_mandatory = true, + .val = 1 + }, + { 0, 0, 0, 0 } + }, + { /* Dependencies of the sender-side (local) CCID2 */ + { + .dependent_feat = DCCPF_SEND_ACK_VECTOR, + .is_local = false, + .is_mandatory = true, + .val = 1 + }, + { 0, 0, 0, 0 } + } + }; + static const struct ccid_dependency ccid3_dependencies[2][5] = { + { /* + * Dependencies of the receiver-side CCID3 + */ + { /* locally disable Ack Vectors */ + .dependent_feat = DCCPF_SEND_ACK_VECTOR, + .is_local = true, + .is_mandatory = false, + .val = 0 + }, + { /* see below why Send Loss Event Rate is on */ + .dependent_feat = DCCPF_SEND_LEV_RATE, + .is_local = true, + .is_mandatory = true, + .val = 1 + }, + { /* NDP Count is needed as per RFC 4342, 6.1.1 */ + .dependent_feat = DCCPF_SEND_NDP_COUNT, + .is_local = false, + .is_mandatory = true, + .val = 1 + }, + { 0, 0, 0, 0 }, + }, + { /* + * CCID3 at the TX side: we request that the HC-receiver + * will not send Ack Vectors (they will be ignored, so + * Mandatory is not set); we enable Send Loss Event Rate + * (Mandatory since the implementation does not support + * the Loss Intervals option of RFC 4342, 8.6). + * The last two options are for peer's information only. + */ + { + .dependent_feat = DCCPF_SEND_ACK_VECTOR, + .is_local = false, + .is_mandatory = false, + .val = 0 + }, + { + .dependent_feat = DCCPF_SEND_LEV_RATE, + .is_local = false, + .is_mandatory = true, + .val = 1 + }, + { /* this CCID does not support Ack Ratio */ + .dependent_feat = DCCPF_ACK_RATIO, + .is_local = true, + .is_mandatory = false, + .val = 0 + }, + { /* tell receiver we are sending NDP counts */ + .dependent_feat = DCCPF_SEND_NDP_COUNT, + .is_local = true, + .is_mandatory = false, + .val = 1 + }, + { 0, 0, 0, 0 } + } + }; + switch (ccid) { + case DCCPC_CCID2: + return ccid2_dependencies[is_local]; + case DCCPC_CCID3: + return ccid3_dependencies[is_local]; + default: + return NULL; } +} - /* generate the confirm [if required] */ - dccp_feat_flush_confirm(sk); - +/** + * dccp_feat_propagate_ccid - Resolve dependencies of features on choice of CCID + * @fn: feature-negotiation list to update + * @id: CCID number to track + * @is_local: whether TX CCID (1) or RX CCID (0) is meant + * This function needs to be called after registering all other features. + */ +static int dccp_feat_propagate_ccid(struct list_head *fn, u8 id, bool is_local) +{ + const struct ccid_dependency *table = dccp_feat_ccid_deps(id, is_local); + int i, rc = (table == NULL); + + for (i = 0; rc == 0 && table[i].dependent_feat != DCCPF_RESERVED; i++) + if (dccp_feat_type(table[i].dependent_feat) == FEAT_SP) + rc = __feat_register_sp(fn, table[i].dependent_feat, + table[i].is_local, + table[i].is_mandatory, + &table[i].val, 1); + else + rc = __feat_register_nn(fn, table[i].dependent_feat, + table[i].is_mandatory, + table[i].val); return rc; } -EXPORT_SYMBOL_GPL(dccp_feat_change_recv); +/** + * dccp_feat_finalise_settings - Finalise settings before starting negotiation + * @dp: client or listening socket (settings will be inherited) + * This is called after all registrations (socket initialisation, sysctls, and + * sockopt calls), and before sending the first packet containing Change options + * (ie. client-Request or server-Response), to ensure internal consistency. + */ +int dccp_feat_finalise_settings(struct dccp_sock *dp) +{ + struct list_head *fn = &dp->dccps_featneg; + struct dccp_feat_entry *entry; + int i = 2, ccids[2] = { -1, -1 }; -int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, - u8 *val, u8 len) + /* + * Propagating CCIDs: + * 1) not useful to propagate CCID settings if this host advertises more + * than one CCID: the choice of CCID may still change - if this is + * the client, or if this is the server and the client sends + * singleton CCID values. + * 2) since is that propagate_ccid changes the list, we defer changing + * the sorted list until after the traversal. + */ + list_for_each_entry(entry, fn, node) + if (entry->feat_num == DCCPF_CCID && entry->val.sp.len == 1) + ccids[entry->is_local] = entry->val.sp.vec[0]; + while (i--) + if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i)) + return -1; + return 0; +} + +/** + * dccp_feat_server_ccid_dependencies - Resolve CCID-dependent features + * It is the server which resolves the dependencies once the CCID has been + * fully negotiated. If no CCID has been negotiated, it uses the default CCID. + */ +int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq) { - u8 t; - struct dccp_opt_pend *opt; - struct dccp_minisock *dmsk = dccp_msk(sk); - int found = 0; - int all_confirmed = 1; + struct list_head *fn = &dreq->dreq_featneg; + struct dccp_feat_entry *entry; + u8 is_local, ccid; - dccp_feat_debug(type, feature, *val); + for (is_local = 0; is_local <= 1; is_local++) { + entry = dccp_feat_list_lookup(fn, DCCPF_CCID, is_local); - /* locate our change request */ - switch (type) { - case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break; - case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break; - default: DCCP_WARN("invalid type %d\n", type); - return 1; + if (entry != NULL && !entry->empty_confirm) + ccid = entry->val.sp.vec[0]; + else + ccid = dccp_feat_default_value(DCCPF_CCID); + if (dccp_feat_propagate_ccid(fn, ccid, is_local)) + return -1; } - /* XXX sanity check feature value */ + return 0; +} - list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { - if (!opt->dccpop_conf && opt->dccpop_type == t && - opt->dccpop_feat == feature) { - found = 1; - dccp_pr_debug("feature %d found\n", opt->dccpop_feat); +/* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */ +static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen) +{ + u8 c, s; - /* XXX do sanity check */ + for (s = 0; s < slen; s++) + for (c = 0; c < clen; c++) + if (servlist[s] == clilist[c]) + return servlist[s]; + return -1; +} - opt->dccpop_conf = 1; +/** + * dccp_feat_prefer - Move preferred entry to the start of array + * Reorder the @array_len elements in @array so that @preferred_value comes + * first. Returns >0 to indicate that @preferred_value does occur in @array. + */ +static u8 dccp_feat_prefer(u8 preferred_value, u8 *array, u8 array_len) +{ + u8 i, does_occur = 0; - /* We got a confirmation---change the option */ - dccp_feat_update(sk, opt->dccpop_type, - opt->dccpop_feat, *val); + if (array != NULL) { + for (i = 0; i < array_len; i++) + if (array[i] == preferred_value) { + array[i] = array[0]; + does_occur++; + } + if (does_occur) + array[0] = preferred_value; + } + return does_occur; +} - /* XXX check the return value of dccp_feat_update */ - break; - } +/** + * dccp_feat_reconcile - Reconcile SP preference lists + * @fval: SP list to reconcile into + * @arr: received SP preference list + * @len: length of @arr in bytes + * @is_server: whether this side is the server (and @fv is the server's list) + * @reorder: whether to reorder the list in @fv after reconciling with @arr + * When successful, > 0 is returned and the reconciled list is in @fval. + * A value of 0 means that negotiation failed (no shared entry). + */ +static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len, + bool is_server, bool reorder) +{ + int rc; - if (!opt->dccpop_conf) - all_confirmed = 0; + if (!fv->sp.vec || !arr) { + DCCP_CRIT("NULL feature value or array"); + return 0; } - /* fix re-transmit timer */ - /* XXX gotta make sure that no option negotiation occurs during - * connection shutdown. Consider that the CLOSEREQ is sent and timer is - * on. if all options are confirmed it might kill timer which should - * remain alive until close is received. - */ - if (all_confirmed) { - dccp_pr_debug("clear feat negotiation timer %p\n", sk); - inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); - } + if (is_server) + rc = dccp_feat_preflist_match(fv->sp.vec, fv->sp.len, arr, len); + else + rc = dccp_feat_preflist_match(arr, len, fv->sp.vec, fv->sp.len); - if (!found) - dccp_pr_debug("%s(%d, ...) never requested\n", - dccp_feat_typename(type), feature); - return 0; -} + if (!reorder) + return rc; + if (rc < 0) + return 0; -EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); + /* + * Reorder list: used for activating features and in dccp_insert_fn_opt. + */ + return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len); +} -void dccp_feat_clean(struct dccp_minisock *dmsk) +/** + * dccp_feat_change_recv - Process incoming ChangeL/R options + * @fn: feature-negotiation list to update + * @is_mandatory: whether the Change was preceded by a Mandatory option + * @opt: %DCCPO_CHANGE_L or %DCCPO_CHANGE_R + * @feat: one of %dccp_feature_numbers + * @val: NN value or SP value/preference list + * @len: length of @val in bytes + * @server: whether this node is the server (1) or the client (0) + */ +static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt, + u8 feat, u8 *val, u8 len, const bool server) { - struct dccp_opt_pend *opt, *next; + u8 defval, type = dccp_feat_type(feat); + const bool local = (opt == DCCPO_CHANGE_R); + struct dccp_feat_entry *entry; + dccp_feat_val fval; - list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending, - dccpop_node) { - BUG_ON(opt->dccpop_val == NULL); - kfree(opt->dccpop_val); + if (len == 0 || type == FEAT_UNKNOWN) /* 6.1 and 6.6.8 */ + goto unknown_feature_or_value; + + /* + * Negotiation of NN features: Change R is invalid, so there is no + * simultaneous negotiation; hence we do not look up in the list. + */ + if (type == FEAT_NN) { + if (local || len > sizeof(fval.nn)) + goto unknown_feature_or_value; + + /* 6.3.2: "The feature remote MUST accept any valid value..." */ + fval.nn = dccp_decode_value_var(val, len); + if (!dccp_feat_is_valid_nn_val(feat, fval.nn)) + goto unknown_feature_or_value; + + return dccp_feat_push_confirm(fn, feat, local, &fval); + } + + /* + * Unidirectional/simultaneous negotiation of SP features (6.3.1) + */ + entry = dccp_feat_list_lookup(fn, feat, local); + if (entry == NULL) { + /* + * No particular preferences have been registered. We deal with + * this situation by assuming that all valid values are equally + * acceptable, and apply the following checks: + * - if the peer's list is a singleton, we accept a valid value; + * - if we are the server, we first try to see if the peer (the + * client) advertises the default value. If yes, we use it, + * otherwise we accept the preferred value; + * - else if we are the client, we use the first list element. + */ + if (dccp_feat_clone_sp_val(&fval, val, 1)) + return DCCP_RESET_CODE_TOO_BUSY; + + if (len > 1 && server) { + defval = dccp_feat_default_value(feat); + if (dccp_feat_preflist_match(&defval, 1, val, len) > -1) + fval.sp.vec[0] = defval; + } else if (!dccp_feat_is_valid_sp_val(feat, fval.sp.vec[0])) { + kfree(fval.sp.vec); + goto unknown_feature_or_value; + } - if (opt->dccpop_sc != NULL) { - BUG_ON(opt->dccpop_sc->dccpoc_val == NULL); - kfree(opt->dccpop_sc->dccpoc_val); - kfree(opt->dccpop_sc); + /* Treat unsupported CCIDs like invalid values */ + if (feat == DCCPF_CCID && !ccid_support_check(fval.sp.vec, 1)) { + kfree(fval.sp.vec); + goto not_valid_or_not_known; } - kfree(opt); + return dccp_feat_push_confirm(fn, feat, local, &fval); + + } else if (entry->state == FEAT_UNSTABLE) { /* 6.6.2 */ + return 0; } - INIT_LIST_HEAD(&dmsk->dccpms_pending); - list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { - BUG_ON(opt == NULL); - if (opt->dccpop_val != NULL) - kfree(opt->dccpop_val); - kfree(opt); + if (dccp_feat_reconcile(&entry->val, val, len, server, true)) { + entry->empty_confirm = 0; + } else if (is_mandatory) { + return DCCP_RESET_CODE_MANDATORY_ERROR; + } else if (entry->state == FEAT_INITIALISING) { + /* + * Failed simultaneous negotiation (server only): try to `save' + * the connection by checking whether entry contains the default + * value for @feat. If yes, send an empty Confirm to signal that + * the received Change was not understood - which implies using + * the default value. + * If this also fails, we use Reset as the last resort. + */ + WARN_ON(!server); + defval = dccp_feat_default_value(feat); + if (!dccp_feat_reconcile(&entry->val, &defval, 1, server, true)) + return DCCP_RESET_CODE_OPTION_ERROR; + entry->empty_confirm = 1; } - INIT_LIST_HEAD(&dmsk->dccpms_conf); -} + entry->needs_confirm = 1; + entry->needs_mandatory = 0; + entry->state = FEAT_STABLE; + return 0; -EXPORT_SYMBOL_GPL(dccp_feat_clean); +unknown_feature_or_value: + if (!is_mandatory) + return dccp_push_empty_confirm(fn, feat, local); -/* this is to be called only when a listening sock creates its child. It is - * assumed by the function---the confirm is not duplicated, but rather it is - * "passed on". +not_valid_or_not_known: + return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR + : DCCP_RESET_CODE_OPTION_ERROR; +} + +/** + * dccp_feat_confirm_recv - Process received Confirm options + * @fn: feature-negotiation list to update + * @is_mandatory: whether @opt was preceded by a Mandatory option + * @opt: %DCCPO_CONFIRM_L or %DCCPO_CONFIRM_R + * @feat: one of %dccp_feature_numbers + * @val: NN value or SP value/preference list + * @len: length of @val in bytes + * @server: whether this node is server (1) or client (0) */ -int dccp_feat_clone(struct sock *oldsk, struct sock *newsk) +static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt, + u8 feat, u8 *val, u8 len, const bool server) { - struct dccp_minisock *olddmsk = dccp_msk(oldsk); - struct dccp_minisock *newdmsk = dccp_msk(newsk); - struct dccp_opt_pend *opt; - int rc = 0; + u8 *plist, plen, type = dccp_feat_type(feat); + const bool local = (opt == DCCPO_CONFIRM_R); + struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local); - INIT_LIST_HEAD(&newdmsk->dccpms_pending); - INIT_LIST_HEAD(&newdmsk->dccpms_conf); + if (entry == NULL) { /* nothing queued: ignore or handle error */ + if (is_mandatory && type == FEAT_UNKNOWN) + return DCCP_RESET_CODE_MANDATORY_ERROR; + + if (!local && type == FEAT_NN) /* 6.3.2 */ + goto confirmation_failed; + return 0; + } - list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) { - struct dccp_opt_pend *newopt; - /* copy the value of the option */ - u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC); + if (entry->state != FEAT_CHANGING) /* 6.6.2 */ + return 0; - if (val == NULL) - goto out_clean; + if (len == 0) { + if (dccp_feat_must_be_understood(feat)) /* 6.6.7 */ + goto confirmation_failed; + /* + * Empty Confirm during connection setup: this means reverting + * to the `old' value, which in this case is the default. Since + * we handle default values automatically when no other values + * have been set, we revert to the old value by removing this + * entry from the list. + */ + dccp_feat_list_pop(entry); + return 0; + } - newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC); - if (newopt == NULL) { - kfree(val); - goto out_clean; - } + if (type == FEAT_NN) { + if (len > sizeof(entry->val.nn)) + goto confirmation_failed; - /* insert the option */ - newopt->dccpop_val = val; - list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending); + if (entry->val.nn == dccp_decode_value_var(val, len)) + goto confirmation_succeeded; - /* XXX what happens with backlogs and multiple connections at - * once... - */ - /* the master socket no longer needs to worry about confirms */ - opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */ + DCCP_WARN("Bogus Confirm for non-existing value\n"); + goto confirmation_failed; + } - /* reset state for a new socket */ - opt->dccpop_conf = 0; + /* + * Parsing SP Confirms: the first element of @val is the preferred + * SP value which the peer confirms, the remainder depends on @len. + * Note that only the confirmed value need to be a valid SP value. + */ + if (!dccp_feat_is_valid_sp_val(feat, *val)) + goto confirmation_failed; + + if (len == 1) { /* peer didn't supply a preference list */ + plist = val; + plen = len; + } else { /* preferred value + preference list */ + plist = val + 1; + plen = len - 1; } - /* XXX not doing anything about the conf queue */ + /* Check whether the peer got the reconciliation right (6.6.8) */ + if (dccp_feat_reconcile(&entry->val, plist, plen, server, 0) != *val) { + DCCP_WARN("Confirm selected the wrong value %u\n", *val); + return DCCP_RESET_CODE_OPTION_ERROR; + } + entry->val.sp.vec[0] = *val; -out: - return rc; +confirmation_succeeded: + entry->state = FEAT_STABLE; + return 0; -out_clean: - dccp_feat_clean(newdmsk); - rc = -ENOMEM; - goto out; +confirmation_failed: + DCCP_WARN("Confirmation failed\n"); + return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR + : DCCP_RESET_CODE_OPTION_ERROR; } -EXPORT_SYMBOL_GPL(dccp_feat_clone); - -static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat, - u8 *val, u8 len) +/** + * dccp_feat_parse_options - Process Feature-Negotiation Options + * @sk: for general use and used by the client during connection setup + * @dreq: used by the server during connection setup + * @mandatory: whether @opt was preceded by a Mandatory option + * @opt: %DCCPO_CHANGE_L | %DCCPO_CHANGE_R | %DCCPO_CONFIRM_L | %DCCPO_CONFIRM_R + * @feat: one of %dccp_feature_numbers + * @val: value contents of @opt + * @len: length of @val in bytes + * Returns 0 on success, a Reset code for ending the connection otherwise. + */ +int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq, + u8 mandatory, u8 opt, u8 feat, u8 *val, u8 len) { - int rc = -ENOMEM; - u8 *copy = kmemdup(val, len, GFP_KERNEL); + struct dccp_sock *dp = dccp_sk(sk); + struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg; + bool server = false; - if (copy != NULL) { - rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL); - if (rc) - kfree(copy); + switch (sk->sk_state) { + /* + * Negotiation during connection setup + */ + case DCCP_LISTEN: + server = true; /* fall through */ + case DCCP_REQUESTING: + switch (opt) { + case DCCPO_CHANGE_L: + case DCCPO_CHANGE_R: + return dccp_feat_change_recv(fn, mandatory, opt, feat, + val, len, server); + case DCCPO_CONFIRM_R: + case DCCPO_CONFIRM_L: + return dccp_feat_confirm_recv(fn, mandatory, opt, feat, + val, len, server); + } } - return rc; + return 0; /* ignore FN options in all other states */ } -int dccp_feat_init(struct dccp_minisock *dmsk) +int dccp_feat_init(struct sock *sk) { + struct dccp_sock *dp = dccp_sk(sk); + struct dccp_minisock *dmsk = dccp_msk(sk); int rc; - INIT_LIST_HEAD(&dmsk->dccpms_pending); - INIT_LIST_HEAD(&dmsk->dccpms_conf); - - /* CCID L */ - rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID, - &dmsk->dccpms_tx_ccid, 1); - if (rc) - goto out; - - /* CCID R */ - rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID, - &dmsk->dccpms_rx_ccid, 1); - if (rc) - goto out; + INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */ + INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */ /* Ack ratio */ - rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO, - &dmsk->dccpms_ack_ratio, 1); -out: + rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0, + dp->dccps_l_ack_ratio); return rc; } EXPORT_SYMBOL_GPL(dccp_feat_init); +int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list) +{ + struct dccp_sock *dp = dccp_sk(sk); + struct dccp_feat_entry *cur, *next; + int idx; + dccp_feat_val *fvals[DCCP_FEAT_SUPPORTED_MAX][2] = { + [0 ... DCCP_FEAT_SUPPORTED_MAX-1] = { NULL, NULL } + }; + + list_for_each_entry(cur, fn_list, node) { + /* + * An empty Confirm means that either an unknown feature type + * or an invalid value was present. In the first case there is + * nothing to activate, in the other the default value is used. + */ + if (cur->empty_confirm) + continue; + + idx = dccp_feat_index(cur->feat_num); + if (idx < 0) { + DCCP_BUG("Unknown feature %u", cur->feat_num); + goto activation_failed; + } + if (cur->state != FEAT_STABLE) { + DCCP_CRIT("Negotiation of %s %u failed in state %u", + cur->is_local ? "local" : "remote", + cur->feat_num, cur->state); + goto activation_failed; + } + fvals[idx][cur->is_local] = &cur->val; + } + + /* + * Activate in decreasing order of index, so that the CCIDs are always + * activated as the last feature. This avoids the case where a CCID + * relies on the initialisation of one or more features that it depends + * on (e.g. Send NDP Count, Send Ack Vector, and Ack Ratio features). + */ + for (idx = DCCP_FEAT_SUPPORTED_MAX; --idx >= 0;) + if (__dccp_feat_activate(sk, idx, 0, fvals[idx][0]) || + __dccp_feat_activate(sk, idx, 1, fvals[idx][1])) { + DCCP_CRIT("Could not activate %d", idx); + goto activation_failed; + } + + /* Clean up Change options which have been confirmed already */ + list_for_each_entry_safe(cur, next, fn_list, node) + if (!cur->needs_confirm) + dccp_feat_list_pop(cur); + + dccp_pr_debug("Activation OK\n"); + return 0; + +activation_failed: + /* + * We clean up everything that may have been allocated, since + * it is difficult to track at which stage negotiation failed. + * This is ok, since all allocation functions below are robust + * against NULL arguments. + */ + ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); + ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); + dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; + dccp_ackvec_free(dp->dccps_hc_rx_ackvec); + dp->dccps_hc_rx_ackvec = NULL; + return -1; +} + #ifdef CONFIG_IP_DCCP_DEBUG const char *dccp_feat_typename(const u8 type) { @@ -639,6 +1233,8 @@ const char *dccp_feat_name(const u8 feat) if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC) return feature_names[DCCPF_RESERVED]; + if (feat == DCCPF_SEND_LEV_RATE) + return "Send Loss Event Rate"; if (feat >= DCCPF_MIN_CCID_SPECIFIC) return "CCID-specific"; diff --git a/net/dccp/feat.h b/net/dccp/feat.h index e272222c7ace353951cf5cade968a54663a5e443..9b46e2a7866e675db04857d21b0b58899af70b8f 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h @@ -3,17 +3,103 @@ /* * net/dccp/feat.h * - * An implementation of the DCCP protocol + * Feature negotiation for the DCCP protocol (RFC 4340, section 6) + * Copyright (c) 2008 Gerrit Renker * Copyright (c) 2005 Andrea Bittau * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. + * This program is 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 #include "dccp.h" +/* + * Known limit values + */ +/* Ack Ratio takes 2-byte integer values (11.3) */ +#define DCCPF_ACK_RATIO_MAX 0xFFFF +/* Wmin=32 and Wmax=2^46-1 from 7.5.2 */ +#define DCCPF_SEQ_WMIN 32 +#define DCCPF_SEQ_WMAX 0x3FFFFFFFFFFFull +/* Maximum number of SP values that fit in a single (Confirm) option */ +#define DCCP_FEAT_MAX_SP_VALS (DCCP_SINGLE_OPT_MAXLEN - 2) + +enum dccp_feat_type { + FEAT_AT_RX = 1, /* located at RX side of half-connection */ + FEAT_AT_TX = 2, /* located at TX side of half-connection */ + FEAT_SP = 4, /* server-priority reconciliation (6.3.1) */ + FEAT_NN = 8, /* non-negotiable reconciliation (6.3.2) */ + FEAT_UNKNOWN = 0xFF /* not understood or invalid feature */ +}; + +enum dccp_feat_state { + FEAT_DEFAULT = 0, /* using default values from 6.4 */ + FEAT_INITIALISING, /* feature is being initialised */ + FEAT_CHANGING, /* Change sent but not confirmed yet */ + FEAT_UNSTABLE, /* local modification in state CHANGING */ + FEAT_STABLE /* both ends (think they) agree */ +}; + +/** + * dccp_feat_val - Container for SP or NN feature values + * @nn: single NN value + * @sp.vec: single SP value plus optional preference list + * @sp.len: length of @sp.vec in bytes + */ +typedef union { + u64 nn; + struct { + u8 *vec; + u8 len; + } sp; +} dccp_feat_val; + +/** + * struct feat_entry - Data structure to perform feature negotiation + * @val: feature's current value (SP features may have preference list) + * @state: feature's current state + * @feat_num: one of %dccp_feature_numbers + * @needs_mandatory: whether Mandatory options should be sent + * @needs_confirm: whether to send a Confirm instead of a Change + * @empty_confirm: whether to send an empty Confirm (depends on @needs_confirm) + * @is_local: feature location (1) or feature-remote (0) + * @node: list pointers, entries arranged in FIFO order + */ +struct dccp_feat_entry { + dccp_feat_val val; + enum dccp_feat_state state:8; + u8 feat_num; + + bool needs_mandatory, + needs_confirm, + empty_confirm, + is_local; + + struct list_head node; +}; + +static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry) +{ + if (entry->needs_confirm) + return entry->is_local ? DCCPO_CONFIRM_L : DCCPO_CONFIRM_R; + return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R; +} + +/** + * struct ccid_dependency - Track changes resulting from choosing a CCID + * @dependent_feat: one of %dccp_feature_numbers + * @is_local: local (1) or remote (0) @dependent_feat + * @is_mandatory: whether presence of @dependent_feat is mission-critical or not + * @val: corresponding default value for @dependent_feat (u8 is sufficient here) + */ +struct ccid_dependency { + u8 dependent_feat; + bool is_local:1, + is_mandatory:1; + u8 val; +}; + #ifdef CONFIG_IP_DCCP_DEBUG extern const char *dccp_feat_typename(const u8 type); extern const char *dccp_feat_name(const u8 feat); @@ -27,14 +113,30 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val) #define dccp_feat_debug(type, feat, val) #endif /* CONFIG_IP_DCCP_DEBUG */ -extern int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, - u8 *val, u8 len, gfp_t gfp); -extern int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, - u8 *val, u8 len); -extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, - u8 *val, u8 len); -extern void dccp_feat_clean(struct dccp_minisock *dmsk); -extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); -extern int dccp_feat_init(struct dccp_minisock *dmsk); +extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, + u8 const *list, u8 len); +extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); +extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *, + u8 mand, u8 opt, u8 feat, u8 *val, u8 len); +extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); +extern int dccp_feat_init(struct sock *sk); + +/* + * Encoding variable-length options and their maximum length. + * + * This affects NN options (SP options are all u8) and other variable-length + * options (see table 3 in RFC 4340). The limit is currently given the Sequence + * Window NN value (sec. 7.5.2) and the NDP count (sec. 7.7) option, all other + * options consume less than 6 bytes (timestamps are 4 bytes). + * When updating this constant (e.g. due to new internet drafts / RFCs), make + * sure that you also update all code which refers to it. + */ +#define DCCP_OPTVAL_MAXLEN 6 + +extern void dccp_encode_value_var(const u64 value, u8 *to, const u8 len); +extern u64 dccp_decode_value_var(const u8 *bf, const u8 len); +extern int dccp_insert_option_mandatory(struct sk_buff *skb); +extern int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat, + u8 *val, u8 len, bool repeat_first); #endif /* _DCCP_FEAT_H */ diff --git a/net/dccp/input.c b/net/dccp/input.c index 779d0ed9ae94420149ef44cf8ad14fb7f8799ca4..5eb443f656c19ea115114379703c72bc31e79fb0 100644 --- a/net/dccp/input.c +++ b/net/dccp/input.c @@ -163,7 +163,7 @@ static void dccp_event_ack_recv(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); - if (dccp_msk(sk)->dccpms_send_ack_vector) + if (dp->dccps_hc_rx_ackvec != NULL) dccp_ackvec_check_rcv_ackno(dp->dccps_hc_rx_ackvec, sk, DCCP_SKB_CB(skb)->dccpd_ack_seq); } @@ -375,7 +375,7 @@ int dccp_rcv_established(struct sock *sk, struct sk_buff *skb, if (DCCP_SKB_CB(skb)->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) dccp_event_ack_recv(sk, skb); - if (dccp_msk(sk)->dccpms_send_ack_vector && + if (dp->dccps_hc_rx_ackvec != NULL && dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, DCCP_SKB_CB(skb)->dccpd_seq, DCCP_ACKVEC_STATE_RECEIVED)) @@ -421,20 +421,19 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, goto out_invalid_packet; } + /* + * If option processing (Step 8) failed, return 1 here so that + * dccp_v4_do_rcv() sends a Reset. The Reset code depends on + * the option type and is set in dccp_parse_options(). + */ if (dccp_parse_options(sk, NULL, skb)) - goto out_invalid_packet; + return 1; /* Obtain usec RTT sample from SYN exchange (used by CCID 3) */ if (likely(dp->dccps_options_received.dccpor_timestamp_echo)) dp->dccps_syn_rtt = dccp_sample_rtt(sk, 10 * (tstamp - dp->dccps_options_received.dccpor_timestamp_echo)); - if (dccp_msk(sk)->dccpms_send_ack_vector && - dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, - DCCP_SKB_CB(skb)->dccpd_seq, - DCCP_ACKVEC_STATE_RECEIVED)) - goto out_invalid_packet; /* FIXME: change error code */ - /* Stop the REQUEST timer */ inet_csk_clear_xmit_timer(sk, ICSK_TIME_RETRANS); WARN_ON(sk->sk_send_head == NULL); @@ -475,6 +474,15 @@ static int dccp_rcv_request_sent_state_process(struct sock *sk, */ dccp_set_state(sk, DCCP_PARTOPEN); + /* + * If feature negotiation was successful, activate features now; + * an activation failure means that this host could not activate + * one ore more features (e.g. insufficient memory), which would + * leave at least one feature in an undefined state. + */ + if (dccp_feat_activate_values(sk, &dp->dccps_featneg)) + goto unable_to_proceed; + /* Make sure socket is routed, for correct metrics. */ icsk->icsk_af_ops->rebuild_header(sk); @@ -509,6 +517,16 @@ out_invalid_packet: /* dccp_v4_do_rcv will send a reset */ DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_PACKET_ERROR; return 1; + +unable_to_proceed: + DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_ABORTED; + /* + * We mark this socket as no longer usable, so that the loop in + * dccp_sendmsg() terminates and the application gets notified. + */ + dccp_set_state(sk, DCCP_CLOSED); + sk->sk_err = ECOMM; + return 1; } static int dccp_rcv_respond_partopen_state_process(struct sock *sk, @@ -590,8 +608,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, if (inet_csk(sk)->icsk_af_ops->conn_request(sk, skb) < 0) return 1; - - /* FIXME: do congestion control initialization */ goto discard; } if (dh->dccph_type == DCCP_PKT_RESET) @@ -602,7 +618,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, return 1; } - if (sk->sk_state != DCCP_REQUESTING) { + if (sk->sk_state != DCCP_REQUESTING && sk->sk_state != DCCP_RESPOND) { if (dccp_check_seqno(sk, skb)) goto discard; @@ -615,7 +631,7 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, if (dcb->dccpd_ack_seq != DCCP_PKT_WITHOUT_ACK_SEQ) dccp_event_ack_recv(sk, skb); - if (dccp_msk(sk)->dccpms_send_ack_vector && + if (dp->dccps_hc_rx_ackvec != NULL && dccp_ackvec_add(dp->dccps_hc_rx_ackvec, sk, DCCP_SKB_CB(skb)->dccpd_seq, DCCP_ACKVEC_STATE_RECEIVED)) @@ -667,8 +683,6 @@ int dccp_rcv_state_process(struct sock *sk, struct sk_buff *skb, return 1; case DCCP_REQUESTING: - /* FIXME: do congestion control initialization */ - queued = dccp_rcv_request_sent_state_process(sk, skb, dh, len); if (queued >= 0) return queued; diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index e3dfddab21cc233e929ff2a6cc81a7d3a4284ce2..d1dd95289b8960bd1556e3cecbd025b4bb83ca8e 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -545,6 +545,7 @@ out: static void dccp_v4_reqsk_destructor(struct request_sock *req) { + dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg); kfree(inet_rsk(req)->opt); } @@ -595,7 +596,8 @@ int dccp_v4_conn_request(struct sock *sk, struct sk_buff *skb) if (req == NULL) goto drop; - dccp_reqsk_init(req, skb); + if (dccp_reqsk_init(req, dccp_sk(sk), skb)) + goto drop_and_free; dreq = dccp_rsk(req); if (dccp_parse_options(sk, dreq, skb)) @@ -792,12 +794,10 @@ static int dccp_v4_rcv(struct sk_buff *skb) DCCP_SKB_CB(skb)->dccpd_seq = dccp_hdr_seq(dh); DCCP_SKB_CB(skb)->dccpd_type = dh->dccph_type; - dccp_pr_debug("%8.8s " - "src=%u.%u.%u.%u@%-5d " - "dst=%u.%u.%u.%u@%-5d seq=%llu", + dccp_pr_debug("%8.8s src=%pI4@%-5d dst=%pI4@%-5d seq=%llu", dccp_packet_name(dh->dccph_type), - NIPQUAD(iph->saddr), ntohs(dh->dccph_sport), - NIPQUAD(iph->daddr), ntohs(dh->dccph_dport), + &iph->saddr, ntohs(dh->dccph_sport), + &iph->daddr, ntohs(dh->dccph_dport), (unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq); if (dccp_packet_without_ack(skb)) { @@ -938,6 +938,7 @@ static struct proto dccp_v4_prot = { .orphan_count = &dccp_orphan_count, .max_header = MAX_DCCP_HEADER, .obj_size = sizeof(struct dccp_sock), + .slab_flags = SLAB_DESTROY_BY_RCU, .rsk_prot = &dccp_request_sock_ops, .twsk_prot = &dccp_timewait_sock_ops, .h.hashinfo = &dccp_hashinfo, diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index d4ce1224e008f13ee4da674cec0c6047a3a9f25f..b963f35c65f6616ae5da169c3f328e7a73767ed0 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -168,7 +168,7 @@ static void dccp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, goto out; } - err = xfrm_lookup(&dst, &fl, sk, 0); + err = xfrm_lookup(net, &dst, &fl, sk, 0); if (err < 0) { sk->sk_err_soft = -err; goto out; @@ -279,7 +279,7 @@ static int dccp_v6_send_response(struct sock *sk, struct request_sock *req) if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - err = xfrm_lookup(&dst, &fl, sk, 0); + err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0); if (err < 0) goto done; @@ -304,6 +304,7 @@ done: static void dccp_v6_reqsk_destructor(struct request_sock *req) { + dccp_feat_list_purge(&dccp_rsk(req)->dreq_featneg); if (inet6_rsk(req)->pktopts != NULL) kfree_skb(inet6_rsk(req)->pktopts); } @@ -342,7 +343,7 @@ static void dccp_v6_ctl_send_reset(struct sock *sk, struct sk_buff *rxskb) /* sk = NULL, but it is safe for now. RST socket required. */ if (!ip6_dst_lookup(ctl_sk, &skb->dst, &fl)) { - if (xfrm_lookup(&skb->dst, &fl, NULL, 0) >= 0) { + if (xfrm_lookup(net, &skb->dst, &fl, NULL, 0) >= 0) { ip6_xmit(ctl_sk, skb, &fl, NULL, 0); DCCP_INC_STATS_BH(DCCP_MIB_OUTSEGS); DCCP_INC_STATS_BH(DCCP_MIB_OUTRSTS); @@ -426,7 +427,8 @@ static int dccp_v6_conn_request(struct sock *sk, struct sk_buff *skb) if (req == NULL) goto drop; - dccp_reqsk_init(req, skb); + if (dccp_reqsk_init(req, dccp_sk(sk), skb)) + goto drop_and_free; dreq = dccp_rsk(req); if (dccp_parse_options(sk, dreq, skb)) @@ -567,7 +569,7 @@ static struct sock *dccp_v6_request_recv_sock(struct sock *sk, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0) + if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) goto out; } @@ -1002,7 +1004,7 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT); + err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT); if (err < 0) { if (err == -EREMOTE) err = ip6_dst_blackhole(sk, &dst, &fl); @@ -1138,6 +1140,7 @@ static struct proto dccp_v6_prot = { .orphan_count = &dccp_orphan_count, .max_header = MAX_DCCP_HEADER, .obj_size = sizeof(struct dccp6_sock), + .slab_flags = SLAB_DESTROY_BY_RCU, .rsk_prot = &dccp6_request_sock_ops, .twsk_prot = &dccp6_timewait_sock_ops, .h.hashinfo = &dccp_hashinfo, diff --git a/net/dccp/minisocks.c b/net/dccp/minisocks.c index e6bf99e3e41a169aec04880e52d60adb41dc8b62..6821ae33dd37a02600dc80b4ba7f8f8452c6185a 100644 --- a/net/dccp/minisocks.c +++ b/net/dccp/minisocks.c @@ -45,11 +45,6 @@ EXPORT_SYMBOL_GPL(dccp_death_row); void dccp_minisock_init(struct dccp_minisock *dmsk) { dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window; - dmsk->dccpms_rx_ccid = sysctl_dccp_feat_rx_ccid; - dmsk->dccpms_tx_ccid = sysctl_dccp_feat_tx_ccid; - dmsk->dccpms_ack_ratio = sysctl_dccp_feat_ack_ratio; - dmsk->dccpms_send_ack_vector = sysctl_dccp_feat_send_ack_vector; - dmsk->dccpms_send_ndp_count = sysctl_dccp_feat_send_ndp_count; } void dccp_time_wait(struct sock *sk, int state, int timeo) @@ -112,7 +107,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk, struct sock *newsk = inet_csk_clone(sk, req, GFP_ATOMIC); if (newsk != NULL) { - const struct dccp_request_sock *dreq = dccp_rsk(req); + struct dccp_request_sock *dreq = dccp_rsk(req); struct inet_connection_sock *newicsk = inet_csk(newsk); struct dccp_sock *newdp = dccp_sk(newsk); struct dccp_minisock *newdmsk = dccp_msk(newsk); @@ -125,35 +120,7 @@ struct sock *dccp_create_openreq_child(struct sock *sk, newdp->dccps_timestamp_time = dreq->dreq_timestamp_time; newicsk->icsk_rto = DCCP_TIMEOUT_INIT; - if (dccp_feat_clone(sk, newsk)) - goto out_free; - - if (newdmsk->dccpms_send_ack_vector) { - newdp->dccps_hc_rx_ackvec = - dccp_ackvec_alloc(GFP_ATOMIC); - if (unlikely(newdp->dccps_hc_rx_ackvec == NULL)) - goto out_free; - } - - newdp->dccps_hc_rx_ccid = - ccid_hc_rx_new(newdmsk->dccpms_rx_ccid, - newsk, GFP_ATOMIC); - newdp->dccps_hc_tx_ccid = - ccid_hc_tx_new(newdmsk->dccpms_tx_ccid, - newsk, GFP_ATOMIC); - if (unlikely(newdp->dccps_hc_rx_ccid == NULL || - newdp->dccps_hc_tx_ccid == NULL)) { - dccp_ackvec_free(newdp->dccps_hc_rx_ackvec); - ccid_hc_rx_delete(newdp->dccps_hc_rx_ccid, newsk); - ccid_hc_tx_delete(newdp->dccps_hc_tx_ccid, newsk); -out_free: - /* It is still raw copy of parent, so invalidate - * destructor and make plain sk_free() */ - newsk->sk_destruct = NULL; - sk_free(newsk); - return NULL; - } - + INIT_LIST_HEAD(&newdp->dccps_featneg); /* * Step 3: Process LISTEN state * @@ -184,6 +151,17 @@ out_free: dccp_set_seqno(&newdp->dccps_awl, max48(newdp->dccps_awl, newdp->dccps_iss)); + /* + * Activate features after initialising the sequence numbers, + * since CCID initialisation may depend on GSS, ISR, ISS etc. + */ + if (dccp_feat_activate_values(newsk, &dreq->dreq_featneg)) { + /* It is still raw copy of parent, so invalidate + * destructor and make plain sk_free() */ + newsk->sk_destruct = NULL; + sk_free(newsk); + return NULL; + } dccp_init_xmit_timers(newsk); DCCP_INC_STATS_BH(DCCP_MIB_PASSIVEOPENS); @@ -304,7 +282,8 @@ void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, EXPORT_SYMBOL_GPL(dccp_reqsk_send_ack); -void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb) +int dccp_reqsk_init(struct request_sock *req, + struct dccp_sock const *dp, struct sk_buff const *skb) { struct dccp_request_sock *dreq = dccp_rsk(req); @@ -313,6 +292,9 @@ void dccp_reqsk_init(struct request_sock *req, struct sk_buff *skb) inet_rsk(req)->acked = 0; req->rcv_wnd = sysctl_dccp_feat_sequence_window; dreq->dreq_timestamp_echo = 0; + + /* inherit feature negotiation options from listening socket */ + return dccp_feat_clone_list(&dp->dccps_featneg, &dreq->dreq_featneg); } EXPORT_SYMBOL_GPL(dccp_reqsk_init); diff --git a/net/dccp/options.c b/net/dccp/options.c index 0809b63cb055a204a0eccbb05d28af88d73ef022..7b1165c21f5173a40c9511f934ccc5dcc02cc896 100644 --- a/net/dccp/options.c +++ b/net/dccp/options.c @@ -26,20 +26,21 @@ int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW; int sysctl_dccp_feat_rx_ccid = DCCPF_INITIAL_CCID; int sysctl_dccp_feat_tx_ccid = DCCPF_INITIAL_CCID; -int sysctl_dccp_feat_ack_ratio = DCCPF_INITIAL_ACK_RATIO; -int sysctl_dccp_feat_send_ack_vector = DCCPF_INITIAL_SEND_ACK_VECTOR; -int sysctl_dccp_feat_send_ndp_count = DCCPF_INITIAL_SEND_NDP_COUNT; -static u32 dccp_decode_value_var(const unsigned char *bf, const u8 len) +u64 dccp_decode_value_var(const u8 *bf, const u8 len) { - u32 value = 0; + u64 value = 0; + if (len >= DCCP_OPTVAL_MAXLEN) + value += ((u64)*bf++) << 40; + if (len > 4) + value += ((u64)*bf++) << 32; if (len > 3) - value += *bf++ << 24; + value += ((u64)*bf++) << 24; if (len > 2) - value += *bf++ << 16; + value += ((u64)*bf++) << 16; if (len > 1) - value += *bf++ << 8; + value += ((u64)*bf++) << 8; if (len > 0) value += *bf; @@ -64,7 +65,7 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, (dh->dccph_doff * 4); struct dccp_options_received *opt_recv = &dp->dccps_options_received; unsigned char opt, len; - unsigned char *value; + unsigned char *uninitialized_var(value); u32 elapsed_time; __be32 opt_val; int rc; @@ -131,41 +132,19 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq, dccp_pr_debug("%s opt: NDP count=%llu\n", dccp_role(sk), (unsigned long long)opt_recv->dccpor_ndp); break; - case DCCPO_CHANGE_L: - /* fall through */ - case DCCPO_CHANGE_R: - if (pkt_type == DCCP_PKT_DATA) + case DCCPO_CHANGE_L ... DCCPO_CONFIRM_R: + if (pkt_type == DCCP_PKT_DATA) /* RFC 4340, 6 */ break; - if (len < 2) - goto out_invalid_option; - rc = dccp_feat_change_recv(sk, opt, *value, value + 1, - len - 1); - /* - * When there is a change error, change_recv is - * responsible for dealing with it. i.e. reply with an - * empty confirm. - * If the change was mandatory, then we need to die. - */ - if (rc && mandatory) - goto out_invalid_option; - break; - case DCCPO_CONFIRM_L: - /* fall through */ - case DCCPO_CONFIRM_R: - if (pkt_type == DCCP_PKT_DATA) - break; - if (len < 2) /* FIXME this disallows empty confirm */ - goto out_invalid_option; - if (dccp_feat_confirm_recv(sk, opt, *value, - value + 1, len - 1)) - goto out_invalid_option; + rc = dccp_feat_parse_options(sk, dreq, mandatory, opt, + *value, value + 1, len - 1); + if (rc) + goto out_featneg_failed; break; case DCCPO_ACK_VECTOR_0: case DCCPO_ACK_VECTOR_1: if (dccp_packet_without_ack(skb)) /* RFC 4340, 11.4 */ break; - - if (dccp_msk(sk)->dccpms_send_ack_vector && + if (dp->dccps_hc_rx_ackvec != NULL && dccp_ackvec_parse(sk, skb, &ackno, opt, value, len)) goto out_invalid_option; break; @@ -289,8 +268,10 @@ out_nonsensical_length: out_invalid_option: DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT); - DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR; - DCCP_WARN("DCCP(%p): invalid option %d, len=%d", sk, opt, len); + rc = DCCP_RESET_CODE_OPTION_ERROR; +out_featneg_failed: + DCCP_WARN("DCCP(%p): Option %d (len=%d) error=%u\n", sk, opt, len, rc); + DCCP_SKB_CB(skb)->dccpd_reset_code = rc; DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt; DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0; DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0; @@ -299,9 +280,12 @@ out_invalid_option: EXPORT_SYMBOL_GPL(dccp_parse_options); -static void dccp_encode_value_var(const u32 value, unsigned char *to, - const unsigned int len) +void dccp_encode_value_var(const u64 value, u8 *to, const u8 len) { + if (len >= DCCP_OPTVAL_MAXLEN) + *to++ = (value & 0xFF0000000000ull) >> 40; + if (len > 4) + *to++ = (value & 0xFF00000000ull) >> 32; if (len > 3) *to++ = (value & 0xFF000000) >> 24; if (len > 2) @@ -461,23 +445,61 @@ static int dccp_insert_option_timestamp_echo(struct dccp_sock *dp, return 0; } -static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, - u8 *val, u8 len) +/** + * dccp_insert_option_mandatory - Mandatory option (5.8.2) + * Note that since we are using skb_push, this function needs to be called + * _after_ inserting the option it is supposed to influence (stack order). + */ +int dccp_insert_option_mandatory(struct sk_buff *skb) +{ + if (DCCP_SKB_CB(skb)->dccpd_opt_len >= DCCP_MAX_OPT_LEN) + return -1; + + DCCP_SKB_CB(skb)->dccpd_opt_len++; + *skb_push(skb, 1) = DCCPO_MANDATORY; + return 0; +} + +/** + * dccp_insert_fn_opt - Insert single Feature-Negotiation option into @skb + * @type: %DCCPO_CHANGE_L, %DCCPO_CHANGE_R, %DCCPO_CONFIRM_L, %DCCPO_CONFIRM_R + * @feat: one out of %dccp_feature_numbers + * @val: NN value or SP array (preferred element first) to copy + * @len: true length of @val in bytes (excluding first element repetition) + * @repeat_first: whether to copy the first element of @val twice + * The last argument is used to construct Confirm options, where the preferred + * value and the preference list appear separately (RFC 4340, 6.3.1). Preference + * lists are kept such that the preferred entry is always first, so we only need + * to copy twice, and avoid the overhead of cloning into a bigger array. + */ +int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat, + u8 *val, u8 len, bool repeat_first) { - u8 *to; + u8 tot_len, *to; - if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 3 > DCCP_MAX_OPT_LEN) { - DCCP_WARN("packet too small for feature %d option!\n", feat); + /* take the `Feature' field and possible repetition into account */ + if (len > (DCCP_SINGLE_OPT_MAXLEN - 2)) { + DCCP_WARN("length %u for feature %u too large\n", len, feat); return -1; } - DCCP_SKB_CB(skb)->dccpd_opt_len += len + 3; + if (unlikely(val == NULL || len == 0)) + len = repeat_first = 0; + tot_len = 3 + repeat_first + len; + + if (DCCP_SKB_CB(skb)->dccpd_opt_len + tot_len > DCCP_MAX_OPT_LEN) { + DCCP_WARN("packet too small for feature %d option!\n", feat); + return -1; + } + DCCP_SKB_CB(skb)->dccpd_opt_len += tot_len; - to = skb_push(skb, len + 3); + to = skb_push(skb, tot_len); *to++ = type; - *to++ = len + 3; + *to++ = tot_len; *to++ = feat; + if (repeat_first) + *to++ = *val; if (len) memcpy(to, val, len); @@ -487,69 +509,6 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat, return 0; } -static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb) -{ - struct dccp_sock *dp = dccp_sk(sk); - struct dccp_minisock *dmsk = dccp_msk(sk); - struct dccp_opt_pend *opt, *next; - int change = 0; - - /* confirm any options [NN opts] */ - list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) { - dccp_insert_feat_opt(skb, opt->dccpop_type, - opt->dccpop_feat, opt->dccpop_val, - opt->dccpop_len); - /* fear empty confirms */ - if (opt->dccpop_val) - kfree(opt->dccpop_val); - kfree(opt); - } - INIT_LIST_HEAD(&dmsk->dccpms_conf); - - /* see which features we need to send */ - list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) { - /* see if we need to send any confirm */ - if (opt->dccpop_sc) { - dccp_insert_feat_opt(skb, opt->dccpop_type + 1, - opt->dccpop_feat, - opt->dccpop_sc->dccpoc_val, - opt->dccpop_sc->dccpoc_len); - - BUG_ON(!opt->dccpop_sc->dccpoc_val); - kfree(opt->dccpop_sc->dccpoc_val); - kfree(opt->dccpop_sc); - opt->dccpop_sc = NULL; - } - - /* any option not confirmed, re-send it */ - if (!opt->dccpop_conf) { - dccp_insert_feat_opt(skb, opt->dccpop_type, - opt->dccpop_feat, opt->dccpop_val, - opt->dccpop_len); - change++; - } - } - - /* Retransmit timer. - * If this is the master listening sock, we don't set a timer on it. It - * should be fine because if the dude doesn't receive our RESPONSE - * [which will contain the CHANGE] he will send another REQUEST which - * will "retrnasmit" the change. - */ - if (change && dp->dccps_role != DCCP_ROLE_LISTEN) { - dccp_pr_debug("reset feat negotiation timer %p\n", sk); - - /* XXX don't reset the timer on re-transmissions. I.e. reset it - * only when sending new stuff i guess. Currently the timer - * never backs off because on re-transmission it just resets it! - */ - inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS, - inet_csk(sk)->icsk_rto, DCCP_RTO_MAX); - } - - return 0; -} - /* The length of all options needs to be a multiple of 4 (5.8) */ static void dccp_insert_option_padding(struct sk_buff *skb) { @@ -565,19 +524,31 @@ static void dccp_insert_option_padding(struct sk_buff *skb) int dccp_insert_options(struct sock *sk, struct sk_buff *skb) { struct dccp_sock *dp = dccp_sk(sk); - struct dccp_minisock *dmsk = dccp_msk(sk); DCCP_SKB_CB(skb)->dccpd_opt_len = 0; - if (dmsk->dccpms_send_ndp_count && - dccp_insert_option_ndp(sk, skb)) + if (dp->dccps_send_ndp_count && dccp_insert_option_ndp(sk, skb)) return -1; - if (!dccp_packet_without_ack(skb)) { - if (dmsk->dccpms_send_ack_vector && - dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) && - dccp_insert_option_ackvec(sk, skb)) + if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA) { + + /* Feature Negotiation */ + if (dccp_feat_insert_opts(dp, NULL, skb)) return -1; + + if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST) { + /* + * Obtain RTT sample from Request/Response exchange. + * This is currently used in CCID 3 initialisation. + */ + if (dccp_insert_option_timestamp(sk, skb)) + return -1; + + } else if (dp->dccps_hc_rx_ackvec != NULL && + dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) && + dccp_insert_option_ackvec(sk, skb)) { + return -1; + } } if (dp->dccps_hc_rx_insert_options) { @@ -586,21 +557,6 @@ int dccp_insert_options(struct sock *sk, struct sk_buff *skb) dp->dccps_hc_rx_insert_options = 0; } - /* Feature negotiation */ - /* Data packets can't do feat negotiation */ - if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA && - DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK && - dccp_insert_options_feat(sk, skb)) - return -1; - - /* - * Obtain RTT sample from Request/Response exchange. - * This is currently used in CCID 3 initialisation. - */ - if (DCCP_SKB_CB(skb)->dccpd_type == DCCP_PKT_REQUEST && - dccp_insert_option_timestamp(sk, skb)) - return -1; - if (dp->dccps_timestamp_echo != 0 && dccp_insert_option_timestamp_echo(dp, NULL, skb)) return -1; @@ -613,6 +569,9 @@ int dccp_insert_options_rsk(struct dccp_request_sock *dreq, struct sk_buff *skb) { DCCP_SKB_CB(skb)->dccpd_opt_len = 0; + if (dccp_feat_insert_opts(NULL, dreq, skb)) + return -1; + if (dreq->dreq_timestamp_echo != 0 && dccp_insert_option_timestamp_echo(NULL, dreq, skb)) return -1; diff --git a/net/dccp/output.c b/net/dccp/output.c index 809d803d5006ec6614821b9d0d48b63cf131a31f..22a618af48936aa9954978cdf8d94117e02d7bac 100644 --- a/net/dccp/output.c +++ b/net/dccp/output.c @@ -175,7 +175,7 @@ unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu) * make it a multiple of 4 */ - cur_mps -= ((5 + 6 + 10 + 6 + 6 + 6 + 3) / 4) * 4; + cur_mps -= roundup(5 + 6 + 10 + 6 + 6 + 6, 4); /* And store cached results */ icsk->icsk_pmtu_cookie = pmtu; @@ -339,10 +339,12 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE; DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_iss; - if (dccp_insert_options_rsk(dreq, skb)) { - kfree_skb(skb); - return NULL; - } + /* Resolve feature dependencies resulting from choice of CCID */ + if (dccp_feat_server_ccid_dependencies(dreq)) + goto response_failed; + + if (dccp_insert_options_rsk(dreq, skb)) + goto response_failed; /* Build and checksum header */ dh = dccp_zeroed_hdr(skb, dccp_header_size); @@ -363,6 +365,9 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst, inet_rsk(req)->acked = 1; DCCP_INC_STATS(DCCP_MIB_OUTSEGS); return skb; +response_failed: + kfree_skb(skb); + return NULL; } EXPORT_SYMBOL_GPL(dccp_make_response); @@ -469,6 +474,10 @@ int dccp_connect(struct sock *sk) struct sk_buff *skb; struct inet_connection_sock *icsk = inet_csk(sk); + /* do not connect if feature negotiation setup fails */ + if (dccp_feat_finalise_settings(dccp_sk(sk))) + return -EPROTO; + dccp_connect_init(sk); skb = alloc_skb(sk->sk_prot->max_header, sk->sk_allocation); diff --git a/net/dccp/probe.c b/net/dccp/probe.c index 81368a7f5379c9907b88e64ac03fa5f23b7313f6..37731da4148164adc741da891a86b27e2484187d 100644 --- a/net/dccp/probe.c +++ b/net/dccp/probe.c @@ -74,30 +74,27 @@ static void printl(const char *fmt, ...) static int jdccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t size) { - const struct dccp_minisock *dmsk = dccp_msk(sk); const struct inet_sock *inet = inet_sk(sk); - const struct ccid3_hc_tx_sock *hctx; + struct ccid3_hc_tx_sock *hctx = NULL; - if (dmsk->dccpms_tx_ccid == DCCPC_CCID3) + if (ccid_get_current_tx_ccid(dccp_sk(sk)) == DCCPC_CCID3) hctx = ccid3_hc_tx_sk(sk); - else - hctx = NULL; if (port == 0 || ntohs(inet->dport) == port || ntohs(inet->sport) == port) { if (hctx) - printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d %d %d %d %u " + printl("%pI4:%u %pI4:%u %d %d %d %d %u " "%llu %llu %d\n", - NIPQUAD(inet->saddr), ntohs(inet->sport), - NIPQUAD(inet->daddr), ntohs(inet->dport), size, + &inet->saddr, ntohs(inet->sport), + &inet->daddr, ntohs(inet->dport), size, hctx->ccid3hctx_s, hctx->ccid3hctx_rtt, hctx->ccid3hctx_p, hctx->ccid3hctx_x_calc, hctx->ccid3hctx_x_recv >> 6, hctx->ccid3hctx_x >> 6, hctx->ccid3hctx_t_ipi); else - printl("%d.%d.%d.%d:%u %d.%d.%d.%d:%u %d\n", - NIPQUAD(inet->saddr), ntohs(inet->sport), - NIPQUAD(inet->daddr), ntohs(inet->dport), size); + printl("%pI4:%u %pI4:%u %d\n", + &inet->saddr, ntohs(inet->sport), + &inet->daddr, ntohs(inet->dport), size); } jprobe_return(); diff --git a/net/dccp/proto.c b/net/dccp/proto.c index d0bd34819761c0983074e54fbff360d0aed75963..d5c2bacb713c6055ffb9a3ca9cb8975ebb907a9a 100644 --- a/net/dccp/proto.c +++ b/net/dccp/proto.c @@ -40,16 +40,10 @@ DEFINE_SNMP_STAT(struct dccp_mib, dccp_statistics) __read_mostly; EXPORT_SYMBOL_GPL(dccp_statistics); -atomic_t dccp_orphan_count = ATOMIC_INIT(0); - +struct percpu_counter dccp_orphan_count; EXPORT_SYMBOL_GPL(dccp_orphan_count); -struct inet_hashinfo __cacheline_aligned dccp_hashinfo = { - .lhash_lock = RW_LOCK_UNLOCKED, - .lhash_users = ATOMIC_INIT(0), - .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(dccp_hashinfo.lhash_wait), -}; - +struct inet_hashinfo dccp_hashinfo; EXPORT_SYMBOL_GPL(dccp_hashinfo); /* the maximum queue length for tx in packets. 0 is no limit */ @@ -67,6 +61,9 @@ void dccp_set_state(struct sock *sk, const int state) case DCCP_OPEN: if (oldstate != DCCP_OPEN) DCCP_INC_STATS(DCCP_MIB_CURRESTAB); + /* Client retransmits all Confirm options until entering OPEN */ + if (oldstate == DCCP_PARTOPEN) + dccp_feat_list_purge(&dccp_sk(sk)->dccps_featneg); break; case DCCP_CLOSED: @@ -175,7 +172,6 @@ EXPORT_SYMBOL_GPL(dccp_state_name); int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) { struct dccp_sock *dp = dccp_sk(sk); - struct dccp_minisock *dmsk = dccp_msk(sk); struct inet_connection_sock *icsk = inet_csk(sk); dccp_minisock_init(&dp->dccps_minisock); @@ -193,45 +189,10 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized) dccp_init_xmit_timers(sk); - /* - * FIXME: We're hardcoding the CCID, and doing this at this point makes - * the listening (master) sock get CCID control blocks, which is not - * necessary, but for now, to not mess with the test userspace apps, - * lets leave it here, later the real solution is to do this in a - * setsockopt(CCIDs-I-want/accept). -acme - */ - if (likely(ctl_sock_initialized)) { - int rc = dccp_feat_init(dmsk); - - if (rc) - return rc; - - if (dmsk->dccpms_send_ack_vector) { - dp->dccps_hc_rx_ackvec = dccp_ackvec_alloc(GFP_KERNEL); - if (dp->dccps_hc_rx_ackvec == NULL) - return -ENOMEM; - } - dp->dccps_hc_rx_ccid = ccid_hc_rx_new(dmsk->dccpms_rx_ccid, - sk, GFP_KERNEL); - dp->dccps_hc_tx_ccid = ccid_hc_tx_new(dmsk->dccpms_tx_ccid, - sk, GFP_KERNEL); - if (unlikely(dp->dccps_hc_rx_ccid == NULL || - dp->dccps_hc_tx_ccid == NULL)) { - ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk); - ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk); - if (dmsk->dccpms_send_ack_vector) { - dccp_ackvec_free(dp->dccps_hc_rx_ackvec); - dp->dccps_hc_rx_ackvec = NULL; - } - dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; - return -ENOMEM; - } - } else { - /* control socket doesn't need feat nego */ - INIT_LIST_HEAD(&dmsk->dccpms_pending); - INIT_LIST_HEAD(&dmsk->dccpms_conf); - } - + INIT_LIST_HEAD(&dp->dccps_featneg); + /* control socket doesn't need feat nego */ + if (likely(ctl_sock_initialized)) + return dccp_feat_init(sk); return 0; } @@ -240,7 +201,6 @@ EXPORT_SYMBOL_GPL(dccp_init_sock); void dccp_destroy_sock(struct sock *sk) { struct dccp_sock *dp = dccp_sk(sk); - struct dccp_minisock *dmsk = dccp_msk(sk); /* * DCCP doesn't use sk_write_queue, just sk_send_head @@ -258,7 +218,7 @@ void dccp_destroy_sock(struct sock *sk) kfree(dp->dccps_service_list); dp->dccps_service_list = NULL; - if (dmsk->dccpms_send_ack_vector) { + if (dp->dccps_hc_rx_ackvec != NULL) { dccp_ackvec_free(dp->dccps_hc_rx_ackvec); dp->dccps_hc_rx_ackvec = NULL; } @@ -267,7 +227,7 @@ void dccp_destroy_sock(struct sock *sk) dp->dccps_hc_rx_ccid = dp->dccps_hc_tx_ccid = NULL; /* clean up feature negotiation state */ - dccp_feat_clean(dmsk); + dccp_feat_list_purge(&dp->dccps_featneg); } EXPORT_SYMBOL_GPL(dccp_destroy_sock); @@ -277,6 +237,9 @@ static inline int dccp_listen_start(struct sock *sk, int backlog) struct dccp_sock *dp = dccp_sk(sk); dp->dccps_role = DCCP_ROLE_LISTEN; + /* do not start to listen if feature negotiation setup fails */ + if (dccp_feat_finalise_settings(dp)) + return -EPROTO; return inet_csk_listen_start(sk, backlog); } @@ -466,42 +429,70 @@ static int dccp_setsockopt_service(struct sock *sk, const __be32 service, return 0; } -/* byte 1 is feature. the rest is the preference list */ -static int dccp_setsockopt_change(struct sock *sk, int type, - struct dccp_so_feat __user *optval) +static int dccp_setsockopt_cscov(struct sock *sk, int cscov, bool rx) { - struct dccp_so_feat opt; - u8 *val; - int rc; + u8 *list, len; + int i, rc; - if (copy_from_user(&opt, optval, sizeof(opt))) - return -EFAULT; + if (cscov < 0 || cscov > 15) + return -EINVAL; /* - * rfc4340: 6.1. Change Options + * Populate a list of permissible values, in the range cscov...15. This + * is necessary since feature negotiation of single values only works if + * both sides incidentally choose the same value. Since the list starts + * lowest-value first, negotiation will pick the smallest shared value. */ - if (opt.dccpsf_len < 1) + if (cscov == 0) + return 0; + len = 16 - cscov; + + list = kmalloc(len, GFP_KERNEL); + if (list == NULL) + return -ENOBUFS; + + for (i = 0; i < len; i++) + list[i] = cscov++; + + rc = dccp_feat_register_sp(sk, DCCPF_MIN_CSUM_COVER, rx, list, len); + + if (rc == 0) { + if (rx) + dccp_sk(sk)->dccps_pcrlen = cscov; + else + dccp_sk(sk)->dccps_pcslen = cscov; + } + kfree(list); + return rc; +} + +static int dccp_setsockopt_ccid(struct sock *sk, int type, + char __user *optval, int optlen) +{ + u8 *val; + int rc = 0; + + if (optlen < 1 || optlen > DCCP_FEAT_MAX_SP_VALS) return -EINVAL; - val = kmalloc(opt.dccpsf_len, GFP_KERNEL); - if (!val) + val = kmalloc(optlen, GFP_KERNEL); + if (val == NULL) return -ENOMEM; - if (copy_from_user(val, opt.dccpsf_val, opt.dccpsf_len)) { - rc = -EFAULT; - goto out_free_val; + if (copy_from_user(val, optval, optlen)) { + kfree(val); + return -EFAULT; } - rc = dccp_feat_change(dccp_msk(sk), type, opt.dccpsf_feat, - val, opt.dccpsf_len, GFP_KERNEL); - if (rc) - goto out_free_val; + lock_sock(sk); + if (type == DCCP_SOCKOPT_TX_CCID || type == DCCP_SOCKOPT_CCID) + rc = dccp_feat_register_sp(sk, DCCPF_CCID, 1, val, optlen); -out: - return rc; + if (!rc && (type == DCCP_SOCKOPT_RX_CCID || type == DCCP_SOCKOPT_CCID)) + rc = dccp_feat_register_sp(sk, DCCPF_CCID, 0, val, optlen); + release_sock(sk); -out_free_val: kfree(val); - goto out; + return rc; } static int do_dccp_setsockopt(struct sock *sk, int level, int optname, @@ -510,7 +501,21 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, struct dccp_sock *dp = dccp_sk(sk); int val, err = 0; - if (optlen < sizeof(int)) + switch (optname) { + case DCCP_SOCKOPT_PACKET_SIZE: + DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n"); + return 0; + case DCCP_SOCKOPT_CHANGE_L: + case DCCP_SOCKOPT_CHANGE_R: + DCCP_WARN("sockopt(CHANGE_L/R) is deprecated: fix your app\n"); + return 0; + case DCCP_SOCKOPT_CCID: + case DCCP_SOCKOPT_RX_CCID: + case DCCP_SOCKOPT_TX_CCID: + return dccp_setsockopt_ccid(sk, optname, optval, optlen); + } + + if (optlen < (int)sizeof(int)) return -EINVAL; if (get_user(val, (int __user *)optval)) @@ -521,53 +526,24 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname, lock_sock(sk); switch (optname) { - case DCCP_SOCKOPT_PACKET_SIZE: - DCCP_WARN("sockopt(PACKET_SIZE) is deprecated: fix your app\n"); - err = 0; - break; - case DCCP_SOCKOPT_CHANGE_L: - if (optlen != sizeof(struct dccp_so_feat)) - err = -EINVAL; - else - err = dccp_setsockopt_change(sk, DCCPO_CHANGE_L, - (struct dccp_so_feat __user *) - optval); - break; - case DCCP_SOCKOPT_CHANGE_R: - if (optlen != sizeof(struct dccp_so_feat)) - err = -EINVAL; - else - err = dccp_setsockopt_change(sk, DCCPO_CHANGE_R, - (struct dccp_so_feat __user *) - optval); - break; case DCCP_SOCKOPT_SERVER_TIMEWAIT: if (dp->dccps_role != DCCP_ROLE_SERVER) err = -EOPNOTSUPP; else dp->dccps_server_timewait = (val != 0); break; - case DCCP_SOCKOPT_SEND_CSCOV: /* sender side, RFC 4340, sec. 9.2 */ - if (val < 0 || val > 15) - err = -EINVAL; - else - dp->dccps_pcslen = val; + case DCCP_SOCKOPT_SEND_CSCOV: + err = dccp_setsockopt_cscov(sk, val, false); break; - case DCCP_SOCKOPT_RECV_CSCOV: /* receiver side, RFC 4340 sec. 9.2.1 */ - if (val < 0 || val > 15) - err = -EINVAL; - else { - dp->dccps_pcrlen = val; - /* FIXME: add feature negotiation, - * ChangeL(MinimumChecksumCoverage, val) */ - } + case DCCP_SOCKOPT_RECV_CSCOV: + err = dccp_setsockopt_cscov(sk, val, true); break; default: err = -ENOPROTOOPT; break; } - release_sock(sk); + return err; } @@ -648,6 +624,18 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname, case DCCP_SOCKOPT_GET_CUR_MPS: val = dp->dccps_mss_cache; break; + case DCCP_SOCKOPT_AVAILABLE_CCIDS: + return ccid_getsockopt_builtin_ccids(sk, len, optval, optlen); + case DCCP_SOCKOPT_TX_CCID: + val = ccid_get_current_tx_ccid(dp); + if (val < 0) + return -ENOPROTOOPT; + break; + case DCCP_SOCKOPT_RX_CCID: + val = ccid_get_current_rx_ccid(dp); + if (val < 0) + return -ENOPROTOOPT; + break; case DCCP_SOCKOPT_SERVER_TIMEWAIT: val = dp->dccps_server_timewait; break; @@ -976,7 +964,7 @@ adjudge_to_death: state = sk->sk_state; sock_hold(sk); sock_orphan(sk); - atomic_inc(sk->sk_prot->orphan_count); + percpu_counter_inc(sk->sk_prot->orphan_count); /* * It is the last release_sock in its life. It will remove backlog. @@ -1040,17 +1028,21 @@ static int __init dccp_init(void) { unsigned long goal; int ehash_order, bhash_order, i; - int rc = -ENOBUFS; + int rc; BUILD_BUG_ON(sizeof(struct dccp_skb_cb) > FIELD_SIZEOF(struct sk_buff, cb)); - + rc = percpu_counter_init(&dccp_orphan_count, 0); + if (rc) + goto out; + rc = -ENOBUFS; + inet_hashinfo_init(&dccp_hashinfo); dccp_hashinfo.bind_bucket_cachep = kmem_cache_create("dccp_bind_bucket", sizeof(struct inet_bind_bucket), 0, SLAB_HWCACHE_ALIGN, NULL); if (!dccp_hashinfo.bind_bucket_cachep) - goto out; + goto out_free_percpu; /* * Size and allocate the main established and bind bucket @@ -1084,8 +1076,8 @@ static int __init dccp_init(void) } for (i = 0; i < dccp_hashinfo.ehash_size; i++) { - INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].chain); - INIT_HLIST_HEAD(&dccp_hashinfo.ehash[i].twchain); + INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].chain, i); + INIT_HLIST_NULLS_HEAD(&dccp_hashinfo.ehash[i].twchain, i); } if (inet_ehash_locks_alloc(&dccp_hashinfo)) @@ -1143,6 +1135,8 @@ out_free_dccp_ehash: out_free_bind_bucket_cachep: kmem_cache_destroy(dccp_hashinfo.bind_bucket_cachep); dccp_hashinfo.bind_bucket_cachep = NULL; +out_free_percpu: + percpu_counter_destroy(&dccp_orphan_count); goto out; } diff --git a/net/dccp/sysctl.c b/net/dccp/sysctl.c index 21295993fdb84f2dd53dea972b137eb95395aca2..018e210875e168141a2aca941ab11ca7daaca9ef 100644 --- a/net/dccp/sysctl.c +++ b/net/dccp/sysctl.c @@ -40,27 +40,6 @@ static struct ctl_table dccp_default_table[] = { .mode = 0644, .proc_handler = proc_dointvec, }, - { - .procname = "ack_ratio", - .data = &sysctl_dccp_feat_ack_ratio, - .maxlen = sizeof(sysctl_dccp_feat_ack_ratio), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "send_ackvec", - .data = &sysctl_dccp_feat_send_ack_vector, - .maxlen = sizeof(sysctl_dccp_feat_send_ack_vector), - .mode = 0644, - .proc_handler = proc_dointvec, - }, - { - .procname = "send_ndp", - .data = &sysctl_dccp_feat_send_ndp_count, - .maxlen = sizeof(sysctl_dccp_feat_send_ndp_count), - .mode = 0644, - .proc_handler = proc_dointvec, - }, { .procname = "request_retries", .data = &sysctl_dccp_request_retries, diff --git a/net/dccp/timer.c b/net/dccp/timer.c index 54b3c7e9e016737eab1614fde3b22afa67456345..162d1e683c3908afc76966353f51e5dc9f769de6 100644 --- a/net/dccp/timer.c +++ b/net/dccp/timer.c @@ -87,17 +87,6 @@ static void dccp_retransmit_timer(struct sock *sk) { struct inet_connection_sock *icsk = inet_csk(sk); - /* retransmit timer is used for feature negotiation throughout - * connection. In this case, no packet is re-transmitted, but rather an - * ack is generated and pending changes are placed into its options. - */ - if (sk->sk_send_head == NULL) { - dccp_pr_debug("feat negotiation retransmit timeout %p\n", sk); - if (sk->sk_state == DCCP_OPEN) - dccp_send_ack(sk); - goto backoff; - } - /* * More than than 4MSL (8 minutes) has passed, a RESET(aborted) was * sent, no need to retransmit, this sock is dead. @@ -126,7 +115,6 @@ static void dccp_retransmit_timer(struct sock *sk) return; } -backoff: icsk->icsk_backoff++; icsk->icsk_rto = min(icsk->icsk_rto << 1, DCCP_RTO_MAX); diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c index 3c23ab33dbc0335dabea5348ff913e70fd880062..cf0e18499297080bac82f4b020409dd2dbb0f5fa 100644 --- a/net/decnet/af_decnet.c +++ b/net/decnet/af_decnet.c @@ -167,7 +167,7 @@ static struct hlist_head *dn_find_list(struct sock *sk) if (scp->addr.sdn_flags & SDF_WILD) return hlist_empty(&dn_wild_sk) ? &dn_wild_sk : NULL; - return &dn_sk_hash[dn_ntohs(scp->addrloc) & DN_SK_HASH_MASK]; + return &dn_sk_hash[le16_to_cpu(scp->addrloc) & DN_SK_HASH_MASK]; } /* @@ -181,7 +181,7 @@ static int check_port(__le16 port) if (port == 0) return -1; - sk_for_each(sk, node, &dn_sk_hash[dn_ntohs(port) & DN_SK_HASH_MASK]) { + sk_for_each(sk, node, &dn_sk_hash[le16_to_cpu(port) & DN_SK_HASH_MASK]) { struct dn_scp *scp = DN_SK(sk); if (scp->addrloc == port) return -1; @@ -195,12 +195,12 @@ static unsigned short port_alloc(struct sock *sk) static unsigned short port = 0x2000; unsigned short i_port = port; - while(check_port(dn_htons(++port)) != 0) { + while(check_port(cpu_to_le16(++port)) != 0) { if (port == i_port) return 0; } - scp->addrloc = dn_htons(port); + scp->addrloc = cpu_to_le16(port); return 1; } @@ -255,7 +255,7 @@ static struct hlist_head *listen_hash(struct sockaddr_dn *addr) if (hash == 0) { hash = addr->sdn_objnamel; - for(i = 0; i < dn_ntohs(addr->sdn_objnamel); i++) { + for(i = 0; i < le16_to_cpu(addr->sdn_objnamel); i++) { hash ^= addr->sdn_objname[i]; hash ^= (hash << 3); } @@ -297,16 +297,16 @@ int dn_sockaddr2username(struct sockaddr_dn *sdn, unsigned char *buf, unsigned c break; case 1: *buf++ = 0; - *buf++ = dn_ntohs(sdn->sdn_objnamel); - memcpy(buf, sdn->sdn_objname, dn_ntohs(sdn->sdn_objnamel)); - len = 3 + dn_ntohs(sdn->sdn_objnamel); + *buf++ = le16_to_cpu(sdn->sdn_objnamel); + memcpy(buf, sdn->sdn_objname, le16_to_cpu(sdn->sdn_objnamel)); + len = 3 + le16_to_cpu(sdn->sdn_objnamel); break; case 2: memset(buf, 0, 5); buf += 5; - *buf++ = dn_ntohs(sdn->sdn_objnamel); - memcpy(buf, sdn->sdn_objname, dn_ntohs(sdn->sdn_objnamel)); - len = 7 + dn_ntohs(sdn->sdn_objnamel); + *buf++ = le16_to_cpu(sdn->sdn_objnamel); + memcpy(buf, sdn->sdn_objname, le16_to_cpu(sdn->sdn_objnamel)); + len = 7 + le16_to_cpu(sdn->sdn_objnamel); break; } @@ -327,7 +327,7 @@ int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *sdn, int namel = 12; sdn->sdn_objnum = 0; - sdn->sdn_objnamel = dn_htons(0); + sdn->sdn_objnamel = cpu_to_le16(0); memset(sdn->sdn_objname, 0, DN_MAXOBJL); if (len < 2) @@ -361,13 +361,13 @@ int dn_username2sockaddr(unsigned char *data, int len, struct sockaddr_dn *sdn, if (len < 0) return -1; - sdn->sdn_objnamel = dn_htons(*data++); - len -= dn_ntohs(sdn->sdn_objnamel); + sdn->sdn_objnamel = cpu_to_le16(*data++); + len -= le16_to_cpu(sdn->sdn_objnamel); - if ((len < 0) || (dn_ntohs(sdn->sdn_objnamel) > namel)) + if ((len < 0) || (le16_to_cpu(sdn->sdn_objnamel) > namel)) return -1; - memcpy(sdn->sdn_objname, data, dn_ntohs(sdn->sdn_objnamel)); + memcpy(sdn->sdn_objname, data, le16_to_cpu(sdn->sdn_objnamel)); return size - len; } @@ -391,7 +391,7 @@ struct sock *dn_sklist_find_listener(struct sockaddr_dn *addr) continue; if (scp->addr.sdn_objnamel != addr->sdn_objnamel) continue; - if (memcmp(scp->addr.sdn_objname, addr->sdn_objname, dn_ntohs(addr->sdn_objnamel)) != 0) + if (memcmp(scp->addr.sdn_objname, addr->sdn_objname, le16_to_cpu(addr->sdn_objnamel)) != 0) continue; } sock_hold(sk); @@ -419,7 +419,7 @@ struct sock *dn_find_by_skb(struct sk_buff *skb) struct dn_scp *scp; read_lock(&dn_hash_lock); - sk_for_each(sk, node, &dn_sk_hash[dn_ntohs(cb->dst_port) & DN_SK_HASH_MASK]) { + sk_for_each(sk, node, &dn_sk_hash[le16_to_cpu(cb->dst_port) & DN_SK_HASH_MASK]) { scp = DN_SK(sk); if (cb->src != dn_saddr2dn(&scp->peer)) continue; @@ -734,10 +734,10 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (saddr->sdn_family != AF_DECnet) return -EINVAL; - if (dn_ntohs(saddr->sdn_nodeaddrl) && (dn_ntohs(saddr->sdn_nodeaddrl) != 2)) + if (le16_to_cpu(saddr->sdn_nodeaddrl) && (le16_to_cpu(saddr->sdn_nodeaddrl) != 2)) return -EINVAL; - if (dn_ntohs(saddr->sdn_objnamel) > DN_MAXOBJL) + if (le16_to_cpu(saddr->sdn_objnamel) > DN_MAXOBJL) return -EINVAL; if (saddr->sdn_flags & ~SDF_WILD) @@ -748,7 +748,7 @@ static int dn_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) return -EACCES; if (!(saddr->sdn_flags & SDF_WILD)) { - if (dn_ntohs(saddr->sdn_nodeaddrl)) { + if (le16_to_cpu(saddr->sdn_nodeaddrl)) { read_lock(&dev_base_lock); ldev = NULL; for_each_netdev(&init_net, dev) { @@ -799,15 +799,15 @@ static int dn_auto_bind(struct socket *sock) if ((scp->accessdata.acc_accl != 0) && (scp->accessdata.acc_accl <= 12)) { - scp->addr.sdn_objnamel = dn_htons(scp->accessdata.acc_accl); - memcpy(scp->addr.sdn_objname, scp->accessdata.acc_acc, dn_ntohs(scp->addr.sdn_objnamel)); + scp->addr.sdn_objnamel = cpu_to_le16(scp->accessdata.acc_accl); + memcpy(scp->addr.sdn_objname, scp->accessdata.acc_acc, le16_to_cpu(scp->addr.sdn_objnamel)); scp->accessdata.acc_accl = 0; memset(scp->accessdata.acc_acc, 0, 40); } /* End of compatibility stuff */ - scp->addr.sdn_add.a_len = dn_htons(2); + scp->addr.sdn_add.a_len = cpu_to_le16(2); rv = dn_dev_bind_default((__le16 *)scp->addr.sdn_add.a_addr); if (rv == 0) { rv = dn_hash_sock(sk); @@ -1027,7 +1027,7 @@ static void dn_user_copy(struct sk_buff *skb, struct optdata_dn *opt) u16 len = *ptr++; /* yes, it's 8bit on the wire */ BUG_ON(len > 16); /* we've checked the contents earlier */ - opt->opt_optl = dn_htons(len); + opt->opt_optl = cpu_to_le16(len); opt->opt_status = 0; memcpy(opt->opt_data, ptr, len); skb_pull(skb, len + 1); @@ -1375,7 +1375,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us if (optlen != sizeof(struct optdata_dn)) return -EINVAL; - if (dn_ntohs(u.opt.opt_optl) > 16) + if (le16_to_cpu(u.opt.opt_optl) > 16) return -EINVAL; memcpy(&scp->conndata_out, &u.opt, optlen); @@ -1388,7 +1388,7 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char __us if (optlen != sizeof(struct optdata_dn)) return -EINVAL; - if (dn_ntohs(u.opt.opt_optl) > 16) + if (le16_to_cpu(u.opt.opt_optl) > 16) return -EINVAL; memcpy(&scp->discdata_out, &u.opt, optlen); @@ -2213,12 +2213,12 @@ static void dn_printable_object(struct sockaddr_dn *dn, unsigned char *buf) { int i; - switch (dn_ntohs(dn->sdn_objnamel)) { + switch (le16_to_cpu(dn->sdn_objnamel)) { case 0: sprintf(buf, "%d", dn->sdn_objnum); break; default: - for (i = 0; i < dn_ntohs(dn->sdn_objnamel); i++) { + for (i = 0; i < le16_to_cpu(dn->sdn_objnamel); i++) { buf[i] = dn->sdn_objname[i]; if (IS_NOT_PRINTABLE(buf[i])) buf[i] = '.'; @@ -2281,7 +2281,7 @@ static inline void dn_socket_format_entry(struct seq_file *seq, struct sock *sk) seq_printf(seq, "%6s/%04X %04d:%04d %04d:%04d %01d %-16s " "%6s/%04X %04d:%04d %04d:%04d %01d %-16s %4s %s\n", - dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->addr)), buf1), + dn_addr2asc(le16_to_cpu(dn_saddr2dn(&scp->addr)), buf1), scp->addrloc, scp->numdat, scp->numoth, @@ -2289,7 +2289,7 @@ static inline void dn_socket_format_entry(struct seq_file *seq, struct sock *sk) scp->ackxmt_oth, scp->flowloc_sw, local_object, - dn_addr2asc(dn_ntohs(dn_saddr2dn(&scp->peer)), buf2), + dn_addr2asc(le16_to_cpu(dn_saddr2dn(&scp->peer)), buf2), scp->addrrem, scp->numdat_rcv, scp->numoth_rcv, diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c index 28e26bd08e24c2422e31ad52cd3f646c97d5843d..daf2b98b15fef79d3d9d1915ebe48a36b6007d1e 100644 --- a/net/decnet/dn_dev.c +++ b/net/decnet/dn_dev.c @@ -885,7 +885,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa) memcpy(msg->tiver, dn_eco_version, 3); dn_dn2eth(msg->id, ifa->ifa_local); msg->iinfo = DN_RT_INFO_ENDN; - msg->blksize = dn_htons(mtu2blksize(dev)); + msg->blksize = cpu_to_le16(mtu2blksize(dev)); msg->area = 0x00; memset(msg->seed, 0, 8); memcpy(msg->neighbor, dn_hiord, ETH_ALEN); @@ -895,13 +895,13 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa) dn_dn2eth(msg->neighbor, dn->addr); } - msg->timer = dn_htons((unsigned short)dn_db->parms.t3); + msg->timer = cpu_to_le16((unsigned short)dn_db->parms.t3); msg->mpd = 0x00; msg->datalen = 0x02; memset(msg->data, 0xAA, 2); pktlen = (__le16 *)skb_push(skb,2); - *pktlen = dn_htons(skb->len - 2); + *pktlen = cpu_to_le16(skb->len - 2); skb_reset_network_header(skb); @@ -929,7 +929,7 @@ static int dn_am_i_a_router(struct dn_neigh *dn, struct dn_dev *dn_db, struct dn if (dn->priority != dn_db->parms.priority) return 0; - if (dn_ntohs(dn->addr) < dn_ntohs(ifa->ifa_local)) + if (le16_to_cpu(dn->addr) < le16_to_cpu(ifa->ifa_local)) return 1; return 0; @@ -973,11 +973,11 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) ptr += ETH_ALEN; *ptr++ = dn_db->parms.forwarding == 1 ? DN_RT_INFO_L1RT : DN_RT_INFO_L2RT; - *((__le16 *)ptr) = dn_htons(mtu2blksize(dev)); + *((__le16 *)ptr) = cpu_to_le16(mtu2blksize(dev)); ptr += 2; *ptr++ = dn_db->parms.priority; /* Priority */ *ptr++ = 0; /* Area: Reserved */ - *((__le16 *)ptr) = dn_htons((unsigned short)dn_db->parms.t3); + *((__le16 *)ptr) = cpu_to_le16((unsigned short)dn_db->parms.t3); ptr += 2; *ptr++ = 0; /* MPD: Reserved */ i1 = ptr++; @@ -993,7 +993,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa) skb_trim(skb, (27 + *i2)); pktlen = (__le16 *)skb_push(skb, 2); - *pktlen = dn_htons(skb->len - 2); + *pktlen = cpu_to_le16(skb->len - 2); skb_reset_network_header(skb); @@ -1106,7 +1106,7 @@ static void dn_dev_set_timer(struct net_device *dev) add_timer(&dn_db->timer); } -struct dn_dev *dn_dev_create(struct net_device *dev, int *err) +static struct dn_dev *dn_dev_create(struct net_device *dev, int *err) { int i; struct dn_dev_parms *p = dn_dev_list; @@ -1401,8 +1401,8 @@ static int dn_dev_seq_show(struct seq_file *seq, void *v) mtu2blksize(dev), dn_db->parms.priority, dn_db->parms.state, dn_db->parms.name, - dn_db->router ? dn_addr2asc(dn_ntohs(*(__le16 *)dn_db->router->primary_key), router_buf) : "", - dn_db->peer ? dn_addr2asc(dn_ntohs(*(__le16 *)dn_db->peer->primary_key), peer_buf) : ""); + dn_db->router ? dn_addr2asc(le16_to_cpu(*(__le16 *)dn_db->router->primary_key), router_buf) : "", + dn_db->peer ? dn_addr2asc(le16_to_cpu(*(__le16 *)dn_db->peer->primary_key), peer_buf) : ""); } return 0; } @@ -1445,7 +1445,7 @@ void __init dn_dev_init(void) return; } - decnet_address = dn_htons((addr[0] << 10) | addr[1]); + decnet_address = cpu_to_le16((addr[0] << 10) | addr[1]); dn_dev_devices_on(); diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c index 1ca13b17974d92e0fed3e1b6a7e475d06059cd55..05b5aa05e50ee3599a68984b12b831a79bcfe3b0 100644 --- a/net/decnet/dn_neigh.c +++ b/net/decnet/dn_neigh.c @@ -250,7 +250,7 @@ static int dn_long_output(struct sk_buff *skb) data = skb_push(skb, sizeof(struct dn_long_packet) + 3); lp = (struct dn_long_packet *)(data+3); - *((__le16 *)data) = dn_htons(skb->len - 2); + *((__le16 *)data) = cpu_to_le16(skb->len - 2); *(data + 2) = 1 | DN_RT_F_PF; /* Padding */ lp->msgflg = DN_RT_PKT_LONG|(cb->rt_flags&(DN_RT_F_IE|DN_RT_F_RQR|DN_RT_F_RTS)); @@ -294,7 +294,7 @@ static int dn_short_output(struct sk_buff *skb) } data = skb_push(skb, sizeof(struct dn_short_packet) + 2); - *((__le16 *)data) = dn_htons(skb->len - 2); + *((__le16 *)data) = cpu_to_le16(skb->len - 2); sp = (struct dn_short_packet *)(data+2); sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS)); @@ -336,12 +336,12 @@ static int dn_phase3_output(struct sk_buff *skb) } data = skb_push(skb, sizeof(struct dn_short_packet) + 2); - *((__le16 *)data) = dn_htons(skb->len - 2); + *((__le16 *)data) = cpu_to_le16(skb->len - 2); sp = (struct dn_short_packet *)(data + 2); sp->msgflg = DN_RT_PKT_SHORT|(cb->rt_flags&(DN_RT_F_RQR|DN_RT_F_RTS)); - sp->dstnode = cb->dst & dn_htons(0x03ff); - sp->srcnode = cb->src & dn_htons(0x03ff); + sp->dstnode = cb->dst & cpu_to_le16(0x03ff); + sp->srcnode = cb->src & cpu_to_le16(0x03ff); sp->forward = cb->hops & 0x3f; skb_reset_network_header(skb); @@ -394,7 +394,7 @@ int dn_neigh_router_hello(struct sk_buff *skb) if (neigh->dev->type == ARPHRD_ETHER) memcpy(neigh->ha, ð_hdr(skb)->h_source, ETH_ALEN); - dn->blksize = dn_ntohs(msg->blksize); + dn->blksize = le16_to_cpu(msg->blksize); dn->priority = msg->priority; dn->flags &= ~DN_NDFLAG_P3; @@ -410,7 +410,7 @@ int dn_neigh_router_hello(struct sk_buff *skb) } /* Only use routers in our area */ - if ((dn_ntohs(src)>>10) == (dn_ntohs((decnet_address))>>10)) { + if ((le16_to_cpu(src)>>10) == (le16_to_cpu((decnet_address))>>10)) { if (!dn_db->router) { dn_db->router = neigh_clone(neigh); } else { @@ -453,7 +453,7 @@ int dn_neigh_endnode_hello(struct sk_buff *skb) if (neigh->dev->type == ARPHRD_ETHER) memcpy(neigh->ha, ð_hdr(skb)->h_source, ETH_ALEN); dn->flags &= ~(DN_NDFLAG_R1 | DN_NDFLAG_R2); - dn->blksize = dn_ntohs(msg->blksize); + dn->blksize = le16_to_cpu(msg->blksize); dn->priority = 0; } @@ -543,7 +543,7 @@ static inline void dn_neigh_format_entry(struct seq_file *seq, read_lock(&n->lock); seq_printf(seq, "%-7s %s%s%s %02x %02d %07ld %-8s\n", - dn_addr2asc(dn_ntohs(dn->addr), buf), + dn_addr2asc(le16_to_cpu(dn->addr), buf), (dn->flags&DN_NDFLAG_R1) ? "1" : "-", (dn->flags&DN_NDFLAG_R2) ? "2" : "-", (dn->flags&DN_NDFLAG_P3) ? "3" : "-", diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c index 4074a6e5d0de90531453c3952de4dc1cc75b1bb2..5d8a2a56fd397a66516cd272e25988a75a901d28 100644 --- a/net/decnet/dn_nsp_in.c +++ b/net/decnet/dn_nsp_in.c @@ -83,7 +83,9 @@ static void dn_log_martian(struct sk_buff *skb, const char *msg) if (decnet_log_martians && net_ratelimit()) { char *devname = skb->dev ? skb->dev->name : "???"; struct dn_skb_cb *cb = DN_SKB_CB(skb); - printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", msg, devname, dn_ntohs(cb->src), dn_ntohs(cb->dst), dn_ntohs(cb->src_port), dn_ntohs(cb->dst_port)); + printk(KERN_INFO "DECnet: Martian packet (%s) dev=%s src=0x%04hx dst=0x%04hx srcport=0x%04hx dstport=0x%04hx\n", + msg, devname, le16_to_cpu(cb->src), le16_to_cpu(cb->dst), + le16_to_cpu(cb->src_port), le16_to_cpu(cb->dst_port)); } } @@ -133,7 +135,7 @@ static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth) if (skb->len < 2) return len; - if ((ack = dn_ntohs(*ptr)) & 0x8000) { + if ((ack = le16_to_cpu(*ptr)) & 0x8000) { skb_pull(skb, 2); ptr++; len += 2; @@ -147,7 +149,7 @@ static int dn_process_ack(struct sock *sk, struct sk_buff *skb, int oth) if (skb->len < 2) return len; - if ((ack = dn_ntohs(*ptr)) & 0x8000) { + if ((ack = le16_to_cpu(*ptr)) & 0x8000) { skb_pull(skb, 2); len += 2; if ((ack & 0x4000) == 0) { @@ -237,7 +239,7 @@ static struct sock *dn_find_listener(struct sk_buff *skb, unsigned short *reason cb->dst_port = msg->dstaddr; cb->services = msg->services; cb->info = msg->info; - cb->segsize = dn_ntohs(msg->segsize); + cb->segsize = le16_to_cpu(msg->segsize); if (!pskb_may_pull(skb, sizeof(*msg))) goto err_out; @@ -344,7 +346,7 @@ static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb) ptr = skb->data; cb->services = *ptr++; cb->info = *ptr++; - cb->segsize = dn_ntohs(*(__le16 *)ptr); + cb->segsize = le16_to_cpu(*(__le16 *)ptr); if ((scp->state == DN_CI) || (scp->state == DN_CD)) { scp->persist = 0; @@ -361,7 +363,7 @@ static void dn_nsp_conn_conf(struct sock *sk, struct sk_buff *skb) if (skb->len > 0) { u16 dlen = *skb->data; if ((dlen <= 16) && (dlen <= skb->len)) { - scp->conndata_in.opt_optl = dn_htons(dlen); + scp->conndata_in.opt_optl = cpu_to_le16(dlen); skb_copy_from_linear_data_offset(skb, 1, scp->conndata_in.opt_data, dlen); } @@ -396,17 +398,17 @@ static void dn_nsp_disc_init(struct sock *sk, struct sk_buff *skb) if (skb->len < 2) goto out; - reason = dn_ntohs(*(__le16 *)skb->data); + reason = le16_to_cpu(*(__le16 *)skb->data); skb_pull(skb, 2); - scp->discdata_in.opt_status = dn_htons(reason); + scp->discdata_in.opt_status = cpu_to_le16(reason); scp->discdata_in.opt_optl = 0; memset(scp->discdata_in.opt_data, 0, 16); if (skb->len > 0) { u16 dlen = *skb->data; if ((dlen <= 16) && (dlen <= skb->len)) { - scp->discdata_in.opt_optl = dn_htons(dlen); + scp->discdata_in.opt_optl = cpu_to_le16(dlen); skb_copy_from_linear_data_offset(skb, 1, scp->discdata_in.opt_data, dlen); } } @@ -463,7 +465,7 @@ static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb) if (skb->len != 2) goto out; - reason = dn_ntohs(*(__le16 *)skb->data); + reason = le16_to_cpu(*(__le16 *)skb->data); sk->sk_state = TCP_CLOSE; @@ -512,7 +514,7 @@ static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb) if (skb->len != 4) goto out; - segnum = dn_ntohs(*(__le16 *)ptr); + segnum = le16_to_cpu(*(__le16 *)ptr); ptr += 2; lsflags = *(unsigned char *)ptr++; fcval = *ptr; @@ -620,7 +622,7 @@ static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb) if (skb->len < 2) goto out; - cb->segnum = segnum = dn_ntohs(*(__le16 *)skb->data); + cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data); skb_pull(skb, 2); if (seq_next(scp->numoth_rcv, segnum)) { @@ -648,7 +650,7 @@ static void dn_nsp_data(struct sock *sk, struct sk_buff *skb) if (skb->len < 2) goto out; - cb->segnum = segnum = dn_ntohs(*(__le16 *)skb->data); + cb->segnum = segnum = le16_to_cpu(*(__le16 *)skb->data); skb_pull(skb, 2); if (seq_next(scp->numdat_rcv, segnum)) { diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c index 1964faf203e48a41d6a30d468db3b8b4503ee533..2013c25b7f5aff64ad41e1ff865072fff705ff79 100644 --- a/net/decnet/dn_nsp_out.c +++ b/net/decnet/dn_nsp_out.c @@ -230,7 +230,6 @@ static inline unsigned dn_nsp_clone_and_send(struct sk_buff *skb, /** * dn_nsp_output - Try and send something from socket queues * @sk: The socket whose queues are to be investigated - * @gfp: The memory allocation flags * * Try and send the packet on the end of the data and other data queues. * Other data gets priority over data, and if we retransmit a packet we @@ -326,8 +325,8 @@ static __le16 *dn_mk_ack_header(struct sock *sk, struct sk_buff *skb, unsigned c ptr = (__le16 *)dn_mk_common_header(scp, skb, msgflag, hlen); - *ptr++ = dn_htons(acknum); - *ptr++ = dn_htons(ackcrs); + *ptr++ = cpu_to_le16(acknum); + *ptr++ = cpu_to_le16(ackcrs); return ptr; } @@ -345,7 +344,7 @@ static __le16 *dn_nsp_mk_data_header(struct sock *sk, struct sk_buff *skb, int o cb->segnum = scp->numdat; seq_add(&scp->numdat, 1); } - *(ptr++) = dn_htons(cb->segnum); + *(ptr++) = cpu_to_le16(cb->segnum); return ptr; } @@ -523,7 +522,7 @@ void dn_send_conn_conf(struct sock *sk, gfp_t gfp) struct dn_scp *scp = DN_SK(sk); struct sk_buff *skb = NULL; struct nsp_conn_init_msg *msg; - __u8 len = (__u8)dn_ntohs(scp->conndata_out.opt_optl); + __u8 len = (__u8)le16_to_cpu(scp->conndata_out.opt_optl); if ((skb = dn_alloc_skb(sk, 50 + len, gfp)) == NULL) return; @@ -534,7 +533,7 @@ void dn_send_conn_conf(struct sock *sk, gfp_t gfp) msg->srcaddr = scp->addrloc; msg->services = scp->services_loc; msg->info = scp->info_loc; - msg->segsize = dn_htons(scp->segsize_loc); + msg->segsize = cpu_to_le16(scp->segsize_loc); *skb_put(skb,1) = len; @@ -560,7 +559,7 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg, if ((dst == NULL) || (rem == 0)) { if (net_ratelimit()) - printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", dn_ntohs(rem), dst); + printk(KERN_DEBUG "DECnet: dn_nsp_do_disc: BUG! Please report this to SteveW@ACM.org rem=%u dst=%p\n", le16_to_cpu(rem), dst); return; } @@ -573,7 +572,7 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg, msg += 2; *(__le16 *)msg = loc; msg += 2; - *(__le16 *)msg = dn_htons(reason); + *(__le16 *)msg = cpu_to_le16(reason); msg += 2; if (msgflg == NSP_DISCINIT) *msg++ = ddl; @@ -599,10 +598,10 @@ void dn_nsp_send_disc(struct sock *sk, unsigned char msgflg, int ddl = 0; if (msgflg == NSP_DISCINIT) - ddl = dn_ntohs(scp->discdata_out.opt_optl); + ddl = le16_to_cpu(scp->discdata_out.opt_optl); if (reason == 0) - reason = dn_ntohs(scp->discdata_out.opt_status); + reason = le16_to_cpu(scp->discdata_out.opt_status); dn_nsp_do_disc(sk, msgflg, reason, gfp, sk->sk_dst_cache, ddl, scp->discdata_out.opt_data, scp->addrrem, scp->addrloc); @@ -676,7 +675,7 @@ void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg) msg->srcaddr = scp->addrloc; msg->services = scp->services_loc; /* Requested flow control */ msg->info = scp->info_loc; /* Version Number */ - msg->segsize = dn_htons(scp->segsize_loc); /* Max segment size */ + msg->segsize = cpu_to_le16(scp->segsize_loc); /* Max segment size */ if (scp->peer.sdn_objnum) type = 0; @@ -709,7 +708,7 @@ void dn_nsp_send_conninit(struct sock *sk, unsigned char msgflg) if (aux > 0) memcpy(skb_put(skb, aux), scp->accessdata.acc_acc, aux); - aux = (__u8)dn_ntohs(scp->conndata_out.opt_optl); + aux = (__u8)le16_to_cpu(scp->conndata_out.opt_optl); *skb_put(skb, 1) = aux; if (aux > 0) memcpy(skb_put(skb,aux), scp->conndata_out.opt_data, aux); diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c index 821bd1cdec04d23125cbe98ca893a329bf8d844d..c754670b7fca4e98376fdb22657efb5e3e5613d6 100644 --- a/net/decnet/dn_route.c +++ b/net/decnet/dn_route.c @@ -131,7 +131,6 @@ static struct dst_ops dn_dst_ops = { .negative_advice = dn_dst_negative_advice, .link_failure = dn_dst_link_failure, .update_pmtu = dn_dst_update_pmtu, - .entry_size = sizeof(struct dn_route), .entries = ATOMIC_INIT(0), }; @@ -312,7 +311,7 @@ static int dn_insert_route(struct dn_route *rt, unsigned hash, struct dn_route * return 0; } -void dn_run_flush(unsigned long dummy) +static void dn_run_flush(unsigned long dummy) { int i; struct dn_route *rt, *next; @@ -476,7 +475,7 @@ static int dn_route_rx_packet(struct sk_buff *skb) printk(KERN_DEBUG "DECnet: dn_route_rx_packet: rt_flags=0x%02x dev=%s len=%d src=0x%04hx dst=0x%04hx err=%d type=%d\n", (int)cb->rt_flags, devname, skb->len, - dn_ntohs(cb->src), dn_ntohs(cb->dst), + le16_to_cpu(cb->src), le16_to_cpu(cb->dst), err, skb->pkt_type); } @@ -576,7 +575,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type { struct dn_skb_cb *cb; unsigned char flags = 0; - __u16 len = dn_ntohs(*(__le16 *)skb->data); + __u16 len = le16_to_cpu(*(__le16 *)skb->data); struct dn_dev *dn = (struct dn_dev *)dev->dn_ptr; unsigned char padlen = 0; @@ -774,7 +773,7 @@ static int dn_rt_bug(struct sk_buff *skb) struct dn_skb_cb *cb = DN_SKB_CB(skb); printk(KERN_DEBUG "dn_rt_bug: skb from:%04x to:%04x\n", - dn_ntohs(cb->src), dn_ntohs(cb->dst)); + le16_to_cpu(cb->src), le16_to_cpu(cb->dst)); } kfree_skb(skb); @@ -817,7 +816,7 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res) static inline int dn_match_addr(__le16 addr1, __le16 addr2) { - __u16 tmp = dn_ntohs(addr1) ^ dn_ntohs(addr2); + __u16 tmp = le16_to_cpu(addr1) ^ le16_to_cpu(addr2); int match = 16; while(tmp) { tmp >>= 1; @@ -887,8 +886,8 @@ static int dn_route_output_slow(struct dst_entry **pprt, const struct flowi *old if (decnet_debug_level & 16) printk(KERN_DEBUG "dn_route_output_slow: dst=%04x src=%04x mark=%d" - " iif=%d oif=%d\n", dn_ntohs(oldflp->fld_dst), - dn_ntohs(oldflp->fld_src), + " iif=%d oif=%d\n", le16_to_cpu(oldflp->fld_dst), + le16_to_cpu(oldflp->fld_src), oldflp->mark, init_net.loopback_dev->ifindex, oldflp->oif); /* If we have an output interface, verify its a DECnet device */ @@ -960,7 +959,7 @@ source_ok: printk(KERN_DEBUG "dn_route_output_slow: initial checks complete." " dst=%o4x src=%04x oif=%d try_hard=%d\n", - dn_ntohs(fl.fld_dst), dn_ntohs(fl.fld_src), + le16_to_cpu(fl.fld_dst), le16_to_cpu(fl.fld_src), fl.oif, try_hard); /* @@ -1185,7 +1184,7 @@ static int dn_route_output_key(struct dst_entry **pprt, struct flowi *flp, int f err = __dn_route_output_key(pprt, flp, flags); if (err == 0 && flp->proto) { - err = xfrm_lookup(pprt, flp, NULL, 0); + err = xfrm_lookup(&init_net, pprt, flp, NULL, 0); } return err; } @@ -1196,8 +1195,8 @@ int dn_route_output_sock(struct dst_entry **pprt, struct flowi *fl, struct sock err = __dn_route_output_key(pprt, fl, flags & MSG_TRYHARD); if (err == 0 && fl->proto) { - err = xfrm_lookup(pprt, fl, sk, (flags & MSG_DONTWAIT) ? - 0 : XFRM_LOOKUP_WAIT); + err = xfrm_lookup(&init_net, pprt, fl, sk, + (flags & MSG_DONTWAIT) ? 0 : XFRM_LOOKUP_WAIT); } return err; } @@ -1423,7 +1422,7 @@ e_neighbour: goto done; } -int dn_route_input(struct sk_buff *skb) +static int dn_route_input(struct sk_buff *skb) { struct dn_route *rt; struct dn_skb_cb *cb = DN_SKB_CB(skb); @@ -1712,8 +1711,8 @@ static int dn_rt_cache_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%-8s %-7s %-7s %04d %04d %04d\n", rt->u.dst.dev ? rt->u.dst.dev->name : "*", - dn_addr2asc(dn_ntohs(rt->rt_daddr), buf1), - dn_addr2asc(dn_ntohs(rt->rt_saddr), buf2), + dn_addr2asc(le16_to_cpu(rt->rt_daddr), buf1), + dn_addr2asc(le16_to_cpu(rt->rt_saddr), buf2), atomic_read(&rt->u.dst.__refcnt), rt->u.dst.__use, (int) dst_metric(&rt->u.dst, RTAX_RTT)); diff --git a/net/decnet/dn_table.c b/net/decnet/dn_table.c index 3a2830ac89c26cbaefa8b97977d9efee26d768ed..69ad9280c6936a99975bdf2f7d8361b8924783c7 100644 --- a/net/decnet/dn_table.c +++ b/net/decnet/dn_table.c @@ -85,7 +85,7 @@ static int dn_fib_hash_zombies; static inline dn_fib_idx_t dn_hash(dn_fib_key_t key, struct dn_zone *dz) { - u16 h = dn_ntohs(key.datum)>>(16 - dz->dz_order); + u16 h = le16_to_cpu(key.datum)>>(16 - dz->dz_order); h ^= (h >> 10); h ^= (h >> 6); h &= DZ_HASHMASK(dz); diff --git a/net/decnet/sysctl_net_decnet.c b/net/decnet/sysctl_net_decnet.c index 36400b2668967c1bb5e4eab723837f78566641f8..965397af9a80f3f1d9c0fc99e84b436485431605 100644 --- a/net/decnet/sysctl_net_decnet.c +++ b/net/decnet/sysctl_net_decnet.c @@ -126,7 +126,7 @@ static int parse_addr(__le16 *addr, char *str) if (INVALID_END_CHAR(*str)) return -1; - *addr = dn_htons((area << 10) | node); + *addr = cpu_to_le16((area << 10) | node); return 0; } @@ -201,7 +201,7 @@ static int dn_node_address_handler(ctl_table *table, int write, return 0; } - dn_addr2asc(dn_ntohs(decnet_address), addr); + dn_addr2asc(le16_to_cpu(decnet_address), addr); len = strlen(addr); addr[len++] = '\n'; @@ -354,8 +354,8 @@ static ctl_table dn_table[] = { .data = node_name, .maxlen = 7, .mode = 0644, - .proc_handler = &proc_dostring, - .strategy = &sysctl_string, + .proc_handler = proc_dostring, + .strategy = sysctl_string, }, { .ctl_name = NET_DECNET_DEFAULT_DEVICE, @@ -371,8 +371,8 @@ static ctl_table dn_table[] = { .data = &decnet_time_wait, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_decnet_time_wait, .extra2 = &max_decnet_time_wait }, @@ -382,8 +382,8 @@ static ctl_table dn_table[] = { .data = &decnet_dn_count, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_state_count, .extra2 = &max_state_count }, @@ -393,8 +393,8 @@ static ctl_table dn_table[] = { .data = &decnet_di_count, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_state_count, .extra2 = &max_state_count }, @@ -404,8 +404,8 @@ static ctl_table dn_table[] = { .data = &decnet_dr_count, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_state_count, .extra2 = &max_state_count }, @@ -415,8 +415,8 @@ static ctl_table dn_table[] = { .data = &decnet_dst_gc_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_decnet_dst_gc_interval, .extra2 = &max_decnet_dst_gc_interval }, @@ -426,8 +426,8 @@ static ctl_table dn_table[] = { .data = &decnet_no_fc_max_cwnd, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_decnet_no_fc_max_cwnd, .extra2 = &max_decnet_no_fc_max_cwnd }, @@ -437,8 +437,8 @@ static ctl_table dn_table[] = { .data = &sysctl_decnet_mem, .maxlen = sizeof(sysctl_decnet_mem), .mode = 0644, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec, }, { .ctl_name = NET_DECNET_RMEM, @@ -446,8 +446,8 @@ static ctl_table dn_table[] = { .data = &sysctl_decnet_rmem, .maxlen = sizeof(sysctl_decnet_rmem), .mode = 0644, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec, }, { .ctl_name = NET_DECNET_WMEM, @@ -455,8 +455,8 @@ static ctl_table dn_table[] = { .data = &sysctl_decnet_wmem, .maxlen = sizeof(sysctl_decnet_wmem), .mode = 0644, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec, }, { .ctl_name = NET_DECNET_DEBUG_LEVEL, @@ -464,8 +464,8 @@ static ctl_table dn_table[] = { .data = &decnet_debug_level, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec, }, {0} }; diff --git a/net/dsa/mv88e6060.c b/net/dsa/mv88e6060.c index 54068ef251e8a34a494ce6442e1e26c5de1140cc..85081ae9fe8915b13cde725d9c6064ba0d49a348 100644 --- a/net/dsa/mv88e6060.c +++ b/net/dsa/mv88e6060.c @@ -222,7 +222,7 @@ static void mv88e6060_poll_link(struct dsa_switch *ds) for (i = 0; i < DSA_MAX_PORTS; i++) { struct net_device *dev; - int port_status; + int uninitialized_var(port_status); int link; int speed; int duplex; @@ -273,14 +273,14 @@ static struct dsa_switch_driver mv88e6060_switch_driver = { .poll_link = mv88e6060_poll_link, }; -int __init mv88e6060_init(void) +static int __init mv88e6060_init(void) { register_switch_driver(&mv88e6060_switch_driver); return 0; } module_init(mv88e6060_init); -void __exit mv88e6060_cleanup(void) +static void __exit mv88e6060_cleanup(void) { unregister_switch_driver(&mv88e6060_switch_driver); } diff --git a/net/dsa/mv88e6123_61_65.c b/net/dsa/mv88e6123_61_65.c index 555b164082fc271d6a15c83ecf398da85d9da9e4..ec8c6a0482d3dde28385c498fbad59707da6ede3 100644 --- a/net/dsa/mv88e6123_61_65.c +++ b/net/dsa/mv88e6123_61_65.c @@ -407,14 +407,14 @@ static struct dsa_switch_driver mv88e6123_61_65_switch_driver = { .get_sset_count = mv88e6123_61_65_get_sset_count, }; -int __init mv88e6123_61_65_init(void) +static int __init mv88e6123_61_65_init(void) { register_switch_driver(&mv88e6123_61_65_switch_driver); return 0; } module_init(mv88e6123_61_65_init); -void __exit mv88e6123_61_65_cleanup(void) +static void __exit mv88e6123_61_65_cleanup(void) { unregister_switch_driver(&mv88e6123_61_65_switch_driver); } diff --git a/net/dsa/mv88e6131.c b/net/dsa/mv88e6131.c index 36e01eb863a0af7f778dd3d748271b918bc4166f..374d46a01265a334901bc652c57b939a419ddfaf 100644 --- a/net/dsa/mv88e6131.c +++ b/net/dsa/mv88e6131.c @@ -366,14 +366,14 @@ static struct dsa_switch_driver mv88e6131_switch_driver = { .get_sset_count = mv88e6131_get_sset_count, }; -int __init mv88e6131_init(void) +static int __init mv88e6131_init(void) { register_switch_driver(&mv88e6131_switch_driver); return 0; } module_init(mv88e6131_init); -void __exit mv88e6131_cleanup(void) +static void __exit mv88e6131_cleanup(void) { unregister_switch_driver(&mv88e6131_switch_driver); } diff --git a/net/dsa/mv88e6xxx.c b/net/dsa/mv88e6xxx.c index aa6c609c59f23f9fbe6d83bb9709722b839e974b..4e4d8b5ad03d3b58fe6c0e353e147b2b78fa5144 100644 --- a/net/dsa/mv88e6xxx.c +++ b/net/dsa/mv88e6xxx.c @@ -358,7 +358,7 @@ void mv88e6xxx_poll_link(struct dsa_switch *ds) for (i = 0; i < DSA_MAX_PORTS; i++) { struct net_device *dev; - int port_status; + int uninitialized_var(port_status); int link; int speed; int duplex; diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 1af5a79309e9c2b1e38a4fbf039fb5d0c4d90284..a3a410d20da07ad44100defd79562f8c6d9ded3f 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -352,7 +352,7 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent, netif_carrier_off(slave_dev); if (p->phy != NULL) { - phy_attach(slave_dev, p->phy->dev.bus_id, + phy_attach(slave_dev, dev_name(&p->phy->dev), 0, PHY_INTERFACE_MODE_GMII); p->phy->autoneg = AUTONEG_ENABLE; diff --git a/net/dsa/tag_dsa.c b/net/dsa/tag_dsa.c index 31866543332ea4c130d47eb9f6539cf5f0f11d94..f99a019b939ed7e2b15e90bcfa5be1716accd1b9 100644 --- a/net/dsa/tag_dsa.c +++ b/net/dsa/tag_dsa.c @@ -162,7 +162,6 @@ static int dsa_rcv(struct sk_buff *skb, struct net_device *dev, skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, skb->dev); - skb->dev->last_rx = jiffies; skb->dev->stats.rx_packets++; skb->dev->stats.rx_bytes += skb->len; diff --git a/net/dsa/tag_edsa.c b/net/dsa/tag_edsa.c index 9f4ce55eae5952b9cd3c5e6606189d10028002f7..328ec957f7864a670ce7ad841ae43010fa2d2e35 100644 --- a/net/dsa/tag_edsa.c +++ b/net/dsa/tag_edsa.c @@ -181,7 +181,6 @@ static int edsa_rcv(struct sk_buff *skb, struct net_device *dev, skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, skb->dev); - skb->dev->last_rx = jiffies; skb->dev->stats.rx_packets++; skb->dev->stats.rx_bytes += skb->len; diff --git a/net/dsa/tag_trailer.c b/net/dsa/tag_trailer.c index efd26697e716a22b6fb8713a5285b88a20fab2ab..b59132878ad1c45ce54271213d5b4909d5113809 100644 --- a/net/dsa/tag_trailer.c +++ b/net/dsa/tag_trailer.c @@ -98,7 +98,6 @@ static int trailer_rcv(struct sk_buff *skb, struct net_device *dev, skb->pkt_type = PACKET_HOST; skb->protocol = eth_type_trans(skb, skb->dev); - skb->dev->last_rx = jiffies; skb->dev->stats.rx_packets++; skb->dev->stats.rx_bytes += skb->len; diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c index b9d85af2dd31f290883db91125eb958440ef0c12..280352aba4034bc2d343171e72f6942635fd74c3 100644 --- a/net/ethernet/eth.c +++ b/net/ethernet/eth.c @@ -165,8 +165,8 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) skb_pull(skb, ETH_HLEN); eth = eth_hdr(skb); - if (is_multicast_ether_addr(eth->h_dest)) { - if (!compare_ether_addr(eth->h_dest, dev->broadcast)) + if (unlikely(is_multicast_ether_addr(eth->h_dest))) { + if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast)) skb->pkt_type = PACKET_BROADCAST; else skb->pkt_type = PACKET_MULTICAST; @@ -181,7 +181,7 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev) */ else if (1 /*dev->flags&IFF_PROMISC */ ) { - if (unlikely(compare_ether_addr(eth->h_dest, dev->dev_addr))) + if (unlikely(compare_ether_addr_64bits(eth->h_dest, dev->dev_addr))) skb->pkt_type = PACKET_OTHERHOST; } @@ -282,7 +282,7 @@ EXPORT_SYMBOL(eth_header_cache_update); * This doesn't change hardware matching, so needs to be overridden * for most real devices. */ -static int eth_mac_addr(struct net_device *dev, void *p) +int eth_mac_addr(struct net_device *dev, void *p) { struct sockaddr *addr = p; @@ -293,6 +293,7 @@ static int eth_mac_addr(struct net_device *dev, void *p) memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN); return 0; } +EXPORT_SYMBOL(eth_mac_addr); /** * eth_change_mtu - set new MTU size @@ -302,21 +303,23 @@ static int eth_mac_addr(struct net_device *dev, void *p) * Allow changing MTU size. Needs to be overridden for devices * supporting jumbo frames. */ -static int eth_change_mtu(struct net_device *dev, int new_mtu) +int eth_change_mtu(struct net_device *dev, int new_mtu) { if (new_mtu < 68 || new_mtu > ETH_DATA_LEN) return -EINVAL; dev->mtu = new_mtu; return 0; } +EXPORT_SYMBOL(eth_change_mtu); -static int eth_validate_addr(struct net_device *dev) +int eth_validate_addr(struct net_device *dev) { if (!is_valid_ether_addr(dev->dev_addr)) return -EADDRNOTAVAIL; return 0; } +EXPORT_SYMBOL(eth_validate_addr); const struct header_ops eth_header_ops ____cacheline_aligned = { .create = eth_header, @@ -334,11 +337,11 @@ const struct header_ops eth_header_ops ____cacheline_aligned = { void ether_setup(struct net_device *dev) { dev->header_ops = ð_header_ops; - +#ifdef CONFIG_COMPAT_NET_DEV_OPS dev->change_mtu = eth_change_mtu; dev->set_mac_address = eth_mac_addr; dev->validate_addr = eth_validate_addr; - +#endif dev->type = ARPHRD_ETHER; dev->hard_header_len = ETH_HLEN; dev->mtu = ETH_DATA_LEN; diff --git a/net/ieee80211/Kconfig b/net/ieee80211/Kconfig deleted file mode 100644 index 94ed7d3cd9dab45e54e292d3c674992c87026cd8..0000000000000000000000000000000000000000 --- a/net/ieee80211/Kconfig +++ /dev/null @@ -1,73 +0,0 @@ -config IEEE80211 - tristate "Generic IEEE 802.11 Networking Stack (DEPRECATED)" - ---help--- - This option enables the hardware independent IEEE 802.11 - networking stack. This component is deprecated in favor of the - mac80211 component. - -config IEEE80211_DEBUG - bool "Enable full debugging output" - depends on IEEE80211 - ---help--- - This option will enable debug tracing output for the - ieee80211 network stack. - - This will result in the kernel module being ~70k larger. You - can control which debug output is sent to the kernel log by - setting the value in - - /proc/net/ieee80211/debug_level - - For example: - - % echo 0x00000FFO > /proc/net/ieee80211/debug_level - - For a list of values you can assign to debug_level, you - can look at the bit mask values in - - If you are not trying to debug or develop the ieee80211 - subsystem, you most likely want to say N here. - -config IEEE80211_CRYPT_WEP - tristate "IEEE 802.11 WEP encryption (802.1x)" - depends on IEEE80211 - select CRYPTO - select CRYPTO_ARC4 - select CRYPTO_ECB - select CRC32 - ---help--- - Include software based cipher suites in support of IEEE - 802.11's WEP. This is needed for WEP as well as 802.1x. - - This can be compiled as a module and it will be called - "ieee80211_crypt_wep". - -config IEEE80211_CRYPT_CCMP - tristate "IEEE 802.11i CCMP support" - depends on IEEE80211 - select CRYPTO - select CRYPTO_AES - ---help--- - Include software based cipher suites in support of IEEE 802.11i - (aka TGi, WPA, WPA2, WPA-PSK, etc.) for use with CCMP enabled - networks. - - This can be compiled as a module and it will be called - "ieee80211_crypt_ccmp". - -config IEEE80211_CRYPT_TKIP - tristate "IEEE 802.11i TKIP encryption" - depends on IEEE80211 - select WIRELESS_EXT - select CRYPTO - select CRYPTO_MICHAEL_MIC - select CRYPTO_ECB - select CRC32 - ---help--- - Include software based cipher suites in support of IEEE 802.11i - (aka TGi, WPA, WPA2, WPA-PSK, etc.) for use with TKIP enabled - networks. - - This can be compiled as a module and it will be called - "ieee80211_crypt_tkip". - diff --git a/net/ieee80211/Makefile b/net/ieee80211/Makefile deleted file mode 100644 index f988417121da76646ad995ce3a556c09349b0338..0000000000000000000000000000000000000000 --- a/net/ieee80211/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -obj-$(CONFIG_IEEE80211) += ieee80211.o -obj-$(CONFIG_IEEE80211) += ieee80211_crypt.o -obj-$(CONFIG_IEEE80211_CRYPT_WEP) += ieee80211_crypt_wep.o -obj-$(CONFIG_IEEE80211_CRYPT_CCMP) += ieee80211_crypt_ccmp.o -obj-$(CONFIG_IEEE80211_CRYPT_TKIP) += ieee80211_crypt_tkip.o -ieee80211-objs := \ - ieee80211_module.o \ - ieee80211_tx.o \ - ieee80211_rx.o \ - ieee80211_wx.o \ - ieee80211_geo.o - diff --git a/net/ieee80211/ieee80211_crypt.c b/net/ieee80211/ieee80211_crypt.c deleted file mode 100644 index df5592c9339fab3030e887dcd9cb3af76e14b0ac..0000000000000000000000000000000000000000 --- a/net/ieee80211/ieee80211_crypt.c +++ /dev/null @@ -1,206 +0,0 @@ -/* - * Host AP crypto routines - * - * Copyright (c) 2002-2003, Jouni Malinen - * Portions Copyright (C) 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 version 2 as - * published by the Free Software Foundation. See README and COPYING for - * more details. - * - */ - -#include -#include -#include -#include -#include -#include - -MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("HostAP crypto"); -MODULE_LICENSE("GPL"); - -struct ieee80211_crypto_alg { - struct list_head list; - struct ieee80211_crypto_ops *ops; -}; - -static LIST_HEAD(ieee80211_crypto_algs); -static DEFINE_SPINLOCK(ieee80211_crypto_lock); - -void ieee80211_crypt_deinit_entries(struct ieee80211_device *ieee, int force) -{ - struct ieee80211_crypt_data *entry, *next; - unsigned long flags; - - spin_lock_irqsave(&ieee->lock, flags); - list_for_each_entry_safe(entry, next, &ieee->crypt_deinit_list, list) { - if (atomic_read(&entry->refcnt) != 0 && !force) - continue; - - list_del(&entry->list); - - if (entry->ops) { - entry->ops->deinit(entry->priv); - module_put(entry->ops->owner); - } - kfree(entry); - } - spin_unlock_irqrestore(&ieee->lock, flags); -} - -/* After this, crypt_deinit_list won't accept new members */ -void ieee80211_crypt_quiescing(struct ieee80211_device *ieee) -{ - unsigned long flags; - - spin_lock_irqsave(&ieee->lock, flags); - ieee->crypt_quiesced = 1; - spin_unlock_irqrestore(&ieee->lock, flags); -} - -void ieee80211_crypt_deinit_handler(unsigned long data) -{ - struct ieee80211_device *ieee = (struct ieee80211_device *)data; - unsigned long flags; - - ieee80211_crypt_deinit_entries(ieee, 0); - - spin_lock_irqsave(&ieee->lock, flags); - if (!list_empty(&ieee->crypt_deinit_list) && !ieee->crypt_quiesced) { - printk(KERN_DEBUG "%s: entries remaining in delayed crypt " - "deletion list\n", ieee->dev->name); - ieee->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&ieee->crypt_deinit_timer); - } - spin_unlock_irqrestore(&ieee->lock, flags); -} - -void ieee80211_crypt_delayed_deinit(struct ieee80211_device *ieee, - struct ieee80211_crypt_data **crypt) -{ - struct ieee80211_crypt_data *tmp; - unsigned long flags; - - if (*crypt == NULL) - return; - - tmp = *crypt; - *crypt = NULL; - - /* must not run ops->deinit() while there may be pending encrypt or - * decrypt operations. Use a list of delayed deinits to avoid needing - * locking. */ - - spin_lock_irqsave(&ieee->lock, flags); - if (!ieee->crypt_quiesced) { - list_add(&tmp->list, &ieee->crypt_deinit_list); - if (!timer_pending(&ieee->crypt_deinit_timer)) { - ieee->crypt_deinit_timer.expires = jiffies + HZ; - add_timer(&ieee->crypt_deinit_timer); - } - } - spin_unlock_irqrestore(&ieee->lock, flags); -} - -int ieee80211_register_crypto_ops(struct ieee80211_crypto_ops *ops) -{ - unsigned long flags; - struct ieee80211_crypto_alg *alg; - - alg = kzalloc(sizeof(*alg), GFP_KERNEL); - if (alg == NULL) - return -ENOMEM; - - alg->ops = ops; - - spin_lock_irqsave(&ieee80211_crypto_lock, flags); - list_add(&alg->list, &ieee80211_crypto_algs); - spin_unlock_irqrestore(&ieee80211_crypto_lock, flags); - - printk(KERN_DEBUG "ieee80211_crypt: registered algorithm '%s'\n", - ops->name); - - return 0; -} - -int ieee80211_unregister_crypto_ops(struct ieee80211_crypto_ops *ops) -{ - struct ieee80211_crypto_alg *alg; - unsigned long flags; - - spin_lock_irqsave(&ieee80211_crypto_lock, flags); - list_for_each_entry(alg, &ieee80211_crypto_algs, list) { - if (alg->ops == ops) - goto found; - } - spin_unlock_irqrestore(&ieee80211_crypto_lock, flags); - return -EINVAL; - - found: - printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm " - "'%s'\n", ops->name); - list_del(&alg->list); - spin_unlock_irqrestore(&ieee80211_crypto_lock, flags); - kfree(alg); - return 0; -} - -struct ieee80211_crypto_ops *ieee80211_get_crypto_ops(const char *name) -{ - struct ieee80211_crypto_alg *alg; - unsigned long flags; - - spin_lock_irqsave(&ieee80211_crypto_lock, flags); - list_for_each_entry(alg, &ieee80211_crypto_algs, list) { - if (strcmp(alg->ops->name, name) == 0) - goto found; - } - spin_unlock_irqrestore(&ieee80211_crypto_lock, flags); - return NULL; - - found: - spin_unlock_irqrestore(&ieee80211_crypto_lock, flags); - return alg->ops; -} - -static void *ieee80211_crypt_null_init(int keyidx) -{ - return (void *)1; -} - -static void ieee80211_crypt_null_deinit(void *priv) -{ -} - -static struct ieee80211_crypto_ops ieee80211_crypt_null = { - .name = "NULL", - .init = ieee80211_crypt_null_init, - .deinit = ieee80211_crypt_null_deinit, - .owner = THIS_MODULE, -}; - -static int __init ieee80211_crypto_init(void) -{ - return ieee80211_register_crypto_ops(&ieee80211_crypt_null); -} - -static void __exit ieee80211_crypto_deinit(void) -{ - ieee80211_unregister_crypto_ops(&ieee80211_crypt_null); - BUG_ON(!list_empty(&ieee80211_crypto_algs)); -} - -EXPORT_SYMBOL(ieee80211_crypt_deinit_entries); -EXPORT_SYMBOL(ieee80211_crypt_deinit_handler); -EXPORT_SYMBOL(ieee80211_crypt_delayed_deinit); -EXPORT_SYMBOL(ieee80211_crypt_quiescing); - -EXPORT_SYMBOL(ieee80211_register_crypto_ops); -EXPORT_SYMBOL(ieee80211_unregister_crypto_ops); -EXPORT_SYMBOL(ieee80211_get_crypto_ops); - -module_init(ieee80211_crypto_init); -module_exit(ieee80211_crypto_deinit); diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c index 1aa2dc9e380ec237c3a4abc8d1e29911bc09dacb..743f5542d65a6385c7ae423ddb49d4c69daaeaee 100644 --- a/net/ipv4/af_inet.c +++ b/net/ipv4/af_inet.c @@ -94,6 +94,7 @@ #include #include #include +#include #include #include #include @@ -245,7 +246,7 @@ static inline int inet_netns_ok(struct net *net, int protocol) int hash; struct net_protocol *ipprot; - if (net == &init_net) + if (net_eq(net, &init_net)) return 1; hash = protocol & (MAX_INET_PROTOS - 1); @@ -272,10 +273,9 @@ static int inet_create(struct net *net, struct socket *sock, int protocol) int try_loading_module = 0; int err; - if (sock->type != SOCK_RAW && - sock->type != SOCK_DGRAM && - !inet_ehash_secret) - build_ehash_secret(); + if (unlikely(!inet_ehash_secret)) + if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) + build_ehash_secret(); sock->state = SS_UNCONNECTED; @@ -1070,11 +1070,8 @@ static int inet_sk_reselect_saddr(struct sock *sk) return 0; if (sysctl_ip_dynaddr > 1) { - printk(KERN_INFO "%s(): shifting inet->" - "saddr from " NIPQUAD_FMT " to " NIPQUAD_FMT "\n", - __func__, - NIPQUAD(old_saddr), - NIPQUAD(new_saddr)); + printk(KERN_INFO "%s(): shifting inet->saddr from %pI4 to %pI4\n", + __func__, &old_saddr, &new_saddr); } inet->saddr = inet->rcv_saddr = new_saddr; @@ -1245,6 +1242,100 @@ out: return segs; } +static struct sk_buff **inet_gro_receive(struct sk_buff **head, + struct sk_buff *skb) +{ + struct net_protocol *ops; + struct sk_buff **pp = NULL; + struct sk_buff *p; + struct iphdr *iph; + int flush = 1; + int proto; + int id; + + if (unlikely(!pskb_may_pull(skb, sizeof(*iph)))) + goto out; + + iph = ip_hdr(skb); + proto = iph->protocol & (MAX_INET_PROTOS - 1); + + rcu_read_lock(); + ops = rcu_dereference(inet_protos[proto]); + if (!ops || !ops->gro_receive) + goto out_unlock; + + if (iph->version != 4 || iph->ihl != 5) + goto out_unlock; + + if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl))) + goto out_unlock; + + flush = ntohs(iph->tot_len) != skb->len || + iph->frag_off != htons(IP_DF); + id = ntohs(iph->id); + + for (p = *head; p; p = p->next) { + struct iphdr *iph2; + + if (!NAPI_GRO_CB(p)->same_flow) + continue; + + iph2 = ip_hdr(p); + + if (iph->protocol != iph2->protocol || + iph->tos != iph2->tos || + memcmp(&iph->saddr, &iph2->saddr, 8)) { + NAPI_GRO_CB(p)->same_flow = 0; + continue; + } + + /* All fields must match except length and checksum. */ + NAPI_GRO_CB(p)->flush |= + memcmp(&iph->frag_off, &iph2->frag_off, 4) || + (u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) != id; + + NAPI_GRO_CB(p)->flush |= flush; + } + + NAPI_GRO_CB(skb)->flush |= flush; + __skb_pull(skb, sizeof(*iph)); + skb_reset_transport_header(skb); + + pp = ops->gro_receive(head, skb); + +out_unlock: + rcu_read_unlock(); + +out: + NAPI_GRO_CB(skb)->flush |= flush; + + return pp; +} + +static int inet_gro_complete(struct sk_buff *skb) +{ + struct net_protocol *ops; + struct iphdr *iph = ip_hdr(skb); + int proto = iph->protocol & (MAX_INET_PROTOS - 1); + int err = -ENOSYS; + __be16 newlen = htons(skb->len - skb_network_offset(skb)); + + csum_replace2(&iph->check, iph->tot_len, newlen); + iph->tot_len = newlen; + + rcu_read_lock(); + ops = rcu_dereference(inet_protos[proto]); + if (WARN_ON(!ops || !ops->gro_complete)) + goto out_unlock; + + err = ops->gro_complete(skb); + +out_unlock: + rcu_read_unlock(); + + return err; +} + int inet_ctl_sock_create(struct sock **sk, unsigned short family, unsigned short type, unsigned char protocol, struct net *net) @@ -1311,6 +1402,7 @@ EXPORT_SYMBOL_GPL(snmp_mib_free); #ifdef CONFIG_IP_MULTICAST static struct net_protocol igmp_protocol = { .handler = igmp_rcv, + .netns_ok = 1, }; #endif @@ -1319,6 +1411,8 @@ static struct net_protocol tcp_protocol = { .err_handler = tcp_v4_err, .gso_send_check = tcp_v4_gso_send_check, .gso_segment = tcp_tso_segment, + .gro_receive = tcp4_gro_receive, + .gro_complete = tcp4_gro_complete, .no_policy = 1, .netns_ok = 1, }; @@ -1411,6 +1505,8 @@ static struct packet_type ip_packet_type = { .func = ip_rcv, .gso_send_check = inet_gso_send_check, .gso_segment = inet_gso_segment, + .gro_receive = inet_gro_receive, + .gro_complete = inet_gro_complete, }; static int __init inet_init(void) diff --git a/net/ipv4/ah4.c b/net/ipv4/ah4.c index 8219b7e0968d1df51a315b2880bf35be09888ab3..e878e494296ef948958bb0ff845a145742cb90ec 100644 --- a/net/ipv4/ah4.c +++ b/net/ipv4/ah4.c @@ -201,15 +201,16 @@ out: static void ah4_err(struct sk_buff *skb, u32 info) { - struct iphdr *iph = (struct iphdr*)skb->data; - struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+(iph->ihl<<2)); + struct net *net = dev_net(skb->dev); + struct iphdr *iph = (struct iphdr *)skb->data; + struct ip_auth_hdr *ah = (struct ip_auth_hdr *)(skb->data+(iph->ihl<<2)); struct xfrm_state *x; if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH || icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) return; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); + x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET); if (!x) return; printk(KERN_DEBUG "pmtu discovery on SA AH/%08x/%08x\n", @@ -293,9 +294,7 @@ static void ah_destroy(struct xfrm_state *x) return; kfree(ahp->work_icv); - ahp->work_icv = NULL; crypto_free_hash(ahp->tfm); - ahp->tfm = NULL; kfree(ahp); } @@ -316,6 +315,7 @@ static struct net_protocol ah4_protocol = { .handler = xfrm4_rcv, .err_handler = ah4_err, .no_policy = 1, + .netns_ok = 1, }; static int __init ah4_init(void) diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 1a9dd66511fccfadf9e1240334e7dcc2a3f073b0..29a74c01d8de54857fa3ef4a82184dc8a03b91cd 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -506,7 +506,7 @@ int arp_bind_neighbour(struct dst_entry *dst) if (dev == NULL) return -EINVAL; if (n == NULL) { - __be32 nexthop = ((struct rtable*)dst)->rt_gateway; + __be32 nexthop = ((struct rtable *)dst)->rt_gateway; if (dev->flags&(IFF_LOOPBACK|IFF_POINTOPOINT)) nexthop = 0; n = __neigh_lookup_errno( @@ -640,14 +640,14 @@ struct sk_buff *arp_create(int type, int ptype, __be32 dest_ip, arp_ptr=(unsigned char *)(arp+1); memcpy(arp_ptr, src_hw, dev->addr_len); - arp_ptr+=dev->addr_len; - memcpy(arp_ptr, &src_ip,4); - arp_ptr+=4; + arp_ptr += dev->addr_len; + memcpy(arp_ptr, &src_ip, 4); + arp_ptr += 4; if (target_hw != NULL) memcpy(arp_ptr, target_hw, dev->addr_len); else memset(arp_ptr, 0, dev->addr_len); - arp_ptr+=dev->addr_len; + arp_ptr += dev->addr_len; memcpy(arp_ptr, &dest_ip, 4); return skb; @@ -818,18 +818,18 @@ static int arp_process(struct sk_buff *skb) addr_type = rt->rt_type; if (addr_type == RTN_LOCAL) { - n = neigh_event_ns(&arp_tbl, sha, &sip, dev); - if (n) { - int dont_send = 0; - - if (!dont_send) - dont_send |= arp_ignore(in_dev,sip,tip); - if (!dont_send && IN_DEV_ARPFILTER(in_dev)) - dont_send |= arp_filter(sip,tip,dev); - if (!dont_send) - arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); + int dont_send = 0; - neigh_release(n); + if (!dont_send) + dont_send |= arp_ignore(in_dev,sip,tip); + if (!dont_send && IN_DEV_ARPFILTER(in_dev)) + dont_send |= arp_filter(sip,tip,dev); + if (!dont_send) { + n = neigh_event_ns(&arp_tbl, sha, &sip, dev); + if (n) { + arp_send(ARPOP_REPLY,ETH_P_ARP,sip,dev,tip,sha,dev->dev_addr,sha); + neigh_release(n); + } } goto out; } else if (IN_DEV_FORWARD(in_dev)) { @@ -1308,7 +1308,7 @@ static void arp_format_neigh_entry(struct seq_file *seq, #if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE) } #endif - sprintf(tbuf, NIPQUAD_FMT, NIPQUAD(*(u32*)n->primary_key)); + sprintf(tbuf, "%pI4", n->primary_key); seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", tbuf, hatype, arp_state_to_flags(n), hbuffer, dev->name); read_unlock(&n->lock); @@ -1321,7 +1321,7 @@ static void arp_format_pneigh_entry(struct seq_file *seq, int hatype = dev ? dev->type : 0; char tbuf[16]; - sprintf(tbuf, NIPQUAD_FMT, NIPQUAD(*(u32*)n->key)); + sprintf(tbuf, "%pI4", n->key); seq_printf(seq, "%-16s 0x%-10x0x%-10x%s * %s\n", tbuf, hatype, ATF_PUBL | ATF_PERM, "00:00:00:00:00:00", dev ? dev->name : "*"); diff --git a/net/ipv4/cipso_ipv4.c b/net/ipv4/cipso_ipv4.c index 2e78f6bd97756db7920367e5fe07ce23e6cd6eb7..e52799047a5feac1c018bc55b01bbce4ff8a8c06 100644 --- a/net/ipv4/cipso_ipv4.c +++ b/net/ipv4/cipso_ipv4.c @@ -490,7 +490,6 @@ int cipso_v4_doi_add(struct cipso_v4_doi *doi_def) } atomic_set(&doi_def->refcount, 1); - INIT_RCU_HEAD(&doi_def->rcu); spin_lock(&cipso_v4_doi_list_lock); if (cipso_v4_doi_search(doi_def->doi) != NULL) diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c index 56fce3ab6c55263c727357ee54c18bf70221451a..309997edc8a5169546e87ed2a51e51214e4bea6f 100644 --- a/net/ipv4/devinet.c +++ b/net/ipv4/devinet.c @@ -112,13 +112,7 @@ static inline void devinet_sysctl_unregister(struct in_device *idev) static struct in_ifaddr *inet_alloc_ifa(void) { - struct in_ifaddr *ifa = kzalloc(sizeof(*ifa), GFP_KERNEL); - - if (ifa) { - INIT_RCU_HEAD(&ifa->rcu_head); - } - - return ifa; + return kzalloc(sizeof(struct in_ifaddr), GFP_KERNEL); } static void inet_rcu_free_ifa(struct rcu_head *head) @@ -161,7 +155,6 @@ static struct in_device *inetdev_init(struct net_device *dev) in_dev = kzalloc(sizeof(*in_dev), GFP_KERNEL); if (!in_dev) goto out; - INIT_RCU_HEAD(&in_dev->rcu_head); memcpy(&in_dev->cnf, dev_net(dev)->ipv4.devconf_dflt, sizeof(in_dev->cnf)); in_dev->cnf.sysctl = NULL; @@ -1108,7 +1101,7 @@ out: } static struct notifier_block ip_netdev_notifier = { - .notifier_call =inetdev_event, + .notifier_call = inetdev_event, }; static inline size_t inet_nlmsg_size(void) @@ -1195,7 +1188,7 @@ done: return skb->len; } -static void rtmsg_ifa(int event, struct in_ifaddr* ifa, struct nlmsghdr *nlh, +static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh, u32 pid) { struct sk_buff *skb; @@ -1262,7 +1255,7 @@ static void inet_forward_change(struct net *net) } static int devinet_conf_proc(ctl_table *ctl, int write, - struct file* filp, void __user *buffer, + struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { int ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos); @@ -1334,7 +1327,7 @@ static int devinet_conf_sysctl(ctl_table *table, } static int devinet_sysctl_forward(ctl_table *ctl, int write, - struct file* filp, void __user *buffer, + struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { int *valp = ctl->data; @@ -1363,7 +1356,7 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write, } int ipv4_doint_and_flush(ctl_table *ctl, int write, - struct file* filp, void __user *buffer, + struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { int *valp = ctl->data; diff --git a/net/ipv4/esp4.c b/net/ipv4/esp4.c index 21515d4c49eb5712c22655ba7d8166909bdcf13e..18bb383ea39354c52ceb593a78f462d839fba5e4 100644 --- a/net/ipv4/esp4.c +++ b/net/ipv4/esp4.c @@ -413,15 +413,16 @@ static u32 esp4_get_mtu(struct xfrm_state *x, int mtu) static void esp4_err(struct sk_buff *skb, u32 info) { - struct iphdr *iph = (struct iphdr*)skb->data; - struct ip_esp_hdr *esph = (struct ip_esp_hdr*)(skb->data+(iph->ihl<<2)); + struct net *net = dev_net(skb->dev); + struct iphdr *iph = (struct iphdr *)skb->data; + struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data+(iph->ihl<<2)); struct xfrm_state *x; if (icmp_hdr(skb)->type != ICMP_DEST_UNREACH || icmp_hdr(skb)->code != ICMP_FRAG_NEEDED) return; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); + x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET); if (!x) return; NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n", @@ -618,6 +619,7 @@ static struct net_protocol esp4_protocol = { .handler = xfrm4_rcv, .err_handler = esp4_err, .no_policy = 1, + .netns_ok = 1, }; static int __init esp4_init(void) diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c index 65c1503f8cc8b1caea7c9242d6e316d734b5e733..741e4fa3e4749e0285c39f65dc306e644fb4032b 100644 --- a/net/ipv4/fib_frontend.c +++ b/net/ipv4/fib_frontend.c @@ -578,7 +578,7 @@ errout: return err; } -static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) +static int inet_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { struct net *net = sock_net(skb->sk); struct fib_config cfg; @@ -600,7 +600,7 @@ errout: return err; } -static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) +static int inet_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg) { struct net *net = sock_net(skb->sk); struct fib_config cfg; @@ -903,7 +903,7 @@ static void fib_disable_ip(struct net_device *dev, int force) static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, void *ptr) { - struct in_ifaddr *ifa = (struct in_ifaddr*)ptr; + struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; struct net_device *dev = ifa->ifa_dev->dev; switch (event) { @@ -964,11 +964,11 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo } static struct notifier_block fib_inetaddr_notifier = { - .notifier_call =fib_inetaddr_event, + .notifier_call = fib_inetaddr_event, }; static struct notifier_block fib_netdev_notifier = { - .notifier_call =fib_netdev_event, + .notifier_call = fib_netdev_event, }; static int __net_init ip_fib_net_init(struct net *net) diff --git a/net/ipv4/fib_hash.c b/net/ipv4/fib_hash.c index c8cac6c7f881ee67e44ede59011f2e267b3ff44d..ded8c44fb848842a99f9bbe75830936eb596a48e 100644 --- a/net/ipv4/fib_hash.c +++ b/net/ipv4/fib_hash.c @@ -247,7 +247,7 @@ fn_hash_lookup(struct fib_table *tb, const struct flowi *flp, struct fib_result { int err; struct fn_zone *fz; - struct fn_hash *t = (struct fn_hash*)tb->tb_data; + struct fn_hash *t = (struct fn_hash *)tb->tb_data; read_lock(&fib_hash_lock); for (fz = t->fn_zone_list; fz; fz = fz->fz_next) { @@ -283,7 +283,7 @@ fn_hash_select_default(struct fib_table *tb, const struct flowi *flp, struct fib struct fib_node *f; struct fib_info *fi = NULL; struct fib_info *last_resort; - struct fn_hash *t = (struct fn_hash*)tb->tb_data; + struct fn_hash *t = (struct fn_hash *)tb->tb_data; struct fn_zone *fz = t->fn_zones[0]; if (fz == NULL) @@ -548,7 +548,7 @@ out: static int fn_hash_delete(struct fib_table *tb, struct fib_config *cfg) { - struct fn_hash *table = (struct fn_hash*)tb->tb_data; + struct fn_hash *table = (struct fn_hash *)tb->tb_data; struct fib_node *f; struct fib_alias *fa, *fa_to_delete; struct fn_zone *fz; @@ -748,7 +748,7 @@ static int fn_hash_dump(struct fib_table *tb, struct sk_buff *skb, struct netlin { int m, s_m; struct fn_zone *fz; - struct fn_hash *table = (struct fn_hash*)tb->tb_data; + struct fn_hash *table = (struct fn_hash *)tb->tb_data; s_m = cb->args[2]; read_lock(&fib_hash_lock); @@ -845,10 +845,10 @@ static struct fib_alias *fib_get_first(struct seq_file *seq) struct hlist_node *node; struct fib_node *fn; - hlist_for_each_entry(fn,node,iter->hash_head,fn_hash) { + hlist_for_each_entry(fn, node, iter->hash_head, fn_hash) { struct fib_alias *fa; - list_for_each_entry(fa,&fn->fn_alias,fa_list) { + list_for_each_entry(fa, &fn->fn_alias, fa_list) { iter->fn = fn; iter->fa = fa; goto out; diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c index ded2ae34eab15017821063de974a8792d4474d0b..4817dea3bc737225ec99a605b3b5d5681ac6e082 100644 --- a/net/ipv4/fib_semantics.c +++ b/net/ipv4/fib_semantics.c @@ -63,16 +63,16 @@ static DEFINE_SPINLOCK(fib_multipath_lock); for (nhsel=0, nh = (fi)->fib_nh; nhsel < (fi)->fib_nhs; nh++, nhsel++) #define change_nexthops(fi) { int nhsel; struct fib_nh * nh; \ -for (nhsel=0, nh = (struct fib_nh*)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++) +for (nhsel=0, nh = (struct fib_nh *)((fi)->fib_nh); nhsel < (fi)->fib_nhs; nh++, nhsel++) #else /* CONFIG_IP_ROUTE_MULTIPATH */ /* Hope, that gcc will optimize it to get rid of dummy loop */ -#define for_nexthops(fi) { int nhsel=0; const struct fib_nh * nh = (fi)->fib_nh; \ +#define for_nexthops(fi) { int nhsel = 0; const struct fib_nh * nh = (fi)->fib_nh; \ for (nhsel=0; nhsel < 1; nhsel++) -#define change_nexthops(fi) { int nhsel=0; struct fib_nh * nh = (struct fib_nh*)((fi)->fib_nh); \ +#define change_nexthops(fi) { int nhsel = 0; struct fib_nh * nh = (struct fib_nh *)((fi)->fib_nh); \ for (nhsel=0; nhsel < 1; nhsel++) #endif /* CONFIG_IP_ROUTE_MULTIPATH */ @@ -358,7 +358,7 @@ int fib_detect_death(struct fib_info *fi, int order, state = n->nud_state; neigh_release(n); } - if (state==NUD_REACHABLE) + if (state == NUD_REACHABLE) return 0; if ((state&NUD_VALID) && order != dflt) return 0; diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index 5cb72786a8af59e290737e6e37896aeaadd4e094..ec0ae490f0b60306029126c0d848674cb2ee055d 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c @@ -2399,8 +2399,8 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) __be32 prf = htonl(mask_pfx(tn->key, tn->pos)); seq_indent(seq, iter->depth-1); - seq_printf(seq, " +-- " NIPQUAD_FMT "/%d %d %d %d\n", - NIPQUAD(prf), tn->pos, tn->bits, tn->full_children, + seq_printf(seq, " +-- %pI4/%d %d %d %d\n", + &prf, tn->pos, tn->bits, tn->full_children, tn->empty_children); } else { @@ -2410,7 +2410,7 @@ static int fib_trie_seq_show(struct seq_file *seq, void *v) __be32 val = htonl(l->key); seq_indent(seq, iter->depth); - seq_printf(seq, " |-- " NIPQUAD_FMT "\n", NIPQUAD(val)); + seq_printf(seq, " |-- %pI4\n", &val); hlist_for_each_entry_rcu(li, node, &l->list, hlist) { struct fib_alias *fa; diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 72b2de76f1cd1683b9dc33c957597a4556d9b36b..705b33b184a33cb3181e698b191c08565229ed56 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -321,12 +321,12 @@ static int icmp_glue_bits(void *from, char *to, int offset, int len, int odd, } static void icmp_push_reply(struct icmp_bxm *icmp_param, - struct ipcm_cookie *ipc, struct rtable *rt) + struct ipcm_cookie *ipc, struct rtable **rt) { struct sock *sk; struct sk_buff *skb; - sk = icmp_sk(dev_net(rt->u.dst.dev)); + sk = icmp_sk(dev_net((*rt)->u.dst.dev)); if (ip_append_data(sk, icmp_glue_bits, icmp_param, icmp_param->data_len+icmp_param->head_len, icmp_param->head_len, @@ -392,7 +392,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) } if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type, icmp_param->data.icmph.code)) - icmp_push_reply(icmp_param, &ipc, rt); + icmp_push_reply(icmp_param, &ipc, &rt); ip_rt_put(rt); out_unlock: icmp_xmit_unlock(sk); @@ -562,7 +562,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) /* No need to clone since we're just using its address. */ rt2 = rt; - err = xfrm_lookup((struct dst_entry **)&rt, &fl, NULL, 0); + err = xfrm_lookup(net, (struct dst_entry **)&rt, &fl, NULL, 0); switch (err) { case 0: if (rt != rt2) @@ -601,7 +601,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) if (err) goto relookup_failed; - err = xfrm_lookup((struct dst_entry **)&rt2, &fl, NULL, + err = xfrm_lookup(net, (struct dst_entry **)&rt2, &fl, NULL, XFRM_LOOKUP_ICMP); switch (err) { case 0: @@ -635,7 +635,7 @@ route_done: icmp_param.data_len = room; icmp_param.head_len = sizeof(struct icmphdr); - icmp_push_reply(&icmp_param, &ipc, rt); + icmp_push_reply(&icmp_param, &ipc, &rt); ende: ip_rt_put(rt); out_unlock: @@ -683,10 +683,8 @@ static void icmp_unreach(struct sk_buff *skb) break; case ICMP_FRAG_NEEDED: if (ipv4_config.no_pmtu_disc) { - LIMIT_NETDEBUG(KERN_INFO "ICMP: " NIPQUAD_FMT ": " - "fragmentation needed " - "and DF set.\n", - NIPQUAD(iph->daddr)); + LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: fragmentation needed and DF set.\n", + &iph->daddr); } else { info = ip_rt_frag_needed(net, iph, ntohs(icmph->un.frag.mtu), @@ -696,9 +694,8 @@ static void icmp_unreach(struct sk_buff *skb) } break; case ICMP_SR_FAILED: - LIMIT_NETDEBUG(KERN_INFO "ICMP: " NIPQUAD_FMT ": Source " - "Route Failed.\n", - NIPQUAD(iph->daddr)); + LIMIT_NETDEBUG(KERN_INFO "ICMP: %pI4: Source Route Failed.\n", + &iph->daddr); break; default: break; @@ -729,12 +726,12 @@ static void icmp_unreach(struct sk_buff *skb) if (!net->ipv4.sysctl_icmp_ignore_bogus_error_responses && inet_addr_type(net, iph->daddr) == RTN_BROADCAST) { if (net_ratelimit()) - printk(KERN_WARNING NIPQUAD_FMT " sent an invalid ICMP " + printk(KERN_WARNING "%pI4 sent an invalid ICMP " "type %u, code %u " - "error to a broadcast: " NIPQUAD_FMT " on %s\n", - NIPQUAD(ip_hdr(skb)->saddr), + "error to a broadcast: %pI4 on %s\n", + &ip_hdr(skb)->saddr, icmph->type, icmph->code, - NIPQUAD(iph->daddr), + &iph->daddr, skb->dev->name); goto out; } @@ -952,9 +949,8 @@ static void icmp_address_reply(struct sk_buff *skb) break; } if (!ifa && net_ratelimit()) { - printk(KERN_INFO "Wrong address mask " NIPQUAD_FMT " from " - "%s/" NIPQUAD_FMT "\n", - NIPQUAD(*mp), dev->name, NIPQUAD(rt->rt_src)); + printk(KERN_INFO "Wrong address mask %pI4 from %s/%pI4\n", + mp, dev->name, &rt->rt_src); } } rcu_read_unlock(); @@ -976,9 +972,10 @@ int icmp_rcv(struct sk_buff *skb) struct net *net = dev_net(rt->u.dst.dev); if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { + struct sec_path *sp = skb_sec_path(skb); int nh; - if (!(skb->sp && skb->sp->xvec[skb->sp->len - 1]->props.flags & + if (!(sp && sp->xvec[sp->len - 1]->props.flags & XFRM_STATE_ICMP)) goto drop; diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index a0d86455c53e3a69fc24adc90fcfcc2e1d293571..9eb6219af615af2327daef1ec461e3b1fdb16500 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -167,7 +167,7 @@ static __inline__ void igmp_stop_timer(struct ip_mc_list *im) spin_lock_bh(&im->lock); if (del_timer(&im->timer)) atomic_dec(&im->refcnt); - im->tm_running=0; + im->tm_running = 0; im->reporter = 0; im->unsolicit_count = 0; spin_unlock_bh(&im->lock); @@ -176,9 +176,9 @@ static __inline__ void igmp_stop_timer(struct ip_mc_list *im) /* It must be called with locked im->lock */ static void igmp_start_timer(struct ip_mc_list *im, int max_delay) { - int tv=net_random() % max_delay; + int tv = net_random() % max_delay; - im->tm_running=1; + im->tm_running = 1; if (!mod_timer(&im->timer, jiffies+tv+2)) atomic_inc(&im->refcnt); } @@ -207,7 +207,7 @@ static void igmp_mod_timer(struct ip_mc_list *im, int max_delay) if (del_timer(&im->timer)) { if ((long)(im->timer.expires-jiffies) < max_delay) { add_timer(&im->timer); - im->tm_running=1; + im->tm_running = 1; spin_unlock_bh(&im->lock); return; } @@ -358,7 +358,7 @@ static int igmpv3_sendpack(struct sk_buff *skb) static int grec_size(struct ip_mc_list *pmc, int type, int gdel, int sdel) { - return sizeof(struct igmpv3_grec) + 4*igmp_scount(pmc,type,gdel,sdel); + return sizeof(struct igmpv3_grec) + 4*igmp_scount(pmc, type, gdel, sdel); } static struct sk_buff *add_grhead(struct sk_buff *skb, struct ip_mc_list *pmc, @@ -653,7 +653,7 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, return -1; } - skb=alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC); + skb = alloc_skb(IGMP_SIZE+LL_ALLOCATED_SPACE(dev), GFP_ATOMIC); if (skb == NULL) { ip_rt_put(rt); return -1; @@ -682,11 +682,11 @@ static int igmp_send_report(struct in_device *in_dev, struct ip_mc_list *pmc, ((u8*)&iph[1])[3] = 0; ih = (struct igmphdr *)skb_put(skb, sizeof(struct igmphdr)); - ih->type=type; - ih->code=0; - ih->csum=0; - ih->group=group; - ih->csum=ip_compute_csum((void *)ih, sizeof(struct igmphdr)); + ih->type = type; + ih->code = 0; + ih->csum = 0; + ih->group = group; + ih->csum = ip_compute_csum((void *)ih, sizeof(struct igmphdr)); return ip_local_out(skb); } @@ -728,7 +728,7 @@ static void igmp_timer_expire(unsigned long data) struct in_device *in_dev = im->interface; spin_lock(&im->lock); - im->tm_running=0; + im->tm_running = 0; if (im->unsolicit_count) { im->unsolicit_count--; @@ -997,7 +997,7 @@ static void ip_mc_filter_add(struct in_device *in_dev, __be32 addr) --ANK */ if (arp_mc_map(addr, buf, dev, 0) == 0) - dev_mc_add(dev,buf,dev->addr_len,0); + dev_mc_add(dev, buf, dev->addr_len, 0); } /* @@ -1010,7 +1010,7 @@ static void ip_mc_filter_del(struct in_device *in_dev, __be32 addr) struct net_device *dev = in_dev->dev; if (arp_mc_map(addr, buf, dev, 0) == 0) - dev_mc_delete(dev,buf,dev->addr_len,0); + dev_mc_delete(dev, buf, dev->addr_len, 0); } #ifdef CONFIG_IP_MULTICAST @@ -1210,10 +1210,10 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) if (!im) goto out; - im->users=1; - im->interface=in_dev; + im->users = 1; + im->interface = in_dev; in_dev_hold(in_dev); - im->multiaddr=addr; + im->multiaddr = addr; /* initial mode is (EX, empty) */ im->sfmode = MCAST_EXCLUDE; im->sfcount[MCAST_INCLUDE] = 0; @@ -1224,7 +1224,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) atomic_set(&im->refcnt, 1); spin_lock_init(&im->lock); #ifdef CONFIG_IP_MULTICAST - im->tm_running=0; + im->tm_running = 0; setup_timer(&im->timer, &igmp_timer_expire, (unsigned long)im); im->unsolicit_count = IGMP_Unsolicited_Report_Count; im->reporter = 0; @@ -1232,8 +1232,8 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) #endif im->loaded = 0; write_lock_bh(&in_dev->mc_list_lock); - im->next=in_dev->mc_list; - in_dev->mc_list=im; + im->next = in_dev->mc_list; + in_dev->mc_list = im; in_dev->mc_count++; write_unlock_bh(&in_dev->mc_list_lock); #ifdef CONFIG_IP_MULTICAST @@ -1279,7 +1279,7 @@ void ip_mc_dec_group(struct in_device *in_dev, __be32 addr) ASSERT_RTNL(); for (ip=&in_dev->mc_list; (i=*ip)!=NULL; ip=&i->next) { - if (i->multiaddr==addr) { + if (i->multiaddr == addr) { if (--i->users == 0) { write_lock_bh(&in_dev->mc_list_lock); *ip = i->next; @@ -1738,7 +1738,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) { int err; __be32 addr = imr->imr_multiaddr.s_addr; - struct ip_mc_socklist *iml=NULL, *i; + struct ip_mc_socklist *iml = NULL, *i; struct in_device *in_dev; struct inet_sock *inet = inet_sk(sk); struct net *net = sock_net(sk); @@ -1769,7 +1769,7 @@ int ip_mc_join_group(struct sock *sk , struct ip_mreqn *imr) err = -ENOBUFS; if (count >= sysctl_igmp_max_memberships) goto done; - iml = sock_kmalloc(sk,sizeof(*iml),GFP_KERNEL); + iml = sock_kmalloc(sk, sizeof(*iml), GFP_KERNEL); if (iml == NULL) goto done; @@ -2275,6 +2275,7 @@ int ip_check_mc(struct in_device *in_dev, __be32 mc_addr, __be32 src_addr, u16 p #if defined(CONFIG_PROC_FS) struct igmp_mc_iter_state { + struct seq_net_private p; struct net_device *dev; struct in_device *in_dev; }; @@ -2283,11 +2284,12 @@ struct igmp_mc_iter_state { static inline struct ip_mc_list *igmp_mc_get_first(struct seq_file *seq) { + struct net *net = seq_file_net(seq); struct ip_mc_list *im = NULL; struct igmp_mc_iter_state *state = igmp_mc_seq_private(seq); state->in_dev = NULL; - for_each_netdev(&init_net, state->dev) { + for_each_netdev(net, state->dev) { struct in_device *in_dev; in_dev = in_dev_get(state->dev); if (!in_dev) @@ -2408,7 +2410,7 @@ static const struct seq_operations igmp_mc_seq_ops = { static int igmp_mc_seq_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &igmp_mc_seq_ops, + return seq_open_net(inode, file, &igmp_mc_seq_ops, sizeof(struct igmp_mc_iter_state)); } @@ -2417,10 +2419,11 @@ static const struct file_operations igmp_mc_seq_fops = { .open = igmp_mc_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; struct igmp_mcf_iter_state { + struct seq_net_private p; struct net_device *dev; struct in_device *idev; struct ip_mc_list *im; @@ -2430,13 +2433,14 @@ struct igmp_mcf_iter_state { static inline struct ip_sf_list *igmp_mcf_get_first(struct seq_file *seq) { + struct net *net = seq_file_net(seq); struct ip_sf_list *psf = NULL; struct ip_mc_list *im = NULL; struct igmp_mcf_iter_state *state = igmp_mcf_seq_private(seq); state->idev = NULL; state->im = NULL; - for_each_netdev(&init_net, state->dev) { + for_each_netdev(net, state->dev) { struct in_device *idev; idev = in_dev_get(state->dev); if (unlikely(idev == NULL)) @@ -2567,7 +2571,7 @@ static const struct seq_operations igmp_mcf_seq_ops = { static int igmp_mcf_seq_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &igmp_mcf_seq_ops, + return seq_open_net(inode, file, &igmp_mcf_seq_ops, sizeof(struct igmp_mcf_iter_state)); } @@ -2576,14 +2580,41 @@ static const struct file_operations igmp_mcf_seq_fops = { .open = igmp_mcf_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; -int __init igmp_mc_proc_init(void) +static int igmp_net_init(struct net *net) { - proc_net_fops_create(&init_net, "igmp", S_IRUGO, &igmp_mc_seq_fops); - proc_net_fops_create(&init_net, "mcfilter", S_IRUGO, &igmp_mcf_seq_fops); + struct proc_dir_entry *pde; + + pde = proc_net_fops_create(net, "igmp", S_IRUGO, &igmp_mc_seq_fops); + if (!pde) + goto out_igmp; + pde = proc_net_fops_create(net, "mcfilter", S_IRUGO, &igmp_mcf_seq_fops); + if (!pde) + goto out_mcfilter; return 0; + +out_mcfilter: + proc_net_remove(net, "igmp"); +out_igmp: + return -ENOMEM; +} + +static void igmp_net_exit(struct net *net) +{ + proc_net_remove(net, "mcfilter"); + proc_net_remove(net, "igmp"); +} + +static struct pernet_operations igmp_net_ops = { + .init = igmp_net_init, + .exit = igmp_net_exit, +}; + +int __init igmp_mc_proc_init(void) +{ + return register_pernet_subsys(&igmp_net_ops); } #endif diff --git a/net/ipv4/inet_connection_sock.c b/net/ipv4/inet_connection_sock.c index bd1278a2d828b30ddae3c4c9e98e06283201ceca..c7cda1ca8e6571232d1cf22c576a2c998983a08a 100644 --- a/net/ipv4/inet_connection_sock.c +++ b/net/ipv4/inet_connection_sock.c @@ -109,7 +109,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) hashinfo->bhash_size)]; spin_lock(&head->lock); inet_bind_bucket_for_each(tb, node, &head->chain) - if (tb->ib_net == net && tb->port == rover) + if (ib_net(tb) == net && tb->port == rover) goto next; break; next: @@ -137,7 +137,7 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum) hashinfo->bhash_size)]; spin_lock(&head->lock); inet_bind_bucket_for_each(tb, node, &head->chain) - if (tb->ib_net == net && tb->port == snum) + if (ib_net(tb) == net && tb->port == snum) goto tb_found; } tb = NULL; @@ -323,7 +323,7 @@ void inet_csk_reset_keepalive_timer(struct sock *sk, unsigned long len) EXPORT_SYMBOL(inet_csk_reset_keepalive_timer); -struct dst_entry* inet_csk_route_req(struct sock *sk, +struct dst_entry *inet_csk_route_req(struct sock *sk, const struct request_sock *req) { struct rtable *rt; @@ -344,16 +344,17 @@ struct dst_entry* inet_csk_route_req(struct sock *sk, struct net *net = sock_net(sk); security_req_classify_flow(req, &fl); - if (ip_route_output_flow(net, &rt, &fl, sk, 0)) { - IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); - return NULL; - } - if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) { - ip_rt_put(rt); - IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); - return NULL; - } + if (ip_route_output_flow(net, &rt, &fl, sk, 0)) + goto no_route; + if (opt && opt->is_strictroute && rt->rt_dst != rt->rt_gateway) + goto route_err; return &rt->u.dst; + +route_err: + ip_rt_put(rt); +no_route: + IP_INC_STATS_BH(net, IPSTATS_MIB_OUTNOROUTES); + return NULL; } EXPORT_SYMBOL_GPL(inet_csk_route_req); @@ -561,7 +562,7 @@ void inet_csk_destroy_sock(struct sock *sk) sk_refcnt_debug_release(sk); - atomic_dec(sk->sk_prot->orphan_count); + percpu_counter_dec(sk->sk_prot->orphan_count); sock_put(sk); } @@ -632,6 +633,8 @@ void inet_csk_listen_stop(struct sock *sk) acc_req = req->dl_next; + percpu_counter_inc(sk->sk_prot->orphan_count); + local_bh_disable(); bh_lock_sock(child); WARN_ON(sock_owned_by_user(child)); @@ -641,8 +644,6 @@ void inet_csk_listen_stop(struct sock *sk) sock_orphan(child); - atomic_inc(sk->sk_prot->orphan_count); - inet_csk_destroy_sock(child); bh_unlock_sock(child); diff --git a/net/ipv4/inet_diag.c b/net/ipv4/inet_diag.c index 564230dabcb8a7ff172bed468a4257dd0a11616f..588a7796e3e3e67ea7a4c2e627e0b557f2bd2e59 100644 --- a/net/ipv4/inet_diag.c +++ b/net/ipv4/inet_diag.c @@ -718,13 +718,15 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) if (!(r->idiag_states & (TCPF_LISTEN | TCPF_SYN_RECV))) goto skip_listen_ht; - inet_listen_lock(hashinfo); for (i = s_i; i < INET_LHTABLE_SIZE; i++) { struct sock *sk; - struct hlist_node *node; + struct hlist_nulls_node *node; + struct inet_listen_hashbucket *ilb; num = 0; - sk_for_each(sk, node, &hashinfo->listening_hash[i]) { + ilb = &hashinfo->listening_hash[i]; + spin_lock_bh(&ilb->lock); + sk_nulls_for_each(sk, node, &ilb->head) { struct inet_sock *inet = inet_sk(sk); if (num < s_num) { @@ -742,7 +744,7 @@ static int inet_diag_dump(struct sk_buff *skb, struct netlink_callback *cb) goto syn_recv; if (inet_csk_diag_dump(sk, skb, cb) < 0) { - inet_listen_unlock(hashinfo); + spin_unlock_bh(&ilb->lock); goto done; } @@ -751,7 +753,7 @@ syn_recv: goto next_listen; if (inet_diag_dump_reqs(skb, sk, cb) < 0) { - inet_listen_unlock(hashinfo); + spin_unlock_bh(&ilb->lock); goto done; } @@ -760,12 +762,12 @@ next_listen: cb->args[4] = 0; ++num; } + spin_unlock_bh(&ilb->lock); s_num = 0; cb->args[3] = 0; cb->args[4] = 0; } - inet_listen_unlock(hashinfo); skip_listen_ht: cb->args[0] = 1; s_i = num = s_num = 0; @@ -776,20 +778,21 @@ skip_listen_ht: for (i = s_i; i < hashinfo->ehash_size; i++) { struct inet_ehash_bucket *head = &hashinfo->ehash[i]; - rwlock_t *lock = inet_ehash_lockp(hashinfo, i); + spinlock_t *lock = inet_ehash_lockp(hashinfo, i); struct sock *sk; - struct hlist_node *node; + struct hlist_nulls_node *node; num = 0; - if (hlist_empty(&head->chain) && hlist_empty(&head->twchain)) + if (hlist_nulls_empty(&head->chain) && + hlist_nulls_empty(&head->twchain)) continue; if (i > s_i) s_num = 0; - read_lock_bh(lock); - sk_for_each(sk, node, &head->chain) { + spin_lock_bh(lock); + sk_nulls_for_each(sk, node, &head->chain) { struct inet_sock *inet = inet_sk(sk); if (num < s_num) @@ -803,7 +806,7 @@ skip_listen_ht: r->id.idiag_dport) goto next_normal; if (inet_csk_diag_dump(sk, skb, cb) < 0) { - read_unlock_bh(lock); + spin_unlock_bh(lock); goto done; } next_normal: @@ -825,14 +828,14 @@ next_normal: r->id.idiag_dport) goto next_dying; if (inet_twsk_diag_dump(tw, skb, cb) < 0) { - read_unlock_bh(lock); + spin_unlock_bh(lock); goto done; } next_dying: ++num; } } - read_unlock_bh(lock); + spin_unlock_bh(lock); } done: diff --git a/net/ipv4/inet_hashtables.c b/net/ipv4/inet_hashtables.c index 44981906fb913e7afbb4f7e03cd0192b9fdcda12..6a1045da48d21774a78f0466deefed4539005306 100644 --- a/net/ipv4/inet_hashtables.c +++ b/net/ipv4/inet_hashtables.c @@ -35,7 +35,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep, struct inet_bind_bucket *tb = kmem_cache_alloc(cachep, GFP_ATOMIC); if (tb != NULL) { - tb->ib_net = hold_net(net); + write_pnet(&tb->ib_net, hold_net(net)); tb->port = snum; tb->fastreuse = 0; INIT_HLIST_HEAD(&tb->owners); @@ -51,7 +51,7 @@ void inet_bind_bucket_destroy(struct kmem_cache *cachep, struct inet_bind_bucket { if (hlist_empty(&tb->owners)) { __hlist_del(&tb->node); - release_net(tb->ib_net); + release_net(ib_net(tb)); kmem_cache_free(cachep, tb); } } @@ -110,33 +110,29 @@ void __inet_inherit_port(struct sock *sk, struct sock *child) EXPORT_SYMBOL_GPL(__inet_inherit_port); -/* - * This lock without WQ_FLAG_EXCLUSIVE is good on UP and it can be very bad on SMP. - * Look, when several writers sleep and reader wakes them up, all but one - * immediately hit write lock and grab all the cpus. Exclusive sleep solves - * this, _but_ remember, it adds useless work on UP machines (wake up each - * exclusive lock release). It should be ifdefed really. - */ -void inet_listen_wlock(struct inet_hashinfo *hashinfo) - __acquires(hashinfo->lhash_lock) +static inline int compute_score(struct sock *sk, struct net *net, + const unsigned short hnum, const __be32 daddr, + const int dif) { - write_lock(&hashinfo->lhash_lock); - - if (atomic_read(&hashinfo->lhash_users)) { - DEFINE_WAIT(wait); + int score = -1; + struct inet_sock *inet = inet_sk(sk); - for (;;) { - prepare_to_wait_exclusive(&hashinfo->lhash_wait, - &wait, TASK_UNINTERRUPTIBLE); - if (!atomic_read(&hashinfo->lhash_users)) - break; - write_unlock_bh(&hashinfo->lhash_lock); - schedule(); - write_lock_bh(&hashinfo->lhash_lock); + if (net_eq(sock_net(sk), net) && inet->num == hnum && + !ipv6_only_sock(sk)) { + __be32 rcv_saddr = inet->rcv_saddr; + score = sk->sk_family == PF_INET ? 1 : 0; + if (rcv_saddr) { + if (rcv_saddr != daddr) + return -1; + score += 2; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + return -1; + score += 2; } - - finish_wait(&hashinfo->lhash_wait, &wait); } + return score; } /* @@ -145,72 +141,48 @@ void inet_listen_wlock(struct inet_hashinfo *hashinfo) * remote address for the connection. So always assume those are both * wildcarded during the search since they can never be otherwise. */ -static struct sock *inet_lookup_listener_slow(struct net *net, - const struct hlist_head *head, - const __be32 daddr, - const unsigned short hnum, - const int dif) -{ - struct sock *result = NULL, *sk; - const struct hlist_node *node; - int hiscore = -1; - - sk_for_each(sk, node, head) { - const struct inet_sock *inet = inet_sk(sk); - - if (net_eq(sock_net(sk), net) && inet->num == hnum && - !ipv6_only_sock(sk)) { - const __be32 rcv_saddr = inet->rcv_saddr; - int score = sk->sk_family == PF_INET ? 1 : 0; - - if (rcv_saddr) { - if (rcv_saddr != daddr) - continue; - score += 2; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - continue; - score += 2; - } - if (score == 5) - return sk; - if (score > hiscore) { - hiscore = score; - result = sk; - } - } - } - return result; -} -/* Optimize the common listener case. */ + struct sock *__inet_lookup_listener(struct net *net, struct inet_hashinfo *hashinfo, const __be32 daddr, const unsigned short hnum, const int dif) { - struct sock *sk = NULL; - const struct hlist_head *head; - - read_lock(&hashinfo->lhash_lock); - head = &hashinfo->listening_hash[inet_lhashfn(net, hnum)]; - if (!hlist_empty(head)) { - const struct inet_sock *inet = inet_sk((sk = __sk_head(head))); - - if (inet->num == hnum && !sk->sk_node.next && - (!inet->rcv_saddr || inet->rcv_saddr == daddr) && - (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && - !sk->sk_bound_dev_if && net_eq(sock_net(sk), net)) - goto sherry_cache; - sk = inet_lookup_listener_slow(net, head, daddr, hnum, dif); + struct sock *sk, *result; + struct hlist_nulls_node *node; + unsigned int hash = inet_lhashfn(net, hnum); + struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; + int score, hiscore; + + rcu_read_lock(); +begin: + result = NULL; + hiscore = -1; + sk_nulls_for_each_rcu(sk, node, &ilb->head) { + score = compute_score(sk, net, hnum, daddr, dif); + if (score > hiscore) { + result = sk; + hiscore = score; + } } - if (sk) { -sherry_cache: - sock_hold(sk); + /* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (get_nulls_value(node) != hash + LISTENING_NULLS_BASE) + goto begin; + if (result) { + if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) + result = NULL; + else if (unlikely(compute_score(result, net, hnum, daddr, + dif) < hiscore)) { + sock_put(result); + goto begin; + } } - read_unlock(&hashinfo->lhash_lock); - return sk; + rcu_read_unlock(); + return result; } EXPORT_SYMBOL_GPL(__inet_lookup_listener); @@ -223,35 +195,65 @@ struct sock * __inet_lookup_established(struct net *net, INET_ADDR_COOKIE(acookie, saddr, daddr) const __portpair ports = INET_COMBINED_PORTS(sport, hnum); struct sock *sk; - const struct hlist_node *node; + const struct hlist_nulls_node *node; /* Optimize here for direct hit, only listening connections can * have wildcards anyways. */ unsigned int hash = inet_ehashfn(net, daddr, hnum, saddr, sport); - struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); - rwlock_t *lock = inet_ehash_lockp(hashinfo, hash); + unsigned int slot = hash & (hashinfo->ehash_size - 1); + struct inet_ehash_bucket *head = &hashinfo->ehash[slot]; - prefetch(head->chain.first); - read_lock(lock); - sk_for_each(sk, node, &head->chain) { + rcu_read_lock(); +begin: + sk_nulls_for_each_rcu(sk, node, &head->chain) { if (INET_MATCH(sk, net, hash, acookie, - saddr, daddr, ports, dif)) - goto hit; /* You sunk my battleship! */ + saddr, daddr, ports, dif)) { + if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) + goto begintw; + if (unlikely(!INET_MATCH(sk, net, hash, acookie, + saddr, daddr, ports, dif))) { + sock_put(sk); + goto begin; + } + goto out; + } } + /* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (get_nulls_value(node) != slot) + goto begin; +begintw: /* Must check for a TIME_WAIT'er before going to listener hash. */ - sk_for_each(sk, node, &head->twchain) { + sk_nulls_for_each_rcu(sk, node, &head->twchain) { if (INET_TW_MATCH(sk, net, hash, acookie, - saddr, daddr, ports, dif)) - goto hit; + saddr, daddr, ports, dif)) { + if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { + sk = NULL; + goto out; + } + if (unlikely(!INET_TW_MATCH(sk, net, hash, acookie, + saddr, daddr, ports, dif))) { + sock_put(sk); + goto begintw; + } + goto out; + } } + /* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (get_nulls_value(node) != slot) + goto begintw; sk = NULL; out: - read_unlock(lock); + rcu_read_unlock(); return sk; -hit: - sock_hold(sk); - goto out; } EXPORT_SYMBOL_GPL(__inet_lookup_established); @@ -270,16 +272,15 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, struct net *net = sock_net(sk); unsigned int hash = inet_ehashfn(net, daddr, lport, saddr, inet->dport); struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); - rwlock_t *lock = inet_ehash_lockp(hinfo, hash); + spinlock_t *lock = inet_ehash_lockp(hinfo, hash); struct sock *sk2; - const struct hlist_node *node; + const struct hlist_nulls_node *node; struct inet_timewait_sock *tw; - prefetch(head->chain.first); - write_lock(lock); + spin_lock(lock); /* Check TIME-WAIT sockets first. */ - sk_for_each(sk2, node, &head->twchain) { + sk_nulls_for_each(sk2, node, &head->twchain) { tw = inet_twsk(sk2); if (INET_TW_MATCH(sk2, net, hash, acookie, @@ -293,7 +294,7 @@ static int __inet_check_established(struct inet_timewait_death_row *death_row, tw = NULL; /* And established part... */ - sk_for_each(sk2, node, &head->chain) { + sk_nulls_for_each(sk2, node, &head->chain) { if (INET_MATCH(sk2, net, hash, acookie, saddr, daddr, ports, dif)) goto not_unique; @@ -306,9 +307,9 @@ unique: inet->sport = htons(lport); sk->sk_hash = hash; WARN_ON(!sk_unhashed(sk)); - __sk_add_node(sk, &head->chain); + __sk_nulls_add_node_rcu(sk, &head->chain); + spin_unlock(lock); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - write_unlock(lock); if (twp) { *twp = tw; @@ -324,7 +325,7 @@ unique: return 0; not_unique: - write_unlock(lock); + spin_unlock(lock); return -EADDRNOTAVAIL; } @@ -338,8 +339,8 @@ static inline u32 inet_sk_port_offset(const struct sock *sk) void __inet_hash_nolisten(struct sock *sk) { struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; - struct hlist_head *list; - rwlock_t *lock; + struct hlist_nulls_head *list; + spinlock_t *lock; struct inet_ehash_bucket *head; WARN_ON(!sk_unhashed(sk)); @@ -349,18 +350,17 @@ void __inet_hash_nolisten(struct sock *sk) list = &head->chain; lock = inet_ehash_lockp(hashinfo, sk->sk_hash); - write_lock(lock); - __sk_add_node(sk, list); + spin_lock(lock); + __sk_nulls_add_node_rcu(sk, list); + spin_unlock(lock); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - write_unlock(lock); } EXPORT_SYMBOL_GPL(__inet_hash_nolisten); static void __inet_hash(struct sock *sk) { struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; - struct hlist_head *list; - rwlock_t *lock; + struct inet_listen_hashbucket *ilb; if (sk->sk_state != TCP_LISTEN) { __inet_hash_nolisten(sk); @@ -368,14 +368,12 @@ static void __inet_hash(struct sock *sk) } WARN_ON(!sk_unhashed(sk)); - list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; - lock = &hashinfo->lhash_lock; + ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; - inet_listen_wlock(hashinfo); - __sk_add_node(sk, list); + spin_lock(&ilb->lock); + __sk_nulls_add_node_rcu(sk, &ilb->head); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - write_unlock(lock); - wake_up(&hashinfo->lhash_wait); + spin_unlock(&ilb->lock); } void inet_hash(struct sock *sk) @@ -390,27 +388,23 @@ EXPORT_SYMBOL_GPL(inet_hash); void inet_unhash(struct sock *sk) { - rwlock_t *lock; struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; + spinlock_t *lock; + int done; if (sk_unhashed(sk)) - goto out; + return; - if (sk->sk_state == TCP_LISTEN) { - local_bh_disable(); - inet_listen_wlock(hashinfo); - lock = &hashinfo->lhash_lock; - } else { + if (sk->sk_state == TCP_LISTEN) + lock = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)].lock; + else lock = inet_ehash_lockp(hashinfo, sk->sk_hash); - write_lock_bh(lock); - } - if (__sk_del_node_init(sk)) + spin_lock_bh(lock); + done =__sk_nulls_del_node_init_rcu(sk); + if (done) sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - write_unlock_bh(lock); -out: - if (sk->sk_state == TCP_LISTEN) - wake_up(&hashinfo->lhash_wait); + spin_unlock_bh(lock); } EXPORT_SYMBOL_GPL(inet_unhash); @@ -449,7 +443,7 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row, * unique enough. */ inet_bind_bucket_for_each(tb, node, &head->chain) { - if (tb->ib_net == net && tb->port == port) { + if (ib_net(tb) == net && tb->port == port) { WARN_ON(hlist_empty(&tb->owners)); if (tb->fastreuse >= 0) goto next_port; @@ -524,3 +518,16 @@ int inet_hash_connect(struct inet_timewait_death_row *death_row, } EXPORT_SYMBOL_GPL(inet_hash_connect); + +void inet_hashinfo_init(struct inet_hashinfo *h) +{ + int i; + + for (i = 0; i < INET_LHTABLE_SIZE; i++) { + spin_lock_init(&h->listening_hash[i].lock); + INIT_HLIST_NULLS_HEAD(&h->listening_hash[i].head, + i + LISTENING_NULLS_BASE); + } +} + +EXPORT_SYMBOL_GPL(inet_hashinfo_init); diff --git a/net/ipv4/inet_lro.c b/net/ipv4/inet_lro.c index cfd034a2b96ed7926f5139aeb161a58ba1820b2f..6a667dae315ec577661f944bb3cd56dfb905c103 100644 --- a/net/ipv4/inet_lro.c +++ b/net/ipv4/inet_lro.c @@ -120,7 +120,7 @@ static void lro_update_tcp_ip_header(struct net_lro_desc *lro_desc) iph->check = ip_fast_csum((u8 *)lro_desc->iph, iph->ihl); tcph->check = 0; - tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), 0); + tcp_hdr_csum = csum_partial(tcph, TCP_HDR_LEN(tcph), 0); lro_desc->data_csum = csum_add(lro_desc->data_csum, tcp_hdr_csum); tcph->check = csum_tcpudp_magic(iph->saddr, iph->daddr, lro_desc->ip_tot_len - @@ -135,7 +135,7 @@ static __wsum lro_tcp_data_csum(struct iphdr *iph, struct tcphdr *tcph, int len) __wsum tcp_ps_hdr_csum; tcp_csum = ~csum_unfold(tcph->check); - tcp_hdr_csum = csum_partial((u8 *)tcph, TCP_HDR_LEN(tcph), tcp_csum); + tcp_hdr_csum = csum_partial(tcph, TCP_HDR_LEN(tcph), tcp_csum); tcp_ps_hdr_csum = csum_tcpudp_nofold(iph->saddr, iph->daddr, len + TCP_HDR_LEN(tcph), diff --git a/net/ipv4/inet_timewait_sock.c b/net/ipv4/inet_timewait_sock.c index 1c5fd38f8824a9a58cafc9220773b134c4a4b771..8554d0ea1719b7621667026a1641cb7da20ca2d4 100644 --- a/net/ipv4/inet_timewait_sock.c +++ b/net/ipv4/inet_timewait_sock.c @@ -20,16 +20,16 @@ static void __inet_twsk_kill(struct inet_timewait_sock *tw, struct inet_bind_hashbucket *bhead; struct inet_bind_bucket *tb; /* Unlink from established hashes. */ - rwlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash); + spinlock_t *lock = inet_ehash_lockp(hashinfo, tw->tw_hash); - write_lock(lock); - if (hlist_unhashed(&tw->tw_node)) { - write_unlock(lock); + spin_lock(lock); + if (hlist_nulls_unhashed(&tw->tw_node)) { + spin_unlock(lock); return; } - __hlist_del(&tw->tw_node); - sk_node_init(&tw->tw_node); - write_unlock(lock); + hlist_nulls_del_rcu(&tw->tw_node); + sk_nulls_node_init(&tw->tw_node); + spin_unlock(lock); /* Disassociate with bind bucket. */ bhead = &hashinfo->bhash[inet_bhashfn(twsk_net(tw), tw->tw_num, @@ -76,7 +76,7 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, const struct inet_sock *inet = inet_sk(sk); const struct inet_connection_sock *icsk = inet_csk(sk); struct inet_ehash_bucket *ehead = inet_ehash_bucket(hashinfo, sk->sk_hash); - rwlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash); + spinlock_t *lock = inet_ehash_lockp(hashinfo, sk->sk_hash); struct inet_bind_hashbucket *bhead; /* Step 1: Put TW into bind hash. Original socket stays there too. Note, that any socket with inet->num != 0 MUST be bound in @@ -90,17 +90,21 @@ void __inet_twsk_hashdance(struct inet_timewait_sock *tw, struct sock *sk, inet_twsk_add_bind_node(tw, &tw->tw_tb->owners); spin_unlock(&bhead->lock); - write_lock(lock); + spin_lock(lock); - /* Step 2: Remove SK from established hash. */ - if (__sk_del_node_init(sk)) - sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); - - /* Step 3: Hash TW into TIMEWAIT chain. */ - inet_twsk_add_node(tw, &ehead->twchain); + /* + * Step 2: Hash TW into TIMEWAIT chain. + * Should be done before removing sk from established chain + * because readers are lockless and search established first. + */ atomic_inc(&tw->tw_refcnt); + inet_twsk_add_node_rcu(tw, &ehead->twchain); - write_unlock(lock); + /* Step 3: Remove SK from established hash. */ + if (__sk_nulls_del_node_init_rcu(sk)) + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + + spin_unlock(lock); } EXPORT_SYMBOL_GPL(__inet_twsk_hashdance); @@ -416,17 +420,17 @@ void inet_twsk_purge(struct net *net, struct inet_hashinfo *hashinfo, { struct inet_timewait_sock *tw; struct sock *sk; - struct hlist_node *node; + struct hlist_nulls_node *node; int h; local_bh_disable(); for (h = 0; h < (hashinfo->ehash_size); h++) { struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, h); - rwlock_t *lock = inet_ehash_lockp(hashinfo, h); + spinlock_t *lock = inet_ehash_lockp(hashinfo, h); restart: - write_lock(lock); - sk_for_each(sk, node, &head->twchain) { + spin_lock(lock); + sk_nulls_for_each(sk, node, &head->twchain) { tw = inet_twsk(sk); if (!net_eq(twsk_net(tw), net) || @@ -434,13 +438,13 @@ restart: continue; atomic_inc(&tw->tw_refcnt); - write_unlock(lock); + spin_unlock(lock); inet_twsk_deschedule(tw, twdr); inet_twsk_put(tw); goto restart; } - write_unlock(lock); + spin_unlock(lock); } local_bh_enable(); } diff --git a/net/ipv4/inetpeer.c b/net/ipv4/inetpeer.c index a456ceeac3f22519e5bac707a6c57d110c89e79a..b1fbe18feb5adf88a6bba3e1f8cdb6e4aae644f7 100644 --- a/net/ipv4/inetpeer.c +++ b/net/ipv4/inetpeer.c @@ -144,7 +144,7 @@ static void unlink_from_unused(struct inet_peer *p) * _stack is known to be NULL or not at compile time, * so compiler will optimize the if (_stack) tests. */ -#define lookup(_daddr,_stack) \ +#define lookup(_daddr, _stack) \ ({ \ struct inet_peer *u, **v; \ if (_stack != NULL) { \ diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index 450016b89a18ea04bcbbf10cfb6a8f6f0ada65d4..df3fe50bbf0dc0a76cebf690c4ec8697c7889d1d 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -106,7 +106,7 @@ int ip_forward(struct sk_buff *skb) * We now generate an ICMP HOST REDIRECT giving the route * we calculated. */ - if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb->sp) + if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb_sec_path(skb)) ip_rt_send_redirect(skb); skb->priority = rt_tos2priority(iph->tos); diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index e4f81f54befee04ad398f6e5a6e3877d388d65bf..6659ac000eeb81c72666a863177301df3ce59d7f 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -56,7 +56,7 @@ struct ipfrag_skb_cb int offset; }; -#define FRAG_CB(skb) ((struct ipfrag_skb_cb*)((skb)->cb)) +#define FRAG_CB(skb) ((struct ipfrag_skb_cb *)((skb)->cb)) /* Describe an entry in the "incomplete datagrams" queue. */ struct ipq { @@ -559,9 +559,8 @@ out_nomem: goto out_fail; out_oversize: if (net_ratelimit()) - printk(KERN_INFO - "Oversized IP packet from " NIPQUAD_FMT ".\n", - NIPQUAD(qp->saddr)); + printk(KERN_INFO "Oversized IP packet from %pI4.\n", + &qp->saddr); out_fail: IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_REASMFAILS); return err; @@ -608,7 +607,7 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = { .data = &init_net.ipv4.frags.high_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_IPFRAG_LOW_THRESH, @@ -616,7 +615,7 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = { .data = &init_net.ipv4.frags.low_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_IPFRAG_TIME, @@ -624,8 +623,8 @@ static struct ctl_table ip4_frags_ns_ctl_table[] = { .data = &init_net.ipv4.frags.timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies }, { } }; @@ -637,15 +636,15 @@ static struct ctl_table ip4_frags_ctl_table[] = { .data = &ip4_frags.secret_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies }, { .procname = "ipfrag_max_dist", .data = &sysctl_ipfrag_max_dist, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, + .proc_handler = proc_dointvec_minmax, .extra1 = &zero }, { } diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c index 85c487b8572b726a365e869a92e8ad00669d76b7..0101521f366b74546cbb90f60e7e6faac597b430 100644 --- a/net/ipv4/ip_gre.c +++ b/net/ipv4/ip_gre.c @@ -126,8 +126,6 @@ static int ipgre_tunnel_bind_dev(struct net_device *dev); /* Fallback tunnel: no source, no destination, no key, no options */ -static int ipgre_fb_tunnel_init(struct net_device *dev); - #define HASH_SIZE 16 static int ipgre_net_id; @@ -371,7 +369,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info) by themself??? */ - struct iphdr *iph = (struct iphdr*)skb->data; + struct iphdr *iph = (struct iphdr *)skb->data; __be16 *p = (__be16*)(skb->data+(iph->ihl<<2)); int grehlen = (iph->ihl<<2) + 4; const int type = icmp_hdr(skb)->type; @@ -632,7 +630,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (dev->header_ops && dev->type == ARPHRD_IPGRE) { gre_hlen = 0; - tiph = (struct iphdr*)skb->data; + tiph = (struct iphdr *)skb->data; } else { gre_hlen = tunnel->hlen; tiph = &tunnel->parms.iph; @@ -660,7 +658,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) if (neigh == NULL) goto tx_error; - addr6 = (struct in6_addr*)&neigh->primary_key; + addr6 = (struct in6_addr *)&neigh->primary_key; addr_type = ipv6_addr_type(addr6); if (addr_type == IPV6_ADDR_ANY) { @@ -726,7 +724,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) } #ifdef CONFIG_IPV6 else if (skb->protocol == htons(ETH_P_IPV6)) { - struct rt6_info *rt6 = (struct rt6_info*)skb->dst; + struct rt6_info *rt6 = (struct rt6_info *)skb->dst; if (rt6 && mtu < dst_mtu(skb->dst) && mtu >= IPV6_MIN_MTU) { if ((tunnel->parms.iph.daddr && @@ -800,7 +798,7 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev) iph->ttl = old_iph->ttl; #ifdef CONFIG_IPV6 else if (skb->protocol == htons(ETH_P_IPV6)) - iph->ttl = ((struct ipv6hdr*)old_iph)->hop_limit; + iph->ttl = ((struct ipv6hdr *)old_iph)->hop_limit; #endif else iph->ttl = dst_metric(&rt->u.dst, RTAX_HOPLIMIT); @@ -962,7 +960,7 @@ ipgre_tunnel_ioctl (struct net_device *dev, struct ifreq *ifr, int cmd) break; } } else { - unsigned nflags=0; + unsigned nflags = 0; t = netdev_priv(dev); @@ -1104,7 +1102,7 @@ static int ipgre_header(struct sk_buff *skb, struct net_device *dev, static int ipgre_header_parse(const struct sk_buff *skb, unsigned char *haddr) { - struct iphdr *iph = (struct iphdr*) skb_mac_header(skb); + struct iphdr *iph = (struct iphdr *) skb_mac_header(skb); memcpy(haddr, &iph->saddr, 4); return 4; } @@ -1142,6 +1140,7 @@ static int ipgre_open(struct net_device *dev) static int ipgre_close(struct net_device *dev) { struct ip_tunnel *t = netdev_priv(dev); + if (ipv4_is_multicast(t->parms.iph.daddr) && t->mlink) { struct in_device *in_dev; in_dev = inetdev_by_index(dev_net(dev), t->mlink); @@ -1155,14 +1154,22 @@ static int ipgre_close(struct net_device *dev) #endif +static const struct net_device_ops ipgre_netdev_ops = { + .ndo_init = ipgre_tunnel_init, + .ndo_uninit = ipgre_tunnel_uninit, +#ifdef CONFIG_NET_IPGRE_BROADCAST + .ndo_open = ipgre_open, + .ndo_stop = ipgre_close, +#endif + .ndo_start_xmit = ipgre_tunnel_xmit, + .ndo_do_ioctl = ipgre_tunnel_ioctl, + .ndo_change_mtu = ipgre_tunnel_change_mtu, +}; + static void ipgre_tunnel_setup(struct net_device *dev) { - dev->init = ipgre_tunnel_init; - dev->uninit = ipgre_tunnel_uninit; + dev->netdev_ops = &ipgre_netdev_ops; dev->destructor = free_netdev; - dev->hard_start_xmit = ipgre_tunnel_xmit; - dev->do_ioctl = ipgre_tunnel_ioctl; - dev->change_mtu = ipgre_tunnel_change_mtu; dev->type = ARPHRD_IPGRE; dev->needed_headroom = LL_MAX_HEADER + sizeof(struct iphdr) + 4; @@ -1194,8 +1201,6 @@ static int ipgre_tunnel_init(struct net_device *dev) return -EINVAL; dev->flags = IFF_BROADCAST; dev->header_ops = &ipgre_header_ops; - dev->open = ipgre_open; - dev->stop = ipgre_close; } #endif } else @@ -1204,7 +1209,7 @@ static int ipgre_tunnel_init(struct net_device *dev) return 0; } -static int ipgre_fb_tunnel_init(struct net_device *dev) +static void ipgre_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; @@ -1220,7 +1225,6 @@ static int ipgre_fb_tunnel_init(struct net_device *dev) dev_hold(dev); ign->tunnels_wc[0] = tunnel; - return 0; } @@ -1264,9 +1268,9 @@ static int ipgre_init_net(struct net *net) err = -ENOMEM; goto err_alloc_dev; } - - ign->fb_tunnel_dev->init = ipgre_fb_tunnel_init; dev_net_set(ign->fb_tunnel_dev, net); + + ipgre_fb_tunnel_init(ign->fb_tunnel_dev); ign->fb_tunnel_dev->rtnl_link_ops = &ipgre_link_ops; if ((err = register_netdev(ign->fb_tunnel_dev))) @@ -1397,16 +1401,22 @@ static int ipgre_tap_init(struct net_device *dev) return 0; } +static const struct net_device_ops ipgre_tap_netdev_ops = { + .ndo_init = ipgre_tap_init, + .ndo_uninit = ipgre_tunnel_uninit, + .ndo_start_xmit = ipgre_tunnel_xmit, + .ndo_set_mac_address = eth_mac_addr, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = ipgre_tunnel_change_mtu, +}; + static void ipgre_tap_setup(struct net_device *dev) { ether_setup(dev); - dev->init = ipgre_tap_init; - dev->uninit = ipgre_tunnel_uninit; + dev->netdev_ops = &ipgre_netdev_ops; dev->destructor = free_netdev; - dev->hard_start_xmit = ipgre_tunnel_xmit; - dev->change_mtu = ipgre_tunnel_change_mtu; dev->iflink = 0; dev->features |= NETIF_F_NETNS_LOCAL; diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index cfb38ac9d698b933cc64a5cd5dbb42298ba07056..1a58a6fa1dc01d1c9eefd48dbb56c5017cec0689 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -302,10 +302,8 @@ static inline int ip_rcv_options(struct sk_buff *skb) if (!IN_DEV_SOURCE_ROUTE(in_dev)) { if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) - printk(KERN_INFO "source route option " - NIPQUAD_FMT " -> " NIPQUAD_FMT "\n", - NIPQUAD(iph->saddr), - NIPQUAD(iph->daddr)); + printk(KERN_INFO "source route option %pI4 -> %pI4\n", + &iph->saddr, &iph->daddr); in_dev_put(in_dev); goto drop; } @@ -350,9 +348,9 @@ static int ip_rcv_finish(struct sk_buff *skb) struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id()); u32 idx = skb->dst->tclassid; st[idx&0xFF].o_packets++; - st[idx&0xFF].o_bytes+=skb->len; + st[idx&0xFF].o_bytes += skb->len; st[(idx>>16)&0xFF].i_packets++; - st[(idx>>16)&0xFF].i_bytes+=skb->len; + st[(idx>>16)&0xFF].i_bytes += skb->len; } #endif diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index d2a8f8bb78a677e5be6b9e39a4f2fe7c3b181a27..8ebe86dd72af159e2250bc315251cf61561cc38a 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -430,7 +430,7 @@ static void ip_copy_metadata(struct sk_buff *to, struct sk_buff *from) * single device frame, and queue such a frame for sending. */ -int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff*)) +int ip_fragment(struct sk_buff *skb, int (*output)(struct sk_buff *)) { struct iphdr *iph; int raw = 0; @@ -720,7 +720,7 @@ static inline int ip_ufo_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int length, int hh_len, int fragheaderlen, - int transhdrlen, int mtu,unsigned int flags) + int transhdrlen, int mtu, unsigned int flags) { struct sk_buff *skb; int err; @@ -741,7 +741,7 @@ static inline int ip_ufo_append_data(struct sock *sk, skb_reserve(skb, hh_len); /* create space for UDP/IP header */ - skb_put(skb,fragheaderlen + transhdrlen); + skb_put(skb, fragheaderlen + transhdrlen); /* initialize network header pointer */ skb_reset_network_header(skb); @@ -778,7 +778,7 @@ int ip_append_data(struct sock *sk, int getfrag(void *from, char *to, int offset, int len, int odd, struct sk_buff *skb), void *from, int length, int transhdrlen, - struct ipcm_cookie *ipc, struct rtable *rt, + struct ipcm_cookie *ipc, struct rtable **rtp, unsigned int flags) { struct inet_sock *inet = inet_sk(sk); @@ -793,6 +793,7 @@ int ip_append_data(struct sock *sk, int offset = 0; unsigned int maxfraglen, fragheaderlen; int csummode = CHECKSUM_NONE; + struct rtable *rt; if (flags&MSG_PROBE) return 0; @@ -812,7 +813,11 @@ int ip_append_data(struct sock *sk, inet->cork.flags |= IPCORK_OPT; inet->cork.addr = ipc->addr; } - dst_hold(&rt->u.dst); + rt = *rtp; + /* + * We steal reference to this route, caller should not release it + */ + *rtp = NULL; inet->cork.fragsize = mtu = inet->pmtudisc == IP_PMTUDISC_PROBE ? rt->u.dst.dev->mtu : dst_mtu(rt->u.dst.path); @@ -1279,7 +1284,12 @@ int ip_push_pending_frames(struct sock *sk) skb->priority = sk->sk_priority; skb->mark = sk->sk_mark; - skb->dst = dst_clone(&rt->u.dst); + /* + * Steal rt from cork.dst to avoid a pair of atomic_inc/atomic_dec + * on dst refcount + */ + inet->cork.dst = NULL; + skb->dst = &rt->u.dst; if (iph->protocol == IPPROTO_ICMP) icmp_out_count(net, ((struct icmphdr *) @@ -1391,7 +1401,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar sk->sk_protocol = ip_hdr(skb)->protocol; sk->sk_bound_dev_if = arg->bound_dev_if; ip_append_data(sk, ip_reply_glue_bits, arg->iov->iov_base, len, 0, - &ipc, rt, MSG_DONTWAIT); + &ipc, &rt, MSG_DONTWAIT); if ((skb = skb_peek(&sk->sk_write_queue)) != NULL) { if (arg->csumoffset >= 0) *((__sum16 *)skb_transport_header(skb) + diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index 465abf0a9869c768ab7b7f0832050a2a0812f05c..43c05854d752f94c88dbb3dbd4ab43a111a93d0d 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -48,6 +48,7 @@ #define IP_CMSG_RECVOPTS 8 #define IP_CMSG_RETOPTS 16 #define IP_CMSG_PASSSEC 32 +#define IP_CMSG_ORIGDSTADDR 64 /* * SOL_IP control messages. @@ -94,7 +95,7 @@ static void ip_cmsg_recv_opts(struct msghdr *msg, struct sk_buff *skb) static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb) { unsigned char optbuf[sizeof(struct ip_options) + 40]; - struct ip_options * opt = (struct ip_options*)optbuf; + struct ip_options * opt = (struct ip_options *)optbuf; if (IPCB(skb)->opt.optlen == 0) return; @@ -126,6 +127,27 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb) security_release_secctx(secdata, seclen); } +static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb) +{ + struct sockaddr_in sin; + struct iphdr *iph = ip_hdr(skb); + __be16 *ports = (__be16 *)skb_transport_header(skb); + + if (skb_transport_offset(skb) + 4 > skb->len) + return; + + /* All current transport protocols have the port numbers in the + * first four bytes of the transport header and this function is + * written with this assumption in mind. + */ + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = iph->daddr; + sin.sin_port = ports[1]; + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); + + put_cmsg(msg, SOL_IP, IP_ORIGDSTADDR, sizeof(sin), &sin); +} void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) { @@ -160,6 +182,12 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb) if (flags & 1) ip_cmsg_recv_security(msg, skb); + + if ((flags>>=1) == 0) + return; + if (flags & 1) + ip_cmsg_recv_dstaddr(msg, skb); + } int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc) @@ -411,7 +439,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval, int optlen) { struct inet_sock *inet = inet_sk(sk); - int val=0,err; + int val = 0, err; if (((1<= sizeof(int)) { if (get_user(val, (int __user *) optval)) return -EFAULT; @@ -437,7 +466,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, /* If optlen==0, it is equivalent to val == 0 */ if (ip_mroute_opt(optname)) - return ip_mroute_setsockopt(sk,optname,optval,optlen); + return ip_mroute_setsockopt(sk, optname, optval, optlen); err = 0; lock_sock(sk); @@ -509,6 +538,12 @@ static int do_ip_setsockopt(struct sock *sk, int level, else inet->cmsg_flags &= ~IP_CMSG_PASSSEC; break; + case IP_RECVORIGDSTADDR: + if (val) + inet->cmsg_flags |= IP_CMSG_ORIGDSTADDR; + else + inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR; + break; case IP_TOS: /* This sets both TOS and Precedence */ if (sk->sk_type == SOCK_STREAM) { val &= ~3; @@ -549,7 +584,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, goto e_inval; if (optlen<1) goto e_inval; - if (val==-1) + if (val == -1) val = 1; if (val < 0 || val > 255) goto e_inval; @@ -573,12 +608,12 @@ static int do_ip_setsockopt(struct sock *sk, int level, err = -EFAULT; if (optlen >= sizeof(struct ip_mreqn)) { - if (copy_from_user(&mreq,optval,sizeof(mreq))) + if (copy_from_user(&mreq, optval, sizeof(mreq))) break; } else { memset(&mreq, 0, sizeof(mreq)); if (optlen >= sizeof(struct in_addr) && - copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr))) + copy_from_user(&mreq.imr_address, optval, sizeof(struct in_addr))) break; } @@ -626,11 +661,11 @@ static int do_ip_setsockopt(struct sock *sk, int level, goto e_inval; err = -EFAULT; if (optlen >= sizeof(struct ip_mreqn)) { - if (copy_from_user(&mreq,optval,sizeof(mreq))) + if (copy_from_user(&mreq, optval, sizeof(mreq))) break; } else { memset(&mreq, 0, sizeof(mreq)); - if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq))) + if (copy_from_user(&mreq, optval, sizeof(struct ip_mreq))) break; } @@ -808,7 +843,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, err = -ENOBUFS; break; } - gsf = kmalloc(optlen,GFP_KERNEL); + gsf = kmalloc(optlen, GFP_KERNEL); if (!gsf) { err = -ENOBUFS; break; @@ -828,7 +863,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, goto mc_msf_out; } msize = IP_MSFILTER_SIZE(gsf->gf_numsrc); - msf = kmalloc(msize,GFP_KERNEL); + msf = kmalloc(msize, GFP_KERNEL); if (!msf) { err = -ENOBUFS; goto mc_msf_out; @@ -971,9 +1006,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, return -EOPNOTSUPP; if (ip_mroute_opt(optname)) - return ip_mroute_getsockopt(sk,optname,optval,optlen); + return ip_mroute_getsockopt(sk, optname, optval, optlen); - if (get_user(len,optlen)) + if (get_user(len, optlen)) return -EFAULT; if (len < 0) return -EINVAL; @@ -984,7 +1019,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, case IP_OPTIONS: { unsigned char optbuf[sizeof(struct ip_options)+40]; - struct ip_options * opt = (struct ip_options*)optbuf; + struct ip_options * opt = (struct ip_options *)optbuf; opt->optlen = 0; if (inet->opt) memcpy(optbuf, inet->opt, @@ -1022,6 +1057,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, case IP_PASSSEC: val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0; break; + case IP_RECVORIGDSTADDR: + val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0; + break; case IP_TOS: val = inet->tos; break; @@ -1154,13 +1192,13 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname, len = 1; if (put_user(len, optlen)) return -EFAULT; - if (copy_to_user(optval,&ucval,1)) + if (copy_to_user(optval, &ucval, 1)) return -EFAULT; } else { len = min_t(unsigned int, sizeof(int), len); if (put_user(len, optlen)) return -EFAULT; - if (copy_to_user(optval,&val,len)) + if (copy_to_user(optval, &val, len)) return -EFAULT; } return 0; @@ -1178,7 +1216,7 @@ int ip_getsockopt(struct sock *sk, int level, !ip_mroute_opt(optname)) { int len; - if (get_user(len,optlen)) + if (get_user(len, optlen)) return -EFAULT; lock_sock(sk); diff --git a/net/ipv4/ipcomp.c b/net/ipv4/ipcomp.c index 38ccb6dfb02e1c755f8ec03f6d793ec16121784f..3262ce06294c314a85bfcb4d643e4d3ec020b4e4 100644 --- a/net/ipv4/ipcomp.c +++ b/net/ipv4/ipcomp.c @@ -35,12 +35,12 @@ static void ipcomp4_err(struct sk_buff *skb, u32 info) return; spi = htonl(ntohs(ipch->cpi)); - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, + x = xfrm_state_lookup(&init_net, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET); if (!x) return; - NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/" NIPQUAD_FMT "\n", - spi, NIPQUAD(iph->daddr)); + NETDEBUG(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%pI4\n", + spi, &iph->daddr); xfrm_state_put(x); } @@ -49,7 +49,7 @@ static struct xfrm_state *ipcomp_tunnel_create(struct xfrm_state *x) { struct xfrm_state *t; - t = xfrm_state_alloc(); + t = xfrm_state_alloc(&init_net); if (t == NULL) goto out; @@ -85,7 +85,7 @@ static int ipcomp_tunnel_attach(struct xfrm_state *x) int err = 0; struct xfrm_state *t; - t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr.a4, + t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr.a4, x->props.saddr.a4, IPPROTO_IPIP, AF_INET); if (!t) { t = ipcomp_tunnel_create(x); diff --git a/net/ipv4/ipconfig.c b/net/ipv4/ipconfig.c index 42065fff46c439809c368cd84a9cb83ba5fb22c5..42a0f3dd3fd64323ac9a087895dbbaaff822e7cd 100644 --- a/net/ipv4/ipconfig.c +++ b/net/ipv4/ipconfig.c @@ -374,7 +374,7 @@ static int __init ic_defaults(void) */ if (!ic_host_name_set) - sprintf(init_utsname()->nodename, NIPQUAD_FMT, NIPQUAD(ic_myaddr)); + sprintf(init_utsname()->nodename, "%pI4", &ic_myaddr); if (root_server_addr == NONE) root_server_addr = ic_servaddr; @@ -387,11 +387,11 @@ static int __init ic_defaults(void) else if (IN_CLASSC(ntohl(ic_myaddr))) ic_netmask = htonl(IN_CLASSC_NET); else { - printk(KERN_ERR "IP-Config: Unable to guess netmask for address " NIPQUAD_FMT "\n", - NIPQUAD(ic_myaddr)); + printk(KERN_ERR "IP-Config: Unable to guess netmask for address %pI4\n", + &ic_myaddr); return -1; } - printk("IP-Config: Guessing netmask " NIPQUAD_FMT "\n", NIPQUAD(ic_netmask)); + printk("IP-Config: Guessing netmask %pI4\n", &ic_netmask); } return 0; @@ -979,10 +979,8 @@ static int __init ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, str ic_myaddr = b->your_ip; ic_servaddr = server_id; #ifdef IPCONFIG_DEBUG - printk("DHCP: Offered address " NIPQUAD_FMT, - NIPQUAD(ic_myaddr)); - printk(" by server " NIPQUAD_FMT "\n", - NIPQUAD(ic_servaddr)); + printk("DHCP: Offered address %pI4 by server %pI4\n", + &ic_myaddr, &ic_servaddr); #endif /* The DHCP indicated server address takes * precedence over the bootp header one if @@ -1177,11 +1175,11 @@ static int __init ic_dynamic(void) return -1; } - printk("IP-Config: Got %s answer from " NIPQUAD_FMT ", ", + printk("IP-Config: Got %s answer from %pI4, ", ((ic_got_reply & IC_RARP) ? "RARP" : (ic_proto_enabled & IC_USE_DHCP) ? "DHCP" : "BOOTP"), - NIPQUAD(ic_servaddr)); - printk("my address is " NIPQUAD_FMT "\n", NIPQUAD(ic_myaddr)); + &ic_servaddr); + printk("my address is %pI4\n", &ic_myaddr); return 0; } @@ -1206,14 +1204,12 @@ static int pnp_seq_show(struct seq_file *seq, void *v) "domain %s\n", ic_domain); for (i = 0; i < CONF_NAMESERVERS_MAX; i++) { if (ic_nameservers[i] != NONE) - seq_printf(seq, - "nameserver " NIPQUAD_FMT "\n", - NIPQUAD(ic_nameservers[i])); + seq_printf(seq, "nameserver %pI4\n", + &ic_nameservers[i]); } if (ic_servaddr != NONE) - seq_printf(seq, - "bootserver " NIPQUAD_FMT "\n", - NIPQUAD(ic_servaddr)); + seq_printf(seq, "bootserver %pI4\n", + &ic_servaddr); return 0; } @@ -1387,13 +1383,13 @@ static int __init ip_auto_config(void) */ printk("IP-Config: Complete:"); printk("\n device=%s", ic_dev->name); - printk(", addr=" NIPQUAD_FMT, NIPQUAD(ic_myaddr)); - printk(", mask=" NIPQUAD_FMT, NIPQUAD(ic_netmask)); - printk(", gw=" NIPQUAD_FMT, NIPQUAD(ic_gateway)); + printk(", addr=%pI4", &ic_myaddr); + printk(", mask=%pI4", &ic_netmask); + printk(", gw=%pI4", &ic_gateway); printk(",\n host=%s, domain=%s, nis-domain=%s", utsname()->nodename, ic_domain, utsname()->domainname); - printk(",\n bootserver=" NIPQUAD_FMT, NIPQUAD(ic_servaddr)); - printk(", rootserver=" NIPQUAD_FMT, NIPQUAD(root_server_addr)); + printk(",\n bootserver=%pI4", &ic_servaddr); + printk(", rootserver=%pI4", &root_server_addr); printk(", rootpath=%s", root_server_path); printk("\n"); #endif /* !SILENT */ diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 29609d29df769350e9d1683209b372a422e9cd3d..5079dfbc6f38b1423b537cd9f8ba27ab2a08c685 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -130,8 +130,8 @@ struct ipip_net { struct net_device *fb_tunnel_dev; }; -static int ipip_fb_tunnel_init(struct net_device *dev); -static int ipip_tunnel_init(struct net_device *dev); +static void ipip_fb_tunnel_init(struct net_device *dev); +static void ipip_tunnel_init(struct net_device *dev); static void ipip_tunnel_setup(struct net_device *dev); static DEFINE_RWLOCK(ipip_lock); @@ -245,9 +245,10 @@ static struct ip_tunnel * ipip_tunnel_locate(struct net *net, } nt = netdev_priv(dev); - dev->init = ipip_tunnel_init; nt->parms = *parms; + ipip_tunnel_init(dev); + if (register_netdevice(dev) < 0) goto failed_free; @@ -281,7 +282,7 @@ static int ipip_err(struct sk_buff *skb, u32 info) 8 bytes of packet payload. It means, that precise relaying of ICMP in the real Internet is absolutely infeasible. */ - struct iphdr *iph = (struct iphdr*)skb->data; + struct iphdr *iph = (struct iphdr *)skb->data; const int type = icmp_hdr(skb)->type; const int code = icmp_hdr(skb)->code; struct ip_tunnel *t; @@ -691,12 +692,17 @@ static int ipip_tunnel_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static const struct net_device_ops ipip_netdev_ops = { + .ndo_uninit = ipip_tunnel_uninit, + .ndo_start_xmit = ipip_tunnel_xmit, + .ndo_do_ioctl = ipip_tunnel_ioctl, + .ndo_change_mtu = ipip_tunnel_change_mtu, + +}; + static void ipip_tunnel_setup(struct net_device *dev) { - dev->uninit = ipip_tunnel_uninit; - dev->hard_start_xmit = ipip_tunnel_xmit; - dev->do_ioctl = ipip_tunnel_ioctl; - dev->change_mtu = ipip_tunnel_change_mtu; + dev->netdev_ops = &ipip_netdev_ops; dev->destructor = free_netdev; dev->type = ARPHRD_TUNNEL; @@ -708,11 +714,9 @@ static void ipip_tunnel_setup(struct net_device *dev) dev->features |= NETIF_F_NETNS_LOCAL; } -static int ipip_tunnel_init(struct net_device *dev) +static void ipip_tunnel_init(struct net_device *dev) { - struct ip_tunnel *tunnel; - - tunnel = netdev_priv(dev); + struct ip_tunnel *tunnel = netdev_priv(dev); tunnel->dev = dev; strcpy(tunnel->parms.name, dev->name); @@ -721,11 +725,9 @@ static int ipip_tunnel_init(struct net_device *dev) memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); ipip_tunnel_bind_dev(dev); - - return 0; } -static int ipip_fb_tunnel_init(struct net_device *dev) +static void ipip_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; @@ -740,7 +742,6 @@ static int ipip_fb_tunnel_init(struct net_device *dev) dev_hold(dev); ipn->tunnels_wc[0] = tunnel; - return 0; } static struct xfrm_tunnel ipip_handler = { @@ -792,10 +793,10 @@ static int ipip_init_net(struct net *net) err = -ENOMEM; goto err_alloc_dev; } - - ipn->fb_tunnel_dev->init = ipip_fb_tunnel_init; dev_net_set(ipn->fb_tunnel_dev, net); + ipip_fb_tunnel_init(ipn->fb_tunnel_dev); + if ((err = register_netdev(ipn->fb_tunnel_dev))) goto err_reg_dev; diff --git a/net/ipv4/ipmr.c b/net/ipv4/ipmr.c index 25924b1eb2efd22ae3c70f4d7e4606f7f30771e4..14666449dc1c2f140da8b64162d2dcfa789d3a78 100644 --- a/net/ipv4/ipmr.c +++ b/net/ipv4/ipmr.c @@ -124,8 +124,8 @@ static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v) dev = __dev_get_by_name(&init_net, "tunl0"); if (dev) { + const struct net_device_ops *ops = dev->netdev_ops; struct ifreq ifr; - mm_segment_t oldfs; struct ip_tunnel_parm p; memset(&p, 0, sizeof(p)); @@ -137,9 +137,13 @@ static void ipmr_del_tunnel(struct net_device *dev, struct vifctl *v) sprintf(p.name, "dvmrp%d", v->vifc_vifi); ifr.ifr_ifru.ifru_data = (__force void __user *)&p; - oldfs = get_fs(); set_fs(KERNEL_DS); - dev->do_ioctl(dev, &ifr, SIOCDELTUNNEL); - set_fs(oldfs); + if (ops->ndo_do_ioctl) { + mm_segment_t oldfs = get_fs(); + + set_fs(KERNEL_DS); + ops->ndo_do_ioctl(dev, &ifr, SIOCDELTUNNEL); + set_fs(oldfs); + } } } @@ -151,9 +155,9 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v) dev = __dev_get_by_name(&init_net, "tunl0"); if (dev) { + const struct net_device_ops *ops = dev->netdev_ops; int err; struct ifreq ifr; - mm_segment_t oldfs; struct ip_tunnel_parm p; struct in_device *in_dev; @@ -166,9 +170,14 @@ struct net_device *ipmr_new_tunnel(struct vifctl *v) sprintf(p.name, "dvmrp%d", v->vifc_vifi); ifr.ifr_ifru.ifru_data = (__force void __user *)&p; - oldfs = get_fs(); set_fs(KERNEL_DS); - err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL); - set_fs(oldfs); + if (ops->ndo_do_ioctl) { + mm_segment_t oldfs = get_fs(); + + set_fs(KERNEL_DS); + err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL); + set_fs(oldfs); + } else + err = -EOPNOTSUPP; dev = NULL; @@ -213,12 +222,16 @@ static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) return 0; } +static const struct net_device_ops reg_vif_netdev_ops = { + .ndo_start_xmit = reg_vif_xmit, +}; + static void reg_vif_setup(struct net_device *dev) { dev->type = ARPHRD_PIMREG; dev->mtu = ETH_DATA_LEN - sizeof(struct iphdr) - 8; dev->flags = IFF_NOARP; - dev->hard_start_xmit = reg_vif_xmit; + dev->netdev_ops = ®_vif_netdev_ops, dev->destructor = free_netdev; } @@ -331,7 +344,7 @@ static void ipmr_destroy_unres(struct mfc_cache *c) atomic_dec(&cache_resolve_queue_len); - while ((skb=skb_dequeue(&c->mfc_un.unres.unresolved))) { + while ((skb = skb_dequeue(&c->mfc_un.unres.unresolved))) { if (ip_hdr(skb)->version == 0) { struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); nlh->nlmsg_type = NLMSG_ERROR; @@ -477,13 +490,13 @@ static int vif_add(struct vifctl *vifc, int mrtsock) /* * Fill in the VIF structures */ - v->rate_limit=vifc->vifc_rate_limit; - v->local=vifc->vifc_lcl_addr.s_addr; - v->remote=vifc->vifc_rmt_addr.s_addr; - v->flags=vifc->vifc_flags; + v->rate_limit = vifc->vifc_rate_limit; + v->local = vifc->vifc_lcl_addr.s_addr; + v->remote = vifc->vifc_rmt_addr.s_addr; + v->flags = vifc->vifc_flags; if (!mrtsock) v->flags |= VIFF_STATIC; - v->threshold=vifc->vifc_threshold; + v->threshold = vifc->vifc_threshold; v->bytes_in = 0; v->bytes_out = 0; v->pkt_in = 0; @@ -494,7 +507,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock) /* And finish update writing critical data */ write_lock_bh(&mrt_lock); - v->dev=dev; + v->dev = dev; #ifdef CONFIG_IP_PIMSM if (v->flags&VIFF_REGISTER) reg_vif_num = vifi; @@ -507,7 +520,7 @@ static int vif_add(struct vifctl *vifc, int mrtsock) static struct mfc_cache *ipmr_cache_find(__be32 origin, __be32 mcastgrp) { - int line=MFC_HASH(mcastgrp,origin); + int line = MFC_HASH(mcastgrp, origin); struct mfc_cache *c; for (c=mfc_cache_array[line]; c; c = c->next) { @@ -522,8 +535,8 @@ static struct mfc_cache *ipmr_cache_find(__be32 origin, __be32 mcastgrp) */ static struct mfc_cache *ipmr_cache_alloc(void) { - struct mfc_cache *c=kmem_cache_zalloc(mrt_cachep, GFP_KERNEL); - if (c==NULL) + struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL); + if (c == NULL) return NULL; c->mfc_un.res.minvif = MAXVIFS; return c; @@ -531,8 +544,8 @@ static struct mfc_cache *ipmr_cache_alloc(void) static struct mfc_cache *ipmr_cache_alloc_unres(void) { - struct mfc_cache *c=kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC); - if (c==NULL) + struct mfc_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC); + if (c == NULL) return NULL; skb_queue_head_init(&c->mfc_un.unres.unresolved); c->mfc_un.unres.expires = jiffies + 10*HZ; @@ -552,7 +565,7 @@ static void ipmr_cache_resolve(struct mfc_cache *uc, struct mfc_cache *c) * Play the pending entries through our router */ - while ((skb=__skb_dequeue(&uc->mfc_un.unres.unresolved))) { + while ((skb = __skb_dequeue(&uc->mfc_un.unres.unresolved))) { if (ip_hdr(skb)->version == 0) { struct nlmsghdr *nlh = (struct nlmsghdr *)skb_pull(skb, sizeof(struct iphdr)); @@ -637,7 +650,7 @@ static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) * Add our header */ - igmp=(struct igmphdr *)skb_put(skb,sizeof(struct igmphdr)); + igmp=(struct igmphdr *)skb_put(skb, sizeof(struct igmphdr)); igmp->type = msg->im_msgtype = assert; igmp->code = 0; @@ -653,7 +666,7 @@ static int ipmr_cache_report(struct sk_buff *pkt, vifi_t vifi, int assert) /* * Deliver to mrouted */ - if ((ret=sock_queue_rcv_skb(mroute_socket,skb))<0) { + if ((ret = sock_queue_rcv_skb(mroute_socket, skb))<0) { if (net_ratelimit()) printk(KERN_WARNING "mroute: pending queue full, dropping entries.\n"); kfree_skb(skb); @@ -685,7 +698,7 @@ ipmr_cache_unresolved(vifi_t vifi, struct sk_buff *skb) * Create a new entry if allowable */ - if (atomic_read(&cache_resolve_queue_len)>=10 || + if (atomic_read(&cache_resolve_queue_len) >= 10 || (c=ipmr_cache_alloc_unres())==NULL) { spin_unlock_bh(&mfc_unres_lock); @@ -728,7 +741,7 @@ ipmr_cache_unresolved(vifi_t vifi, struct sk_buff *skb) kfree_skb(skb); err = -ENOBUFS; } else { - skb_queue_tail(&c->mfc_un.unres.unresolved,skb); + skb_queue_tail(&c->mfc_un.unres.unresolved, skb); err = 0; } @@ -745,7 +758,7 @@ static int ipmr_mfc_delete(struct mfcctl *mfc) int line; struct mfc_cache *c, **cp; - line=MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr); + line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr); for (cp=&mfc_cache_array[line]; (c=*cp) != NULL; cp = &c->next) { if (c->mfc_origin == mfc->mfcc_origin.s_addr && @@ -766,7 +779,7 @@ static int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock) int line; struct mfc_cache *uc, *c, **cp; - line=MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr); + line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr); for (cp=&mfc_cache_array[line]; (c=*cp) != NULL; cp = &c->next) { if (c->mfc_origin == mfc->mfcc_origin.s_addr && @@ -787,13 +800,13 @@ static int ipmr_mfc_add(struct mfcctl *mfc, int mrtsock) if (!ipv4_is_multicast(mfc->mfcc_mcastgrp.s_addr)) return -EINVAL; - c=ipmr_cache_alloc(); - if (c==NULL) + c = ipmr_cache_alloc(); + if (c == NULL) return -ENOMEM; - c->mfc_origin=mfc->mfcc_origin.s_addr; - c->mfc_mcastgrp=mfc->mfcc_mcastgrp.s_addr; - c->mfc_parent=mfc->mfcc_parent; + c->mfc_origin = mfc->mfcc_origin.s_addr; + c->mfc_mcastgrp = mfc->mfcc_mcastgrp.s_addr; + c->mfc_parent = mfc->mfcc_parent; ipmr_update_thresholds(c, mfc->mfcc_ttls); if (!mrtsock) c->mfc_flags |= MFC_STATIC; @@ -846,7 +859,7 @@ static void mroute_clean_tables(struct sock *sk) /* * Wipe the cache */ - for (i=0;isk_type != SOCK_RAW || inet_sk(sk)->num != IPPROTO_IGMP) return -EOPNOTSUPP; - if (optlen!=sizeof(int)) + if (optlen != sizeof(int)) return -ENOPROTOOPT; rtnl_lock(); @@ -930,7 +943,7 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt ret = ip_ra_control(sk, 1, mrtsock_destruct); if (ret == 0) { write_lock_bh(&mrt_lock); - mroute_socket=sk; + mroute_socket = sk; write_unlock_bh(&mrt_lock); IPV4_DEVCONF_ALL(sock_net(sk), MC_FORWARDING)++; @@ -938,19 +951,19 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt rtnl_unlock(); return ret; case MRT_DONE: - if (sk!=mroute_socket) + if (sk != mroute_socket) return -EACCES; return ip_ra_control(sk, 0, NULL); case MRT_ADD_VIF: case MRT_DEL_VIF: - if (optlen!=sizeof(vif)) + if (optlen != sizeof(vif)) return -EINVAL; - if (copy_from_user(&vif,optval,sizeof(vif))) + if (copy_from_user(&vif, optval, sizeof(vif))) return -EFAULT; if (vif.vifc_vifi >= MAXVIFS) return -ENFILE; rtnl_lock(); - if (optname==MRT_ADD_VIF) { + if (optname == MRT_ADD_VIF) { ret = vif_add(&vif, sk==mroute_socket); } else { ret = vif_delete(vif.vifc_vifi, 0); @@ -964,12 +977,12 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt */ case MRT_ADD_MFC: case MRT_DEL_MFC: - if (optlen!=sizeof(mfc)) + if (optlen != sizeof(mfc)) return -EINVAL; - if (copy_from_user(&mfc,optval, sizeof(mfc))) + if (copy_from_user(&mfc, optval, sizeof(mfc))) return -EFAULT; rtnl_lock(); - if (optname==MRT_DEL_MFC) + if (optname == MRT_DEL_MFC) ret = ipmr_mfc_delete(&mfc); else ret = ipmr_mfc_add(&mfc, sk==mroute_socket); @@ -1028,12 +1041,12 @@ int ip_mroute_setsockopt(struct sock *sk,int optname,char __user *optval,int opt * Getsock opt support for the multicast routing system. */ -int ip_mroute_getsockopt(struct sock *sk,int optname,char __user *optval,int __user *optlen) +int ip_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, int __user *optlen) { int olr; int val; - if (optname!=MRT_VERSION && + if (optname != MRT_VERSION && #ifdef CONFIG_IP_PIMSM optname!=MRT_PIM && #endif @@ -1047,17 +1060,17 @@ int ip_mroute_getsockopt(struct sock *sk,int optname,char __user *optval,int __u if (olr < 0) return -EINVAL; - if (put_user(olr,optlen)) + if (put_user(olr, optlen)) return -EFAULT; - if (optname==MRT_VERSION) - val=0x0305; + if (optname == MRT_VERSION) + val = 0x0305; #ifdef CONFIG_IP_PIMSM - else if (optname==MRT_PIM) - val=mroute_do_pim; + else if (optname == MRT_PIM) + val = mroute_do_pim; #endif else - val=mroute_do_assert; - if (copy_to_user(optval,&val,olr)) + val = mroute_do_assert; + if (copy_to_user(optval, &val, olr)) return -EFAULT; return 0; } @@ -1075,27 +1088,27 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) switch (cmd) { case SIOCGETVIFCNT: - if (copy_from_user(&vr,arg,sizeof(vr))) + if (copy_from_user(&vr, arg, sizeof(vr))) return -EFAULT; - if (vr.vifi>=maxvif) + if (vr.vifi >= maxvif) return -EINVAL; read_lock(&mrt_lock); vif=&vif_table[vr.vifi]; if (VIF_EXISTS(vr.vifi)) { - vr.icount=vif->pkt_in; - vr.ocount=vif->pkt_out; - vr.ibytes=vif->bytes_in; - vr.obytes=vif->bytes_out; + vr.icount = vif->pkt_in; + vr.ocount = vif->pkt_out; + vr.ibytes = vif->bytes_in; + vr.obytes = vif->bytes_out; read_unlock(&mrt_lock); - if (copy_to_user(arg,&vr,sizeof(vr))) + if (copy_to_user(arg, &vr, sizeof(vr))) return -EFAULT; return 0; } read_unlock(&mrt_lock); return -EADDRNOTAVAIL; case SIOCGETSGCNT: - if (copy_from_user(&sr,arg,sizeof(sr))) + if (copy_from_user(&sr, arg, sizeof(sr))) return -EFAULT; read_lock(&mrt_lock); @@ -1106,7 +1119,7 @@ int ipmr_ioctl(struct sock *sk, int cmd, void __user *arg) sr.wrong_if = c->mfc_un.res.wrong_if; read_unlock(&mrt_lock); - if (copy_to_user(arg,&sr,sizeof(sr))) + if (copy_to_user(arg, &sr, sizeof(sr))) return -EFAULT; return 0; } @@ -1130,15 +1143,15 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v if (event != NETDEV_UNREGISTER) return NOTIFY_DONE; v=&vif_table[0]; - for (ct=0;ctdev==dev) + for (ct=0; ctdev == dev) vif_delete(ct, 1); } return NOTIFY_DONE; } -static struct notifier_block ip_mr_notifier={ +static struct notifier_block ip_mr_notifier = { .notifier_call = ipmr_device_event, }; @@ -1204,7 +1217,7 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) #ifdef CONFIG_IP_PIMSM if (vif->flags & VIFF_REGISTER) { vif->pkt_out++; - vif->bytes_out+=skb->len; + vif->bytes_out += skb->len; vif->dev->stats.tx_bytes += skb->len; vif->dev->stats.tx_packets++; ipmr_cache_report(skb, vifi, IGMPMSG_WHOLEPKT); @@ -1254,7 +1267,7 @@ static void ipmr_queue_xmit(struct sk_buff *skb, struct mfc_cache *c, int vifi) } vif->pkt_out++; - vif->bytes_out+=skb->len; + vif->bytes_out += skb->len; dst_release(skb->dst); skb->dst = &rt->u.dst; @@ -1352,7 +1365,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local } vif_table[vif].pkt_in++; - vif_table[vif].bytes_in+=skb->len; + vif_table[vif].bytes_in += skb->len; /* * Forward the frame @@ -1364,7 +1377,7 @@ static int ip_mr_forward(struct sk_buff *skb, struct mfc_cache *cache, int local if (skb2) ipmr_queue_xmit(skb2, cache, psend); } - psend=ct; + psend = ct; } } if (psend != -1) { @@ -1428,7 +1441,7 @@ int ip_mr_input(struct sk_buff *skb) /* * No usable cache entry */ - if (cache==NULL) { + if (cache == NULL) { int vif; if (local) { @@ -1469,29 +1482,13 @@ dont_forward: return 0; } -#ifdef CONFIG_IP_PIMSM_V1 -/* - * Handle IGMP messages of PIMv1 - */ - -int pim_rcv_v1(struct sk_buff * skb) +#ifdef CONFIG_IP_PIMSM +static int __pim_rcv(struct sk_buff *skb, unsigned int pimlen) { - struct igmphdr *pim; - struct iphdr *encap; - struct net_device *reg_dev = NULL; - - if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap))) - goto drop; + struct net_device *reg_dev = NULL; + struct iphdr *encap; - pim = igmp_hdr(skb); - - if (!mroute_do_pim || - skb->len < sizeof(*pim) + sizeof(*encap) || - pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER) - goto drop; - - encap = (struct iphdr *)(skb_transport_header(skb) + - sizeof(struct igmphdr)); + encap = (struct iphdr *)(skb_transport_header(skb) + pimlen); /* Check that: a. packet is really destinted to a multicast group @@ -1500,8 +1497,8 @@ int pim_rcv_v1(struct sk_buff * skb) */ if (!ipv4_is_multicast(encap->daddr) || encap->tot_len == 0 || - ntohs(encap->tot_len) + sizeof(*pim) > skb->len) - goto drop; + ntohs(encap->tot_len) + pimlen > skb->len) + return 1; read_lock(&mrt_lock); if (reg_vif_num >= 0) @@ -1511,7 +1508,7 @@ int pim_rcv_v1(struct sk_buff * skb) read_unlock(&mrt_lock); if (reg_dev == NULL) - goto drop; + return 1; skb->mac_header = skb->network_header; skb_pull(skb, (u8*)encap - skb->data); @@ -1527,9 +1524,33 @@ int pim_rcv_v1(struct sk_buff * skb) nf_reset(skb); netif_rx(skb); dev_put(reg_dev); + return 0; - drop: - kfree_skb(skb); +} +#endif + +#ifdef CONFIG_IP_PIMSM_V1 +/* + * Handle IGMP messages of PIMv1 + */ + +int pim_rcv_v1(struct sk_buff * skb) +{ + struct igmphdr *pim; + + if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr))) + goto drop; + + pim = igmp_hdr(skb); + + if (!mroute_do_pim || + pim->group != PIM_V1_VERSION || pim->code != PIM_V1_REGISTER) + goto drop; + + if (__pim_rcv(skb, sizeof(*pim))) { +drop: + kfree_skb(skb); + } return 0; } #endif @@ -1538,10 +1559,8 @@ int pim_rcv_v1(struct sk_buff * skb) static int pim_rcv(struct sk_buff * skb) { struct pimreghdr *pim; - struct iphdr *encap; - struct net_device *reg_dev = NULL; - if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap))) + if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(struct iphdr))) goto drop; pim = (struct pimreghdr *)skb_transport_header(skb); @@ -1551,41 +1570,10 @@ static int pim_rcv(struct sk_buff * skb) csum_fold(skb_checksum(skb, 0, skb->len, 0)))) goto drop; - /* check if the inner packet is destined to mcast group */ - encap = (struct iphdr *)(skb_transport_header(skb) + - sizeof(struct pimreghdr)); - if (!ipv4_is_multicast(encap->daddr) || - encap->tot_len == 0 || - ntohs(encap->tot_len) + sizeof(*pim) > skb->len) - goto drop; - - read_lock(&mrt_lock); - if (reg_vif_num >= 0) - reg_dev = vif_table[reg_vif_num].dev; - if (reg_dev) - dev_hold(reg_dev); - read_unlock(&mrt_lock); - - if (reg_dev == NULL) - goto drop; - - skb->mac_header = skb->network_header; - skb_pull(skb, (u8*)encap - skb->data); - skb_reset_network_header(skb); - skb->dev = reg_dev; - skb->protocol = htons(ETH_P_IP); - skb->ip_summed = 0; - skb->pkt_type = PACKET_HOST; - dst_release(skb->dst); - reg_dev->stats.rx_bytes += skb->len; - reg_dev->stats.rx_packets++; - skb->dst = NULL; - nf_reset(skb); - netif_rx(skb); - dev_put(reg_dev); - return 0; - drop: - kfree_skb(skb); + if (__pim_rcv(skb, sizeof(*pim))) { +drop: + kfree_skb(skb); + } return 0; } #endif @@ -1602,13 +1590,13 @@ ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm) if (dev) RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex); - mp_head = (struct rtattr*)skb_put(skb, RTA_LENGTH(0)); + mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0)); for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) { if (c->mfc_un.res.ttls[ct] < 255) { if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4)) goto rtattr_failure; - nhp = (struct rtnexthop*)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); + nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); nhp->rtnh_flags = 0; nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; nhp->rtnh_ifindex = vif_table[ct].dev->ifindex; @@ -1634,7 +1622,7 @@ int ipmr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait) read_lock(&mrt_lock); cache = ipmr_cache_find(rt->rt_src, rt->rt_dst); - if (cache==NULL) { + if (cache == NULL) { struct sk_buff *skb2; struct iphdr *iph; struct net_device *dev; @@ -1866,15 +1854,16 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) const struct mfc_cache *mfc = v; const struct ipmr_mfc_iter *it = seq->private; - seq_printf(seq, "%08lX %08lX %-3d %8ld %8ld %8ld", + seq_printf(seq, "%08lX %08lX %-3hd", (unsigned long) mfc->mfc_mcastgrp, (unsigned long) mfc->mfc_origin, - mfc->mfc_parent, - mfc->mfc_un.res.pkt, - mfc->mfc_un.res.bytes, - mfc->mfc_un.res.wrong_if); + mfc->mfc_parent); if (it->cache != &mfc_unres_queue) { + seq_printf(seq, " %8lu %8lu %8lu", + mfc->mfc_un.res.pkt, + mfc->mfc_un.res.bytes, + mfc->mfc_un.res.wrong_if); for (n = mfc->mfc_un.res.minvif; n < mfc->mfc_un.res.maxvif; n++ ) { if (VIF_EXISTS(n) @@ -1883,6 +1872,11 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) " %2d:%-3d", n, mfc->mfc_un.res.ttls[n]); } + } else { + /* unresolved mfc_caches don't contain + * pkt, bytes and wrong_if values + */ + seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul); } seq_putc(seq, '\n'); } diff --git a/net/ipv4/netfilter.c b/net/ipv4/netfilter.c index 6efdb70b3eb2fb9106e031195f4caf56dd41d918..fdf6811c31a246df891495fdc76b46c00e5f783b 100644 --- a/net/ipv4/netfilter.c +++ b/net/ipv4/netfilter.c @@ -66,7 +66,7 @@ int ip_route_me_harder(struct sk_buff *skb, unsigned addr_type) #ifdef CONFIG_XFRM if (!(IPCB(skb)->flags & IPSKB_XFRM_TRANSFORMED) && xfrm_decode_session(skb, &fl, AF_INET) == 0) - if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0)) + if (xfrm_lookup(net, &skb->dst, &fl, skb->sk, 0)) return -1; #endif @@ -97,7 +97,7 @@ int ip_xfrm_me_harder(struct sk_buff *skb) dst = ((struct xfrm_dst *)dst)->route; dst_hold(dst); - if (xfrm_lookup(&dst, &fl, skb->sk, 0) < 0) + if (xfrm_lookup(dev_net(dst->dev), &dst, &fl, skb->sk, 0) < 0) return -1; dst_release(skb->dst); @@ -125,6 +125,7 @@ struct ip_rt_info { __be32 daddr; __be32 saddr; u_int8_t tos; + u_int32_t mark; }; static void nf_ip_saveroute(const struct sk_buff *skb, @@ -138,6 +139,7 @@ static void nf_ip_saveroute(const struct sk_buff *skb, rt_info->tos = iph->tos; rt_info->daddr = iph->daddr; rt_info->saddr = iph->saddr; + rt_info->mark = skb->mark; } } @@ -150,6 +152,7 @@ static int nf_ip_reroute(struct sk_buff *skb, const struct iphdr *iph = ip_hdr(skb); if (!(iph->tos == rt_info->tos + && skb->mark == rt_info->mark && iph->daddr == rt_info->daddr && iph->saddr == rt_info->saddr)) return ip_route_me_harder(skb, RTN_UNSPEC); diff --git a/net/ipv4/netfilter/arp_tables.c b/net/ipv4/netfilter/arp_tables.c index 8d70d29f1ccf8b7664829f3c83a1e5cd4c579062..7ea88b61cb0dd7d854c8e46e029ec3dcb40f057c 100644 --- a/net/ipv4/netfilter/arp_tables.c +++ b/net/ipv4/netfilter/arp_tables.c @@ -142,15 +142,15 @@ static inline int arp_packet_match(const struct arphdr *arphdr, ARPT_INV_TGTIP)) { dprintf("Source or target IP address mismatch.\n"); - dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n", - NIPQUAD(src_ipaddr), - NIPQUAD(arpinfo->smsk.s_addr), - NIPQUAD(arpinfo->src.s_addr), + dprintf("SRC: %pI4. Mask: %pI4. Target: %pI4.%s\n", + &src_ipaddr, + &arpinfo->smsk.s_addr, + &arpinfo->src.s_addr, arpinfo->invflags & ARPT_INV_SRCIP ? " (INV)" : ""); - dprintf("TGT: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n", - NIPQUAD(tgt_ipaddr), - NIPQUAD(arpinfo->tmsk.s_addr), - NIPQUAD(arpinfo->tgt.s_addr), + dprintf("TGT: %pI4 Mask: %pI4 Target: %pI4.%s\n", + &tgt_ipaddr, + &arpinfo->tmsk.s_addr, + &arpinfo->tgt.s_addr, arpinfo->invflags & ARPT_INV_TGTIP ? " (INV)" : ""); return 0; } diff --git a/net/ipv4/netfilter/arptable_filter.c b/net/ipv4/netfilter/arptable_filter.c index bee3d117661a54127666209e3005f9b2f7be7ebc..e091187e864fe95ac03437bc73cd0713f2d93a01 100644 --- a/net/ipv4/netfilter/arptable_filter.c +++ b/net/ipv4/netfilter/arptable_filter.c @@ -75,16 +75,6 @@ static unsigned int arpt_out_hook(unsigned int hook, dev_net(out)->ipv4.arptable_filter); } -static unsigned int arpt_forward_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - return arpt_do_table(skb, hook, in, out, - dev_net(in)->ipv4.arptable_filter); -} - static struct nf_hook_ops arpt_ops[] __read_mostly = { { .hook = arpt_in_hook, @@ -101,7 +91,7 @@ static struct nf_hook_ops arpt_ops[] __read_mostly = { .priority = NF_IP_PRI_FILTER, }, { - .hook = arpt_forward_hook, + .hook = arpt_in_hook, .owner = THIS_MODULE, .pf = NFPROTO_ARP, .hooknum = NF_ARP_FORWARD, diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c index 213fb27debc1e583adb548b4628ad0ac782d3492..ef8b6ca068b280aabe538d58af8da7c580d09b2b 100644 --- a/net/ipv4/netfilter/ip_tables.c +++ b/net/ipv4/netfilter/ip_tables.c @@ -94,15 +94,11 @@ ip_packet_match(const struct iphdr *ip, IPT_INV_DSTIP)) { dprintf("Source or dest mismatch.\n"); - dprintf("SRC: %u.%u.%u.%u. Mask: %u.%u.%u.%u. Target: %u.%u.%u.%u.%s\n", - NIPQUAD(ip->saddr), - NIPQUAD(ipinfo->smsk.s_addr), - NIPQUAD(ipinfo->src.s_addr), + dprintf("SRC: %pI4. Mask: %pI4. Target: %pI4.%s\n", + &ip->saddr, &ipinfo->smsk.s_addr, &ipinfo->src.s_addr, ipinfo->invflags & IPT_INV_SRCIP ? " (INV)" : ""); - dprintf("DST: %u.%u.%u.%u Mask: %u.%u.%u.%u Target: %u.%u.%u.%u.%s\n", - NIPQUAD(ip->daddr), - NIPQUAD(ipinfo->dmsk.s_addr), - NIPQUAD(ipinfo->dst.s_addr), + dprintf("DST: %pI4 Mask: %pI4 Target: %pI4.%s\n", + &ip->daddr, &ipinfo->dmsk.s_addr, &ipinfo->dst.s_addr, ipinfo->invflags & IPT_INV_DSTIP ? " (INV)" : ""); return false; } diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index 7ac1677419a9154331dc5d81ba0973bc5383c4e8..2e4f98b85524ab6fa7baf8c945dc2017e90fcfff 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -168,7 +168,7 @@ clusterip_config_init(const struct ipt_clusterip_tgt_info *i, __be32 ip, char buffer[16]; /* create proc dir entry */ - sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip)); + sprintf(buffer, "%pI4", &ip); c->pde = proc_create_data(buffer, S_IWUSR|S_IRUSR, clusterip_procdir, &clusterip_proc_fops, c); @@ -373,7 +373,7 @@ static bool clusterip_tg_check(const struct xt_tgchk_param *par) config = clusterip_config_find_get(e->ip.dst.s_addr, 1); if (!config) { if (!(cipinfo->flags & CLUSTERIP_FLAG_NEW)) { - printk(KERN_WARNING "CLUSTERIP: no config found for %u.%u.%u.%u, need 'new'\n", NIPQUAD(e->ip.dst.s_addr)); + printk(KERN_WARNING "CLUSTERIP: no config found for %pI4, need 'new'\n", &e->ip.dst.s_addr); return false; } else { struct net_device *dev; @@ -478,9 +478,8 @@ static void arp_print(struct arp_payload *payload) } hbuffer[--k]='\0'; - printk("src %u.%u.%u.%u@%s, dst %u.%u.%u.%u\n", - NIPQUAD(payload->src_ip), hbuffer, - NIPQUAD(payload->dst_ip)); + printk("src %pI4@%s, dst %pI4\n", + &payload->src_ip, hbuffer, &payload->dst_ip); } #endif diff --git a/net/ipv4/netfilter/ipt_LOG.c b/net/ipv4/netfilter/ipt_LOG.c index 7b5dbe118c091f84cb41ac5638dc88e8ba8fc638..27a78fbbd92bd63018ef9748e3d822ca0be2a35e 100644 --- a/net/ipv4/netfilter/ipt_LOG.c +++ b/net/ipv4/netfilter/ipt_LOG.c @@ -54,8 +54,8 @@ static void dump_packet(const struct nf_loginfo *info, /* Important fields: * TOS, len, DF/MF, fragment offset, TTL, src, dst, options. */ /* Max length: 40 "SRC=255.255.255.255 DST=255.255.255.255 " */ - printk("SRC=%u.%u.%u.%u DST=%u.%u.%u.%u ", - NIPQUAD(ih->saddr), NIPQUAD(ih->daddr)); + printk("SRC=%pI4 DST=%pI4 ", + &ih->saddr, &ih->daddr); /* Max length: 46 "LEN=65535 TOS=0xFF PREC=0xFF TTL=255 ID=65535 " */ printk("LEN=%u TOS=0x%02X PREC=0x%02X TTL=%u ID=%u ", @@ -262,8 +262,7 @@ static void dump_packet(const struct nf_loginfo *info, break; case ICMP_REDIRECT: /* Max length: 24 "GATEWAY=255.255.255.255 " */ - printk("GATEWAY=%u.%u.%u.%u ", - NIPQUAD(ich->un.gateway)); + printk("GATEWAY=%pI4 ", &ich->un.gateway); /* Fall through */ case ICMP_DEST_UNREACH: case ICMP_SOURCE_QUENCH: diff --git a/net/ipv4/netfilter/ipt_addrtype.c b/net/ipv4/netfilter/ipt_addrtype.c index 88762f02779d001270a9186c1f1569aed7fe6068..3b216be3bc9fbcf940d00dff5c8d428ec229fe59 100644 --- a/net/ipv4/netfilter/ipt_addrtype.c +++ b/net/ipv4/netfilter/ipt_addrtype.c @@ -23,24 +23,25 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Patrick McHardy "); MODULE_DESCRIPTION("Xtables: address type match for IPv4"); -static inline bool match_type(const struct net_device *dev, __be32 addr, - u_int16_t mask) +static inline bool match_type(struct net *net, const struct net_device *dev, + __be32 addr, u_int16_t mask) { - return !!(mask & (1 << inet_dev_addr_type(&init_net, dev, addr))); + return !!(mask & (1 << inet_dev_addr_type(net, dev, addr))); } static bool addrtype_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) { + struct net *net = dev_net(par->in ? par->in : par->out); const struct ipt_addrtype_info *info = par->matchinfo; const struct iphdr *iph = ip_hdr(skb); bool ret = true; if (info->source) - ret &= match_type(NULL, iph->saddr, info->source) ^ + ret &= match_type(net, NULL, iph->saddr, info->source) ^ info->invert_source; if (info->dest) - ret &= match_type(NULL, iph->daddr, info->dest) ^ + ret &= match_type(net, NULL, iph->daddr, info->dest) ^ info->invert_dest; return ret; @@ -49,6 +50,7 @@ addrtype_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) static bool addrtype_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) { + struct net *net = dev_net(par->in ? par->in : par->out); const struct ipt_addrtype_info_v1 *info = par->matchinfo; const struct iphdr *iph = ip_hdr(skb); const struct net_device *dev = NULL; @@ -60,10 +62,10 @@ addrtype_mt_v1(const struct sk_buff *skb, const struct xt_match_param *par) dev = par->out; if (info->source) - ret &= match_type(dev, iph->saddr, info->source) ^ + ret &= match_type(net, dev, iph->saddr, info->source) ^ (info->flags & IPT_ADDRTYPE_INVERT_SOURCE); if (ret && info->dest) - ret &= match_type(dev, iph->daddr, info->dest) ^ + ret &= match_type(net, dev, iph->daddr, info->dest) ^ !!(info->flags & IPT_ADDRTYPE_INVERT_DEST); return ret; } diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c index 4a7c35275396381f787b3bef34121ee4ec7c24ef..b2141e11575ebb33cb93deec8202525a70348eb5 100644 --- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c +++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c @@ -60,9 +60,8 @@ static bool ipv4_invert_tuple(struct nf_conntrack_tuple *tuple, static int ipv4_print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple) { - return seq_printf(s, "src=%u.%u.%u.%u dst=%u.%u.%u.%u ", - NIPQUAD(tuple->src.u3.ip), - NIPQUAD(tuple->dst.u3.ip)); + return seq_printf(s, "src=%pI4 dst=%pI4 ", + &tuple->src.u3.ip, &tuple->dst.u3.ip); } static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff, @@ -198,7 +197,7 @@ static ctl_table ip_ct_sysctl_table[] = { .data = &nf_conntrack_max, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_NF_CONNTRACK_COUNT, @@ -206,7 +205,7 @@ static ctl_table ip_ct_sysctl_table[] = { .data = &init_net.ct.count, .maxlen = sizeof(int), .mode = 0444, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_NF_CONNTRACK_BUCKETS, @@ -214,7 +213,7 @@ static ctl_table ip_ct_sysctl_table[] = { .data = &nf_conntrack_htable_size, .maxlen = sizeof(unsigned int), .mode = 0444, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_NF_CONNTRACK_CHECKSUM, @@ -222,7 +221,7 @@ static ctl_table ip_ct_sysctl_table[] = { .data = &init_net.ct.sysctl_checksum, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_NF_CONNTRACK_LOG_INVALID, @@ -230,8 +229,8 @@ static ctl_table ip_ct_sysctl_table[] = { .data = &init_net.ct.sysctl_log_invalid, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &log_invalid_proto_min, .extra2 = &log_invalid_proto_max, }, @@ -284,17 +283,17 @@ getorigdst(struct sock *sk, int optval, void __user *user, int *len) .tuple.dst.u3.ip; memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); - pr_debug("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n", - NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); + pr_debug("SO_ORIGINAL_DST: %pI4 %u\n", + &sin.sin_addr.s_addr, ntohs(sin.sin_port)); nf_ct_put(ct); if (copy_to_user(user, &sin, sizeof(sin)) != 0) return -EFAULT; else return 0; } - pr_debug("SO_ORIGINAL_DST: Can't find %u.%u.%u.%u/%u-%u.%u.%u.%u/%u.\n", - NIPQUAD(tuple.src.u3.ip), ntohs(tuple.src.u.tcp.port), - NIPQUAD(tuple.dst.u3.ip), ntohs(tuple.dst.u.tcp.port)); + pr_debug("SO_ORIGINAL_DST: Can't find %pI4/%u-%pI4/%u.\n", + &tuple.src.u3.ip, ntohs(tuple.src.u.tcp.port), + &tuple.dst.u3.ip, ntohs(tuple.dst.u.tcp.port)); return -ENOENT; } diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c index 4e88792202226368c315c33ddda0eb9c68bbfe77..1fd3ef7718b60cfec90235220f9494c6c3f05757 100644 --- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c +++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c @@ -272,7 +272,7 @@ static struct ctl_table icmp_sysctl_table[] = { .data = &nf_ct_icmp_timeout, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 @@ -285,7 +285,7 @@ static struct ctl_table icmp_compat_sysctl_table[] = { .data = &nf_ct_icmp_timeout, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 diff --git a/net/ipv4/netfilter/nf_nat_h323.c b/net/ipv4/netfilter/nf_nat_h323.c index ee47bf28c82547463629288cc16249bcceb1e20c..7e8e6fc754133526abf86638b176e2c9e4d005e0 100644 --- a/net/ipv4/netfilter/nf_nat_h323.c +++ b/net/ipv4/netfilter/nf_nat_h323.c @@ -119,10 +119,9 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct, (ntohl(addr.ip) & 0xff000000) == 0x7f000000) i = 0; - pr_debug("nf_nat_ras: set signal address " - "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", - NIPQUAD(addr.ip), port, - NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip), + pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n", + &addr.ip, port, + &ct->tuplehash[!dir].tuple.dst.u3.ip, info->sig_port[!dir]); return set_h225_addr(skb, data, 0, &taddr[i], &ct->tuplehash[!dir]. @@ -131,10 +130,9 @@ static int set_sig_addr(struct sk_buff *skb, struct nf_conn *ct, } else if (addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && port == info->sig_port[dir]) { /* GK->GW */ - pr_debug("nf_nat_ras: set signal address " - "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", - NIPQUAD(addr.ip), port, - NIPQUAD(ct->tuplehash[!dir].tuple.src.u3.ip), + pr_debug("nf_nat_ras: set signal address %pI4:%hu->%pI4:%hu\n", + &addr.ip, port, + &ct->tuplehash[!dir].tuple.src.u3.ip, info->sig_port[!dir]); return set_h225_addr(skb, data, 0, &taddr[i], &ct->tuplehash[!dir]. @@ -162,10 +160,9 @@ static int set_ras_addr(struct sk_buff *skb, struct nf_conn *ct, if (get_h225_addr(ct, *data, &taddr[i], &addr, &port) && addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && port == ct->tuplehash[dir].tuple.src.u.udp.port) { - pr_debug("nf_nat_ras: set rasAddress " - "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", - NIPQUAD(addr.ip), ntohs(port), - NIPQUAD(ct->tuplehash[!dir].tuple.dst.u3.ip), + pr_debug("nf_nat_ras: set rasAddress %pI4:%hu->%pI4:%hu\n", + &addr.ip, ntohs(port), + &ct->tuplehash[!dir].tuple.dst.u3.ip, ntohs(ct->tuplehash[!dir].tuple.dst.u.udp.port)); return set_h225_addr(skb, data, 0, &taddr[i], &ct->tuplehash[!dir].tuple.dst.u3, @@ -257,15 +254,15 @@ static int nat_rtp_rtcp(struct sk_buff *skb, struct nf_conn *ct, } /* Success */ - pr_debug("nf_nat_h323: expect RTP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", - NIPQUAD(rtp_exp->tuple.src.u3.ip), + pr_debug("nf_nat_h323: expect RTP %pI4:%hu->%pI4:%hu\n", + &rtp_exp->tuple.src.u3.ip, ntohs(rtp_exp->tuple.src.u.udp.port), - NIPQUAD(rtp_exp->tuple.dst.u3.ip), + &rtp_exp->tuple.dst.u3.ip, ntohs(rtp_exp->tuple.dst.u.udp.port)); - pr_debug("nf_nat_h323: expect RTCP %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", - NIPQUAD(rtcp_exp->tuple.src.u3.ip), + pr_debug("nf_nat_h323: expect RTCP %pI4:%hu->%pI4:%hu\n", + &rtcp_exp->tuple.src.u3.ip, ntohs(rtcp_exp->tuple.src.u.udp.port), - NIPQUAD(rtcp_exp->tuple.dst.u3.ip), + &rtcp_exp->tuple.dst.u3.ip, ntohs(rtcp_exp->tuple.dst.u.udp.port)); return 0; @@ -307,10 +304,10 @@ static int nat_t120(struct sk_buff *skb, struct nf_conn *ct, return -1; } - pr_debug("nf_nat_h323: expect T.120 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", - NIPQUAD(exp->tuple.src.u3.ip), + pr_debug("nf_nat_h323: expect T.120 %pI4:%hu->%pI4:%hu\n", + &exp->tuple.src.u3.ip, ntohs(exp->tuple.src.u.tcp.port), - NIPQUAD(exp->tuple.dst.u3.ip), + &exp->tuple.dst.u3.ip, ntohs(exp->tuple.dst.u.tcp.port)); return 0; @@ -361,10 +358,10 @@ static int nat_h245(struct sk_buff *skb, struct nf_conn *ct, return -1; } - pr_debug("nf_nat_q931: expect H.245 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", - NIPQUAD(exp->tuple.src.u3.ip), + pr_debug("nf_nat_q931: expect H.245 %pI4:%hu->%pI4:%hu\n", + &exp->tuple.src.u3.ip, ntohs(exp->tuple.src.u.tcp.port), - NIPQUAD(exp->tuple.dst.u3.ip), + &exp->tuple.dst.u3.ip, ntohs(exp->tuple.dst.u.tcp.port)); return 0; @@ -455,10 +452,10 @@ static int nat_q931(struct sk_buff *skb, struct nf_conn *ct, } /* Success */ - pr_debug("nf_nat_ras: expect Q.931 %u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", - NIPQUAD(exp->tuple.src.u3.ip), + pr_debug("nf_nat_ras: expect Q.931 %pI4:%hu->%pI4:%hu\n", + &exp->tuple.src.u3.ip, ntohs(exp->tuple.src.u.tcp.port), - NIPQUAD(exp->tuple.dst.u3.ip), + &exp->tuple.dst.u3.ip, ntohs(exp->tuple.dst.u.tcp.port)); return 0; @@ -524,11 +521,10 @@ static int nat_callforwarding(struct sk_buff *skb, struct nf_conn *ct, } /* Success */ - pr_debug("nf_nat_q931: expect Call Forwarding " - "%u.%u.%u.%u:%hu->%u.%u.%u.%u:%hu\n", - NIPQUAD(exp->tuple.src.u3.ip), + pr_debug("nf_nat_q931: expect Call Forwarding %pI4:%hu->%pI4:%hu\n", + &exp->tuple.src.u3.ip, ntohs(exp->tuple.src.u.tcp.port), - NIPQUAD(exp->tuple.dst.u3.ip), + &exp->tuple.dst.u3.ip, ntohs(exp->tuple.dst.u.tcp.port)); return 0; diff --git a/net/ipv4/netfilter/nf_nat_irc.c b/net/ipv4/netfilter/nf_nat_irc.c index fe6f9cef6c854d4c13c9a8ecb5951a6f33f68b00..ea83a886b03e6ac3204f410047542a9edea8c4dc 100644 --- a/net/ipv4/netfilter/nf_nat_irc.c +++ b/net/ipv4/netfilter/nf_nat_irc.c @@ -55,8 +55,8 @@ static unsigned int help(struct sk_buff *skb, ip = ntohl(exp->master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip); sprintf(buffer, "%u %u", ip, port); - pr_debug("nf_nat_irc: inserting '%s' == %u.%u.%u.%u, port %u\n", - buffer, NIPQUAD(ip), port); + pr_debug("nf_nat_irc: inserting '%s' == %pI4, port %u\n", + buffer, &ip, port); ret = nf_nat_mangle_tcp_packet(skb, exp->master, ctinfo, matchoff, matchlen, buffer, diff --git a/net/ipv4/netfilter/nf_nat_rule.c b/net/ipv4/netfilter/nf_nat_rule.c index 8d489e746b21cb513d0d1b49b3984b514f6e634c..a7eb04719044f0107be50104c874c3cbc84be128 100644 --- a/net/ipv4/netfilter/nf_nat_rule.c +++ b/net/ipv4/netfilter/nf_nat_rule.c @@ -86,25 +86,6 @@ ipt_snat_target(struct sk_buff *skb, const struct xt_target_param *par) return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_SRC); } -/* Before 2.6.11 we did implicit source NAT if required. Warn about change. */ -static void warn_if_extra_mangle(struct net *net, __be32 dstip, __be32 srcip) -{ - static int warned = 0; - struct flowi fl = { .nl_u = { .ip4_u = { .daddr = dstip } } }; - struct rtable *rt; - - if (ip_route_output_key(net, &rt, &fl) != 0) - return; - - if (rt->rt_src != srcip && !warned) { - printk("NAT: no longer support implicit source local NAT\n"); - printk("NAT: packet src %u.%u.%u.%u -> dst %u.%u.%u.%u\n", - NIPQUAD(srcip), NIPQUAD(dstip)); - warned = 1; - } - ip_rt_put(rt); -} - static unsigned int ipt_dnat_target(struct sk_buff *skb, const struct xt_target_param *par) { @@ -120,11 +101,6 @@ ipt_dnat_target(struct sk_buff *skb, const struct xt_target_param *par) /* Connection must be valid and new. */ NF_CT_ASSERT(ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED)); - if (par->hooknum == NF_INET_LOCAL_OUT && - mr->range[0].flags & IP_NAT_RANGE_MAP_IPS) - warn_if_extra_mangle(dev_net(par->out), ip_hdr(skb)->daddr, - mr->range[0].min_ip); - return nf_nat_setup_info(ct, &mr->range[0], IP_NAT_MANIP_DST); } @@ -166,8 +142,7 @@ alloc_null_binding(struct nf_conn *ct, unsigned int hooknum) struct nf_nat_range range = { IP_NAT_RANGE_MAP_IPS, ip, ip, { 0 }, { 0 } }; - pr_debug("Allocating NULL binding for %p (%u.%u.%u.%u)\n", - ct, NIPQUAD(ip)); + pr_debug("Allocating NULL binding for %p (%pI4)\n", ct, &ip); return nf_nat_setup_info(ct, &range, HOOK2MANIP(hooknum)); } diff --git a/net/ipv4/netfilter/nf_nat_sip.c b/net/ipv4/netfilter/nf_nat_sip.c index 14544320c54577233ead8b41369eedc1c65d7720..07d61a57613c6a0a21685874b497559c2a005619 100644 --- a/net/ipv4/netfilter/nf_nat_sip.c +++ b/net/ipv4/netfilter/nf_nat_sip.c @@ -74,8 +74,7 @@ static int map_addr(struct sk_buff *skb, if (newaddr == addr->ip && newport == port) return 1; - buflen = sprintf(buffer, "%u.%u.%u.%u:%u", - NIPQUAD(newaddr), ntohs(newport)); + buflen = sprintf(buffer, "%pI4:%u", &newaddr, ntohs(newport)); return mangle_packet(skb, dptr, datalen, matchoff, matchlen, buffer, buflen); @@ -152,8 +151,8 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, &addr) > 0 && addr.ip == ct->tuplehash[dir].tuple.src.u3.ip && addr.ip != ct->tuplehash[!dir].tuple.dst.u3.ip) { - __be32 ip = ct->tuplehash[!dir].tuple.dst.u3.ip; - buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip)); + buflen = sprintf(buffer, "%pI4", + &ct->tuplehash[!dir].tuple.dst.u3.ip); if (!mangle_packet(skb, dptr, datalen, poff, plen, buffer, buflen)) return NF_DROP; @@ -166,8 +165,8 @@ static unsigned int ip_nat_sip(struct sk_buff *skb, &addr) > 0 && addr.ip == ct->tuplehash[dir].tuple.dst.u3.ip && addr.ip != ct->tuplehash[!dir].tuple.src.u3.ip) { - __be32 ip = ct->tuplehash[!dir].tuple.src.u3.ip; - buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(ip)); + buflen = sprintf(buffer, "%pI4", + &ct->tuplehash[!dir].tuple.src.u3.ip); if (!mangle_packet(skb, dptr, datalen, poff, plen, buffer, buflen)) return NF_DROP; @@ -279,8 +278,7 @@ static unsigned int ip_nat_sip_expect(struct sk_buff *skb, if (exp->tuple.dst.u3.ip != exp->saved_ip || exp->tuple.dst.u.udp.port != exp->saved_proto.udp.port) { - buflen = sprintf(buffer, "%u.%u.%u.%u:%u", - NIPQUAD(newip), port); + buflen = sprintf(buffer, "%pI4:%u", &newip, port); if (!mangle_packet(skb, dptr, datalen, matchoff, matchlen, buffer, buflen)) goto err; @@ -345,7 +343,7 @@ static unsigned int ip_nat_sdp_addr(struct sk_buff *skb, const char **dptr, char buffer[sizeof("nnn.nnn.nnn.nnn")]; unsigned int buflen; - buflen = sprintf(buffer, NIPQUAD_FMT, NIPQUAD(addr->ip)); + buflen = sprintf(buffer, "%pI4", &addr->ip); if (mangle_sdp_packet(skb, dptr, dataoff, datalen, type, term, buffer, buflen)) return 0; @@ -380,7 +378,7 @@ static unsigned int ip_nat_sdp_session(struct sk_buff *skb, const char **dptr, unsigned int buflen; /* Mangle session description owner and contact addresses */ - buflen = sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(addr->ip)); + buflen = sprintf(buffer, "%pI4", &addr->ip); if (mangle_sdp_packet(skb, dptr, dataoff, datalen, SDP_HDR_OWNER_IP4, SDP_HDR_MEDIA, buffer, buflen)) diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index 8303e4b406c05b15245d7f89d8e0c2d16f50b992..182f845de92f762e76a5bb5546aa417cf81330bf 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -930,8 +930,8 @@ static inline void mangle_address(unsigned char *begin, } if (debug) - printk(KERN_DEBUG "bsalg: mapped %u.%u.%u.%u to " - "%u.%u.%u.%u\n", NIPQUAD(old), NIPQUAD(*addr)); + printk(KERN_DEBUG "bsalg: mapped %pI4 to %pI4\n", + &old, addr); } } @@ -1267,9 +1267,8 @@ static int help(struct sk_buff *skb, unsigned int protoff, */ if (ntohs(udph->len) != skb->len - (iph->ihl << 2)) { if (net_ratelimit()) - printk(KERN_WARNING "SNMP: dropping malformed packet " - "src=%u.%u.%u.%u dst=%u.%u.%u.%u\n", - NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); + printk(KERN_WARNING "SNMP: dropping malformed packet src=%pI4 dst=%pI4\n", + &iph->saddr, &iph->daddr); return NF_DROP; } diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index a631a1f110caab546d4d5e46aff34d7f67c66f03..614958b7c27695aa6ed2a60822dd759b64648214 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c @@ -54,8 +54,9 @@ static int sockstat_seq_show(struct seq_file *seq, void *v) socket_seq_show(seq); seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %d\n", sock_prot_inuse_get(net, &tcp_prot), - atomic_read(&tcp_orphan_count), - tcp_death_row.tw_count, atomic_read(&tcp_sockets_allocated), + (int)percpu_counter_sum_positive(&tcp_orphan_count), + tcp_death_row.tw_count, + (int)percpu_counter_sum_positive(&tcp_sockets_allocated), atomic_read(&tcp_memory_allocated)); seq_printf(seq, "UDP: inuse %d mem %d\n", sock_prot_inuse_get(net, &udp_prot), @@ -234,6 +235,9 @@ static const struct snmp_mib snmp4_net_list[] = { SNMP_MIB_ITEM("TCPSpuriousRTOs", LINUX_MIB_TCPSPURIOUSRTOS), SNMP_MIB_ITEM("TCPMD5NotFound", LINUX_MIB_TCPMD5NOTFOUND), SNMP_MIB_ITEM("TCPMD5Unexpected", LINUX_MIB_TCPMD5UNEXPECTED), + SNMP_MIB_ITEM("TCPSackShifted", LINUX_MIB_SACKSHIFTED), + SNMP_MIB_ITEM("TCPSackMerged", LINUX_MIB_SACKMERGED), + SNMP_MIB_ITEM("TCPSackShiftFallback", LINUX_MIB_SACKSHIFTFALLBACK), SNMP_MIB_SENTINEL }; diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index cd975743bcd2f098ab449589b7145c95b7f3bc86..dff8bc4e0facd1cc804397bfc7e9c581962ae7c9 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -247,7 +247,7 @@ static void raw_err(struct sock *sk, struct sk_buff *skb, u32 info) } if (inet->recverr) { - struct iphdr *iph = (struct iphdr*)skb->data; + struct iphdr *iph = (struct iphdr *)skb->data; u8 *payload = skb->data + (iph->ihl << 2); if (inet->hdrincl) @@ -465,7 +465,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, */ if (msg->msg_namelen) { - struct sockaddr_in *usin = (struct sockaddr_in*)msg->msg_name; + struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name; err = -EINVAL; if (msg->msg_namelen < sizeof(*usin)) goto out; @@ -572,7 +572,7 @@ back_from_confirm: ipc.addr = rt->rt_dst; lock_sock(sk); err = ip_append_data(sk, ip_generic_getfrag, msg->msg_iov, len, 0, - &ipc, rt, msg->msg_flags); + &ipc, &rt, msg->msg_flags); if (err) ip_flush_pending_frames(sk); else if (!(msg->msg_flags & MSG_MORE)) @@ -851,7 +851,7 @@ struct proto raw_prot = { static struct sock *raw_get_first(struct seq_file *seq) { struct sock *sk; - struct raw_iter_state* state = raw_seq_private(seq); + struct raw_iter_state *state = raw_seq_private(seq); for (state->bucket = 0; state->bucket < RAW_HTABLE_SIZE; ++state->bucket) { @@ -868,7 +868,7 @@ found: static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk) { - struct raw_iter_state* state = raw_seq_private(seq); + struct raw_iter_state *state = raw_seq_private(seq); do { sk = sk_next(sk); diff --git a/net/ipv4/route.c b/net/ipv4/route.c index 2ea6dcc3e2ccd62b6faedb97b31e2206f121764a..77bfba975959efcd52047656281101adaa185ffc 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -129,6 +129,7 @@ static int ip_rt_mtu_expires __read_mostly = 10 * 60 * HZ; static int ip_rt_min_pmtu __read_mostly = 512 + 20 + 20; static int ip_rt_min_advmss __read_mostly = 256; static int ip_rt_secret_interval __read_mostly = 10 * 60 * HZ; +static int rt_chain_length_max __read_mostly = 20; static void rt_worker_func(struct work_struct *work); static DECLARE_DELAYED_WORK(expires_work, rt_worker_func); @@ -145,6 +146,7 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst); static void ipv4_link_failure(struct sk_buff *skb); static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu); static int rt_garbage_collect(struct dst_ops *ops); +static void rt_emergency_hash_rebuild(struct net *net); static struct dst_ops ipv4_dst_ops = { @@ -158,7 +160,6 @@ static struct dst_ops ipv4_dst_ops = { .link_failure = ipv4_link_failure, .update_pmtu = ip_rt_update_pmtu, .local_out = __ip_local_out, - .entry_size = sizeof(struct rtable), .entries = ATOMIC_INIT(0), }; @@ -201,6 +202,7 @@ const __u8 ip_tos2prio[16] = { struct rt_hash_bucket { struct rtable *chain; }; + #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) || \ defined(CONFIG_PROVE_LOCKING) /* @@ -674,6 +676,20 @@ static inline u32 rt_score(struct rtable *rt) return score; } +static inline bool rt_caching(const struct net *net) +{ + return net->ipv4.current_rt_cache_rebuild_count <= + net->ipv4.sysctl_rt_cache_rebuild_count; +} + +static inline bool compare_hash_inputs(const struct flowi *fl1, + const struct flowi *fl2) +{ + return (__force u32)(((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | + (fl1->nl_u.ip4_u.saddr ^ fl2->nl_u.ip4_u.saddr) | + (fl1->iif ^ fl2->iif)) == 0); +} + static inline int compare_keys(struct flowi *fl1, struct flowi *fl2) { return ((__force u32)((fl1->nl_u.ip4_u.daddr ^ fl2->nl_u.ip4_u.daddr) | @@ -753,11 +769,24 @@ static void rt_do_flush(int process_context) } } +/* + * While freeing expired entries, we compute average chain length + * and standard deviation, using fixed-point arithmetic. + * This to have an estimation of rt_chain_length_max + * rt_chain_length_max = max(elasticity, AVG + 4*SD) + * We use 3 bits for frational part, and 29 (or 61) for magnitude. + */ + +#define FRACT_BITS 3 +#define ONE (1UL << FRACT_BITS) + static void rt_check_expire(void) { static unsigned int rover; unsigned int i = rover, goal; struct rtable *rth, **rthp; + unsigned long length = 0, samples = 0; + unsigned long sum = 0, sum2 = 0; u64 mult; mult = ((u64)ip_rt_gc_interval) << rt_hash_log; @@ -766,6 +795,7 @@ static void rt_check_expire(void) goal = (unsigned int)mult; if (goal > rt_hash_mask) goal = rt_hash_mask + 1; + length = 0; for (; goal > 0; goal--) { unsigned long tmo = ip_rt_gc_timeout; @@ -775,6 +805,8 @@ static void rt_check_expire(void) if (need_resched()) cond_resched(); + samples++; + if (*rthp == NULL) continue; spin_lock_bh(rt_hash_lock_addr(i)); @@ -789,11 +821,29 @@ static void rt_check_expire(void) if (time_before_eq(jiffies, rth->u.dst.expires)) { tmo >>= 1; rthp = &rth->u.dst.rt_next; + /* + * Only bump our length if the hash + * inputs on entries n and n+1 are not + * the same, we only count entries on + * a chain with equal hash inputs once + * so that entries for different QOS + * levels, and other non-hash input + * attributes don't unfairly skew + * the length computation + */ + if ((*rthp == NULL) || + !compare_hash_inputs(&(*rthp)->fl, + &rth->fl)) + length += ONE; continue; } } else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout)) { tmo >>= 1; rthp = &rth->u.dst.rt_next; + if ((*rthp == NULL) || + !compare_hash_inputs(&(*rthp)->fl, + &rth->fl)) + length += ONE; continue; } @@ -802,6 +852,15 @@ static void rt_check_expire(void) rt_free(rth); } spin_unlock_bh(rt_hash_lock_addr(i)); + sum += length; + sum2 += length*length; + } + if (samples) { + unsigned long avg = sum / samples; + unsigned long sd = int_sqrt(sum2 / samples - avg*avg); + rt_chain_length_max = max_t(unsigned long, + ip_rt_gc_elasticity, + (avg + 4*sd) >> FRACT_BITS); } rover = i; } @@ -851,6 +910,26 @@ static void rt_secret_rebuild(unsigned long __net) mod_timer(&net->ipv4.rt_secret_timer, jiffies + ip_rt_secret_interval); } +static void rt_secret_rebuild_oneshot(struct net *net) +{ + del_timer_sync(&net->ipv4.rt_secret_timer); + rt_cache_invalidate(net); + if (ip_rt_secret_interval) { + net->ipv4.rt_secret_timer.expires += ip_rt_secret_interval; + add_timer(&net->ipv4.rt_secret_timer); + } +} + +static void rt_emergency_hash_rebuild(struct net *net) +{ + if (net_ratelimit()) { + printk(KERN_WARNING "Route hash chain too long!\n"); + printk(KERN_WARNING "Adjust your secret_interval!\n"); + } + + rt_secret_rebuild_oneshot(net); +} + /* Short description of GC goals. @@ -989,6 +1068,7 @@ out: return 0; static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp) { struct rtable *rth, **rthp; + struct rtable *rthi; unsigned long now; struct rtable *cand, **candp; u32 min_score; @@ -1002,7 +1082,13 @@ restart: candp = NULL; now = jiffies; + if (!rt_caching(dev_net(rt->u.dst.dev))) { + rt_drop(rt); + return 0; + } + rthp = &rt_hash_table[hash].chain; + rthi = NULL; spin_lock_bh(rt_hash_lock_addr(hash)); while ((rth = *rthp) != NULL) { @@ -1048,6 +1134,17 @@ restart: chain_length++; rthp = &rth->u.dst.rt_next; + + /* + * check to see if the next entry in the chain + * contains the same hash input values as rt. If it does + * This is where we will insert into the list, instead of + * at the head. This groups entries that differ by aspects not + * relvant to the hash function together, which we use to adjust + * our chain length + */ + if (*rthp && compare_hash_inputs(&(*rthp)->fl, &rt->fl)) + rthi = rth; } if (cand) { @@ -1061,6 +1158,16 @@ restart: *candp = cand->u.dst.rt_next; rt_free(cand); } + } else { + if (chain_length > rt_chain_length_max) { + struct net *net = dev_net(rt->u.dst.dev); + int num = ++net->ipv4.current_rt_cache_rebuild_count; + if (!rt_caching(dev_net(rt->u.dst.dev))) { + printk(KERN_WARNING "%s: %d rebuilds is over limit, route caching disabled\n", + rt->u.dst.dev->name, num); + } + rt_emergency_hash_rebuild(dev_net(rt->u.dst.dev)); + } } /* Try to bind route to arp only if it is output @@ -1098,14 +1205,17 @@ restart: } } - rt->u.dst.rt_next = rt_hash_table[hash].chain; + if (rthi) + rt->u.dst.rt_next = rthi->u.dst.rt_next; + else + rt->u.dst.rt_next = rt_hash_table[hash].chain; + #if RT_CACHE_DEBUG >= 2 if (rt->u.dst.rt_next) { struct rtable *trt; - printk(KERN_DEBUG "rt_cache @%02x: " NIPQUAD_FMT, hash, - NIPQUAD(rt->rt_dst)); + printk(KERN_DEBUG "rt_cache @%02x: %pI4", hash, &rt->rt_dst); for (trt = rt->u.dst.rt_next; trt; trt = trt->u.dst.rt_next) - printk(" . " NIPQUAD_FMT, NIPQUAD(trt->rt_dst)); + printk(" . %pI4", &trt->rt_dst); printk("\n"); } #endif @@ -1114,7 +1224,11 @@ restart: * previous writes to rt are comitted to memory * before making rt visible to other CPUS. */ - rcu_assign_pointer(rt_hash_table[hash].chain, rt); + if (rthi) + rcu_assign_pointer(rthi->u.dst.rt_next, rt); + else + rcu_assign_pointer(rt_hash_table[hash].chain, rt); + spin_unlock_bh(rt_hash_lock_addr(hash)); *rp = rt; return 0; @@ -1217,6 +1331,9 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, || ipv4_is_zeronet(new_gw)) goto reject_redirect; + if (!rt_caching(net)) + goto reject_redirect; + if (!IN_DEV_SHARED_MEDIA(in_dev)) { if (!inet_addr_onlink(in_dev, new_gw, old_gw)) goto reject_redirect; @@ -1267,7 +1384,6 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, /* Copy all the information. */ *rt = *rth; - INIT_RCU_HEAD(&rt->u.dst.rcu_head); rt->u.dst.__use = 1; atomic_set(&rt->u.dst.__refcnt, 1); rt->u.dst.child = NULL; @@ -1280,7 +1396,9 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, rt->u.dst.path = &rt->u.dst; rt->u.dst.neighbour = NULL; rt->u.dst.hh = NULL; +#ifdef CONFIG_XFRM rt->u.dst.xfrm = NULL; +#endif rt->rt_genid = rt_genid(net); rt->rt_flags |= RTCF_REDIRECTED; @@ -1324,11 +1442,10 @@ void ip_rt_redirect(__be32 old_gw, __be32 daddr, __be32 new_gw, reject_redirect: #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) - printk(KERN_INFO "Redirect from " NIPQUAD_FMT " on %s about " - NIPQUAD_FMT " ignored.\n" - " Advised path = " NIPQUAD_FMT " -> " NIPQUAD_FMT "\n", - NIPQUAD(old_gw), dev->name, NIPQUAD(new_gw), - NIPQUAD(saddr), NIPQUAD(daddr)); + printk(KERN_INFO "Redirect from %pI4 on %s about %pI4 ignored.\n" + " Advised path = %pI4 -> %pI4\n", + &old_gw, dev->name, &new_gw, + &saddr, &daddr); #endif in_dev_put(in_dev); } @@ -1348,9 +1465,8 @@ static struct dst_entry *ipv4_negative_advice(struct dst_entry *dst) rt->fl.oif, rt_genid(dev_net(dst->dev))); #if RT_CACHE_DEBUG >= 1 - printk(KERN_DEBUG "ipv4_negative_advice: redirect to " - NIPQUAD_FMT "/%02x dropped\n", - NIPQUAD(rt->rt_dst), rt->fl.fl4_tos); + printk(KERN_DEBUG "ipv4_negative_advice: redirect to %pI4/%02x dropped\n", + &rt->rt_dst, rt->fl.fl4_tos); #endif rt_del(hash, rt); ret = NULL; @@ -1414,10 +1530,9 @@ void ip_rt_send_redirect(struct sk_buff *skb) if (IN_DEV_LOG_MARTIANS(in_dev) && rt->u.dst.rate_tokens == ip_rt_redirect_number && net_ratelimit()) - printk(KERN_WARNING "host " NIPQUAD_FMT "/if%d ignores " - "redirects for " NIPQUAD_FMT " to " NIPQUAD_FMT ".\n", - NIPQUAD(rt->rt_src), rt->rt_iif, - NIPQUAD(rt->rt_dst), NIPQUAD(rt->rt_gateway)); + printk(KERN_WARNING "host %pI4/if%d ignores redirects for %pI4 to %pI4.\n", + &rt->rt_src, rt->rt_iif, + &rt->rt_dst, &rt->rt_gateway); #endif } out: @@ -1610,8 +1725,8 @@ static void ipv4_link_failure(struct sk_buff *skb) static int ip_rt_bug(struct sk_buff *skb) { - printk(KERN_DEBUG "ip_rt_bug: " NIPQUAD_FMT " -> " NIPQUAD_FMT ", %s\n", - NIPQUAD(ip_hdr(skb)->saddr), NIPQUAD(ip_hdr(skb)->daddr), + printk(KERN_DEBUG "ip_rt_bug: %pI4 -> %pI4, %s\n", + &ip_hdr(skb)->saddr, &ip_hdr(skb)->daddr, skb->dev ? skb->dev->name : "?"); kfree_skb(skb); return 0; @@ -1788,9 +1903,8 @@ static void ip_handle_martian_source(struct net_device *dev, * RFC1812 recommendation, if source is martian, * the only hint is MAC header. */ - printk(KERN_WARNING "martian source " NIPQUAD_FMT " from " - NIPQUAD_FMT", on dev %s\n", - NIPQUAD(daddr), NIPQUAD(saddr), dev->name); + printk(KERN_WARNING "martian source %pI4 from %pI4, on dev %s\n", + &daddr, &saddr, dev->name); if (dev->hard_header_len && skb_mac_header_was_set(skb)) { int i; const unsigned char *p = skb_mac_header(skb); @@ -2099,9 +2213,8 @@ martian_destination: RT_CACHE_STAT_INC(in_martian_dst); #ifdef CONFIG_IP_ROUTE_VERBOSE if (IN_DEV_LOG_MARTIANS(in_dev) && net_ratelimit()) - printk(KERN_WARNING "martian destination " NIPQUAD_FMT " from " - NIPQUAD_FMT ", dev %s\n", - NIPQUAD(daddr), NIPQUAD(saddr), dev->name); + printk(KERN_WARNING "martian destination %pI4 from %pI4, dev %s\n", + &daddr, &saddr, dev->name); #endif e_hostunreach: @@ -2130,6 +2243,10 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, struct net *net; net = dev_net(dev); + + if (!rt_caching(net)) + goto skip_cache; + tos &= IPTOS_RT_MASK; hash = rt_hash(daddr, saddr, iif, rt_genid(net)); @@ -2154,6 +2271,7 @@ int ip_route_input(struct sk_buff *skb, __be32 daddr, __be32 saddr, } rcu_read_unlock(); +skip_cache: /* Multicast recognition logic is moved from route cache to here. The problem was that too many Ethernet cards have broken/missing hardware multicast filters :-( As result the host on multicasting @@ -2539,6 +2657,9 @@ int __ip_route_output_key(struct net *net, struct rtable **rp, unsigned hash; struct rtable *rth; + if (!rt_caching(net)) + goto slow_output; + hash = rt_hash(flp->fl4_dst, flp->fl4_src, flp->oif, rt_genid(net)); rcu_read_lock_bh(); @@ -2563,6 +2684,7 @@ int __ip_route_output_key(struct net *net, struct rtable **rp, } rcu_read_unlock_bh(); +slow_output: return ip_route_output_slow(net, rp, flp); } @@ -2578,7 +2700,6 @@ static struct dst_ops ipv4_dst_blackhole_ops = { .destroy = ipv4_dst_destroy, .check = ipv4_dst_check, .update_pmtu = ipv4_rt_blackhole_update_pmtu, - .entry_size = sizeof(struct rtable), .entries = ATOMIC_INIT(0), }; @@ -2640,7 +2761,7 @@ int ip_route_output_flow(struct net *net, struct rtable **rp, struct flowi *flp, flp->fl4_src = (*rp)->rt_src; if (!flp->fl4_dst) flp->fl4_dst = (*rp)->rt_dst; - err = __xfrm_lookup((struct dst_entry **)rp, flp, sk, + err = __xfrm_lookup(net, (struct dst_entry **)rp, flp, sk, flags ? XFRM_LOOKUP_WAIT : 0); if (err == -EREMOTE) err = ipv4_dst_blackhole(net, rp, flp); @@ -2995,7 +3116,7 @@ static ctl_table ipv4_route_table[] = { .data = &ipv4_dst_ops.gc_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_ROUTE_MAX_SIZE, @@ -3003,7 +3124,7 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_max_size, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { /* Deprecated. Use gc_min_interval_ms */ @@ -3013,8 +3134,8 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_gc_min_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV4_ROUTE_GC_MIN_INTERVAL_MS, @@ -3022,8 +3143,8 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_gc_min_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_ms_jiffies, - .strategy = &sysctl_ms_jiffies, + .proc_handler = proc_dointvec_ms_jiffies, + .strategy = sysctl_ms_jiffies, }, { .ctl_name = NET_IPV4_ROUTE_GC_TIMEOUT, @@ -3031,8 +3152,8 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_gc_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV4_ROUTE_GC_INTERVAL, @@ -3040,8 +3161,8 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_gc_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV4_ROUTE_REDIRECT_LOAD, @@ -3049,7 +3170,7 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_redirect_load, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_ROUTE_REDIRECT_NUMBER, @@ -3057,7 +3178,7 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_redirect_number, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_ROUTE_REDIRECT_SILENCE, @@ -3065,7 +3186,7 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_redirect_silence, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_ROUTE_ERROR_COST, @@ -3073,7 +3194,7 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_error_cost, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_ROUTE_ERROR_BURST, @@ -3081,7 +3202,7 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_error_burst, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_ROUTE_GC_ELASTICITY, @@ -3089,7 +3210,7 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_gc_elasticity, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_ROUTE_MTU_EXPIRES, @@ -3097,8 +3218,8 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_mtu_expires, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV4_ROUTE_MIN_PMTU, @@ -3106,7 +3227,7 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_min_pmtu, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_ROUTE_MIN_ADVMSS, @@ -3114,7 +3235,7 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_min_advmss, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_ROUTE_SECRET_INTERVAL, @@ -3122,8 +3243,8 @@ static ctl_table ipv4_route_table[] = { .data = &ip_rt_secret_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &ipv4_sysctl_rt_secret_interval, - .strategy = &ipv4_sysctl_rt_secret_interval_strategy, + .proc_handler = ipv4_sysctl_rt_secret_interval, + .strategy = ipv4_sysctl_rt_secret_interval_strategy, }, { .ctl_name = 0 } }; @@ -3151,8 +3272,8 @@ static struct ctl_table ipv4_route_flush_table[] = { .procname = "flush", .maxlen = sizeof(int), .mode = 0200, - .proc_handler = &ipv4_sysctl_rtcache_flush, - .strategy = &ipv4_sysctl_rtcache_flush_strategy, + .proc_handler = ipv4_sysctl_rtcache_flush, + .strategy = ipv4_sysctl_rtcache_flush_strategy, }, { .ctl_name = 0 }, }; diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index 1bb10df8ce7dd94b89a0b43b170307557cf521f0..4710d219f06ae9df6c2754906ca09663ed4da738 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -195,7 +195,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_timestamps, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_TCP_WINDOW_SCALING, @@ -203,7 +203,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_window_scaling, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_TCP_SACK, @@ -211,7 +211,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_sack, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_TCP_RETRANS_COLLAPSE, @@ -219,7 +219,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_retrans_collapse, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_DEFAULT_TTL, @@ -227,8 +227,8 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_ip_default_ttl, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &ipv4_doint_and_flush, - .strategy = &ipv4_doint_and_flush_strategy, + .proc_handler = ipv4_doint_and_flush, + .strategy = ipv4_doint_and_flush_strategy, .extra2 = &init_net, }, { @@ -237,7 +237,7 @@ static struct ctl_table ipv4_table[] = { .data = &ipv4_config.no_pmtu_disc, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_NONLOCAL_BIND, @@ -245,7 +245,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_ip_nonlocal_bind, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_TCP_SYN_RETRIES, @@ -253,7 +253,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_syn_retries, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_SYNACK_RETRIES, @@ -261,7 +261,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_synack_retries, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_MAX_ORPHANS, @@ -269,7 +269,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_max_orphans, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_MAX_TW_BUCKETS, @@ -277,7 +277,7 @@ static struct ctl_table ipv4_table[] = { .data = &tcp_death_row.sysctl_max_tw_buckets, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_DYNADDR, @@ -285,7 +285,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_ip_dynaddr, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_TCP_KEEPALIVE_TIME, @@ -293,8 +293,8 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_keepalive_time, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies }, { .ctl_name = NET_IPV4_TCP_KEEPALIVE_PROBES, @@ -302,7 +302,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_keepalive_probes, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_TCP_KEEPALIVE_INTVL, @@ -310,8 +310,8 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_keepalive_intvl, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies }, { .ctl_name = NET_IPV4_TCP_RETRIES1, @@ -319,8 +319,8 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_retries1, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra2 = &tcp_retr1_max }, { @@ -329,7 +329,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_retries2, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_TCP_FIN_TIMEOUT, @@ -337,8 +337,8 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_fin_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies }, #ifdef CONFIG_SYN_COOKIES { @@ -347,7 +347,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_syncookies, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, #endif { @@ -356,7 +356,7 @@ static struct ctl_table ipv4_table[] = { .data = &tcp_death_row.sysctl_tw_recycle, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_ABORT_ON_OVERFLOW, @@ -364,7 +364,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_abort_on_overflow, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_STDURG, @@ -372,7 +372,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_stdurg, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_RFC1337, @@ -380,7 +380,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_rfc1337, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_MAX_SYN_BACKLOG, @@ -388,7 +388,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_max_syn_backlog, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_LOCAL_PORT_RANGE, @@ -396,8 +396,8 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_local_ports.range, .maxlen = sizeof(sysctl_local_ports.range), .mode = 0644, - .proc_handler = &ipv4_local_port_range, - .strategy = &ipv4_sysctl_local_port_range, + .proc_handler = ipv4_local_port_range, + .strategy = ipv4_sysctl_local_port_range, }, #ifdef CONFIG_IP_MULTICAST { @@ -406,7 +406,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_igmp_max_memberships, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, #endif @@ -416,7 +416,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_igmp_max_msf, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_INET_PEER_THRESHOLD, @@ -424,7 +424,7 @@ static struct ctl_table ipv4_table[] = { .data = &inet_peer_threshold, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_INET_PEER_MINTTL, @@ -432,8 +432,8 @@ static struct ctl_table ipv4_table[] = { .data = &inet_peer_minttl, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies }, { .ctl_name = NET_IPV4_INET_PEER_MAXTTL, @@ -441,8 +441,8 @@ static struct ctl_table ipv4_table[] = { .data = &inet_peer_maxttl, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies }, { .ctl_name = NET_IPV4_INET_PEER_GC_MINTIME, @@ -450,8 +450,8 @@ static struct ctl_table ipv4_table[] = { .data = &inet_peer_gc_mintime, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies }, { .ctl_name = NET_IPV4_INET_PEER_GC_MAXTIME, @@ -459,8 +459,8 @@ static struct ctl_table ipv4_table[] = { .data = &inet_peer_gc_maxtime, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies }, { .ctl_name = NET_TCP_ORPHAN_RETRIES, @@ -468,7 +468,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_orphan_retries, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_FACK, @@ -476,7 +476,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_fack, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_REORDERING, @@ -484,7 +484,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_reordering, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_ECN, @@ -492,7 +492,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_ecn, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_DSACK, @@ -500,7 +500,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_dsack, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_MEM, @@ -508,7 +508,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_mem, .maxlen = sizeof(sysctl_tcp_mem), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_WMEM, @@ -516,7 +516,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_wmem, .maxlen = sizeof(sysctl_tcp_wmem), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_RMEM, @@ -524,7 +524,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_rmem, .maxlen = sizeof(sysctl_tcp_rmem), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_APP_WIN, @@ -532,7 +532,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_app_win, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_ADV_WIN_SCALE, @@ -540,7 +540,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_adv_win_scale, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_TW_REUSE, @@ -548,7 +548,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_tw_reuse, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_FRTO, @@ -556,7 +556,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_frto, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_FRTO_RESPONSE, @@ -564,7 +564,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_frto_response, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_LOW_LATENCY, @@ -572,7 +572,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_low_latency, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_TCP_NO_METRICS_SAVE, @@ -580,7 +580,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_nometrics_save, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_TCP_MODERATE_RCVBUF, @@ -588,7 +588,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_moderate_rcvbuf, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_TCP_TSO_WIN_DIVISOR, @@ -596,15 +596,15 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_tso_win_divisor, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_TCP_CONG_CONTROL, .procname = "tcp_congestion_control", .mode = 0644, .maxlen = TCP_CA_NAME_MAX, - .proc_handler = &proc_tcp_congestion_control, - .strategy = &sysctl_tcp_congestion_control, + .proc_handler = proc_tcp_congestion_control, + .strategy = sysctl_tcp_congestion_control, }, { .ctl_name = NET_TCP_ABC, @@ -612,7 +612,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_abc, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_TCP_MTU_PROBING, @@ -620,7 +620,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_mtu_probing, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_TCP_BASE_MSS, @@ -628,7 +628,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_base_mss, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_TCP_WORKAROUND_SIGNED_WINDOWS, @@ -636,7 +636,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_workaround_signed_windows, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, #ifdef CONFIG_NET_DMA { @@ -645,7 +645,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_dma_copybreak, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, #endif { @@ -654,7 +654,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_slow_start_after_idle, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, #ifdef CONFIG_NETLABEL { @@ -663,7 +663,7 @@ static struct ctl_table ipv4_table[] = { .data = &cipso_v4_cache_enabled, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_CIPSOV4_CACHE_BUCKET_SIZE, @@ -671,7 +671,7 @@ static struct ctl_table ipv4_table[] = { .data = &cipso_v4_cache_bucketsize, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_CIPSOV4_RBM_OPTFMT, @@ -679,7 +679,7 @@ static struct ctl_table ipv4_table[] = { .data = &cipso_v4_rbm_optfmt, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_CIPSOV4_RBM_STRICTVALID, @@ -687,22 +687,22 @@ static struct ctl_table ipv4_table[] = { .data = &cipso_v4_rbm_strictvalid, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, #endif /* CONFIG_NETLABEL */ { .procname = "tcp_available_congestion_control", .maxlen = TCP_CA_BUF_MAX, .mode = 0444, - .proc_handler = &proc_tcp_available_congestion_control, + .proc_handler = proc_tcp_available_congestion_control, }, { .ctl_name = NET_TCP_ALLOWED_CONG_CONTROL, .procname = "tcp_allowed_congestion_control", .maxlen = TCP_CA_BUF_MAX, .mode = 0644, - .proc_handler = &proc_allowed_congestion_control, - .strategy = &strategy_allowed_congestion_control, + .proc_handler = proc_allowed_congestion_control, + .strategy = strategy_allowed_congestion_control, }, { .ctl_name = NET_TCP_MAX_SSTHRESH, @@ -710,7 +710,7 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_tcp_max_ssthresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = CTL_UNNUMBERED, @@ -718,8 +718,8 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_udp_mem, .maxlen = sizeof(sysctl_udp_mem), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &zero }, { @@ -728,8 +728,8 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_udp_rmem_min, .maxlen = sizeof(sysctl_udp_rmem_min), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &zero }, { @@ -738,8 +738,8 @@ static struct ctl_table ipv4_table[] = { .data = &sysctl_udp_wmem_min, .maxlen = sizeof(sysctl_udp_wmem_min), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &zero }, { .ctl_name = 0 } @@ -752,7 +752,7 @@ static struct ctl_table ipv4_net_table[] = { .data = &init_net.ipv4.sysctl_icmp_echo_ignore_all, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_ICMP_ECHO_IGNORE_BROADCASTS, @@ -760,7 +760,7 @@ static struct ctl_table ipv4_net_table[] = { .data = &init_net.ipv4.sysctl_icmp_echo_ignore_broadcasts, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES, @@ -768,7 +768,7 @@ static struct ctl_table ipv4_net_table[] = { .data = &init_net.ipv4.sysctl_icmp_ignore_bogus_error_responses, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR, @@ -776,7 +776,7 @@ static struct ctl_table ipv4_net_table[] = { .data = &init_net.ipv4.sysctl_icmp_errors_use_inbound_ifaddr, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV4_ICMP_RATELIMIT, @@ -784,8 +784,8 @@ static struct ctl_table ipv4_net_table[] = { .data = &init_net.ipv4.sysctl_icmp_ratelimit, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_ms_jiffies, - .strategy = &sysctl_ms_jiffies + .proc_handler = proc_dointvec_ms_jiffies, + .strategy = sysctl_ms_jiffies }, { .ctl_name = NET_IPV4_ICMP_RATEMASK, @@ -793,7 +793,15 @@ static struct ctl_table ipv4_net_table[] = { .data = &init_net.ipv4.sysctl_icmp_ratemask, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "rt_cache_rebuild_count", + .data = &init_net.ipv4.sysctl_rt_cache_rebuild_count, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec }, { } }; @@ -827,8 +835,12 @@ static __net_init int ipv4_sysctl_init_net(struct net *net) &net->ipv4.sysctl_icmp_ratelimit; table[5].data = &net->ipv4.sysctl_icmp_ratemask; + table[6].data = + &net->ipv4.sysctl_rt_cache_rebuild_count; } + net->ipv4.sysctl_rt_cache_rebuild_count = 4; + net->ipv4.ipv4_hdr = register_net_sysctl_table(net, net_ipv4_ctl_path, table); if (net->ipv4.ipv4_hdr == NULL) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index c5aca0bb116ae36ead0a824236ab4a5df9162d74..1f3d52946b3b84f604385fb5542390bb6b593ce1 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -277,8 +277,7 @@ int sysctl_tcp_fin_timeout __read_mostly = TCP_FIN_TIMEOUT; -atomic_t tcp_orphan_count = ATOMIC_INIT(0); - +struct percpu_counter tcp_orphan_count; EXPORT_SYMBOL_GPL(tcp_orphan_count); int sysctl_tcp_mem[3] __read_mostly; @@ -290,9 +289,12 @@ EXPORT_SYMBOL(sysctl_tcp_rmem); EXPORT_SYMBOL(sysctl_tcp_wmem); atomic_t tcp_memory_allocated; /* Current allocated memory. */ -atomic_t tcp_sockets_allocated; /* Current number of TCP sockets. */ - EXPORT_SYMBOL(tcp_memory_allocated); + +/* + * Current number of TCP sockets. + */ +struct percpu_counter tcp_sockets_allocated; EXPORT_SYMBOL(tcp_sockets_allocated); /* @@ -1680,7 +1682,7 @@ void tcp_set_state(struct sock *sk, int state) inet_put_port(sk); /* fall through */ default: - if (oldstate==TCP_ESTABLISHED) + if (oldstate == TCP_ESTABLISHED) TCP_DEC_STATS(sock_net(sk), TCP_MIB_CURRESTAB); } @@ -1690,7 +1692,7 @@ void tcp_set_state(struct sock *sk, int state) sk->sk_state = state; #ifdef STATE_TRACE - SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n",sk, statename[oldstate],statename[state]); + SOCK_DEBUG(sk, "TCP sk=%p, State %s -> %s\n", sk, statename[oldstate], statename[state]); #endif } EXPORT_SYMBOL_GPL(tcp_set_state); @@ -1834,7 +1836,7 @@ adjudge_to_death: state = sk->sk_state; sock_hold(sk); sock_orphan(sk); - atomic_inc(sk->sk_prot->orphan_count); + percpu_counter_inc(sk->sk_prot->orphan_count); /* It is the last release_sock in its life. It will remove backlog. */ release_sock(sk); @@ -1885,9 +1887,11 @@ adjudge_to_death: } } if (sk->sk_state != TCP_CLOSE) { + int orphan_count = percpu_counter_read_positive( + sk->sk_prot->orphan_count); + sk_mem_reclaim(sk); - if (tcp_too_many_orphans(sk, - atomic_read(sk->sk_prot->orphan_count))) { + if (tcp_too_many_orphans(sk, orphan_count)) { if (net_ratelimit()) printk(KERN_INFO "TCP: too many of orphaned " "sockets\n"); @@ -2461,6 +2465,106 @@ out: } EXPORT_SYMBOL(tcp_tso_segment); +struct sk_buff **tcp_gro_receive(struct sk_buff **head, struct sk_buff *skb) +{ + struct sk_buff **pp = NULL; + struct sk_buff *p; + struct tcphdr *th; + struct tcphdr *th2; + unsigned int thlen; + unsigned int flags; + unsigned int total; + unsigned int mss = 1; + int flush = 1; + + if (!pskb_may_pull(skb, sizeof(*th))) + goto out; + + th = tcp_hdr(skb); + thlen = th->doff * 4; + if (thlen < sizeof(*th)) + goto out; + + if (!pskb_may_pull(skb, thlen)) + goto out; + + th = tcp_hdr(skb); + __skb_pull(skb, thlen); + + flags = tcp_flag_word(th); + + for (; (p = *head); head = &p->next) { + if (!NAPI_GRO_CB(p)->same_flow) + continue; + + th2 = tcp_hdr(p); + + if (th->source != th2->source || th->dest != th2->dest) { + NAPI_GRO_CB(p)->same_flow = 0; + continue; + } + + goto found; + } + + goto out_check_final; + +found: + flush = NAPI_GRO_CB(p)->flush; + flush |= flags & TCP_FLAG_CWR; + flush |= (flags ^ tcp_flag_word(th2)) & + ~(TCP_FLAG_CWR | TCP_FLAG_FIN | TCP_FLAG_PSH); + flush |= th->ack_seq != th2->ack_seq || th->window != th2->window; + flush |= memcmp(th + 1, th2 + 1, thlen - sizeof(*th)); + + total = p->len; + mss = total; + if (skb_shinfo(p)->frag_list) + mss = skb_shinfo(p)->frag_list->len; + + flush |= skb->len > mss || skb->len <= 0; + flush |= ntohl(th2->seq) + total != ntohl(th->seq); + + if (flush || skb_gro_receive(head, skb)) { + mss = 1; + goto out_check_final; + } + + p = *head; + th2 = tcp_hdr(p); + tcp_flag_word(th2) |= flags & (TCP_FLAG_FIN | TCP_FLAG_PSH); + +out_check_final: + flush = skb->len < mss; + flush |= flags & (TCP_FLAG_URG | TCP_FLAG_PSH | TCP_FLAG_RST | + TCP_FLAG_SYN | TCP_FLAG_FIN); + + if (p && (!NAPI_GRO_CB(skb)->same_flow || flush)) + pp = head; + +out: + NAPI_GRO_CB(skb)->flush |= flush; + + return pp; +} + +int tcp_gro_complete(struct sk_buff *skb) +{ + struct tcphdr *th = tcp_hdr(skb); + + skb->csum_start = skb_transport_header(skb) - skb->head; + skb->csum_offset = offsetof(struct tcphdr, check); + skb->ip_summed = CHECKSUM_PARTIAL; + + skb_shinfo(skb)->gso_size = skb_shinfo(skb)->frag_list->len; + skb_shinfo(skb)->gso_segs = NAPI_GRO_CB(skb)->count; + + if (th->cwr) + skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN; + + return 0; +} + #ifdef CONFIG_TCP_MD5SIG static unsigned long tcp_md5sig_users; static struct tcp_md5sig_pool **tcp_md5sig_pool; @@ -2650,7 +2754,7 @@ EXPORT_SYMBOL(tcp_md5_hash_key); void tcp_done(struct sock *sk) { - if(sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) + if (sk->sk_state == TCP_SYN_SENT || sk->sk_state == TCP_SYN_RECV) TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_ATTEMPTFAILS); tcp_set_state(sk, TCP_CLOSE); @@ -2685,6 +2789,8 @@ void __init tcp_init(void) BUILD_BUG_ON(sizeof(struct tcp_skb_cb) > sizeof(skb->cb)); + percpu_counter_init(&tcp_sockets_allocated, 0); + percpu_counter_init(&tcp_orphan_count, 0); tcp_hashinfo.bind_bucket_cachep = kmem_cache_create("tcp_bind_bucket", sizeof(struct inet_bind_bucket), 0, @@ -2707,8 +2813,8 @@ void __init tcp_init(void) thash_entries ? 0 : 512 * 1024); tcp_hashinfo.ehash_size = 1 << tcp_hashinfo.ehash_size; for (i = 0; i < tcp_hashinfo.ehash_size; i++) { - INIT_HLIST_HEAD(&tcp_hashinfo.ehash[i].chain); - INIT_HLIST_HEAD(&tcp_hashinfo.ehash[i].twchain); + INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].chain, i); + INIT_HLIST_NULLS_HEAD(&tcp_hashinfo.ehash[i].twchain, i); } if (inet_ehash_locks_alloc(&tcp_hashinfo)) panic("TCP: failed to alloc ehash_locks"); diff --git a/net/ipv4/tcp_cubic.c b/net/ipv4/tcp_cubic.c index 4a1221e5e8ee2ec8b7d1a5157aa063f6a3f8011e..ee467ec40c4f3c0b08123d042921c2f87481632f 100644 --- a/net/ipv4/tcp_cubic.c +++ b/net/ipv4/tcp_cubic.c @@ -1,13 +1,23 @@ /* - * TCP CUBIC: Binary Increase Congestion control for TCP v2.2 + * TCP CUBIC: Binary Increase Congestion control for TCP v2.3 * 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 + * Sangtae Ha, Injong Rhee and Lisong Xu, + * "CUBIC: A New TCP-Friendly High-Speed TCP Variant" + * in ACM SIGOPS Operating System Review, July 2008. * Available from: - * http://netsrv.csc.ncsu.edu/export/cubic-paper.pdf + * http://netsrv.csc.ncsu.edu/export/cubic_a_new_tcp_2008.pdf + * + * CUBIC integrates a new slow start algorithm, called HyStart. + * The details of HyStart are presented in + * Sangtae Ha and Injong Rhee, + * "Taming the Elephants: New TCP Slow Start", NCSU TechReport 2008. + * Available from: + * http://netsrv.csc.ncsu.edu/export/hystart_techreport_2008.pdf + * + * All testing results are available from: + * http://netsrv.csc.ncsu.edu/wiki/index.php/TCP_Testing * * Unless CUBIC is enabled and congestion window is large * this behaves the same as the original Reno. @@ -23,12 +33,26 @@ */ #define BICTCP_HZ 10 /* BIC HZ 2^10 = 1024 */ +/* Two methods of hybrid slow start */ +#define HYSTART_ACK_TRAIN 0x1 +#define HYSTART_DELAY 0x2 + +/* Number of delay samples for detecting the increase of delay */ +#define HYSTART_MIN_SAMPLES 8 +#define HYSTART_DELAY_MIN (2U<<3) +#define HYSTART_DELAY_MAX (16U<<3) +#define HYSTART_DELAY_THRESH(x) clamp(x, HYSTART_DELAY_MIN, HYSTART_DELAY_MAX) + static int fast_convergence __read_mostly = 1; 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; +static int hystart __read_mostly = 1; +static int hystart_detect __read_mostly = HYSTART_ACK_TRAIN | HYSTART_DELAY; +static int hystart_low_window __read_mostly = 16; + static u32 cube_rtt_scale __read_mostly; static u32 beta_scale __read_mostly; static u64 cube_factor __read_mostly; @@ -44,6 +68,13 @@ module_param(bic_scale, int, 0444); MODULE_PARM_DESC(bic_scale, "scale (scaled by 1024) value for bic function (bic_scale/1024)"); module_param(tcp_friendliness, int, 0644); MODULE_PARM_DESC(tcp_friendliness, "turn on/off tcp friendliness"); +module_param(hystart, int, 0644); +MODULE_PARM_DESC(hystart, "turn on/off hybrid slow start algorithm"); +module_param(hystart_detect, int, 0644); +MODULE_PARM_DESC(hystart_detect, "hyrbrid slow start detection mechanisms" + " 1: packet-train 2: delay 3: both packet-train and delay"); +module_param(hystart_low_window, int, 0644); +MODULE_PARM_DESC(hystart_low_window, "lower bound cwnd for hybrid slow start"); /* BIC TCP Parameters */ struct bictcp { @@ -59,7 +90,13 @@ struct bictcp { u32 ack_cnt; /* number of acks */ u32 tcp_cwnd; /* estimated tcp cwnd */ #define ACK_RATIO_SHIFT 4 - u32 delayed_ack; /* estimate the ratio of Packets/ACKs << 4 */ + u16 delayed_ack; /* estimate the ratio of Packets/ACKs << 4 */ + u8 sample_cnt; /* number of samples to decide curr_rtt */ + u8 found; /* the exit point is found? */ + u32 round_start; /* beginning of each round */ + u32 end_seq; /* end_seq of the round */ + u32 last_jiffies; /* last time when the ACK spacing is close */ + u32 curr_rtt; /* the minimum rtt of current round */ }; static inline void bictcp_reset(struct bictcp *ca) @@ -76,12 +113,28 @@ static inline void bictcp_reset(struct bictcp *ca) ca->delayed_ack = 2 << ACK_RATIO_SHIFT; ca->ack_cnt = 0; ca->tcp_cwnd = 0; + ca->found = 0; +} + +static inline void bictcp_hystart_reset(struct sock *sk) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct bictcp *ca = inet_csk_ca(sk); + + ca->round_start = ca->last_jiffies = jiffies; + ca->end_seq = tp->snd_nxt; + ca->curr_rtt = 0; + ca->sample_cnt = 0; } static void bictcp_init(struct sock *sk) { bictcp_reset(inet_csk_ca(sk)); - if (initial_ssthresh) + + if (hystart) + bictcp_hystart_reset(sk); + + if (!hystart && initial_ssthresh) tcp_sk(sk)->snd_ssthresh = initial_ssthresh; } @@ -235,9 +288,11 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) if (!tcp_is_cwnd_limited(sk, in_flight)) return; - if (tp->snd_cwnd <= tp->snd_ssthresh) + if (tp->snd_cwnd <= tp->snd_ssthresh) { + if (hystart && after(ack, ca->end_seq)) + bictcp_hystart_reset(sk); tcp_slow_start(tp); - else { + } else { bictcp_update(ca, tp->snd_cwnd); /* In dangerous area, increase slowly. @@ -281,8 +336,45 @@ static u32 bictcp_undo_cwnd(struct sock *sk) static void bictcp_state(struct sock *sk, u8 new_state) { - if (new_state == TCP_CA_Loss) + if (new_state == TCP_CA_Loss) { bictcp_reset(inet_csk_ca(sk)); + bictcp_hystart_reset(sk); + } +} + +static void hystart_update(struct sock *sk, u32 delay) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct bictcp *ca = inet_csk_ca(sk); + + if (!(ca->found & hystart_detect)) { + u32 curr_jiffies = jiffies; + + /* first detection parameter - ack-train detection */ + if (curr_jiffies - ca->last_jiffies <= msecs_to_jiffies(2)) { + ca->last_jiffies = curr_jiffies; + if (curr_jiffies - ca->round_start >= ca->delay_min>>4) + ca->found |= HYSTART_ACK_TRAIN; + } + + /* obtain the minimum delay of more than sampling packets */ + if (ca->sample_cnt < HYSTART_MIN_SAMPLES) { + if (ca->curr_rtt == 0 || ca->curr_rtt > delay) + ca->curr_rtt = delay; + + ca->sample_cnt++; + } else { + if (ca->curr_rtt > ca->delay_min + + HYSTART_DELAY_THRESH(ca->delay_min>>4)) + ca->found |= HYSTART_DELAY; + } + /* + * Either one of two conditions are met, + * we exit from slow start immediately. + */ + if (ca->found & hystart_detect) + tp->snd_ssthresh = tp->snd_cwnd; + } } /* Track delayed acknowledgment ratio using sliding window @@ -291,6 +383,7 @@ static void bictcp_state(struct sock *sk, u8 new_state) static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt_us) { const struct inet_connection_sock *icsk = inet_csk(sk); + const struct tcp_sock *tp = tcp_sk(sk); struct bictcp *ca = inet_csk_ca(sk); u32 delay; @@ -314,6 +407,11 @@ static void bictcp_acked(struct sock *sk, u32 cnt, s32 rtt_us) /* first time call or link delay decreases */ if (ca->delay_min == 0 || ca->delay_min > delay) ca->delay_min = delay; + + /* hystart triggers when cwnd is larger than some threshold */ + if (hystart && tp->snd_cwnd <= tp->snd_ssthresh && + tp->snd_cwnd >= hystart_low_window) + hystart_update(sk, delay); } static struct tcp_congestion_ops cubictcp = { @@ -372,4 +470,4 @@ module_exit(cubictcp_unregister); MODULE_AUTHOR("Sangtae Ha, Stephen Hemminger"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("CUBIC TCP"); -MODULE_VERSION("2.2"); +MODULE_VERSION("2.3"); diff --git a/net/ipv4/tcp_diag.c b/net/ipv4/tcp_diag.c index 838d491dfda7e09d8c9c313a25edfe50913047f7..fcbcd4ff6c5f250adc4c27397d1ef8992697a736 100644 --- a/net/ipv4/tcp_diag.c +++ b/net/ipv4/tcp_diag.c @@ -34,7 +34,7 @@ static void tcp_diag_get_info(struct sock *sk, struct inet_diag_msg *r, tcp_get_info(sk, info); } -static struct inet_diag_handler tcp_diag_handler = { +static const struct inet_diag_handler tcp_diag_handler = { .idiag_hashinfo = &tcp_hashinfo, .idiag_get_info = tcp_diag_get_info, .idiag_type = TCPDIAG_GETSOCK, diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index d77c0d29e2396bb6c2e4ea4cc159019a106be325..99b7ecbe88934a5f5cd4bc6b6a0a676677c7b12a 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -701,13 +701,10 @@ static inline void tcp_set_rto(struct sock *sk) * all the algo is pure shit and should be replaced * with correct one. It is exactly, which we pretend to do. */ -} -/* NOTE: clamping at TCP_RTO_MIN is not required, current algo - * guarantees that rto is higher. - */ -static inline void tcp_bound_rto(struct sock *sk) -{ + /* NOTE: clamping at TCP_RTO_MIN is not required, current algo + * guarantees that rto is higher. + */ if (inet_csk(sk)->icsk_rto > TCP_RTO_MAX) inet_csk(sk)->icsk_rto = TCP_RTO_MAX; } @@ -928,7 +925,6 @@ static void tcp_init_metrics(struct sock *sk) tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk)); } tcp_set_rto(sk); - tcp_bound_rto(sk); if (inet_csk(sk)->icsk_rto < TCP_TIMEOUT_INIT && !tp->rx_opt.saw_tstamp) goto reset; tp->snd_cwnd = tcp_init_cwnd(tp, dst); @@ -1002,7 +998,8 @@ static void tcp_skb_mark_lost(struct tcp_sock *tp, struct sk_buff *skb) } } -void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, struct sk_buff *skb) +static void tcp_skb_mark_lost_uncond_verify(struct tcp_sock *tp, + struct sk_buff *skb) { tcp_verify_retransmit_hint(tp, skb); @@ -1236,31 +1233,58 @@ static int tcp_check_dsack(struct sock *sk, struct sk_buff *ack_skb, return dup_sack; } +struct tcp_sacktag_state { + int reord; + int fack_count; + int flag; +}; + /* Check if skb is fully within the SACK block. In presence of GSO skbs, * the incoming SACK may not exactly match but we can find smaller MSS * aligned portion of it that matches. Therefore we might need to fragment * which may fail and creates some hassle (caller must handle error case * returns). + * + * FIXME: this could be merged to shift decision code */ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb, u32 start_seq, u32 end_seq) { int in_sack, err; unsigned int pkt_len; + unsigned int mss; in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && !before(end_seq, TCP_SKB_CB(skb)->end_seq); if (tcp_skb_pcount(skb) > 1 && !in_sack && after(TCP_SKB_CB(skb)->end_seq, start_seq)) { - + mss = tcp_skb_mss(skb); in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq); - if (!in_sack) + if (!in_sack) { pkt_len = start_seq - TCP_SKB_CB(skb)->seq; - else + if (pkt_len < mss) + pkt_len = mss; + } else { pkt_len = end_seq - TCP_SKB_CB(skb)->seq; - err = tcp_fragment(sk, skb, pkt_len, skb_shinfo(skb)->gso_size); + if (pkt_len < mss) + return -EINVAL; + } + + /* Round if necessary so that SACKs cover only full MSSes + * and/or the remaining small portion (if present) + */ + if (pkt_len > mss) { + unsigned int new_len = (pkt_len / mss) * mss; + if (!in_sack && new_len < pkt_len) { + new_len += mss; + if (new_len > skb->len) + return 0; + } + pkt_len = new_len; + } + err = tcp_fragment(sk, skb, pkt_len, mss); if (err < 0) return err; } @@ -1268,24 +1292,25 @@ static int tcp_match_skb_to_sack(struct sock *sk, struct sk_buff *skb, return in_sack; } -static int tcp_sacktag_one(struct sk_buff *skb, struct sock *sk, - int *reord, int dup_sack, int fack_count) +static u8 tcp_sacktag_one(struct sk_buff *skb, struct sock *sk, + struct tcp_sacktag_state *state, + int dup_sack, int pcount) { struct tcp_sock *tp = tcp_sk(sk); u8 sacked = TCP_SKB_CB(skb)->sacked; - int flag = 0; + int fack_count = state->fack_count; /* Account D-SACK for retransmitted packet. */ if (dup_sack && (sacked & TCPCB_RETRANS)) { if (after(TCP_SKB_CB(skb)->end_seq, tp->undo_marker)) tp->undo_retrans--; if (sacked & TCPCB_SACKED_ACKED) - *reord = min(fack_count, *reord); + state->reord = min(fack_count, state->reord); } /* Nothing to do; acked frame is about to be dropped (was ACKed). */ if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) - return flag; + return sacked; if (!(sacked & TCPCB_SACKED_ACKED)) { if (sacked & TCPCB_SACKED_RETRANS) { @@ -1294,10 +1319,9 @@ static int tcp_sacktag_one(struct sk_buff *skb, struct sock *sk, * that retransmission is still in flight. */ if (sacked & TCPCB_LOST) { - TCP_SKB_CB(skb)->sacked &= - ~(TCPCB_LOST|TCPCB_SACKED_RETRANS); - tp->lost_out -= tcp_skb_pcount(skb); - tp->retrans_out -= tcp_skb_pcount(skb); + sacked &= ~(TCPCB_LOST|TCPCB_SACKED_RETRANS); + tp->lost_out -= pcount; + tp->retrans_out -= pcount; } } else { if (!(sacked & TCPCB_RETRANS)) { @@ -1306,56 +1330,280 @@ static int tcp_sacktag_one(struct sk_buff *skb, struct sock *sk, */ if (before(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp))) - *reord = min(fack_count, *reord); + state->reord = min(fack_count, + state->reord); /* SACK enhanced F-RTO (RFC4138; Appendix B) */ if (!after(TCP_SKB_CB(skb)->end_seq, tp->frto_highmark)) - flag |= FLAG_ONLY_ORIG_SACKED; + state->flag |= FLAG_ONLY_ORIG_SACKED; } if (sacked & TCPCB_LOST) { - TCP_SKB_CB(skb)->sacked &= ~TCPCB_LOST; - tp->lost_out -= tcp_skb_pcount(skb); + sacked &= ~TCPCB_LOST; + tp->lost_out -= pcount; } } - TCP_SKB_CB(skb)->sacked |= TCPCB_SACKED_ACKED; - flag |= FLAG_DATA_SACKED; - tp->sacked_out += tcp_skb_pcount(skb); + sacked |= TCPCB_SACKED_ACKED; + state->flag |= FLAG_DATA_SACKED; + tp->sacked_out += pcount; - fack_count += tcp_skb_pcount(skb); + fack_count += pcount; /* Lost marker hint past SACKed? Tweak RFC3517 cnt */ if (!tcp_is_fack(tp) && (tp->lost_skb_hint != NULL) && before(TCP_SKB_CB(skb)->seq, TCP_SKB_CB(tp->lost_skb_hint)->seq)) - tp->lost_cnt_hint += tcp_skb_pcount(skb); + tp->lost_cnt_hint += pcount; if (fack_count > tp->fackets_out) tp->fackets_out = fack_count; - - if (!before(TCP_SKB_CB(skb)->seq, tcp_highest_sack_seq(tp))) - tcp_advance_highest_sack(sk, skb); } /* D-SACK. We can detect redundant retransmission in S|R and plain R * frames and clear it. undo_retrans is decreased above, L|R frames * are accounted above as well. */ - if (dup_sack && (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS)) { - TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; - tp->retrans_out -= tcp_skb_pcount(skb); + if (dup_sack && (sacked & TCPCB_SACKED_RETRANS)) { + sacked &= ~TCPCB_SACKED_RETRANS; + tp->retrans_out -= pcount; } - return flag; + return sacked; +} + +static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb, + struct tcp_sacktag_state *state, + unsigned int pcount, int shifted, int mss) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *prev = tcp_write_queue_prev(sk, skb); + + BUG_ON(!pcount); + + /* Tweak before seqno plays */ + if (!tcp_is_fack(tp) && tcp_is_sack(tp) && tp->lost_skb_hint && + !before(TCP_SKB_CB(tp->lost_skb_hint)->seq, TCP_SKB_CB(skb)->seq)) + tp->lost_cnt_hint += pcount; + + TCP_SKB_CB(prev)->end_seq += shifted; + TCP_SKB_CB(skb)->seq += shifted; + + skb_shinfo(prev)->gso_segs += pcount; + BUG_ON(skb_shinfo(skb)->gso_segs < pcount); + skb_shinfo(skb)->gso_segs -= pcount; + + /* When we're adding to gso_segs == 1, gso_size will be zero, + * in theory this shouldn't be necessary but as long as DSACK + * code can come after this skb later on it's better to keep + * setting gso_size to something. + */ + if (!skb_shinfo(prev)->gso_size) { + skb_shinfo(prev)->gso_size = mss; + skb_shinfo(prev)->gso_type = sk->sk_gso_type; + } + + /* CHECKME: To clear or not to clear? Mimics normal skb currently */ + if (skb_shinfo(skb)->gso_segs <= 1) { + skb_shinfo(skb)->gso_size = 0; + skb_shinfo(skb)->gso_type = 0; + } + + /* We discard results */ + tcp_sacktag_one(skb, sk, state, 0, pcount); + + /* Difference in this won't matter, both ACKed by the same cumul. ACK */ + TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS); + + if (skb->len > 0) { + BUG_ON(!tcp_skb_pcount(skb)); + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SACKSHIFTED); + return 0; + } + + /* Whole SKB was eaten :-) */ + + if (skb == tp->retransmit_skb_hint) + tp->retransmit_skb_hint = prev; + if (skb == tp->scoreboard_skb_hint) + tp->scoreboard_skb_hint = prev; + if (skb == tp->lost_skb_hint) { + tp->lost_skb_hint = prev; + tp->lost_cnt_hint -= tcp_skb_pcount(prev); + } + + TCP_SKB_CB(skb)->flags |= TCP_SKB_CB(prev)->flags; + if (skb == tcp_highest_sack(sk)) + tcp_advance_highest_sack(sk, skb); + + tcp_unlink_write_queue(skb, sk); + sk_wmem_free_skb(sk, skb); + + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SACKMERGED); + + return 1; +} + +/* I wish gso_size would have a bit more sane initialization than + * something-or-zero which complicates things + */ +static int tcp_skb_seglen(struct sk_buff *skb) +{ + return tcp_skb_pcount(skb) == 1 ? skb->len : tcp_skb_mss(skb); +} + +/* Shifting pages past head area doesn't work */ +static int skb_can_shift(struct sk_buff *skb) +{ + return !skb_headlen(skb) && skb_is_nonlinear(skb); +} + +/* Try collapsing SACK blocks spanning across multiple skbs to a single + * skb. + */ +static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb, + struct tcp_sacktag_state *state, + u32 start_seq, u32 end_seq, + int dup_sack) +{ + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *prev; + int mss; + int pcount = 0; + int len; + int in_sack; + + if (!sk_can_gso(sk)) + goto fallback; + + /* Normally R but no L won't result in plain S */ + if (!dup_sack && + (TCP_SKB_CB(skb)->sacked & (TCPCB_LOST|TCPCB_SACKED_RETRANS)) == TCPCB_SACKED_RETRANS) + goto fallback; + if (!skb_can_shift(skb)) + goto fallback; + /* This frame is about to be dropped (was ACKed). */ + if (!after(TCP_SKB_CB(skb)->end_seq, tp->snd_una)) + goto fallback; + + /* Can only happen with delayed DSACK + discard craziness */ + if (unlikely(skb == tcp_write_queue_head(sk))) + goto fallback; + prev = tcp_write_queue_prev(sk, skb); + + if ((TCP_SKB_CB(prev)->sacked & TCPCB_TAGBITS) != TCPCB_SACKED_ACKED) + goto fallback; + + in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) && + !before(end_seq, TCP_SKB_CB(skb)->end_seq); + + if (in_sack) { + len = skb->len; + pcount = tcp_skb_pcount(skb); + mss = tcp_skb_seglen(skb); + + /* TODO: Fix DSACKs to not fragment already SACKed and we can + * drop this restriction as unnecessary + */ + if (mss != tcp_skb_seglen(prev)) + goto fallback; + } else { + if (!after(TCP_SKB_CB(skb)->end_seq, start_seq)) + goto noop; + /* CHECKME: This is non-MSS split case only?, this will + * cause skipped skbs due to advancing loop btw, original + * has that feature too + */ + if (tcp_skb_pcount(skb) <= 1) + goto noop; + + in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq); + if (!in_sack) { + /* TODO: head merge to next could be attempted here + * if (!after(TCP_SKB_CB(skb)->end_seq, end_seq)), + * though it might not be worth of the additional hassle + * + * ...we can probably just fallback to what was done + * previously. We could try merging non-SACKed ones + * as well but it probably isn't going to buy off + * because later SACKs might again split them, and + * it would make skb timestamp tracking considerably + * harder problem. + */ + goto fallback; + } + + len = end_seq - TCP_SKB_CB(skb)->seq; + BUG_ON(len < 0); + BUG_ON(len > skb->len); + + /* MSS boundaries should be honoured or else pcount will + * severely break even though it makes things bit trickier. + * Optimize common case to avoid most of the divides + */ + mss = tcp_skb_mss(skb); + + /* TODO: Fix DSACKs to not fragment already SACKed and we can + * drop this restriction as unnecessary + */ + if (mss != tcp_skb_seglen(prev)) + goto fallback; + + if (len == mss) { + pcount = 1; + } else if (len < mss) { + goto noop; + } else { + pcount = len / mss; + len = pcount * mss; + } + } + + if (!skb_shift(prev, skb, len)) + goto fallback; + if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss)) + goto out; + + /* Hole filled allows collapsing with the next as well, this is very + * useful when hole on every nth skb pattern happens + */ + if (prev == tcp_write_queue_tail(sk)) + goto out; + skb = tcp_write_queue_next(sk, prev); + + if (!skb_can_shift(skb) || + (skb == tcp_send_head(sk)) || + ((TCP_SKB_CB(skb)->sacked & TCPCB_TAGBITS) != TCPCB_SACKED_ACKED) || + (mss != tcp_skb_seglen(skb))) + goto out; + + len = skb->len; + if (skb_shift(prev, skb, len)) { + pcount += tcp_skb_pcount(skb); + tcp_shifted_skb(sk, skb, state, tcp_skb_pcount(skb), len, mss); + } + +out: + state->fack_count += pcount; + return prev; + +noop: + return skb; + +fallback: + NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SACKSHIFTFALLBACK); + return NULL; } static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk, struct tcp_sack_block *next_dup, + struct tcp_sacktag_state *state, u32 start_seq, u32 end_seq, - int dup_sack_in, int *fack_count, - int *reord, int *flag) + int dup_sack_in) { + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *tmp; + tcp_for_write_queue_from(skb, sk) { int in_sack = 0; int dup_sack = dup_sack_in; @@ -1376,17 +1624,42 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk, dup_sack = 1; } - if (in_sack <= 0) - in_sack = tcp_match_skb_to_sack(sk, skb, start_seq, - end_seq); + /* skb reference here is a bit tricky to get right, since + * shifting can eat and free both this skb and the next, + * so not even _safe variant of the loop is enough. + */ + if (in_sack <= 0) { + tmp = tcp_shift_skb_data(sk, skb, state, + start_seq, end_seq, dup_sack); + if (tmp != NULL) { + if (tmp != skb) { + skb = tmp; + continue; + } + + in_sack = 0; + } else { + in_sack = tcp_match_skb_to_sack(sk, skb, + start_seq, + end_seq); + } + } + if (unlikely(in_sack < 0)) break; - if (in_sack) - *flag |= tcp_sacktag_one(skb, sk, reord, dup_sack, - *fack_count); + if (in_sack) { + TCP_SKB_CB(skb)->sacked = tcp_sacktag_one(skb, sk, + state, + dup_sack, + tcp_skb_pcount(skb)); + + if (!before(TCP_SKB_CB(skb)->seq, + tcp_highest_sack_seq(tp))) + tcp_advance_highest_sack(sk, skb); + } - *fack_count += tcp_skb_pcount(skb); + state->fack_count += tcp_skb_pcount(skb); } return skb; } @@ -1395,16 +1668,17 @@ static struct sk_buff *tcp_sacktag_walk(struct sk_buff *skb, struct sock *sk, * a normal way */ static struct sk_buff *tcp_sacktag_skip(struct sk_buff *skb, struct sock *sk, - u32 skip_to_seq, int *fack_count) + struct tcp_sacktag_state *state, + u32 skip_to_seq) { tcp_for_write_queue_from(skb, sk) { if (skb == tcp_send_head(sk)) break; - if (!before(TCP_SKB_CB(skb)->end_seq, skip_to_seq)) + if (after(TCP_SKB_CB(skb)->end_seq, skip_to_seq)) break; - *fack_count += tcp_skb_pcount(skb); + state->fack_count += tcp_skb_pcount(skb); } return skb; } @@ -1412,18 +1686,17 @@ static struct sk_buff *tcp_sacktag_skip(struct sk_buff *skb, struct sock *sk, static struct sk_buff *tcp_maybe_skipping_dsack(struct sk_buff *skb, struct sock *sk, struct tcp_sack_block *next_dup, - u32 skip_to_seq, - int *fack_count, int *reord, - int *flag) + struct tcp_sacktag_state *state, + u32 skip_to_seq) { if (next_dup == NULL) return skb; if (before(next_dup->start_seq, skip_to_seq)) { - skb = tcp_sacktag_skip(skb, sk, next_dup->start_seq, fack_count); - skb = tcp_sacktag_walk(skb, sk, NULL, - next_dup->start_seq, next_dup->end_seq, - 1, fack_count, reord, flag); + skb = tcp_sacktag_skip(skb, sk, state, next_dup->start_seq); + skb = tcp_sacktag_walk(skb, sk, NULL, state, + next_dup->start_seq, next_dup->end_seq, + 1); } return skb; @@ -1445,16 +1718,17 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, struct tcp_sack_block_wire *sp_wire = (struct tcp_sack_block_wire *)(ptr+2); struct tcp_sack_block sp[TCP_NUM_SACKS]; struct tcp_sack_block *cache; + struct tcp_sacktag_state state; struct sk_buff *skb; int num_sacks = min(TCP_NUM_SACKS, (ptr[1] - TCPOLEN_SACK_BASE) >> 3); int used_sacks; - int reord = tp->packets_out; - int flag = 0; int found_dup_sack = 0; - int fack_count; int i, j; int first_sack_index; + state.flag = 0; + state.reord = tp->packets_out; + if (!tp->sacked_out) { if (WARN_ON(tp->fackets_out)) tp->fackets_out = 0; @@ -1464,7 +1738,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, found_dup_sack = tcp_check_dsack(sk, ack_skb, sp_wire, num_sacks, prior_snd_una); if (found_dup_sack) - flag |= FLAG_DSACKING_ACK; + state.flag |= FLAG_DSACKING_ACK; /* Eliminate too old ACKs, but take into * account more or less fresh ones, they can @@ -1533,7 +1807,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, } skb = tcp_write_queue_head(sk); - fack_count = 0; + state.fack_count = 0; i = 0; if (!tp->sacked_out) { @@ -1558,7 +1832,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, /* Event "B" in the comment above. */ if (after(end_seq, tp->high_seq)) - flag |= FLAG_DATA_LOST; + state.flag |= FLAG_DATA_LOST; /* Skip too early cached blocks */ while (tcp_sack_cache_ok(tp, cache) && @@ -1571,13 +1845,13 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, /* Head todo? */ if (before(start_seq, cache->start_seq)) { - skb = tcp_sacktag_skip(skb, sk, start_seq, - &fack_count); + skb = tcp_sacktag_skip(skb, sk, &state, + start_seq); skb = tcp_sacktag_walk(skb, sk, next_dup, + &state, start_seq, cache->start_seq, - dup_sack, &fack_count, - &reord, &flag); + dup_sack); } /* Rest of the block already fully processed? */ @@ -1585,9 +1859,8 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, goto advance_sp; skb = tcp_maybe_skipping_dsack(skb, sk, next_dup, - cache->end_seq, - &fack_count, &reord, - &flag); + &state, + cache->end_seq); /* ...tail remains todo... */ if (tcp_highest_sack_seq(tp) == cache->end_seq) { @@ -1595,13 +1868,12 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, skb = tcp_highest_sack(sk); if (skb == NULL) break; - fack_count = tp->fackets_out; + state.fack_count = tp->fackets_out; cache++; goto walk; } - skb = tcp_sacktag_skip(skb, sk, cache->end_seq, - &fack_count); + skb = tcp_sacktag_skip(skb, sk, &state, cache->end_seq); /* Check overlap against next cached too (past this one already) */ cache++; continue; @@ -1611,20 +1883,20 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, skb = tcp_highest_sack(sk); if (skb == NULL) break; - fack_count = tp->fackets_out; + state.fack_count = tp->fackets_out; } - skb = tcp_sacktag_skip(skb, sk, start_seq, &fack_count); + skb = tcp_sacktag_skip(skb, sk, &state, start_seq); walk: - skb = tcp_sacktag_walk(skb, sk, next_dup, start_seq, end_seq, - dup_sack, &fack_count, &reord, &flag); + skb = tcp_sacktag_walk(skb, sk, next_dup, &state, + start_seq, end_seq, dup_sack); advance_sp: /* SACK enhanced FRTO (RFC4138, Appendix B): Clearing correct * due to in-order walk */ if (after(end_seq, tp->frto_highmark)) - flag &= ~FLAG_ONLY_ORIG_SACKED; + state.flag &= ~FLAG_ONLY_ORIG_SACKED; i++; } @@ -1641,10 +1913,10 @@ advance_sp: tcp_verify_left_out(tp); - if ((reord < tp->fackets_out) && + if ((state.reord < tp->fackets_out) && ((icsk->icsk_ca_state != TCP_CA_Loss) || tp->undo_marker) && (!tp->frto_highmark || after(tp->snd_una, tp->frto_highmark))) - tcp_update_reordering(sk, tp->fackets_out - reord, 0); + tcp_update_reordering(sk, tp->fackets_out - state.reord, 0); out: @@ -1654,13 +1926,13 @@ out: WARN_ON((int)tp->retrans_out < 0); WARN_ON((int)tcp_packets_in_flight(tp) < 0); #endif - return flag; + return state.flag; } /* Limits sacked_out so that sum with lost_out isn't ever larger than * packets_out. Returns zero if sacked_out adjustement wasn't necessary. */ -int tcp_limit_reno_sacked(struct tcp_sock *tp) +static int tcp_limit_reno_sacked(struct tcp_sock *tp) { u32 holes; @@ -2336,9 +2608,9 @@ static void DBGUNDO(struct sock *sk, const char *msg) struct inet_sock *inet = inet_sk(sk); if (sk->sk_family == AF_INET) { - printk(KERN_DEBUG "Undo %s " NIPQUAD_FMT "/%u c%u l%u ss%u/%u p%u\n", + printk(KERN_DEBUG "Undo %s %pI4/%u c%u l%u ss%u/%u p%u\n", msg, - NIPQUAD(inet->daddr), ntohs(inet->dport), + &inet->daddr, ntohs(inet->dport), tp->snd_cwnd, tcp_left_out(tp), tp->snd_ssthresh, tp->prior_ssthresh, tp->packets_out); @@ -2346,9 +2618,9 @@ static void DBGUNDO(struct sock *sk, const char *msg) #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) else if (sk->sk_family == AF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); - printk(KERN_DEBUG "Undo %s " NIP6_FMT "/%u c%u l%u ss%u/%u p%u\n", + printk(KERN_DEBUG "Undo %s %pI6/%u c%u l%u ss%u/%u p%u\n", msg, - NIP6(np->daddr), ntohs(inet->dport), + &np->daddr, ntohs(inet->dport), tp->snd_cwnd, tcp_left_out(tp), tp->snd_ssthresh, tp->prior_ssthresh, tp->packets_out); @@ -2559,6 +2831,56 @@ static void tcp_mtup_probe_success(struct sock *sk, struct sk_buff *skb) tcp_sync_mss(sk, icsk->icsk_pmtu_cookie); } +/* Do a simple retransmit without using the backoff mechanisms in + * tcp_timer. This is used for path mtu discovery. + * The socket is already locked here. + */ +void tcp_simple_retransmit(struct sock *sk) +{ + const struct inet_connection_sock *icsk = inet_csk(sk); + struct tcp_sock *tp = tcp_sk(sk); + struct sk_buff *skb; + unsigned int mss = tcp_current_mss(sk, 0); + u32 prior_lost = tp->lost_out; + + tcp_for_write_queue(skb, sk) { + if (skb == tcp_send_head(sk)) + break; + if (tcp_skb_seglen(skb) > mss && + !(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) { + if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) { + TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; + tp->retrans_out -= tcp_skb_pcount(skb); + } + tcp_skb_mark_lost_uncond_verify(tp, skb); + } + } + + tcp_clear_retrans_hints_partial(tp); + + if (prior_lost == tp->lost_out) + return; + + if (tcp_is_reno(tp)) + tcp_limit_reno_sacked(tp); + + tcp_verify_left_out(tp); + + /* Don't muck with the congestion window here. + * Reason is that we do not increase amount of _data_ + * in network, but units changed and effective + * cwnd/ssthresh really reduced now. + */ + if (icsk->icsk_ca_state != TCP_CA_Loss) { + tp->high_seq = tp->snd_nxt; + tp->snd_ssthresh = tcp_current_ssthresh(sk); + tp->prior_ssthresh = 0; + tp->undo_marker = 0; + tcp_set_ca_state(sk, TCP_CA_Loss); + } + tcp_xmit_retransmit_queue(sk); +} + /* Process an event, which can update packets-in-flight not trivially. * Main goal of this function is to calculate new estimate for left_out, * taking into account both packets sitting in receiver's buffer and @@ -2730,6 +3052,13 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag) tcp_xmit_retransmit_queue(sk); } +static void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt) +{ + tcp_rtt_estimator(sk, seq_rtt); + tcp_set_rto(sk); + inet_csk(sk)->icsk_backoff = 0; +} + /* Read draft-ietf-tcplw-high-performance before mucking * with this code. (Supersedes RFC1323) */ @@ -2751,11 +3080,8 @@ static void tcp_ack_saw_tstamp(struct sock *sk, int flag) * in window is lost... Voila. --ANK (010210) */ struct tcp_sock *tp = tcp_sk(sk); - const __u32 seq_rtt = tcp_time_stamp - tp->rx_opt.rcv_tsecr; - tcp_rtt_estimator(sk, seq_rtt); - tcp_set_rto(sk); - inet_csk(sk)->icsk_backoff = 0; - tcp_bound_rto(sk); + + tcp_valid_rtt_meas(sk, tcp_time_stamp - tp->rx_opt.rcv_tsecr); } static void tcp_ack_no_tstamp(struct sock *sk, u32 seq_rtt, int flag) @@ -2772,10 +3098,7 @@ static void tcp_ack_no_tstamp(struct sock *sk, u32 seq_rtt, int flag) if (flag & FLAG_RETRANS_DATA_ACKED) return; - tcp_rtt_estimator(sk, seq_rtt); - tcp_set_rto(sk); - inet_csk(sk)->icsk_backoff = 0; - tcp_bound_rto(sk); + tcp_valid_rtt_meas(sk, seq_rtt); } static inline void tcp_ack_update_rtt(struct sock *sk, const int flag, diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5c8fa7f1e327821dbcb378244e8674183025906c..10172487921b944d3f82b1d527b4674a9af449a4 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -97,11 +97,7 @@ struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr) } #endif -struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { - .lhash_lock = __RW_LOCK_UNLOCKED(tcp_hashinfo.lhash_lock), - .lhash_users = ATOMIC_INIT(0), - .lhash_wait = __WAIT_QUEUE_HEAD_INITIALIZER(tcp_hashinfo.lhash_wait), -}; +struct inet_hashinfo tcp_hashinfo; static inline __u32 tcp_v4_init_sequence(struct sk_buff *skb) { @@ -492,7 +488,7 @@ void tcp_v4_send_check(struct sock *sk, int len, struct sk_buff *skb) skb->csum_offset = offsetof(struct tcphdr, check); } else { th->check = tcp_v4_check(len, inet->saddr, inet->daddr, - csum_partial((char *)th, + csum_partial(th, th->doff << 2, skb->csum)); } @@ -726,7 +722,7 @@ static int __tcp_v4_send_synack(struct sock *sk, struct request_sock *req, th->check = tcp_v4_check(skb->len, ireq->loc_addr, ireq->rmt_addr, - csum_partial((char *)th, skb->len, + csum_partial(th, skb->len, skb->csum)); err = ip_build_and_send_pkt(skb, sk, ireq->loc_addr, @@ -1139,10 +1135,9 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) if (genhash || memcmp(hash_location, newhash, 16) != 0) { if (net_ratelimit()) { - printk(KERN_INFO "MD5 Hash failed for " - "(" NIPQUAD_FMT ", %d)->(" NIPQUAD_FMT ", %d)%s\n", - NIPQUAD(iph->saddr), ntohs(th->source), - NIPQUAD(iph->daddr), ntohs(th->dest), + printk(KERN_INFO "MD5 Hash failed for (%pI4, %d)->(%pI4, %d)%s\n", + &iph->saddr, ntohs(th->source), + &iph->daddr, ntohs(th->dest), genhash ? " tcp_v4_calc_md5_hash failed" : ""); } return 1; @@ -1297,10 +1292,8 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) * to destinations, already remembered * to the moment of synflood. */ - LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open " - "request from " NIPQUAD_FMT "/%u\n", - NIPQUAD(saddr), - ntohs(tcp_hdr(skb)->source)); + LIMIT_NETDEBUG(KERN_DEBUG "TCP: drop open request from %pI4/%u\n", + &saddr, ntohs(tcp_hdr(skb)->source)); goto drop_and_release; } @@ -1804,7 +1797,7 @@ static int tcp_v4_init_sock(struct sock *sk) sk->sk_sndbuf = sysctl_tcp_wmem[1]; sk->sk_rcvbuf = sysctl_tcp_rmem[1]; - atomic_inc(&tcp_sockets_allocated); + percpu_counter_inc(&tcp_sockets_allocated); return 0; } @@ -1852,7 +1845,7 @@ void tcp_v4_destroy_sock(struct sock *sk) sk->sk_sndmsg_page = NULL; } - atomic_dec(&tcp_sockets_allocated); + percpu_counter_dec(&tcp_sockets_allocated); } EXPORT_SYMBOL(tcp_v4_destroy_sock); @@ -1860,32 +1853,35 @@ EXPORT_SYMBOL(tcp_v4_destroy_sock); #ifdef CONFIG_PROC_FS /* Proc filesystem TCP sock list dumping. */ -static inline struct inet_timewait_sock *tw_head(struct hlist_head *head) +static inline struct inet_timewait_sock *tw_head(struct hlist_nulls_head *head) { - return hlist_empty(head) ? NULL : + return hlist_nulls_empty(head) ? NULL : list_entry(head->first, struct inet_timewait_sock, tw_node); } static inline struct inet_timewait_sock *tw_next(struct inet_timewait_sock *tw) { - return tw->tw_node.next ? - hlist_entry(tw->tw_node.next, typeof(*tw), tw_node) : NULL; + return !is_a_nulls(tw->tw_node.next) ? + hlist_nulls_entry(tw->tw_node.next, typeof(*tw), tw_node) : NULL; } static void *listening_get_next(struct seq_file *seq, void *cur) { struct inet_connection_sock *icsk; - struct hlist_node *node; + struct hlist_nulls_node *node; struct sock *sk = cur; - struct tcp_iter_state* st = seq->private; + struct inet_listen_hashbucket *ilb; + struct tcp_iter_state *st = seq->private; struct net *net = seq_file_net(seq); if (!sk) { st->bucket = 0; - sk = sk_head(&tcp_hashinfo.listening_hash[0]); + ilb = &tcp_hashinfo.listening_hash[0]; + spin_lock_bh(&ilb->lock); + sk = sk_nulls_head(&ilb->head); goto get_sk; } - + ilb = &tcp_hashinfo.listening_hash[st->bucket]; ++st->num; if (st->state == TCP_SEQ_STATE_OPENREQ) { @@ -1918,7 +1914,7 @@ get_req: sk = sk_next(sk); } get_sk: - sk_for_each_from(sk, node) { + sk_nulls_for_each_from(sk, node) { if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) { cur = sk; goto out; @@ -1935,8 +1931,11 @@ start_req: } read_unlock_bh(&icsk->icsk_accept_queue.syn_wait_lock); } + spin_unlock_bh(&ilb->lock); if (++st->bucket < INET_LHTABLE_SIZE) { - sk = sk_head(&tcp_hashinfo.listening_hash[st->bucket]); + ilb = &tcp_hashinfo.listening_hash[st->bucket]; + spin_lock_bh(&ilb->lock); + sk = sk_nulls_head(&ilb->head); goto get_sk; } cur = NULL; @@ -1957,28 +1956,28 @@ static void *listening_get_idx(struct seq_file *seq, loff_t *pos) static inline int empty_bucket(struct tcp_iter_state *st) { - return hlist_empty(&tcp_hashinfo.ehash[st->bucket].chain) && - hlist_empty(&tcp_hashinfo.ehash[st->bucket].twchain); + return hlist_nulls_empty(&tcp_hashinfo.ehash[st->bucket].chain) && + hlist_nulls_empty(&tcp_hashinfo.ehash[st->bucket].twchain); } static void *established_get_first(struct seq_file *seq) { - struct tcp_iter_state* st = seq->private; + struct tcp_iter_state *st = seq->private; struct net *net = seq_file_net(seq); void *rc = NULL; for (st->bucket = 0; st->bucket < tcp_hashinfo.ehash_size; ++st->bucket) { struct sock *sk; - struct hlist_node *node; + struct hlist_nulls_node *node; struct inet_timewait_sock *tw; - rwlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, st->bucket); + spinlock_t *lock = inet_ehash_lockp(&tcp_hashinfo, st->bucket); /* Lockless fast path for the common case of empty buckets */ if (empty_bucket(st)) continue; - read_lock_bh(lock); - sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) { + spin_lock_bh(lock); + sk_nulls_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) { if (sk->sk_family != st->family || !net_eq(sock_net(sk), net)) { continue; @@ -1996,7 +1995,7 @@ static void *established_get_first(struct seq_file *seq) rc = tw; goto out; } - read_unlock_bh(lock); + spin_unlock_bh(lock); st->state = TCP_SEQ_STATE_ESTABLISHED; } out: @@ -2007,8 +2006,8 @@ static void *established_get_next(struct seq_file *seq, void *cur) { struct sock *sk = cur; struct inet_timewait_sock *tw; - struct hlist_node *node; - struct tcp_iter_state* st = seq->private; + struct hlist_nulls_node *node; + struct tcp_iter_state *st = seq->private; struct net *net = seq_file_net(seq); ++st->num; @@ -2024,7 +2023,7 @@ get_tw: cur = tw; goto out; } - read_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket)); + spin_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket)); st->state = TCP_SEQ_STATE_ESTABLISHED; /* Look for next non empty bucket */ @@ -2034,12 +2033,12 @@ get_tw: if (st->bucket >= tcp_hashinfo.ehash_size) return NULL; - read_lock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket)); - sk = sk_head(&tcp_hashinfo.ehash[st->bucket].chain); + spin_lock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket)); + sk = sk_nulls_head(&tcp_hashinfo.ehash[st->bucket].chain); } else - sk = sk_next(sk); + sk = sk_nulls_next(sk); - sk_for_each_from(sk, node) { + sk_nulls_for_each_from(sk, node) { if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) goto found; } @@ -2067,14 +2066,12 @@ static void *established_get_idx(struct seq_file *seq, loff_t pos) static void *tcp_get_idx(struct seq_file *seq, loff_t pos) { void *rc; - struct tcp_iter_state* st = seq->private; + struct tcp_iter_state *st = seq->private; - inet_listen_lock(&tcp_hashinfo); st->state = TCP_SEQ_STATE_LISTENING; rc = listening_get_idx(seq, &pos); if (!rc) { - inet_listen_unlock(&tcp_hashinfo); st->state = TCP_SEQ_STATE_ESTABLISHED; rc = established_get_idx(seq, pos); } @@ -2084,7 +2081,7 @@ static void *tcp_get_idx(struct seq_file *seq, loff_t pos) static void *tcp_seq_start(struct seq_file *seq, loff_t *pos) { - struct tcp_iter_state* st = seq->private; + struct tcp_iter_state *st = seq->private; st->state = TCP_SEQ_STATE_LISTENING; st->num = 0; return *pos ? tcp_get_idx(seq, *pos - 1) : SEQ_START_TOKEN; @@ -2093,7 +2090,7 @@ static void *tcp_seq_start(struct seq_file *seq, loff_t *pos) static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos) { void *rc = NULL; - struct tcp_iter_state* st; + struct tcp_iter_state *st; if (v == SEQ_START_TOKEN) { rc = tcp_get_idx(seq, 0); @@ -2106,7 +2103,6 @@ static void *tcp_seq_next(struct seq_file *seq, void *v, loff_t *pos) case TCP_SEQ_STATE_LISTENING: rc = listening_get_next(seq, v); if (!rc) { - inet_listen_unlock(&tcp_hashinfo); st->state = TCP_SEQ_STATE_ESTABLISHED; rc = established_get_first(seq); } @@ -2123,7 +2119,7 @@ out: static void tcp_seq_stop(struct seq_file *seq, void *v) { - struct tcp_iter_state* st = seq->private; + struct tcp_iter_state *st = seq->private; switch (st->state) { case TCP_SEQ_STATE_OPENREQ: @@ -2133,12 +2129,12 @@ static void tcp_seq_stop(struct seq_file *seq, void *v) } case TCP_SEQ_STATE_LISTENING: if (v != SEQ_START_TOKEN) - inet_listen_unlock(&tcp_hashinfo); + spin_unlock_bh(&tcp_hashinfo.listening_hash[st->bucket].lock); break; case TCP_SEQ_STATE_TIME_WAIT: case TCP_SEQ_STATE_ESTABLISHED: if (v) - read_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket)); + spin_unlock_bh(inet_ehash_lockp(&tcp_hashinfo, st->bucket)); break; } } @@ -2284,7 +2280,7 @@ static void get_timewait4_sock(struct inet_timewait_sock *tw, static int tcp4_seq_show(struct seq_file *seq, void *v) { - struct tcp_iter_state* st; + struct tcp_iter_state *st; int len; if (v == SEQ_START_TOKEN) { @@ -2350,6 +2346,41 @@ void tcp4_proc_exit(void) } #endif /* CONFIG_PROC_FS */ +struct sk_buff **tcp4_gro_receive(struct sk_buff **head, struct sk_buff *skb) +{ + struct iphdr *iph = ip_hdr(skb); + + switch (skb->ip_summed) { + case CHECKSUM_COMPLETE: + if (!tcp_v4_check(skb->len, iph->saddr, iph->daddr, + skb->csum)) { + skb->ip_summed = CHECKSUM_UNNECESSARY; + break; + } + + /* fall through */ + case CHECKSUM_NONE: + NAPI_GRO_CB(skb)->flush = 1; + return NULL; + } + + return tcp_gro_receive(head, skb); +} +EXPORT_SYMBOL(tcp4_gro_receive); + +int tcp4_gro_complete(struct sk_buff *skb) +{ + struct iphdr *iph = ip_hdr(skb); + struct tcphdr *th = tcp_hdr(skb); + + th->check = ~tcp_v4_check(skb->len - skb_transport_offset(skb), + iph->saddr, iph->daddr, 0); + skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4; + + return tcp_gro_complete(skb); +} +EXPORT_SYMBOL(tcp4_gro_complete); + struct proto tcp_prot = { .name = "TCP", .owner = THIS_MODULE, @@ -2378,6 +2409,7 @@ struct proto tcp_prot = { .sysctl_rmem = sysctl_tcp_rmem, .max_header = MAX_TCP_HEADER, .obj_size = sizeof(struct tcp_sock), + .slab_flags = SLAB_DESTROY_BY_RCU, .twsk_prot = &tcp_timewait_sock_ops, .rsk_prot = &tcp_request_sock_ops, .h.hashinfo = &tcp_hashinfo, @@ -2407,6 +2439,7 @@ static struct pernet_operations __net_initdata tcp_sk_ops = { void __init tcp_v4_init(void) { + inet_hashinfo_init(&tcp_hashinfo); if (register_pernet_device(&tcp_sk_ops)) panic("Failed to create the TCP control socket.\n"); } diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c index 779f2e9d0689449bbf94b3e9c061269c05708d7c..f67effbb102be04ae72b759fa24bef202612f296 100644 --- a/net/ipv4/tcp_minisocks.c +++ b/net/ipv4/tcp_minisocks.c @@ -491,7 +491,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req, * as a request_sock. */ -struct sock *tcp_check_req(struct sock *sk,struct sk_buff *skb, +struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb, struct request_sock *req, struct request_sock **prev) { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index fe3b4bdfd2516d6cfd5297354b7046bf4c97d8e3..557fe16cbfb0c8498e179ddebecc2e602abf5d2e 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -42,7 +42,7 @@ /* People can turn this off for buggy TCP's found in printers etc. */ int sysctl_tcp_retrans_collapse __read_mostly = 1; -/* People can turn this on to work with those rare, broken TCPs that +/* People can turn this on to work with those rare, broken TCPs that * interpret the window field as a signed quantity. */ int sysctl_tcp_workaround_signed_windows __read_mostly = 0; @@ -484,7 +484,7 @@ static unsigned tcp_syn_options(struct sock *sk, struct sk_buff *skb, } if (likely(sysctl_tcp_window_scaling)) { opts->ws = tp->rx_opt.rcv_wscale; - if(likely(opts->ws)) + if (likely(opts->ws)) size += TCPOLEN_WSCALE_ALIGNED; } if (likely(sysctl_tcp_sack)) { @@ -526,7 +526,7 @@ static unsigned tcp_synack_options(struct sock *sk, if (likely(ireq->wscale_ok)) { opts->ws = ireq->rcv_wscale; - if(likely(opts->ws)) + if (likely(opts->ws)) size += TCPOLEN_WSCALE_ALIGNED; } if (likely(doing_ts)) { @@ -663,10 +663,14 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, th->urg_ptr = 0; /* The urg_mode check is necessary during a below snd_una win probe */ - if (unlikely(tcp_urg_mode(tp) && - between(tp->snd_up, tcb->seq + 1, tcb->seq + 0xFFFF))) { - th->urg_ptr = htons(tp->snd_up - tcb->seq); - th->urg = 1; + if (unlikely(tcp_urg_mode(tp))) { + if (between(tp->snd_up, tcb->seq + 1, tcb->seq + 0xFFFF)) { + th->urg_ptr = htons(tp->snd_up - tcb->seq); + th->urg = 1; + } else if (after(tcb->seq + 0xFFFF, tp->snd_nxt)) { + th->urg_ptr = 0xFFFF; + th->urg = 1; + } } tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location); @@ -1168,7 +1172,7 @@ static int tcp_init_tso_segs(struct sock *sk, struct sk_buff *skb, static inline int tcp_minshall_check(const struct tcp_sock *tp) { - return after(tp->snd_sml,tp->snd_una) && + return after(tp->snd_sml, tp->snd_una) && !after(tp->snd_sml, tp->snd_nxt); } @@ -1334,7 +1338,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb) /* Defer for less than two clock ticks. */ if (tp->tso_deferred && - ((jiffies << 1) >> 1) - (tp->tso_deferred >> 1) > 1) + (((u32)jiffies << 1) >> 1) - (tp->tso_deferred >> 1) > 1) goto send_now; in_flight = tcp_packets_in_flight(tp); @@ -1519,7 +1523,8 @@ static int tcp_mtu_probe(struct sock *sk) * Returns 1, if no segments are in flight and we have queued segments, but * cannot send anything now because of SWS or another problem. */ -static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle) +static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle, + int push_one, gfp_t gfp) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; @@ -1527,20 +1532,16 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle) int cwnd_quota; int result; - /* If we are closed, the bytes will have to remain here. - * In time closedown will finish, we empty the write queue and all - * will be happy. - */ - if (unlikely(sk->sk_state == TCP_CLOSE)) - return 0; - sent_pkts = 0; - /* Do MTU probing. */ - if ((result = tcp_mtu_probe(sk)) == 0) { - return 0; - } else if (result > 0) { - sent_pkts = 1; + if (!push_one) { + /* Do MTU probing. */ + result = tcp_mtu_probe(sk); + if (!result) { + return 0; + } else if (result > 0) { + sent_pkts = 1; + } } while ((skb = tcp_send_head(sk))) { @@ -1562,7 +1563,7 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle) nonagle : TCP_NAGLE_PUSH)))) break; } else { - if (tcp_tso_should_defer(sk, skb)) + if (!push_one && tcp_tso_should_defer(sk, skb)) break; } @@ -1577,7 +1578,7 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle) TCP_SKB_CB(skb)->when = tcp_time_stamp; - if (unlikely(tcp_transmit_skb(sk, skb, 1, GFP_ATOMIC))) + if (unlikely(tcp_transmit_skb(sk, skb, 1, gfp))) break; /* Advance the send_head. This one is sent out. @@ -1587,6 +1588,9 @@ static int tcp_write_xmit(struct sock *sk, unsigned int mss_now, int nonagle) tcp_minshall_update(tp, mss_now, skb); sent_pkts++; + + if (push_one) + break; } if (likely(sent_pkts)) { @@ -1605,10 +1609,18 @@ void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, { struct sk_buff *skb = tcp_send_head(sk); - if (skb) { - if (tcp_write_xmit(sk, cur_mss, nonagle)) - tcp_check_probe_timer(sk); - } + if (!skb) + return; + + /* If we are closed, the bytes will have to remain here. + * In time closedown will finish, we empty the write queue and + * all will be happy. + */ + if (unlikely(sk->sk_state == TCP_CLOSE)) + return; + + if (tcp_write_xmit(sk, cur_mss, nonagle, 0, GFP_ATOMIC)) + tcp_check_probe_timer(sk); } /* Send _single_ skb sitting at the send head. This function requires @@ -1616,38 +1628,11 @@ void __tcp_push_pending_frames(struct sock *sk, unsigned int cur_mss, */ void tcp_push_one(struct sock *sk, unsigned int mss_now) { - struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb = tcp_send_head(sk); - unsigned int tso_segs, cwnd_quota; BUG_ON(!skb || skb->len < mss_now); - tso_segs = tcp_init_tso_segs(sk, skb, mss_now); - cwnd_quota = tcp_snd_test(sk, skb, mss_now, TCP_NAGLE_PUSH); - - if (likely(cwnd_quota)) { - unsigned int limit; - - BUG_ON(!tso_segs); - - limit = mss_now; - if (tso_segs > 1 && !tcp_urg_mode(tp)) - limit = tcp_mss_split_point(sk, skb, mss_now, - cwnd_quota); - - if (skb->len > limit && - unlikely(tso_fragment(sk, skb, limit, mss_now))) - return; - - /* Send it out now. */ - TCP_SKB_CB(skb)->when = tcp_time_stamp; - - if (likely(!tcp_transmit_skb(sk, skb, 1, sk->sk_allocation))) { - tcp_event_new_data_sent(sk, skb); - tcp_cwnd_validate(sk); - return; - } - } + tcp_write_xmit(sk, mss_now, TCP_NAGLE_PUSH, 1, sk->sk_allocation); } /* This function returns the amount that we can raise the @@ -1767,46 +1752,22 @@ u32 __tcp_select_window(struct sock *sk) return window; } -/* Attempt to collapse two adjacent SKB's during retransmission. */ -static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, - int mss_now) +/* Collapses two adjacent SKB's during retransmission. */ +static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb) { struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *next_skb = tcp_write_queue_next(sk, skb); int skb_size, next_skb_size; u16 flags; - /* The first test we must make is that neither of these two - * SKB's are still referenced by someone else. - */ - if (skb_cloned(skb) || skb_cloned(next_skb)) - return; - skb_size = skb->len; next_skb_size = next_skb->len; flags = TCP_SKB_CB(skb)->flags; - /* Also punt if next skb has been SACK'd. */ - if (TCP_SKB_CB(next_skb)->sacked & TCPCB_SACKED_ACKED) - return; - - /* Next skb is out of window. */ - if (after(TCP_SKB_CB(next_skb)->end_seq, tcp_wnd_end(tp))) - return; - - /* Punt if not enough space exists in the first SKB for - * the data in the second, or the total combined payload - * would exceed the MSS. - */ - if ((next_skb_size > skb_tailroom(skb)) || - ((skb_size + next_skb_size) > mss_now)) - return; - BUG_ON(tcp_skb_pcount(skb) != 1 || tcp_skb_pcount(next_skb) != 1); tcp_highest_sack_combine(sk, next_skb, skb); - /* Ok. We will be able to collapse the packet. */ tcp_unlink_write_queue(next_skb, sk); skb_copy_from_linear_data(next_skb, skb_put(skb, next_skb_size), @@ -1848,54 +1809,60 @@ static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *skb, sk_wmem_free_skb(sk, next_skb); } -/* Do a simple retransmit without using the backoff mechanisms in - * tcp_timer. This is used for path mtu discovery. - * The socket is already locked here. - */ -void tcp_simple_retransmit(struct sock *sk) +static int tcp_can_collapse(struct sock *sk, struct sk_buff *skb) +{ + if (tcp_skb_pcount(skb) > 1) + return 0; + /* TODO: SACK collapsing could be used to remove this condition */ + if (skb_shinfo(skb)->nr_frags != 0) + return 0; + if (skb_cloned(skb)) + return 0; + if (skb == tcp_send_head(sk)) + return 0; + /* Some heurestics for collapsing over SACK'd could be invented */ + if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED) + return 0; + + return 1; +} + +static void tcp_retrans_try_collapse(struct sock *sk, struct sk_buff *to, + int space) { - const struct inet_connection_sock *icsk = inet_csk(sk); struct tcp_sock *tp = tcp_sk(sk); - struct sk_buff *skb; - unsigned int mss = tcp_current_mss(sk, 0); - u32 prior_lost = tp->lost_out; + struct sk_buff *skb = to, *tmp; + int first = 1; - tcp_for_write_queue(skb, sk) { - if (skb == tcp_send_head(sk)) + if (!sysctl_tcp_retrans_collapse) + return; + if (TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) + return; + + tcp_for_write_queue_from_safe(skb, tmp, sk) { + if (!tcp_can_collapse(sk, skb)) break; - if (skb->len > mss && - !(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_ACKED)) { - if (TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS) { - TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS; - tp->retrans_out -= tcp_skb_pcount(skb); - } - tcp_skb_mark_lost_uncond_verify(tp, skb); - } - } - tcp_clear_retrans_hints_partial(tp); + space -= skb->len; - if (prior_lost == tp->lost_out) - return; + if (first) { + first = 0; + continue; + } - if (tcp_is_reno(tp)) - tcp_limit_reno_sacked(tp); + if (space < 0) + break; + /* Punt if not enough space exists in the first SKB for + * the data in the second + */ + if (skb->len > skb_tailroom(to)) + break; - tcp_verify_left_out(tp); + if (after(TCP_SKB_CB(skb)->end_seq, tcp_wnd_end(tp))) + break; - /* Don't muck with the congestion window here. - * Reason is that we do not increase amount of _data_ - * in network, but units changed and effective - * cwnd/ssthresh really reduced now. - */ - if (icsk->icsk_ca_state != TCP_CA_Loss) { - tp->high_seq = tp->snd_nxt; - tp->snd_ssthresh = tcp_current_ssthresh(sk); - tp->prior_ssthresh = 0; - tp->undo_marker = 0; - tcp_set_ca_state(sk, TCP_CA_Loss); + tcp_collapse_retrans(sk, to); } - tcp_xmit_retransmit_queue(sk); } /* This retransmits one SKB. Policy decisions and retransmit queue @@ -1947,17 +1914,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb) return -ENOMEM; /* We'll try again later. */ } - /* Collapse two adjacent packets if worthwhile and we can. */ - if (!(TCP_SKB_CB(skb)->flags & TCPCB_FLAG_SYN) && - (skb->len < (cur_mss >> 1)) && - (!tcp_skb_is_last(sk, skb)) && - (tcp_write_queue_next(sk, skb) != tcp_send_head(sk)) && - (skb_shinfo(skb)->nr_frags == 0 && - skb_shinfo(tcp_write_queue_next(sk, skb))->nr_frags == 0) && - (tcp_skb_pcount(skb) == 1 && - tcp_skb_pcount(tcp_write_queue_next(sk, skb)) == 1) && - (sysctl_tcp_retrans_collapse != 0)) - tcp_retrans_try_collapse(sk, skb, cur_mss); + tcp_retrans_try_collapse(sk, skb, cur_mss); /* Some Solaris stacks overoptimize and ignore the FIN on a * retransmit when old data is attached. So strip it off diff --git a/net/ipv4/tcp_probe.c b/net/ipv4/tcp_probe.c index 7ddc30f0744ff13afe250c37f000fe46d144efcc..25524d4e372a387a4897c64281c3bd8eefc70b53 100644 --- a/net/ipv4/tcp_probe.c +++ b/net/ipv4/tcp_probe.c @@ -153,12 +153,11 @@ static int tcpprobe_sprint(char *tbuf, int n) = ktime_to_timespec(ktime_sub(p->tstamp, tcp_probe.start)); return snprintf(tbuf, n, - "%lu.%09lu " NIPQUAD_FMT ":%u " NIPQUAD_FMT ":%u" - " %d %#x %#x %u %u %u %u\n", + "%lu.%09lu %pI4:%u %pI4:%u %d %#x %#x %u %u %u %u\n", (unsigned long) tv.tv_sec, (unsigned long) tv.tv_nsec, - NIPQUAD(p->saddr), ntohs(p->sport), - NIPQUAD(p->daddr), ntohs(p->dport), + &p->saddr, ntohs(p->sport), + &p->daddr, ntohs(p->dport), p->length, p->snd_nxt, p->snd_una, p->snd_cwnd, p->ssthresh, p->snd_wnd, p->srtt); } diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c index 6b6dff1164b93209da97bf673fd76707c216ea1b..0170e914f1b0472efb13b5d26179936faaa66ec0 100644 --- a/net/ipv4/tcp_timer.c +++ b/net/ipv4/tcp_timer.c @@ -65,7 +65,7 @@ static void tcp_write_err(struct sock *sk) static int tcp_out_of_resources(struct sock *sk, int do_reset) { struct tcp_sock *tp = tcp_sk(sk); - int orphans = atomic_read(&tcp_orphan_count); + int orphans = percpu_counter_read_positive(&tcp_orphan_count); /* If peer does not open window for long time, or did not transmit * anything for long time, penalize it. */ @@ -171,7 +171,7 @@ static int tcp_write_timeout(struct sock *sk) static void tcp_delack_timer(unsigned long data) { - struct sock *sk = (struct sock*)data; + struct sock *sk = (struct sock *)data; struct tcp_sock *tp = tcp_sk(sk); struct inet_connection_sock *icsk = inet_csk(sk); @@ -299,15 +299,15 @@ static void tcp_retransmit_timer(struct sock *sk) #ifdef TCP_DEBUG struct inet_sock *inet = inet_sk(sk); if (sk->sk_family == AF_INET) { - LIMIT_NETDEBUG(KERN_DEBUG "TCP: Treason uncloaked! Peer " NIPQUAD_FMT ":%u/%u shrinks window %u:%u. Repaired.\n", - NIPQUAD(inet->daddr), ntohs(inet->dport), + LIMIT_NETDEBUG(KERN_DEBUG "TCP: Peer %pI4:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", + &inet->daddr, ntohs(inet->dport), inet->num, tp->snd_una, tp->snd_nxt); } #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) else if (sk->sk_family == AF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); - LIMIT_NETDEBUG(KERN_DEBUG "TCP: Treason uncloaked! Peer " NIP6_FMT ":%u/%u shrinks window %u:%u. Repaired.\n", - NIP6(np->daddr), ntohs(inet->dport), + LIMIT_NETDEBUG(KERN_DEBUG "TCP: Peer %pI6:%u/%u unexpectedly shrunk window %u:%u (repaired)\n", + &np->daddr, ntohs(inet->dport), inet->num, tp->snd_una, tp->snd_nxt); } #endif @@ -396,7 +396,7 @@ out:; static void tcp_write_timer(unsigned long data) { - struct sock *sk = (struct sock*)data; + struct sock *sk = (struct sock *)data; struct inet_connection_sock *icsk = inet_csk(sk); int event; diff --git a/net/ipv4/tcp_yeah.c b/net/ipv4/tcp_yeah.c index e03b10183a8b86810cc7f33d4bc69815d3c05f7f..9ec843a9bbb2507a9d96cc088ef6b167747ea603 100644 --- a/net/ipv4/tcp_yeah.c +++ b/net/ipv4/tcp_yeah.c @@ -83,7 +83,7 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) else if (!yeah->doing_reno_now) { /* Scalable */ - tp->snd_cwnd_cnt+=yeah->pkts_acked; + tp->snd_cwnd_cnt += yeah->pkts_acked; if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)){ if (tp->snd_cwnd < tp->snd_cwnd_clamp) tp->snd_cwnd++; @@ -224,7 +224,7 @@ static u32 tcp_yeah_ssthresh(struct sock *sk) { reduction = max( reduction, tp->snd_cwnd >> TCP_YEAH_DELTA); } else - reduction = max(tp->snd_cwnd>>1,2U); + reduction = max(tp->snd_cwnd>>1, 2U); yeah->fast_count = 0; yeah->reno_count = max(yeah->reno_count>>1, 2U); diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 98c1fd09be88c352c29b9f2229cd81fd695f4460..cf5ab0581ebac98ddf919f92083f7066aa0bf61f 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -81,6 +81,8 @@ #include #include #include +#include +#include #include #include #include @@ -104,12 +106,8 @@ #include #include "udp_impl.h" -/* - * Snmp MIB for the UDP layer - */ - -struct hlist_head udp_hash[UDP_HTABLE_SIZE]; -DEFINE_RWLOCK(udp_hash_lock); +struct udp_table udp_table; +EXPORT_SYMBOL(udp_table); int sysctl_udp_mem[3] __read_mostly; int sysctl_udp_rmem_min __read_mostly; @@ -123,15 +121,15 @@ atomic_t udp_memory_allocated; EXPORT_SYMBOL(udp_memory_allocated); static int udp_lib_lport_inuse(struct net *net, __u16 num, - const struct hlist_head udptable[], + const struct udp_hslot *hslot, struct sock *sk, int (*saddr_comp)(const struct sock *sk1, const struct sock *sk2)) { struct sock *sk2; - struct hlist_node *node; + struct hlist_nulls_node *node; - sk_for_each(sk2, node, &udptable[udp_hashfn(net, num)]) + sk_nulls_for_each(sk2, node, &hslot->head) if (net_eq(sock_net(sk2), net) && sk2 != sk && sk2->sk_hash == num && @@ -154,12 +152,11 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, int (*saddr_comp)(const struct sock *sk1, const struct sock *sk2 ) ) { - struct hlist_head *udptable = sk->sk_prot->h.udp_hash; + struct udp_hslot *hslot; + struct udp_table *udptable = sk->sk_prot->h.udp_table; int error = 1; struct net *net = sock_net(sk); - write_lock_bh(&udp_hash_lock); - if (!snum) { int low, high, remaining; unsigned rand; @@ -171,26 +168,34 @@ int udp_lib_get_port(struct sock *sk, unsigned short snum, rand = net_random(); snum = first = rand % remaining + low; rand |= 1; - while (udp_lib_lport_inuse(net, snum, udptable, sk, - saddr_comp)) { + for (;;) { + hslot = &udptable->hash[udp_hashfn(net, snum)]; + spin_lock_bh(&hslot->lock); + if (!udp_lib_lport_inuse(net, snum, hslot, sk, saddr_comp)) + break; + spin_unlock_bh(&hslot->lock); do { snum = snum + rand; } while (snum < low || snum > high); if (snum == first) goto fail; } - } else if (udp_lib_lport_inuse(net, snum, udptable, sk, saddr_comp)) - goto fail; - + } else { + hslot = &udptable->hash[udp_hashfn(net, snum)]; + spin_lock_bh(&hslot->lock); + if (udp_lib_lport_inuse(net, snum, hslot, sk, saddr_comp)) + goto fail_unlock; + } inet_sk(sk)->num = snum; sk->sk_hash = snum; if (sk_unhashed(sk)) { - sk_add_node(sk, &udptable[udp_hashfn(net, snum)]); + sk_nulls_add_node_rcu(sk, &hslot->head); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); } error = 0; +fail_unlock: + spin_unlock_bh(&hslot->lock); fail: - write_unlock_bh(&udp_hash_lock); return error; } @@ -208,63 +213,91 @@ int udp_v4_get_port(struct sock *sk, unsigned short snum) return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal); } +static inline int compute_score(struct sock *sk, struct net *net, __be32 saddr, + unsigned short hnum, + __be16 sport, __be32 daddr, __be16 dport, int dif) +{ + int score = -1; + + if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && + !ipv6_only_sock(sk)) { + struct inet_sock *inet = inet_sk(sk); + + score = (sk->sk_family == PF_INET ? 1 : 0); + if (inet->rcv_saddr) { + if (inet->rcv_saddr != daddr) + return -1; + score += 2; + } + if (inet->daddr) { + if (inet->daddr != saddr) + return -1; + score += 2; + } + if (inet->dport) { + if (inet->dport != sport) + return -1; + score += 2; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + return -1; + score += 2; + } + } + return score; +} + /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, __be32 daddr, __be16 dport, - int dif, struct hlist_head udptable[]) + int dif, struct udp_table *udptable) { - struct sock *sk, *result = NULL; - struct hlist_node *node; + struct sock *sk, *result; + struct hlist_nulls_node *node; unsigned short hnum = ntohs(dport); - int badness = -1; - - read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udptable[udp_hashfn(net, hnum)]) { - struct inet_sock *inet = inet_sk(sk); - - if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && - !ipv6_only_sock(sk)) { - int score = (sk->sk_family == PF_INET ? 1 : 0); - if (inet->rcv_saddr) { - if (inet->rcv_saddr != daddr) - continue; - score+=2; - } - if (inet->daddr) { - if (inet->daddr != saddr) - continue; - score+=2; - } - if (inet->dport) { - if (inet->dport != sport) - continue; - score+=2; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - continue; - score+=2; - } - if (score == 9) { - result = sk; - break; - } else if (score > badness) { - result = sk; - badness = score; - } + unsigned int hash = udp_hashfn(net, hnum); + struct udp_hslot *hslot = &udptable->hash[hash]; + int score, badness; + + rcu_read_lock(); +begin: + result = NULL; + badness = -1; + sk_nulls_for_each_rcu(sk, node, &hslot->head) { + score = compute_score(sk, net, saddr, hnum, sport, + daddr, dport, dif); + if (score > badness) { + result = sk; + badness = score; } } - if (result) - sock_hold(result); - read_unlock(&udp_hash_lock); + /* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (get_nulls_value(node) != hash) + goto begin; + + if (result) { + if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) + result = NULL; + else if (unlikely(compute_score(result, net, saddr, hnum, sport, + daddr, dport, dif) < badness)) { + sock_put(result); + goto begin; + } + } + rcu_read_unlock(); return result; } static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb, __be16 sport, __be16 dport, - struct hlist_head udptable[]) + struct udp_table *udptable) { struct sock *sk; const struct iphdr *iph = ip_hdr(skb); @@ -280,7 +313,7 @@ static inline struct sock *__udp4_lib_lookup_skb(struct sk_buff *skb, struct sock *udp4_lib_lookup(struct net *net, __be32 saddr, __be16 sport, __be32 daddr, __be16 dport, int dif) { - return __udp4_lib_lookup(net, saddr, sport, daddr, dport, dif, udp_hash); + return __udp4_lib_lookup(net, saddr, sport, daddr, dport, dif, &udp_table); } EXPORT_SYMBOL_GPL(udp4_lib_lookup); @@ -289,11 +322,11 @@ static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk, __be16 rmt_port, __be32 rmt_addr, int dif) { - struct hlist_node *node; + struct hlist_nulls_node *node; struct sock *s = sk; unsigned short hnum = ntohs(loc_port); - sk_for_each_from(s, node) { + sk_nulls_for_each_from(s, node) { struct inet_sock *inet = inet_sk(s); if (!net_eq(sock_net(s), net) || @@ -324,7 +357,7 @@ found: * to find the appropriate port. */ -void __udp4_lib_err(struct sk_buff *skb, u32 info, struct hlist_head udptable[]) +void __udp4_lib_err(struct sk_buff *skb, u32 info, struct udp_table *udptable) { struct inet_sock *inet; struct iphdr *iph = (struct iphdr*)skb->data; @@ -393,7 +426,7 @@ out: void udp_err(struct sk_buff *skb, u32 info) { - __udp4_lib_err(skb, info, udp_hash); + __udp4_lib_err(skb, info, &udp_table); } /* @@ -686,7 +719,7 @@ do_append_data: up->len += ulen; getfrag = is_udplite ? udplite_getfrag : ip_generic_getfrag; err = ip_append_data(sk, getfrag, msg->msg_iov, ulen, - sizeof(struct udphdr), &ipc, rt, + sizeof(struct udphdr), &ipc, &rt, corkreq ? msg->msg_flags|MSG_MORE : msg->msg_flags); if (err) udp_flush_pending_frames(sk); @@ -935,6 +968,23 @@ int udp_disconnect(struct sock *sk, int flags) return 0; } +void udp_lib_unhash(struct sock *sk) +{ + if (sk_hashed(sk)) { + struct udp_table *udptable = sk->sk_prot->h.udp_table; + unsigned int hash = udp_hashfn(sock_net(sk), sk->sk_hash); + struct udp_hslot *hslot = &udptable->hash[hash]; + + spin_lock_bh(&hslot->lock); + if (sk_nulls_del_node_init_rcu(sk)) { + inet_sk(sk)->num = 0; + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + } + spin_unlock_bh(&hslot->lock); + } +} +EXPORT_SYMBOL(udp_lib_unhash); + static int __udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) { int is_udplite = IS_UDPLITE(sk); @@ -1073,13 +1123,14 @@ drop: static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, struct udphdr *uh, __be32 saddr, __be32 daddr, - struct hlist_head udptable[]) + struct udp_table *udptable) { struct sock *sk; + struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))]; int dif; - read_lock(&udp_hash_lock); - sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]); + spin_lock(&hslot->lock); + sk = sk_nulls_head(&hslot->head); dif = skb->dev->ifindex; sk = udp_v4_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); if (sk) { @@ -1088,7 +1139,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, do { struct sk_buff *skb1 = skb; - sknext = udp_v4_mcast_next(net, sk_next(sk), uh->dest, + sknext = udp_v4_mcast_next(net, sk_nulls_next(sk), uh->dest, daddr, uh->source, saddr, dif); if (sknext) @@ -1105,7 +1156,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb, } while (sknext); } else kfree_skb(skb); - read_unlock(&udp_hash_lock); + spin_unlock(&hslot->lock); return 0; } @@ -1151,7 +1202,7 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh, * All we need to do is get the socket, and then do a checksum. */ -int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], +int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, int proto) { struct sock *sk; @@ -1219,13 +1270,13 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], return 0; short_packet: - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From " NIPQUAD_FMT ":%u %d/%d to " NIPQUAD_FMT ":%u\n", + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: short packet: From %pI4:%u %d/%d to %pI4:%u\n", proto == IPPROTO_UDPLITE ? "-Lite" : "", - NIPQUAD(saddr), + &saddr, ntohs(uh->source), ulen, skb->len, - NIPQUAD(daddr), + &daddr, ntohs(uh->dest)); goto drop; @@ -1234,11 +1285,11 @@ csum_error: * RFC1122: OK. Discards the bad packet silently (as far as * the network is concerned, anyway) as per 4.1.3.4 (MUST). */ - LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From " NIPQUAD_FMT ":%u to " NIPQUAD_FMT ":%u ulen %d\n", + LIMIT_NETDEBUG(KERN_DEBUG "UDP%s: bad checksum. From %pI4:%u to %pI4:%u ulen %d\n", proto == IPPROTO_UDPLITE ? "-Lite" : "", - NIPQUAD(saddr), + &saddr, ntohs(uh->source), - NIPQUAD(daddr), + &daddr, ntohs(uh->dest), ulen); drop: @@ -1249,7 +1300,7 @@ drop: int udp_rcv(struct sk_buff *skb) { - return __udp4_lib_rcv(skb, udp_hash, IPPROTO_UDP); + return __udp4_lib_rcv(skb, &udp_table, IPPROTO_UDP); } void udp_destroy_sock(struct sock *sk) @@ -1491,7 +1542,8 @@ struct proto udp_prot = { .sysctl_wmem = &sysctl_udp_wmem_min, .sysctl_rmem = &sysctl_udp_rmem_min, .obj_size = sizeof(struct udp_sock), - .h.udp_hash = udp_hash, + .slab_flags = SLAB_DESTROY_BY_RCU, + .h.udp_table = &udp_table, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_udp_setsockopt, .compat_getsockopt = compat_udp_getsockopt, @@ -1501,20 +1553,23 @@ struct proto udp_prot = { /* ------------------------------------------------------------------------ */ #ifdef CONFIG_PROC_FS -static struct sock *udp_get_first(struct seq_file *seq) +static struct sock *udp_get_first(struct seq_file *seq, int start) { struct sock *sk; struct udp_iter_state *state = seq->private; struct net *net = seq_file_net(seq); - for (state->bucket = 0; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { - struct hlist_node *node; - sk_for_each(sk, node, state->hashtable + state->bucket) { + for (state->bucket = start; state->bucket < UDP_HTABLE_SIZE; ++state->bucket) { + struct hlist_nulls_node *node; + struct udp_hslot *hslot = &state->udp_table->hash[state->bucket]; + spin_lock_bh(&hslot->lock); + sk_nulls_for_each(sk, node, &hslot->head) { if (!net_eq(sock_net(sk), net)) continue; if (sk->sk_family == state->family) goto found; } + spin_unlock_bh(&hslot->lock); } sk = NULL; found: @@ -1527,21 +1582,19 @@ static struct sock *udp_get_next(struct seq_file *seq, struct sock *sk) struct net *net = seq_file_net(seq); do { - sk = sk_next(sk); -try_again: - ; + sk = sk_nulls_next(sk); } while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family)); - if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { - sk = sk_head(state->hashtable + state->bucket); - goto try_again; + if (!sk) { + spin_unlock_bh(&state->udp_table->hash[state->bucket].lock); + return udp_get_first(seq, state->bucket + 1); } return sk; } static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos) { - struct sock *sk = udp_get_first(seq); + struct sock *sk = udp_get_first(seq, 0); if (sk) while (pos && (sk = udp_get_next(seq, sk)) != NULL) @@ -1550,9 +1603,7 @@ static struct sock *udp_get_idx(struct seq_file *seq, loff_t pos) } static void *udp_seq_start(struct seq_file *seq, loff_t *pos) - __acquires(udp_hash_lock) { - read_lock(&udp_hash_lock); return *pos ? udp_get_idx(seq, *pos-1) : SEQ_START_TOKEN; } @@ -1570,9 +1621,11 @@ static void *udp_seq_next(struct seq_file *seq, void *v, loff_t *pos) } static void udp_seq_stop(struct seq_file *seq, void *v) - __releases(udp_hash_lock) { - read_unlock(&udp_hash_lock); + struct udp_iter_state *state = seq->private; + + if (state->bucket < UDP_HTABLE_SIZE) + spin_unlock_bh(&state->udp_table->hash[state->bucket].lock); } static int udp_seq_open(struct inode *inode, struct file *file) @@ -1588,7 +1641,7 @@ static int udp_seq_open(struct inode *inode, struct file *file) s = ((struct seq_file *)file->private_data)->private; s->family = afinfo->family; - s->hashtable = afinfo->hashtable; + s->udp_table = afinfo->udp_table; return err; } @@ -1660,7 +1713,7 @@ int udp4_seq_show(struct seq_file *seq, void *v) static struct udp_seq_afinfo udp4_seq_afinfo = { .name = "udp", .family = AF_INET, - .hashtable = udp_hash, + .udp_table = &udp_table, .seq_fops = { .owner = THIS_MODULE, }, @@ -1695,16 +1748,28 @@ void udp4_proc_exit(void) } #endif /* CONFIG_PROC_FS */ +void __init udp_table_init(struct udp_table *table) +{ + int i; + + for (i = 0; i < UDP_HTABLE_SIZE; i++) { + INIT_HLIST_NULLS_HEAD(&table->hash[i].head, i); + spin_lock_init(&table->hash[i].lock); + } +} + void __init udp_init(void) { - unsigned long limit; + unsigned long nr_pages, limit; + udp_table_init(&udp_table); /* Set the pressure threshold up by the same strategy of TCP. It is a * fraction of global memory that is up to 1/2 at 256 MB, decreasing * toward zero with the amount of memory, with a floor of 128 pages. */ - limit = min(nr_all_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT); - limit = (limit * (nr_all_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11); + nr_pages = totalram_pages - totalhigh_pages; + limit = min(nr_pages, 1UL<<(28-PAGE_SHIFT)) >> (20-PAGE_SHIFT); + limit = (limit * (nr_pages >> (20-PAGE_SHIFT))) >> (PAGE_SHIFT-11); limit = max(limit, 128UL); sysctl_udp_mem[0] = limit / 4 * 3; sysctl_udp_mem[1] = limit; @@ -1715,8 +1780,6 @@ void __init udp_init(void) } EXPORT_SYMBOL(udp_disconnect); -EXPORT_SYMBOL(udp_hash); -EXPORT_SYMBOL(udp_hash_lock); EXPORT_SYMBOL(udp_ioctl); EXPORT_SYMBOL(udp_prot); EXPORT_SYMBOL(udp_sendmsg); diff --git a/net/ipv4/udp_impl.h b/net/ipv4/udp_impl.h index 2e9bad2fa1bcd682049846179e2ee19ecf1bd1b6..9f4a6165f7229ca68deaf98aeadae777a61437a0 100644 --- a/net/ipv4/udp_impl.h +++ b/net/ipv4/udp_impl.h @@ -5,8 +5,8 @@ #include #include -extern int __udp4_lib_rcv(struct sk_buff *, struct hlist_head [], int ); -extern void __udp4_lib_err(struct sk_buff *, u32, struct hlist_head []); +extern int __udp4_lib_rcv(struct sk_buff *, struct udp_table *, int ); +extern void __udp4_lib_err(struct sk_buff *, u32, struct udp_table *); extern int udp_v4_get_port(struct sock *sk, unsigned short snum); diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index 3c807964da96a95eb08f738974abda92b0959f87..c784891cb7e57b3f037b26f858c714bfc9614a33 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -12,16 +12,17 @@ */ #include "udp_impl.h" -struct hlist_head udplite_hash[UDP_HTABLE_SIZE]; +struct udp_table udplite_table; +EXPORT_SYMBOL(udplite_table); static int udplite_rcv(struct sk_buff *skb) { - return __udp4_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); + return __udp4_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE); } static void udplite_err(struct sk_buff *skb, u32 info) { - __udp4_lib_err(skb, info, udplite_hash); + __udp4_lib_err(skb, info, &udplite_table); } static struct net_protocol udplite_protocol = { @@ -50,7 +51,8 @@ struct proto udplite_prot = { .unhash = udp_lib_unhash, .get_port = udp_v4_get_port, .obj_size = sizeof(struct udp_sock), - .h.udp_hash = udplite_hash, + .slab_flags = SLAB_DESTROY_BY_RCU, + .h.udp_table = &udplite_table, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_udp_setsockopt, .compat_getsockopt = compat_udp_getsockopt, @@ -71,7 +73,7 @@ static struct inet_protosw udplite4_protosw = { static struct udp_seq_afinfo udplite4_seq_afinfo = { .name = "udplite", .family = AF_INET, - .hashtable = udplite_hash, + .udp_table = &udplite_table, .seq_fops = { .owner = THIS_MODULE, }, @@ -108,6 +110,7 @@ static inline int udplite4_proc_init(void) void __init udplite4_register(void) { + udp_table_init(&udplite_table); if (proto_register(&udplite_prot, 1)) goto out_register_err; @@ -126,5 +129,4 @@ out_register_err: printk(KERN_CRIT "%s: Cannot add UDP-Lite protocol.\n", __func__); } -EXPORT_SYMBOL(udplite_hash); EXPORT_SYMBOL(udplite_prot); diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 390dcb1354a5e4f6c76ad0c9bf8d3bc238a217ab..4ec2162a437ecc1faca91a862486e53422ab8cb2 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -78,7 +78,6 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) struct udphdr *uh; struct iphdr *iph; int iphlen, len; - int ret; __u8 *udpdata; __be32 *udpdata32; @@ -152,8 +151,7 @@ int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb) skb_reset_transport_header(skb); /* process ESP */ - ret = xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type); - return ret; + return xfrm4_rcv_encap(skb, IPPROTO_ESP, 0, encap_type); drop: kfree_skb(skb); diff --git a/net/ipv4/xfrm4_policy.c b/net/ipv4/xfrm4_policy.c index c63de0a72aba746184e1c4e9f97aefe57cdff1a8..2ad24ba31f9de591df4305d7b3d406318ec18976 100644 --- a/net/ipv4/xfrm4_policy.c +++ b/net/ipv4/xfrm4_policy.c @@ -18,7 +18,8 @@ static struct dst_ops xfrm4_dst_ops; static struct xfrm_policy_afinfo xfrm4_policy_afinfo; -static struct dst_entry *xfrm4_dst_lookup(int tos, xfrm_address_t *saddr, +static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, + xfrm_address_t *saddr, xfrm_address_t *daddr) { struct flowi fl = { @@ -36,19 +37,20 @@ static struct dst_entry *xfrm4_dst_lookup(int tos, xfrm_address_t *saddr, if (saddr) fl.fl4_src = saddr->a4; - err = __ip_route_output_key(&init_net, &rt, &fl); + err = __ip_route_output_key(net, &rt, &fl); dst = &rt->u.dst; if (err) dst = ERR_PTR(err); return dst; } -static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) +static int xfrm4_get_saddr(struct net *net, + xfrm_address_t *saddr, xfrm_address_t *daddr) { struct dst_entry *dst; struct rtable *rt; - dst = xfrm4_dst_lookup(0, NULL, daddr); + dst = xfrm4_dst_lookup(net, 0, NULL, daddr); if (IS_ERR(dst)) return -EHOSTUNREACH; @@ -65,7 +67,7 @@ __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy) read_lock_bh(&policy->lock); for (dst = policy->bundles; dst; dst = dst->next) { - struct xfrm_dst *xdst = (struct xfrm_dst*)dst; + struct xfrm_dst *xdst = (struct xfrm_dst *)dst; if (xdst->u.rt.fl.oif == fl->oif && /*XXX*/ xdst->u.rt.fl.fl4_dst == fl->fl4_dst && xdst->u.rt.fl.fl4_src == fl->fl4_src && @@ -187,7 +189,7 @@ _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) static inline int xfrm4_garbage_collect(struct dst_ops *ops) { - xfrm4_policy_afinfo.garbage_collect(); + xfrm4_policy_afinfo.garbage_collect(&init_net); return (atomic_read(&xfrm4_dst_ops.entries) > xfrm4_dst_ops.gc_thresh*2); } @@ -246,7 +248,6 @@ static struct dst_ops xfrm4_dst_ops = { .ifdown = xfrm4_dst_ifdown, .local_out = __ip_local_out, .gc_thresh = 1024, - .entry_size = sizeof(struct xfrm_dst), .entries = ATOMIC_INIT(0), }; diff --git a/net/ipv4/xfrm4_state.c b/net/ipv4/xfrm4_state.c index 55dc6beab9aa5344629021d04c526870fddd1fe4..1ef1366a0a03775eed25ab5ef0b083aed593726e 100644 --- a/net/ipv4/xfrm4_state.c +++ b/net/ipv4/xfrm4_state.c @@ -13,8 +13,6 @@ #include #include -static struct xfrm_state_afinfo xfrm4_state_afinfo; - static int xfrm4_init_flags(struct xfrm_state *x) { if (ipv4_config.no_pmtu_disc) diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index d9da5eb9dcb20c81f9b04619b6b2f9c73c7f0ca7..e92ad8455c63a851ef9966705b627299459f0bb2 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -2031,8 +2031,8 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg) #if defined(CONFIG_IPV6_SIT) || defined(CONFIG_IPV6_SIT_MODULE) if (dev->type == ARPHRD_SIT) { + const struct net_device_ops *ops = dev->netdev_ops; struct ifreq ifr; - mm_segment_t oldfs; struct ip_tunnel_parm p; err = -EADDRNOTAVAIL; @@ -2048,9 +2048,14 @@ int addrconf_set_dstaddr(struct net *net, void __user *arg) p.iph.ttl = 64; ifr.ifr_ifru.ifru_data = (__force void __user *)&p; - oldfs = get_fs(); set_fs(KERNEL_DS); - err = dev->do_ioctl(dev, &ifr, SIOCADDTUNNEL); - set_fs(oldfs); + if (ops->ndo_do_ioctl) { + mm_segment_t oldfs = get_fs(); + + set_fs(KERNEL_DS); + err = ops->ndo_do_ioctl(dev, &ifr, SIOCADDTUNNEL); + set_fs(oldfs); + } else + err = -EOPNOTSUPP; if (err == 0) { err = -ENOBUFS; @@ -2988,9 +2993,8 @@ static void if6_seq_stop(struct seq_file *seq, void *v) static int if6_seq_show(struct seq_file *seq, void *v) { struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v; - seq_printf(seq, - NIP6_SEQFMT " %02x %02x %02x %02x %8s\n", - NIP6(ifp->addr), + seq_printf(seq, "%pi6 %02x %02x %02x %02x %8s\n", + &ifp->addr, ifp->idev->dev->ifindex, ifp->prefix_len, ifp->scope, @@ -4033,8 +4037,8 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.forwarding, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &addrconf_sysctl_forward, - .strategy = &addrconf_sysctl_forward_strategy, + .proc_handler = addrconf_sysctl_forward, + .strategy = addrconf_sysctl_forward_strategy, }, { .ctl_name = NET_IPV6_HOP_LIMIT, @@ -4050,7 +4054,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.mtu6, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_ACCEPT_RA, @@ -4058,7 +4062,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.accept_ra, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_ACCEPT_REDIRECTS, @@ -4066,7 +4070,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.accept_redirects, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_AUTOCONF, @@ -4074,7 +4078,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.autoconf, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_DAD_TRANSMITS, @@ -4082,7 +4086,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.dad_transmits, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_RTR_SOLICITS, @@ -4090,7 +4094,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.rtr_solicits, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_RTR_SOLICIT_INTERVAL, @@ -4098,8 +4102,8 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.rtr_solicit_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV6_RTR_SOLICIT_DELAY, @@ -4107,8 +4111,8 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.rtr_solicit_delay, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV6_FORCE_MLD_VERSION, @@ -4116,7 +4120,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.force_mld_version, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, #ifdef CONFIG_IPV6_PRIVACY { @@ -4125,7 +4129,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.use_tempaddr, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_TEMP_VALID_LFT, @@ -4133,7 +4137,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.temp_valid_lft, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_TEMP_PREFERED_LFT, @@ -4141,7 +4145,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.temp_prefered_lft, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_REGEN_MAX_RETRY, @@ -4149,7 +4153,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.regen_max_retry, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_MAX_DESYNC_FACTOR, @@ -4157,7 +4161,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.max_desync_factor, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, #endif { @@ -4166,7 +4170,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.max_addresses, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_ACCEPT_RA_DEFRTR, @@ -4174,7 +4178,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.accept_ra_defrtr, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_ACCEPT_RA_PINFO, @@ -4182,7 +4186,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.accept_ra_pinfo, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, #ifdef CONFIG_IPV6_ROUTER_PREF { @@ -4191,7 +4195,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.accept_ra_rtr_pref, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_RTR_PROBE_INTERVAL, @@ -4199,8 +4203,8 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.rtr_probe_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, #ifdef CONFIG_IPV6_ROUTE_INFO { @@ -4209,7 +4213,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.accept_ra_rt_info_max_plen, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, #endif #endif @@ -4219,7 +4223,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.proxy_ndp, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_ACCEPT_SOURCE_ROUTE, @@ -4227,7 +4231,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.accept_source_route, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, #ifdef CONFIG_IPV6_OPTIMISTIC_DAD { @@ -4236,7 +4240,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.optimistic_dad, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, #endif @@ -4247,7 +4251,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.mc_forwarding, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, #endif { @@ -4256,7 +4260,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.disable_ipv6, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = CTL_UNNUMBERED, @@ -4264,7 +4268,7 @@ static struct addrconf_sysctl_table .data = &ipv6_devconf.accept_dad, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = 0, /* sentinel */ diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c index 08909039d87b570617750c8b9e6a27f973bbbfc4..6ff73c4c126aeabc14e102df05d879f4463825e9 100644 --- a/net/ipv6/addrlabel.c +++ b/net/ipv6/addrlabel.c @@ -186,10 +186,8 @@ u32 ipv6_addr_label(struct net *net, label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT; rcu_read_unlock(); - ADDRLABEL(KERN_DEBUG "%s(addr=" NIP6_FMT ", type=%d, ifindex=%d) => %08x\n", - __func__, - NIP6(*addr), type, ifindex, - label); + ADDRLABEL(KERN_DEBUG "%s(addr=%pI6, type=%d, ifindex=%d) => %08x\n", + __func__, addr, type, ifindex, label); return label; } @@ -203,11 +201,8 @@ static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net, struct ip6addrlbl_entry *newp; int addrtype; - ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d, label=%u)\n", - __func__, - NIP6(*prefix), prefixlen, - ifindex, - (unsigned int)label); + ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u)\n", + __func__, prefix, prefixlen, ifindex, (unsigned int)label); addrtype = ipv6_addr_type(prefix) & (IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK); @@ -294,12 +289,9 @@ static int ip6addrlbl_add(struct net *net, struct ip6addrlbl_entry *newp; int ret = 0; - ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n", - __func__, - NIP6(*prefix), prefixlen, - ifindex, - (unsigned int)label, - replace); + ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d, label=%u, replace=%d)\n", + __func__, prefix, prefixlen, ifindex, (unsigned int)label, + replace); newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label); if (IS_ERR(newp)) @@ -321,10 +313,8 @@ static int __ip6addrlbl_del(struct net *net, struct hlist_node *pos, *n; int ret = -ESRCH; - ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d)\n", - __func__, - NIP6(*prefix), prefixlen, - ifindex); + ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n", + __func__, prefix, prefixlen, ifindex); hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) { if (p->prefixlen == prefixlen && @@ -347,10 +337,8 @@ static int ip6addrlbl_del(struct net *net, struct in6_addr prefix_buf; int ret; - ADDRLABEL(KERN_DEBUG "%s(prefix=" NIP6_FMT ", prefixlen=%d, ifindex=%d)\n", - __func__, - NIP6(*prefix), prefixlen, - ifindex); + ADDRLABEL(KERN_DEBUG "%s(prefix=%pI6, prefixlen=%d, ifindex=%d)\n", + __func__, prefix, prefixlen, ifindex); ipv6_addr_prefix(&prefix_buf, prefix, prefixlen); spin_lock(&ip6addrlbl_table.lock); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index 01edac888510cb7f4efb0c1ff994c4978a11bfaf..437b750b98fdebd6d280d1c710a0f1d7569b2bf2 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -637,7 +637,7 @@ int inet6_sk_rebuild_header(struct sock *sk) if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { + if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) { sk->sk_err_soft = -err; return err; } diff --git a/net/ipv6/ah6.c b/net/ipv6/ah6.c index 2ff0c8233e47a0096e5670aaa3e41d80d7e3f6a3..52449f7a1b715cf830fb4d051cb31ebd10cc3350 100644 --- a/net/ipv6/ah6.c +++ b/net/ipv6/ah6.c @@ -407,6 +407,7 @@ out: static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __be32 info) { + struct net *net = dev_net(skb->dev); struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; struct ip_auth_hdr *ah = (struct ip_auth_hdr*)(skb->data+offset); struct xfrm_state *x; @@ -415,12 +416,12 @@ static void ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, type != ICMPV6_PKT_TOOBIG) return; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); + x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6); if (!x) return; - NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/" NIP6_FMT "\n", - ntohl(ah->spi), NIP6(iph->daddr)); + NETDEBUG(KERN_DEBUG "pmtu discovery on SA AH/%08x/%pI6\n", + ntohl(ah->spi), &iph->daddr); xfrm_state_put(x); } @@ -509,9 +510,7 @@ static void ah6_destroy(struct xfrm_state *x) return; kfree(ahp->work_icv); - ahp->work_icv = NULL; crypto_free_hash(ahp->tfm); - ahp->tfm = NULL; kfree(ahp); } diff --git a/net/ipv6/anycast.c b/net/ipv6/anycast.c index 8336cd81cb4ffbef03708de15f2faad55a5f936d..1ae58bec1de08bf8cb860bb127a2e947d9b149f7 100644 --- a/net/ipv6/anycast.c +++ b/net/ipv6/anycast.c @@ -512,11 +512,9 @@ static int ac6_seq_show(struct seq_file *seq, void *v) struct ifacaddr6 *im = (struct ifacaddr6 *)v; struct ac6_iter_state *state = ac6_seq_private(seq); - seq_printf(seq, - "%-4d %-15s " NIP6_SEQFMT " %5d\n", + seq_printf(seq, "%-4d %-15s %pi6 %5d\n", state->dev->ifindex, state->dev->name, - NIP6(im->aca_addr), - im->aca_users); + &im->aca_addr, im->aca_users); return 0; } diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index e44deb8d4df28c54cfd90392c63647fc88b591fc..e2bdc6d83a43364dbc0989c22eed43b13c88750f 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -175,7 +175,8 @@ ipv4_connected: if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) { + err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT); + if (err < 0) { if (err == -EREMOTE) err = ip6_dst_blackhole(sk, &dst, &fl); if (err < 0) diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c index b181b08fb761c4f9cab3e4f06dfc439734213298..c2f250150db10a6d1c68c6904404e258860fc30d 100644 --- a/net/ipv6/esp6.c +++ b/net/ipv6/esp6.c @@ -356,6 +356,7 @@ static u32 esp6_get_mtu(struct xfrm_state *x, int mtu) static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __be32 info) { + struct net *net = dev_net(skb->dev); struct ipv6hdr *iph = (struct ipv6hdr*)skb->data; struct ip_esp_hdr *esph = (struct ip_esp_hdr *)(skb->data + offset); struct xfrm_state *x; @@ -364,11 +365,11 @@ static void esp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, type != ICMPV6_PKT_TOOBIG) return; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); + x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET6); if (!x) return; - printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/" NIP6_FMT "\n", - ntohl(esph->spi), NIP6(iph->daddr)); + printk(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%pI6\n", + ntohl(esph->spi), &iph->daddr); xfrm_state_put(x); } diff --git a/net/ipv6/exthdrs.c b/net/ipv6/exthdrs.c index 6bfffec2371ccf4cced48a9ffb3cdcb512c9dc00..1c7f400a3cfe5d58e95233de5a785b293d2fbeae 100644 --- a/net/ipv6/exthdrs.c +++ b/net/ipv6/exthdrs.c @@ -219,7 +219,7 @@ static int ipv6_dest_hao(struct sk_buff *skb, int optoff) if (!(ipv6_addr_type(&hao->addr) & IPV6_ADDR_UNICAST)) { LIMIT_NETDEBUG( - KERN_DEBUG "hao is not an unicast addr: " NIP6_FMT "\n", NIP6(hao->addr)); + KERN_DEBUG "hao is not an unicast addr: %pI6\n", &hao->addr); goto discard; } diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 9b7d19ae5ced5c7aa50dc5e48b98d7d7007c8770..4f433847d95f51724c0a943d50a5a67edb80b34c 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -233,7 +233,7 @@ static int icmpv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct icmp6h->icmp6_cksum = 0; if (skb_queue_len(&sk->sk_write_queue) == 1) { - skb->csum = csum_partial((char *)icmp6h, + skb->csum = csum_partial(icmp6h, sizeof(struct icmp6hdr), skb->csum); icmp6h->icmp6_cksum = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, @@ -246,7 +246,7 @@ static int icmpv6_push_pending_frames(struct sock *sk, struct flowi *fl, struct tmp_csum = csum_add(tmp_csum, skb->csum); } - tmp_csum = csum_partial((char *)icmp6h, + tmp_csum = csum_partial(icmp6h, sizeof(struct icmp6hdr), tmp_csum); icmp6h->icmp6_cksum = csum_ipv6_magic(&fl->fl6_src, &fl->fl6_dst, @@ -427,7 +427,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, /* No need to clone since we're just using its address. */ dst2 = dst; - err = xfrm_lookup(&dst, &fl, sk, 0); + err = xfrm_lookup(net, &dst, &fl, sk, 0); switch (err) { case 0: if (dst != dst2) @@ -446,7 +446,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, if (ip6_dst_lookup(sk, &dst2, &fl)) goto relookup_failed; - err = xfrm_lookup(&dst2, &fl, sk, XFRM_LOOKUP_ICMP); + err = xfrm_lookup(net, &dst2, &fl, sk, XFRM_LOOKUP_ICMP); switch (err) { case 0: dst_release(dst); @@ -552,7 +552,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) err = ip6_dst_lookup(sk, &dst, &fl); if (err) goto out; - if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) + if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0) goto out; if (ipv6_addr_is_multicast(&fl.fl6_dst)) @@ -646,9 +646,10 @@ static int icmpv6_rcv(struct sk_buff *skb) int type; if (!xfrm6_policy_check(NULL, XFRM_POLICY_IN, skb)) { + struct sec_path *sp = skb_sec_path(skb); int nh; - if (!(skb->sp && skb->sp->xvec[skb->sp->len - 1]->props.flags & + if (!(sp && sp->xvec[sp->len - 1]->props.flags & XFRM_STATE_ICMP)) goto drop_no_count; @@ -680,8 +681,8 @@ static int icmpv6_rcv(struct sk_buff *skb) skb->csum = ~csum_unfold(csum_ipv6_magic(saddr, daddr, skb->len, IPPROTO_ICMPV6, 0)); if (__skb_checksum_complete(skb)) { - LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [" NIP6_FMT " > " NIP6_FMT "]\n", - NIP6(*saddr), NIP6(*daddr)); + LIMIT_NETDEBUG(KERN_DEBUG "ICMPv6 checksum failed [%pI6 > %pI6]\n", + saddr, daddr); goto discard_it; } } @@ -955,8 +956,8 @@ ctl_table ipv6_icmp_table_template[] = { .data = &init_net.ipv6.sysctl.icmpv6_time, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_ms_jiffies, - .strategy = &sysctl_ms_jiffies + .proc_handler = proc_dointvec_ms_jiffies, + .strategy = sysctl_ms_jiffies }, { .ctl_name = 0 }, }; diff --git a/net/ipv6/inet6_connection_sock.c b/net/ipv6/inet6_connection_sock.c index 16d43f20b32f83c5994cb4d1479c6393c5ae0961..3c3732d50c1a167bf362319778562b495d4afdb1 100644 --- a/net/ipv6/inet6_connection_sock.c +++ b/net/ipv6/inet6_connection_sock.c @@ -219,7 +219,7 @@ int inet6_csk_xmit(struct sk_buff *skb, int ipfragok) if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { + if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) { sk->sk_route_caps = 0; kfree_skb(skb); return err; diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 1646a565825513421332b02411f00aa863f9c261..8fe267feb81e2af5e110f97e67916345df0493a1 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -25,26 +25,30 @@ void __inet6_hash(struct sock *sk) { struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo; - struct hlist_head *list; - rwlock_t *lock; WARN_ON(!sk_unhashed(sk)); if (sk->sk_state == TCP_LISTEN) { - list = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; - lock = &hashinfo->lhash_lock; - inet_listen_wlock(hashinfo); + struct inet_listen_hashbucket *ilb; + + ilb = &hashinfo->listening_hash[inet_sk_listen_hashfn(sk)]; + spin_lock(&ilb->lock); + __sk_nulls_add_node_rcu(sk, &ilb->head); + spin_unlock(&ilb->lock); } else { unsigned int hash; + struct hlist_nulls_head *list; + spinlock_t *lock; + sk->sk_hash = hash = inet6_sk_ehashfn(sk); list = &inet_ehash_bucket(hashinfo, hash)->chain; lock = inet_ehash_lockp(hashinfo, hash); - write_lock(lock); + spin_lock(lock); + __sk_nulls_add_node_rcu(sk, list); + spin_unlock(lock); } - __sk_add_node(sk, list); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - write_unlock(lock); } EXPORT_SYMBOL(__inet6_hash); @@ -63,77 +67,122 @@ struct sock *__inet6_lookup_established(struct net *net, const int dif) { struct sock *sk; - const struct hlist_node *node; + const struct hlist_nulls_node *node; const __portpair ports = INET_COMBINED_PORTS(sport, hnum); /* Optimize here for direct hit, only listening connections can * have wildcards anyways. */ unsigned int hash = inet6_ehashfn(net, daddr, hnum, saddr, sport); - struct inet_ehash_bucket *head = inet_ehash_bucket(hashinfo, hash); - rwlock_t *lock = inet_ehash_lockp(hashinfo, hash); + unsigned int slot = hash & (hashinfo->ehash_size - 1); + struct inet_ehash_bucket *head = &hashinfo->ehash[slot]; - prefetch(head->chain.first); - read_lock(lock); - sk_for_each(sk, node, &head->chain) { + + rcu_read_lock(); +begin: + sk_nulls_for_each_rcu(sk, node, &head->chain) { /* For IPV6 do the cheaper port and family tests first. */ - if (INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif)) - goto hit; /* You sunk my battleship! */ + if (INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { + if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) + goto begintw; + if (!INET6_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { + sock_put(sk); + goto begin; + } + goto out; + } } + if (get_nulls_value(node) != slot) + goto begin; + +begintw: /* Must check for a TIME_WAIT'er before going to listener hash. */ - sk_for_each(sk, node, &head->twchain) { - if (INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) - goto hit; + sk_nulls_for_each_rcu(sk, node, &head->twchain) { + if (INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { + if (unlikely(!atomic_inc_not_zero(&sk->sk_refcnt))) { + sk = NULL; + goto out; + } + if (!INET6_TW_MATCH(sk, net, hash, saddr, daddr, ports, dif)) { + sock_put(sk); + goto begintw; + } + goto out; + } } - read_unlock(lock); - return NULL; - -hit: - sock_hold(sk); - read_unlock(lock); + if (get_nulls_value(node) != slot) + goto begintw; + sk = NULL; +out: + rcu_read_unlock(); return sk; } EXPORT_SYMBOL(__inet6_lookup_established); +static int inline compute_score(struct sock *sk, struct net *net, + const unsigned short hnum, + const struct in6_addr *daddr, + const int dif) +{ + int score = -1; + + if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum && + sk->sk_family == PF_INET6) { + const struct ipv6_pinfo *np = inet6_sk(sk); + + score = 1; + if (!ipv6_addr_any(&np->rcv_saddr)) { + if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) + return -1; + score++; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + return -1; + score++; + } + } + return score; +} + struct sock *inet6_lookup_listener(struct net *net, struct inet_hashinfo *hashinfo, const struct in6_addr *daddr, const unsigned short hnum, const int dif) { struct sock *sk; - const struct hlist_node *node; - struct sock *result = NULL; - int score, hiscore = 0; - - read_lock(&hashinfo->lhash_lock); - sk_for_each(sk, node, - &hashinfo->listening_hash[inet_lhashfn(net, hnum)]) { - if (net_eq(sock_net(sk), net) && inet_sk(sk)->num == hnum && - sk->sk_family == PF_INET6) { - const struct ipv6_pinfo *np = inet6_sk(sk); - - score = 1; - if (!ipv6_addr_any(&np->rcv_saddr)) { - if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) - continue; - score++; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - continue; - score++; - } - if (score == 3) { - result = sk; - break; - } - if (score > hiscore) { - hiscore = score; - result = sk; - } + const struct hlist_nulls_node *node; + struct sock *result; + int score, hiscore; + unsigned int hash = inet_lhashfn(net, hnum); + struct inet_listen_hashbucket *ilb = &hashinfo->listening_hash[hash]; + + rcu_read_lock(); +begin: + result = NULL; + hiscore = -1; + sk_nulls_for_each(sk, node, &ilb->head) { + score = compute_score(sk, net, hnum, daddr, dif); + if (score > hiscore) { + hiscore = score; + result = sk; + } + } + /* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (get_nulls_value(node) != hash + LISTENING_NULLS_BASE) + goto begin; + if (result) { + if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) + result = NULL; + else if (unlikely(compute_score(result, net, hnum, daddr, + dif) < hiscore)) { + sock_put(result); + goto begin; } } - if (result) - sock_hold(result); - read_unlock(&hashinfo->lhash_lock); + rcu_read_unlock(); return result; } @@ -170,16 +219,15 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, const unsigned int hash = inet6_ehashfn(net, daddr, lport, saddr, inet->dport); struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); - rwlock_t *lock = inet_ehash_lockp(hinfo, hash); + spinlock_t *lock = inet_ehash_lockp(hinfo, hash); struct sock *sk2; - const struct hlist_node *node; + const struct hlist_nulls_node *node; struct inet_timewait_sock *tw; - prefetch(head->chain.first); - write_lock(lock); + spin_lock(lock); /* Check TIME-WAIT sockets first. */ - sk_for_each(sk2, node, &head->twchain) { + sk_nulls_for_each(sk2, node, &head->twchain) { tw = inet_twsk(sk2); if (INET6_TW_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) { @@ -192,7 +240,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, tw = NULL; /* And established part... */ - sk_for_each(sk2, node, &head->chain) { + sk_nulls_for_each(sk2, node, &head->chain) { if (INET6_MATCH(sk2, net, hash, saddr, daddr, ports, dif)) goto not_unique; } @@ -203,10 +251,10 @@ unique: inet->num = lport; inet->sport = htons(lport); WARN_ON(!sk_unhashed(sk)); - __sk_add_node(sk, &head->chain); + __sk_nulls_add_node_rcu(sk, &head->chain); sk->sk_hash = hash; + spin_unlock(lock); sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); - write_unlock(lock); if (twp != NULL) { *twp = tw; @@ -221,7 +269,7 @@ unique: return 0; not_unique: - write_unlock(lock); + spin_unlock(lock); return -EADDRNOTAVAIL; } diff --git a/net/ipv6/ip6_flowlabel.c b/net/ipv6/ip6_flowlabel.c index bd3c7b96bbaa627c55f2ec96818fcaf12e50d1de..c62dd247774f8242fa6f12872c8a6b349b288fd4 100644 --- a/net/ipv6/ip6_flowlabel.c +++ b/net/ipv6/ip6_flowlabel.c @@ -464,7 +464,7 @@ static inline void fl_link(struct ipv6_pinfo *np, struct ipv6_fl_socklist *sfl, int ipv6_flowlabel_opt(struct sock *sk, char __user *optval, int optlen) { - int err; + int uninitialized_var(err); struct net *net = sock_net(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct in6_flowlabel_req freq; @@ -696,14 +696,14 @@ static int ip6fl_seq_show(struct seq_file *seq, void *v) else { struct ip6_flowlabel *fl = v; seq_printf(seq, - "%05X %-1d %-6d %-6d %-6ld %-8ld " NIP6_SEQFMT " %-4d\n", + "%05X %-1d %-6d %-6d %-6ld %-8ld %pi6 %-4d\n", (unsigned)ntohl(fl->label), fl->share, (unsigned)fl->owner, atomic_read(&fl->users), fl->linger/HZ, (long)(fl->expires - jiffies)/HZ, - NIP6(fl->dst), + &fl->dst, fl->opt ? fl->opt->opt_nflen : 0); } return 0; diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index c77db0b95e263cd24a2571c0f76c69dfcc89a0bd..4b15938bef4dabd3f09087369d752a2400820a00 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -137,7 +137,8 @@ static int ip6_output2(struct sk_buff *skb) struct inet6_dev *idev = ip6_dst_idev(skb->dst); if (!(dev->flags & IFF_LOOPBACK) && (!np || np->mc_loop) && - ((mroute6_socket && !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || + ((mroute6_socket(dev_net(dev)) && + !(IP6CB(skb)->flags & IP6SKB_FORWARDED)) || ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr, &ipv6_hdr(skb)->saddr))) { struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC); @@ -490,7 +491,7 @@ int ip6_forward(struct sk_buff *skb) We don't send redirects to frames decapsulated from IPsec. */ if (skb->dev == dst->dev && dst->neighbour && opt->srcrt == 0 && - !skb->sp) { + !skb_sec_path(skb)) { struct in6_addr *target = NULL; struct rt6_info *rt; struct neighbour *n = dst->neighbour; diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 64ce3d33d9c66d11f69bff09a8ac3c78947f2d03..58e2b0d937585a6e8da53ae7fc97ac6c1cc2dd27 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -74,8 +74,8 @@ MODULE_LICENSE("GPL"); (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \ (HASH_SIZE - 1)) -static int ip6_fb_tnl_dev_init(struct net_device *dev); -static int ip6_tnl_dev_init(struct net_device *dev); +static void ip6_fb_tnl_dev_init(struct net_device *dev); +static void ip6_tnl_dev_init(struct net_device *dev); static void ip6_tnl_dev_setup(struct net_device *dev); static int ip6_tnl_net_id; @@ -249,7 +249,7 @@ static struct ip6_tnl *ip6_tnl_create(struct net *net, struct ip6_tnl_parm *p) } t = netdev_priv(dev); - dev->init = ip6_tnl_dev_init; + ip6_tnl_dev_init(dev); t->parms = *p; if ((err = register_netdevice(dev)) < 0) @@ -846,6 +846,7 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, int encap_limit, __u32 *pmtu) { + struct net *net = dev_net(dev); struct ip6_tnl *t = netdev_priv(dev); struct net_device_stats *stats = &t->dev->stats; struct ipv6hdr *ipv6h = ipv6_hdr(skb); @@ -861,9 +862,9 @@ static int ip6_tnl_xmit2(struct sk_buff *skb, if ((dst = ip6_tnl_dst_check(t)) != NULL) dst_hold(dst); else { - dst = ip6_route_output(dev_net(dev), NULL, fl); + dst = ip6_route_output(net, NULL, fl); - if (dst->error || xfrm_lookup(&dst, fl, NULL, 0) < 0) + if (dst->error || xfrm_lookup(net, &dst, fl, NULL, 0) < 0) goto tx_err_link_failure; } @@ -1150,7 +1151,6 @@ static void ip6_tnl_link_config(struct ip6_tnl *t) * ip6_tnl_change - update the tunnel parameters * @t: tunnel to be changed * @p: tunnel configuration parameters - * @active: != 0 if tunnel is ready for use * * Description: * ip6_tnl_change() updates the tunnel parameters @@ -1306,6 +1306,14 @@ ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) return 0; } + +static const struct net_device_ops ip6_tnl_netdev_ops = { + .ndo_uninit = ip6_tnl_dev_uninit, + .ndo_start_xmit = ip6_tnl_xmit, + .ndo_do_ioctl = ip6_tnl_ioctl, + .ndo_change_mtu = ip6_tnl_change_mtu, +}; + /** * ip6_tnl_dev_setup - setup virtual tunnel device * @dev: virtual device associated with tunnel @@ -1316,11 +1324,8 @@ ip6_tnl_change_mtu(struct net_device *dev, int new_mtu) static void ip6_tnl_dev_setup(struct net_device *dev) { - dev->uninit = ip6_tnl_dev_uninit; + dev->netdev_ops = &ip6_tnl_netdev_ops; dev->destructor = free_netdev; - dev->hard_start_xmit = ip6_tnl_xmit; - dev->do_ioctl = ip6_tnl_ioctl; - dev->change_mtu = ip6_tnl_change_mtu; dev->type = ARPHRD_TUNNEL6; dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr); @@ -1349,13 +1354,11 @@ ip6_tnl_dev_init_gen(struct net_device *dev) * @dev: virtual device associated with tunnel **/ -static int -ip6_tnl_dev_init(struct net_device *dev) +static void ip6_tnl_dev_init(struct net_device *dev) { struct ip6_tnl *t = netdev_priv(dev); ip6_tnl_dev_init_gen(dev); ip6_tnl_link_config(t); - return 0; } /** @@ -1365,8 +1368,7 @@ ip6_tnl_dev_init(struct net_device *dev) * Return: 0 **/ -static int -ip6_fb_tnl_dev_init(struct net_device *dev) +static void ip6_fb_tnl_dev_init(struct net_device *dev) { struct ip6_tnl *t = netdev_priv(dev); struct net *net = dev_net(dev); @@ -1376,7 +1378,6 @@ ip6_fb_tnl_dev_init(struct net_device *dev) t->parms.proto = IPPROTO_IPV6; dev_hold(dev); ip6n->tnls_wc[0] = t; - return 0; } static struct xfrm6_tunnel ip4ip6_handler = { @@ -1428,10 +1429,10 @@ static int ip6_tnl_init_net(struct net *net) if (!ip6n->fb_tnl_dev) goto err_alloc_dev; - - ip6n->fb_tnl_dev->init = ip6_fb_tnl_dev_init; dev_net_set(ip6n->fb_tnl_dev, net); + ip6_fb_tnl_dev_init(ip6n->fb_tnl_dev); + err = register_netdev(ip6n->fb_tnl_dev); if (err < 0) goto err_register; diff --git a/net/ipv6/ip6mr.c b/net/ipv6/ip6mr.c index 0524769632e7f0593e8e17d0c575793aa5ebce66..3c51b2d827f4b82966502e7a210c028260f52419 100644 --- a/net/ipv6/ip6mr.c +++ b/net/ipv6/ip6mr.c @@ -49,9 +49,6 @@ #include #include -struct sock *mroute6_socket; - - /* Big lock, protecting vif table, mrt cache and mroute socket state. Note that the changes are semaphored via rtnl_lock. */ @@ -62,22 +59,9 @@ static DEFINE_RWLOCK(mrt_lock); * Multicast router control variables */ -static struct mif_device vif6_table[MAXMIFS]; /* Devices */ -static int maxvif; - -#define MIF_EXISTS(idx) (vif6_table[idx].dev != NULL) - -static int mroute_do_assert; /* Set in PIM assert */ -#ifdef CONFIG_IPV6_PIMSM_V2 -static int mroute_do_pim; -#else -#define mroute_do_pim 0 -#endif - -static struct mfc6_cache *mfc6_cache_array[MFC6_LINES]; /* Forwarding cache */ +#define MIF_EXISTS(_net, _idx) ((_net)->ipv6.vif6_table[_idx].dev != NULL) static struct mfc6_cache *mfc_unres_queue; /* Queue of unresolved entries */ -static atomic_t cache_resolve_queue_len; /* Size of unresolved */ /* Special spinlock for queue of unresolved entries */ static DEFINE_SPINLOCK(mfc_unres_lock); @@ -93,8 +77,10 @@ static DEFINE_SPINLOCK(mfc_unres_lock); static struct kmem_cache *mrt_cachep __read_mostly; static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache); -static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert); +static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, + mifi_t mifi, int assert); static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm); +static void mroute_clean_tables(struct net *net); #ifdef CONFIG_IPV6_PIMSM_V2 static struct inet6_protocol pim6_protocol; @@ -106,19 +92,22 @@ static struct timer_list ipmr_expire_timer; #ifdef CONFIG_PROC_FS struct ipmr_mfc_iter { + struct seq_net_private p; struct mfc6_cache **cache; int ct; }; -static struct mfc6_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos) +static struct mfc6_cache *ipmr_mfc_seq_idx(struct net *net, + struct ipmr_mfc_iter *it, loff_t pos) { struct mfc6_cache *mfc; - it->cache = mfc6_cache_array; + it->cache = net->ipv6.mfc6_cache_array; read_lock(&mrt_lock); - for (it->ct = 0; it->ct < ARRAY_SIZE(mfc6_cache_array); it->ct++) - for (mfc = mfc6_cache_array[it->ct]; mfc; mfc = mfc->next) + for (it->ct = 0; it->ct < MFC6_LINES; it->ct++) + for (mfc = net->ipv6.mfc6_cache_array[it->ct]; + mfc; mfc = mfc->next) if (pos-- == 0) return mfc; read_unlock(&mrt_lock); @@ -126,7 +115,8 @@ static struct mfc6_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos) it->cache = &mfc_unres_queue; spin_lock_bh(&mfc_unres_lock); for (mfc = mfc_unres_queue; mfc; mfc = mfc->next) - if (pos-- == 0) + if (net_eq(mfc6_net(mfc), net) && + pos-- == 0) return mfc; spin_unlock_bh(&mfc_unres_lock); @@ -142,17 +132,19 @@ static struct mfc6_cache *ipmr_mfc_seq_idx(struct ipmr_mfc_iter *it, loff_t pos) */ struct ipmr_vif_iter { + struct seq_net_private p; int ct; }; -static struct mif_device *ip6mr_vif_seq_idx(struct ipmr_vif_iter *iter, +static struct mif_device *ip6mr_vif_seq_idx(struct net *net, + struct ipmr_vif_iter *iter, loff_t pos) { - for (iter->ct = 0; iter->ct < maxvif; ++iter->ct) { - if (!MIF_EXISTS(iter->ct)) + for (iter->ct = 0; iter->ct < net->ipv6.maxvif; ++iter->ct) { + if (!MIF_EXISTS(net, iter->ct)) continue; if (pos-- == 0) - return &vif6_table[iter->ct]; + return &net->ipv6.vif6_table[iter->ct]; } return NULL; } @@ -160,23 +152,26 @@ static struct mif_device *ip6mr_vif_seq_idx(struct ipmr_vif_iter *iter, static void *ip6mr_vif_seq_start(struct seq_file *seq, loff_t *pos) __acquires(mrt_lock) { + struct net *net = seq_file_net(seq); + read_lock(&mrt_lock); - return (*pos ? ip6mr_vif_seq_idx(seq->private, *pos - 1) - : SEQ_START_TOKEN); + return *pos ? ip6mr_vif_seq_idx(net, seq->private, *pos - 1) + : SEQ_START_TOKEN; } static void *ip6mr_vif_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct ipmr_vif_iter *iter = seq->private; + struct net *net = seq_file_net(seq); ++*pos; if (v == SEQ_START_TOKEN) - return ip6mr_vif_seq_idx(iter, 0); + return ip6mr_vif_seq_idx(net, iter, 0); - while (++iter->ct < maxvif) { - if (!MIF_EXISTS(iter->ct)) + while (++iter->ct < net->ipv6.maxvif) { + if (!MIF_EXISTS(net, iter->ct)) continue; - return &vif6_table[iter->ct]; + return &net->ipv6.vif6_table[iter->ct]; } return NULL; } @@ -189,6 +184,8 @@ static void ip6mr_vif_seq_stop(struct seq_file *seq, void *v) static int ip6mr_vif_seq_show(struct seq_file *seq, void *v) { + struct net *net = seq_file_net(seq); + if (v == SEQ_START_TOKEN) { seq_puts(seq, "Interface BytesIn PktsIn BytesOut PktsOut Flags\n"); @@ -198,7 +195,7 @@ static int ip6mr_vif_seq_show(struct seq_file *seq, void *v) seq_printf(seq, "%2td %-10s %8ld %7ld %8ld %7ld %05X\n", - vif - vif6_table, + vif - net->ipv6.vif6_table, name, vif->bytes_in, vif->pkt_in, vif->bytes_out, vif->pkt_out, vif->flags); @@ -215,8 +212,8 @@ static struct seq_operations ip6mr_vif_seq_ops = { static int ip6mr_vif_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &ip6mr_vif_seq_ops, - sizeof(struct ipmr_vif_iter)); + return seq_open_net(inode, file, &ip6mr_vif_seq_ops, + sizeof(struct ipmr_vif_iter)); } static struct file_operations ip6mr_vif_fops = { @@ -224,24 +221,27 @@ static struct file_operations ip6mr_vif_fops = { .open = ip6mr_vif_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; static void *ipmr_mfc_seq_start(struct seq_file *seq, loff_t *pos) { - return (*pos ? ipmr_mfc_seq_idx(seq->private, *pos - 1) - : SEQ_START_TOKEN); + struct net *net = seq_file_net(seq); + + return *pos ? ipmr_mfc_seq_idx(net, seq->private, *pos - 1) + : SEQ_START_TOKEN; } static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos) { struct mfc6_cache *mfc = v; struct ipmr_mfc_iter *it = seq->private; + struct net *net = seq_file_net(seq); ++*pos; if (v == SEQ_START_TOKEN) - return ipmr_mfc_seq_idx(seq->private, 0); + return ipmr_mfc_seq_idx(net, seq->private, 0); if (mfc->next) return mfc->next; @@ -249,10 +249,10 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos) if (it->cache == &mfc_unres_queue) goto end_of_list; - BUG_ON(it->cache != mfc6_cache_array); + BUG_ON(it->cache != net->ipv6.mfc6_cache_array); - while (++it->ct < ARRAY_SIZE(mfc6_cache_array)) { - mfc = mfc6_cache_array[it->ct]; + while (++it->ct < MFC6_LINES) { + mfc = net->ipv6.mfc6_cache_array[it->ct]; if (mfc) return mfc; } @@ -277,16 +277,18 @@ static void *ipmr_mfc_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void ipmr_mfc_seq_stop(struct seq_file *seq, void *v) { struct ipmr_mfc_iter *it = seq->private; + struct net *net = seq_file_net(seq); if (it->cache == &mfc_unres_queue) spin_unlock_bh(&mfc_unres_lock); - else if (it->cache == mfc6_cache_array) + else if (it->cache == net->ipv6.mfc6_cache_array) read_unlock(&mrt_lock); } static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) { int n; + struct net *net = seq_file_net(seq); if (v == SEQ_START_TOKEN) { seq_puts(seq, @@ -297,23 +299,28 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v) const struct mfc6_cache *mfc = v; const struct ipmr_mfc_iter *it = seq->private; - seq_printf(seq, - NIP6_FMT " " NIP6_FMT " %-3d %8ld %8ld %8ld", - NIP6(mfc->mf6c_mcastgrp), NIP6(mfc->mf6c_origin), - mfc->mf6c_parent, - mfc->mfc_un.res.pkt, - mfc->mfc_un.res.bytes, - mfc->mfc_un.res.wrong_if); + seq_printf(seq, "%pI6 %pI6 %-3hd", + &mfc->mf6c_mcastgrp, &mfc->mf6c_origin, + mfc->mf6c_parent); if (it->cache != &mfc_unres_queue) { + seq_printf(seq, " %8lu %8lu %8lu", + mfc->mfc_un.res.pkt, + mfc->mfc_un.res.bytes, + mfc->mfc_un.res.wrong_if); for (n = mfc->mfc_un.res.minvif; n < mfc->mfc_un.res.maxvif; n++) { - if (MIF_EXISTS(n) && + if (MIF_EXISTS(net, n) && mfc->mfc_un.res.ttls[n] < 255) seq_printf(seq, " %2d:%-3d", n, mfc->mfc_un.res.ttls[n]); } + } else { + /* unresolved mfc_caches don't contain + * pkt, bytes and wrong_if values + */ + seq_printf(seq, " %8lu %8lu %8lu", 0ul, 0ul, 0ul); } seq_putc(seq, '\n'); } @@ -329,8 +336,8 @@ static struct seq_operations ipmr_mfc_seq_ops = { static int ipmr_mfc_open(struct inode *inode, struct file *file) { - return seq_open_private(file, &ipmr_mfc_seq_ops, - sizeof(struct ipmr_mfc_iter)); + return seq_open_net(inode, file, &ipmr_mfc_seq_ops, + sizeof(struct ipmr_mfc_iter)); } static struct file_operations ip6mr_mfc_fops = { @@ -338,18 +345,19 @@ static struct file_operations ip6mr_mfc_fops = { .open = ipmr_mfc_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release_private, + .release = seq_release_net, }; #endif #ifdef CONFIG_IPV6_PIMSM_V2 -static int reg_vif_num = -1; static int pim6_rcv(struct sk_buff *skb) { struct pimreghdr *pim; struct ipv6hdr *encap; struct net_device *reg_dev = NULL; + struct net *net = dev_net(skb->dev); + int reg_vif_num = net->ipv6.mroute_reg_vif_num; if (!pskb_may_pull(skb, sizeof(*pim) + sizeof(*encap))) goto drop; @@ -372,7 +380,7 @@ static int pim6_rcv(struct sk_buff *skb) read_lock(&mrt_lock); if (reg_vif_num >= 0) - reg_dev = vif6_table[reg_vif_num].dev; + reg_dev = net->ipv6.vif6_table[reg_vif_num].dev; if (reg_dev) dev_hold(reg_dev); read_unlock(&mrt_lock); @@ -408,25 +416,32 @@ static struct inet6_protocol pim6_protocol = { static int reg_vif_xmit(struct sk_buff *skb, struct net_device *dev) { + struct net *net = dev_net(dev); + read_lock(&mrt_lock); dev->stats.tx_bytes += skb->len; dev->stats.tx_packets++; - ip6mr_cache_report(skb, reg_vif_num, MRT6MSG_WHOLEPKT); + ip6mr_cache_report(net, skb, net->ipv6.mroute_reg_vif_num, + MRT6MSG_WHOLEPKT); read_unlock(&mrt_lock); kfree_skb(skb); return 0; } +static const struct net_device_ops reg_vif_netdev_ops = { + .ndo_start_xmit = reg_vif_xmit, +}; + static void reg_vif_setup(struct net_device *dev) { dev->type = ARPHRD_PIMREG; dev->mtu = 1500 - sizeof(struct ipv6hdr) - 8; dev->flags = IFF_NOARP; - dev->hard_start_xmit = reg_vif_xmit; + dev->netdev_ops = ®_vif_netdev_ops; dev->destructor = free_netdev; } -static struct net_device *ip6mr_reg_vif(void) +static struct net_device *ip6mr_reg_vif(struct net *net) { struct net_device *dev; @@ -434,6 +449,8 @@ static struct net_device *ip6mr_reg_vif(void) if (dev == NULL) return NULL; + dev_net_set(dev, net); + if (register_netdevice(dev)) { free_netdev(dev); return NULL; @@ -460,14 +477,14 @@ failure: * Delete a VIF entry */ -static int mif6_delete(int vifi) +static int mif6_delete(struct net *net, int vifi) { struct mif_device *v; struct net_device *dev; - if (vifi < 0 || vifi >= maxvif) + if (vifi < 0 || vifi >= net->ipv6.maxvif) return -EADDRNOTAVAIL; - v = &vif6_table[vifi]; + v = &net->ipv6.vif6_table[vifi]; write_lock_bh(&mrt_lock); dev = v->dev; @@ -479,17 +496,17 @@ static int mif6_delete(int vifi) } #ifdef CONFIG_IPV6_PIMSM_V2 - if (vifi == reg_vif_num) - reg_vif_num = -1; + if (vifi == net->ipv6.mroute_reg_vif_num) + net->ipv6.mroute_reg_vif_num = -1; #endif - if (vifi + 1 == maxvif) { + if (vifi + 1 == net->ipv6.maxvif) { int tmp; for (tmp = vifi - 1; tmp >= 0; tmp--) { - if (MIF_EXISTS(tmp)) + if (MIF_EXISTS(net, tmp)) break; } - maxvif = tmp + 1; + net->ipv6.maxvif = tmp + 1; } write_unlock_bh(&mrt_lock); @@ -503,6 +520,12 @@ static int mif6_delete(int vifi) return 0; } +static inline void ip6mr_cache_free(struct mfc6_cache *c) +{ + release_net(mfc6_net(c)); + kmem_cache_free(mrt_cachep, c); +} + /* Destroy an unresolved cache entry, killing queued skbs and reporting error to netlink readers. */ @@ -510,8 +533,9 @@ static int mif6_delete(int vifi) static void ip6mr_destroy_unres(struct mfc6_cache *c) { struct sk_buff *skb; + struct net *net = mfc6_net(c); - atomic_dec(&cache_resolve_queue_len); + atomic_dec(&net->ipv6.cache_resolve_queue_len); while((skb = skb_dequeue(&c->mfc_un.unres.unresolved)) != NULL) { if (ipv6_hdr(skb)->version == 0) { @@ -520,12 +544,12 @@ static void ip6mr_destroy_unres(struct mfc6_cache *c) nlh->nlmsg_len = NLMSG_LENGTH(sizeof(struct nlmsgerr)); skb_trim(skb, nlh->nlmsg_len); ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -ETIMEDOUT; - rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid); + rtnl_unicast(skb, net, NETLINK_CB(skb).pid); } else kfree_skb(skb); } - kmem_cache_free(mrt_cachep, c); + ip6mr_cache_free(c); } @@ -553,7 +577,7 @@ static void ipmr_do_expire_process(unsigned long dummy) ip6mr_destroy_unres(c); } - if (atomic_read(&cache_resolve_queue_len)) + if (mfc_unres_queue != NULL) mod_timer(&ipmr_expire_timer, jiffies + expires); } @@ -564,7 +588,7 @@ static void ipmr_expire_process(unsigned long dummy) return; } - if (atomic_read(&cache_resolve_queue_len)) + if (mfc_unres_queue != NULL) ipmr_do_expire_process(dummy); spin_unlock(&mfc_unres_lock); @@ -575,13 +599,15 @@ static void ipmr_expire_process(unsigned long dummy) static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttls) { int vifi; + struct net *net = mfc6_net(cache); cache->mfc_un.res.minvif = MAXMIFS; cache->mfc_un.res.maxvif = 0; memset(cache->mfc_un.res.ttls, 255, MAXMIFS); - for (vifi = 0; vifi < maxvif; vifi++) { - if (MIF_EXISTS(vifi) && ttls[vifi] && ttls[vifi] < 255) { + for (vifi = 0; vifi < net->ipv6.maxvif; vifi++) { + if (MIF_EXISTS(net, vifi) && + ttls[vifi] && ttls[vifi] < 255) { cache->mfc_un.res.ttls[vifi] = ttls[vifi]; if (cache->mfc_un.res.minvif > vifi) cache->mfc_un.res.minvif = vifi; @@ -591,15 +617,15 @@ static void ip6mr_update_thresholds(struct mfc6_cache *cache, unsigned char *ttl } } -static int mif6_add(struct mif6ctl *vifc, int mrtsock) +static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock) { int vifi = vifc->mif6c_mifi; - struct mif_device *v = &vif6_table[vifi]; + struct mif_device *v = &net->ipv6.vif6_table[vifi]; struct net_device *dev; int err; /* Is vif busy ? */ - if (MIF_EXISTS(vifi)) + if (MIF_EXISTS(net, vifi)) return -EADDRINUSE; switch (vifc->mif6c_flags) { @@ -609,9 +635,9 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock) * Special Purpose VIF in PIM * All the packets will be sent to the daemon */ - if (reg_vif_num >= 0) + if (net->ipv6.mroute_reg_vif_num >= 0) return -EADDRINUSE; - dev = ip6mr_reg_vif(); + dev = ip6mr_reg_vif(net); if (!dev) return -ENOBUFS; err = dev_set_allmulti(dev, 1); @@ -623,7 +649,7 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock) break; #endif case 0: - dev = dev_get_by_index(&init_net, vifc->mif6c_pifi); + dev = dev_get_by_index(net, vifc->mif6c_pifi); if (!dev) return -EADDRNOTAVAIL; err = dev_set_allmulti(dev, 1); @@ -657,20 +683,22 @@ static int mif6_add(struct mif6ctl *vifc, int mrtsock) v->dev = dev; #ifdef CONFIG_IPV6_PIMSM_V2 if (v->flags & MIFF_REGISTER) - reg_vif_num = vifi; + net->ipv6.mroute_reg_vif_num = vifi; #endif - if (vifi + 1 > maxvif) - maxvif = vifi + 1; + if (vifi + 1 > net->ipv6.maxvif) + net->ipv6.maxvif = vifi + 1; write_unlock_bh(&mrt_lock); return 0; } -static struct mfc6_cache *ip6mr_cache_find(struct in6_addr *origin, struct in6_addr *mcastgrp) +static struct mfc6_cache *ip6mr_cache_find(struct net *net, + struct in6_addr *origin, + struct in6_addr *mcastgrp) { int line = MFC6_HASH(mcastgrp, origin); struct mfc6_cache *c; - for (c = mfc6_cache_array[line]; c; c = c->next) { + for (c = net->ipv6.mfc6_cache_array[line]; c; c = c->next) { if (ipv6_addr_equal(&c->mf6c_origin, origin) && ipv6_addr_equal(&c->mf6c_mcastgrp, mcastgrp)) break; @@ -681,24 +709,24 @@ static struct mfc6_cache *ip6mr_cache_find(struct in6_addr *origin, struct in6_a /* * Allocate a multicast cache entry */ -static struct mfc6_cache *ip6mr_cache_alloc(void) +static struct mfc6_cache *ip6mr_cache_alloc(struct net *net) { - struct mfc6_cache *c = kmem_cache_alloc(mrt_cachep, GFP_KERNEL); + struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_KERNEL); if (c == NULL) return NULL; - memset(c, 0, sizeof(*c)); c->mfc_un.res.minvif = MAXMIFS; + mfc6_net_set(c, net); return c; } -static struct mfc6_cache *ip6mr_cache_alloc_unres(void) +static struct mfc6_cache *ip6mr_cache_alloc_unres(struct net *net) { - struct mfc6_cache *c = kmem_cache_alloc(mrt_cachep, GFP_ATOMIC); + struct mfc6_cache *c = kmem_cache_zalloc(mrt_cachep, GFP_ATOMIC); if (c == NULL) return NULL; - memset(c, 0, sizeof(*c)); skb_queue_head_init(&c->mfc_un.unres.unresolved); c->mfc_un.unres.expires = jiffies + 10 * HZ; + mfc6_net_set(c, net); return c; } @@ -727,7 +755,7 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c) skb_trim(skb, nlh->nlmsg_len); ((struct nlmsgerr *)NLMSG_DATA(nlh))->error = -EMSGSIZE; } - err = rtnl_unicast(skb, &init_net, NETLINK_CB(skb).pid); + err = rtnl_unicast(skb, mfc6_net(uc), NETLINK_CB(skb).pid); } else ip6_mr_forward(skb, c); } @@ -740,7 +768,8 @@ static void ip6mr_cache_resolve(struct mfc6_cache *uc, struct mfc6_cache *c) * Called under mrt_lock. */ -static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert) +static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi, + int assert) { struct sk_buff *skb; struct mrt6msg *msg; @@ -776,7 +805,7 @@ static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert) msg = (struct mrt6msg *)skb_transport_header(skb); msg->im6_mbz = 0; msg->im6_msgtype = MRT6MSG_WHOLEPKT; - msg->im6_mif = reg_vif_num; + msg->im6_mif = net->ipv6.mroute_reg_vif_num; msg->im6_pad = 0; ipv6_addr_copy(&msg->im6_src, &ipv6_hdr(pkt)->saddr); ipv6_addr_copy(&msg->im6_dst, &ipv6_hdr(pkt)->daddr); @@ -813,7 +842,7 @@ static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert) skb_pull(skb, sizeof(struct ipv6hdr)); } - if (mroute6_socket == NULL) { + if (net->ipv6.mroute6_sk == NULL) { kfree_skb(skb); return -EINVAL; } @@ -821,7 +850,8 @@ static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert) /* * Deliver to user space multicast routing algorithms */ - if ((ret = sock_queue_rcv_skb(mroute6_socket, skb)) < 0) { + ret = sock_queue_rcv_skb(net->ipv6.mroute6_sk, skb); + if (ret < 0) { if (net_ratelimit()) printk(KERN_WARNING "mroute6: pending queue full, dropping entries.\n"); kfree_skb(skb); @@ -835,14 +865,15 @@ static int ip6mr_cache_report(struct sk_buff *pkt, mifi_t mifi, int assert) */ static int -ip6mr_cache_unresolved(mifi_t mifi, struct sk_buff *skb) +ip6mr_cache_unresolved(struct net *net, mifi_t mifi, struct sk_buff *skb) { int err; struct mfc6_cache *c; spin_lock_bh(&mfc_unres_lock); for (c = mfc_unres_queue; c; c = c->next) { - if (ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) && + if (net_eq(mfc6_net(c), net) && + ipv6_addr_equal(&c->mf6c_mcastgrp, &ipv6_hdr(skb)->daddr) && ipv6_addr_equal(&c->mf6c_origin, &ipv6_hdr(skb)->saddr)) break; } @@ -852,8 +883,8 @@ ip6mr_cache_unresolved(mifi_t mifi, struct sk_buff *skb) * Create a new entry if allowable */ - if (atomic_read(&cache_resolve_queue_len) >= 10 || - (c = ip6mr_cache_alloc_unres()) == NULL) { + if (atomic_read(&net->ipv6.cache_resolve_queue_len) >= 10 || + (c = ip6mr_cache_alloc_unres(net)) == NULL) { spin_unlock_bh(&mfc_unres_lock); kfree_skb(skb); @@ -870,18 +901,19 @@ ip6mr_cache_unresolved(mifi_t mifi, struct sk_buff *skb) /* * Reflect first query at pim6sd */ - if ((err = ip6mr_cache_report(skb, mifi, MRT6MSG_NOCACHE)) < 0) { + err = ip6mr_cache_report(net, skb, mifi, MRT6MSG_NOCACHE); + if (err < 0) { /* If the report failed throw the cache entry out - Brad Parker */ spin_unlock_bh(&mfc_unres_lock); - kmem_cache_free(mrt_cachep, c); + ip6mr_cache_free(c); kfree_skb(skb); return err; } - atomic_inc(&cache_resolve_queue_len); + atomic_inc(&net->ipv6.cache_resolve_queue_len); c->next = mfc_unres_queue; mfc_unres_queue = c; @@ -907,21 +939,22 @@ ip6mr_cache_unresolved(mifi_t mifi, struct sk_buff *skb) * MFC6 cache manipulation by user space */ -static int ip6mr_mfc_delete(struct mf6cctl *mfc) +static int ip6mr_mfc_delete(struct net *net, struct mf6cctl *mfc) { int line; struct mfc6_cache *c, **cp; line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr); - for (cp = &mfc6_cache_array[line]; (c = *cp) != NULL; cp = &c->next) { + for (cp = &net->ipv6.mfc6_cache_array[line]; + (c = *cp) != NULL; cp = &c->next) { if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) { write_lock_bh(&mrt_lock); *cp = c->next; write_unlock_bh(&mrt_lock); - kmem_cache_free(mrt_cachep, c); + ip6mr_cache_free(c); return 0; } } @@ -932,19 +965,17 @@ static int ip6mr_device_event(struct notifier_block *this, unsigned long event, void *ptr) { struct net_device *dev = ptr; + struct net *net = dev_net(dev); struct mif_device *v; int ct; - if (!net_eq(dev_net(dev), &init_net)) - return NOTIFY_DONE; - if (event != NETDEV_UNREGISTER) return NOTIFY_DONE; - v = &vif6_table[0]; - for (ct = 0; ct < maxvif; ct++, v++) { + v = &net->ipv6.vif6_table[0]; + for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) { if (v->dev == dev) - mif6_delete(ct); + mif6_delete(net, ct); } return NOTIFY_DONE; } @@ -957,6 +988,66 @@ static struct notifier_block ip6_mr_notifier = { * Setup for IP multicast routing */ +static int __net_init ip6mr_net_init(struct net *net) +{ + int err = 0; + net->ipv6.vif6_table = kcalloc(MAXMIFS, sizeof(struct mif_device), + GFP_KERNEL); + if (!net->ipv6.vif6_table) { + err = -ENOMEM; + goto fail; + } + + /* Forwarding cache */ + net->ipv6.mfc6_cache_array = kcalloc(MFC6_LINES, + sizeof(struct mfc6_cache *), + GFP_KERNEL); + if (!net->ipv6.mfc6_cache_array) { + err = -ENOMEM; + goto fail_mfc6_cache; + } + +#ifdef CONFIG_IPV6_PIMSM_V2 + net->ipv6.mroute_reg_vif_num = -1; +#endif + +#ifdef CONFIG_PROC_FS + err = -ENOMEM; + if (!proc_net_fops_create(net, "ip6_mr_vif", 0, &ip6mr_vif_fops)) + goto proc_vif_fail; + if (!proc_net_fops_create(net, "ip6_mr_cache", 0, &ip6mr_mfc_fops)) + goto proc_cache_fail; +#endif + return 0; + +#ifdef CONFIG_PROC_FS +proc_cache_fail: + proc_net_remove(net, "ip6_mr_vif"); +proc_vif_fail: + kfree(net->ipv6.mfc6_cache_array); +#endif +fail_mfc6_cache: + kfree(net->ipv6.vif6_table); +fail: + return err; +} + +static void __net_exit ip6mr_net_exit(struct net *net) +{ +#ifdef CONFIG_PROC_FS + proc_net_remove(net, "ip6_mr_cache"); + proc_net_remove(net, "ip6_mr_vif"); +#endif + mroute_clean_tables(net); + kfree(net->ipv6.mfc6_cache_array); + kfree(net->ipv6.vif6_table); +} + +static struct pernet_operations ip6mr_net_ops = { + .init = ip6mr_net_init, + .exit = ip6mr_net_exit, +}; + int __init ip6_mr_init(void) { int err; @@ -968,43 +1059,32 @@ int __init ip6_mr_init(void) if (!mrt_cachep) return -ENOMEM; + err = register_pernet_subsys(&ip6mr_net_ops); + if (err) + goto reg_pernet_fail; + setup_timer(&ipmr_expire_timer, ipmr_expire_process, 0); err = register_netdevice_notifier(&ip6_mr_notifier); if (err) goto reg_notif_fail; -#ifdef CONFIG_PROC_FS - err = -ENOMEM; - if (!proc_net_fops_create(&init_net, "ip6_mr_vif", 0, &ip6mr_vif_fops)) - goto proc_vif_fail; - if (!proc_net_fops_create(&init_net, "ip6_mr_cache", - 0, &ip6mr_mfc_fops)) - goto proc_cache_fail; -#endif return 0; -#ifdef CONFIG_PROC_FS -proc_cache_fail: - proc_net_remove(&init_net, "ip6_mr_vif"); -proc_vif_fail: - unregister_netdevice_notifier(&ip6_mr_notifier); -#endif reg_notif_fail: del_timer(&ipmr_expire_timer); + unregister_pernet_subsys(&ip6mr_net_ops); +reg_pernet_fail: kmem_cache_destroy(mrt_cachep); return err; } void ip6_mr_cleanup(void) { -#ifdef CONFIG_PROC_FS - proc_net_remove(&init_net, "ip6_mr_cache"); - proc_net_remove(&init_net, "ip6_mr_vif"); -#endif unregister_netdevice_notifier(&ip6_mr_notifier); del_timer(&ipmr_expire_timer); + unregister_pernet_subsys(&ip6mr_net_ops); kmem_cache_destroy(mrt_cachep); } -static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) +static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock) { int line; struct mfc6_cache *uc, *c, **cp; @@ -1020,7 +1100,8 @@ static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) line = MFC6_HASH(&mfc->mf6cc_mcastgrp.sin6_addr, &mfc->mf6cc_origin.sin6_addr); - for (cp = &mfc6_cache_array[line]; (c = *cp) != NULL; cp = &c->next) { + for (cp = &net->ipv6.mfc6_cache_array[line]; + (c = *cp) != NULL; cp = &c->next) { if (ipv6_addr_equal(&c->mf6c_origin, &mfc->mf6cc_origin.sin6_addr) && ipv6_addr_equal(&c->mf6c_mcastgrp, &mfc->mf6cc_mcastgrp.sin6_addr)) break; @@ -1039,7 +1120,7 @@ static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) if (!ipv6_addr_is_multicast(&mfc->mf6cc_mcastgrp.sin6_addr)) return -EINVAL; - c = ip6mr_cache_alloc(); + c = ip6mr_cache_alloc(net); if (c == NULL) return -ENOMEM; @@ -1051,8 +1132,8 @@ static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) c->mfc_flags |= MFC_STATIC; write_lock_bh(&mrt_lock); - c->next = mfc6_cache_array[line]; - mfc6_cache_array[line] = c; + c->next = net->ipv6.mfc6_cache_array[line]; + net->ipv6.mfc6_cache_array[line] = c; write_unlock_bh(&mrt_lock); /* @@ -1062,19 +1143,21 @@ static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) spin_lock_bh(&mfc_unres_lock); for (cp = &mfc_unres_queue; (uc = *cp) != NULL; cp = &uc->next) { - if (ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) && + if (net_eq(mfc6_net(uc), net) && + ipv6_addr_equal(&uc->mf6c_origin, &c->mf6c_origin) && ipv6_addr_equal(&uc->mf6c_mcastgrp, &c->mf6c_mcastgrp)) { *cp = uc->next; - if (atomic_dec_and_test(&cache_resolve_queue_len)) - del_timer(&ipmr_expire_timer); + atomic_dec(&net->ipv6.cache_resolve_queue_len); break; } } + if (mfc_unres_queue == NULL) + del_timer(&ipmr_expire_timer); spin_unlock_bh(&mfc_unres_lock); if (uc) { ip6mr_cache_resolve(uc, c); - kmem_cache_free(mrt_cachep, uc); + ip6mr_cache_free(uc); } return 0; } @@ -1083,25 +1166,25 @@ static int ip6mr_mfc_add(struct mf6cctl *mfc, int mrtsock) * Close the multicast socket, and clear the vif tables etc */ -static void mroute_clean_tables(struct sock *sk) +static void mroute_clean_tables(struct net *net) { int i; /* * Shut down all active vif entries */ - for (i = 0; i < maxvif; i++) { - if (!(vif6_table[i].flags & VIFF_STATIC)) - mif6_delete(i); + for (i = 0; i < net->ipv6.maxvif; i++) { + if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC)) + mif6_delete(net, i); } /* * Wipe the cache */ - for (i = 0; i < ARRAY_SIZE(mfc6_cache_array); i++) { + for (i = 0; i < MFC6_LINES; i++) { struct mfc6_cache *c, **cp; - cp = &mfc6_cache_array[i]; + cp = &net->ipv6.mfc6_cache_array[i]; while ((c = *cp) != NULL) { if (c->mfc_flags & MFC_STATIC) { cp = &c->next; @@ -1111,22 +1194,22 @@ static void mroute_clean_tables(struct sock *sk) *cp = c->next; write_unlock_bh(&mrt_lock); - kmem_cache_free(mrt_cachep, c); + ip6mr_cache_free(c); } } - if (atomic_read(&cache_resolve_queue_len) != 0) { - struct mfc6_cache *c; + if (atomic_read(&net->ipv6.cache_resolve_queue_len) != 0) { + struct mfc6_cache *c, **cp; spin_lock_bh(&mfc_unres_lock); - while (mfc_unres_queue != NULL) { - c = mfc_unres_queue; - mfc_unres_queue = c->next; - spin_unlock_bh(&mfc_unres_lock); - + cp = &mfc_unres_queue; + while ((c = *cp) != NULL) { + if (!net_eq(mfc6_net(c), net)) { + cp = &c->next; + continue; + } + *cp = c->next; ip6mr_destroy_unres(c); - - spin_lock_bh(&mfc_unres_lock); } spin_unlock_bh(&mfc_unres_lock); } @@ -1135,11 +1218,12 @@ static void mroute_clean_tables(struct sock *sk) static int ip6mr_sk_init(struct sock *sk) { int err = 0; + struct net *net = sock_net(sk); rtnl_lock(); write_lock_bh(&mrt_lock); - if (likely(mroute6_socket == NULL)) - mroute6_socket = sk; + if (likely(net->ipv6.mroute6_sk == NULL)) + net->ipv6.mroute6_sk = sk; else err = -EADDRINUSE; write_unlock_bh(&mrt_lock); @@ -1152,14 +1236,15 @@ static int ip6mr_sk_init(struct sock *sk) int ip6mr_sk_done(struct sock *sk) { int err = 0; + struct net *net = sock_net(sk); rtnl_lock(); - if (sk == mroute6_socket) { + if (sk == net->ipv6.mroute6_sk) { write_lock_bh(&mrt_lock); - mroute6_socket = NULL; + net->ipv6.mroute6_sk = NULL; write_unlock_bh(&mrt_lock); - mroute_clean_tables(sk); + mroute_clean_tables(net); } else err = -EACCES; rtnl_unlock(); @@ -1180,9 +1265,10 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int struct mif6ctl vif; struct mf6cctl mfc; mifi_t mifi; + struct net *net = sock_net(sk); if (optname != MRT6_INIT) { - if (sk != mroute6_socket && !capable(CAP_NET_ADMIN)) + if (sk != net->ipv6.mroute6_sk && !capable(CAP_NET_ADMIN)) return -EACCES; } @@ -1207,7 +1293,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int if (vif.mif6c_mifi >= MAXMIFS) return -ENFILE; rtnl_lock(); - ret = mif6_add(&vif, sk == mroute6_socket); + ret = mif6_add(net, &vif, sk == net->ipv6.mroute6_sk); rtnl_unlock(); return ret; @@ -1217,7 +1303,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int if (copy_from_user(&mifi, optval, sizeof(mifi_t))) return -EFAULT; rtnl_lock(); - ret = mif6_delete(mifi); + ret = mif6_delete(net, mifi); rtnl_unlock(); return ret; @@ -1233,9 +1319,10 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int return -EFAULT; rtnl_lock(); if (optname == MRT6_DEL_MFC) - ret = ip6mr_mfc_delete(&mfc); + ret = ip6mr_mfc_delete(net, &mfc); else - ret = ip6mr_mfc_add(&mfc, sk == mroute6_socket); + ret = ip6mr_mfc_add(net, &mfc, + sk == net->ipv6.mroute6_sk); rtnl_unlock(); return ret; @@ -1247,7 +1334,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int int v; if (get_user(v, (int __user *)optval)) return -EFAULT; - mroute_do_assert = !!v; + net->ipv6.mroute_do_assert = !!v; return 0; } @@ -1260,10 +1347,10 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int v = !!v; rtnl_lock(); ret = 0; - if (v != mroute_do_pim) { - mroute_do_pim = v; - mroute_do_assert = v; - if (mroute_do_pim) + if (v != net->ipv6.mroute_do_pim) { + net->ipv6.mroute_do_pim = v; + net->ipv6.mroute_do_assert = v; + if (net->ipv6.mroute_do_pim) ret = inet6_add_protocol(&pim6_protocol, IPPROTO_PIM); else @@ -1295,6 +1382,7 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, { int olr; int val; + struct net *net = sock_net(sk); switch (optname) { case MRT6_VERSION: @@ -1302,11 +1390,11 @@ int ip6_mroute_getsockopt(struct sock *sk, int optname, char __user *optval, break; #ifdef CONFIG_IPV6_PIMSM_V2 case MRT6_PIM: - val = mroute_do_pim; + val = net->ipv6.mroute_do_pim; break; #endif case MRT6_ASSERT: - val = mroute_do_assert; + val = net->ipv6.mroute_do_assert; break; default: return -ENOPROTOOPT; @@ -1336,16 +1424,17 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) struct sioc_mif_req6 vr; struct mif_device *vif; struct mfc6_cache *c; + struct net *net = sock_net(sk); switch (cmd) { case SIOCGETMIFCNT_IN6: if (copy_from_user(&vr, arg, sizeof(vr))) return -EFAULT; - if (vr.mifi >= maxvif) + if (vr.mifi >= net->ipv6.maxvif) return -EINVAL; read_lock(&mrt_lock); - vif = &vif6_table[vr.mifi]; - if (MIF_EXISTS(vr.mifi)) { + vif = &net->ipv6.vif6_table[vr.mifi]; + if (MIF_EXISTS(net, vr.mifi)) { vr.icount = vif->pkt_in; vr.ocount = vif->pkt_out; vr.ibytes = vif->bytes_in; @@ -1363,7 +1452,7 @@ int ip6mr_ioctl(struct sock *sk, int cmd, void __user *arg) return -EFAULT; read_lock(&mrt_lock); - c = ip6mr_cache_find(&sr.src.sin6_addr, &sr.grp.sin6_addr); + c = ip6mr_cache_find(net, &sr.src.sin6_addr, &sr.grp.sin6_addr); if (c) { sr.pktcnt = c->mfc_un.res.pkt; sr.bytecnt = c->mfc_un.res.bytes; @@ -1396,7 +1485,8 @@ static inline int ip6mr_forward2_finish(struct sk_buff *skb) static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) { struct ipv6hdr *ipv6h; - struct mif_device *vif = &vif6_table[vifi]; + struct net *net = mfc6_net(c); + struct mif_device *vif = &net->ipv6.vif6_table[vifi]; struct net_device *dev; struct dst_entry *dst; struct flowi fl; @@ -1410,9 +1500,8 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) vif->bytes_out += skb->len; vif->dev->stats.tx_bytes += skb->len; vif->dev->stats.tx_packets++; - ip6mr_cache_report(skb, vifi, MRT6MSG_WHOLEPKT); - kfree_skb(skb); - return 0; + ip6mr_cache_report(net, skb, vifi, MRT6MSG_WHOLEPKT); + goto out_free; } #endif @@ -1425,7 +1514,7 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi) } }; - dst = ip6_route_output(&init_net, NULL, &fl); + dst = ip6_route_output(net, NULL, &fl); if (!dst) goto out_free; @@ -1468,9 +1557,10 @@ out_free: static int ip6mr_find_vif(struct net_device *dev) { + struct net *net = dev_net(dev); int ct; - for (ct = maxvif - 1; ct >= 0; ct--) { - if (vif6_table[ct].dev == dev) + for (ct = net->ipv6.maxvif - 1; ct >= 0; ct--) { + if (net->ipv6.vif6_table[ct].dev == dev) break; } return ct; @@ -1480,6 +1570,7 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) { int psend = -1; int vif, ct; + struct net *net = mfc6_net(cache); vif = cache->mf6c_parent; cache->mfc_un.res.pkt++; @@ -1488,29 +1579,30 @@ static int ip6_mr_forward(struct sk_buff *skb, struct mfc6_cache *cache) /* * Wrong interface: drop packet and (maybe) send PIM assert. */ - if (vif6_table[vif].dev != skb->dev) { + if (net->ipv6.vif6_table[vif].dev != skb->dev) { int true_vifi; cache->mfc_un.res.wrong_if++; true_vifi = ip6mr_find_vif(skb->dev); - if (true_vifi >= 0 && mroute_do_assert && + if (true_vifi >= 0 && net->ipv6.mroute_do_assert && /* pimsm uses asserts, when switching from RPT to SPT, so that we cannot check that packet arrived on an oif. It is bad, but otherwise we would need to move pretty large chunk of pimd to kernel. Ough... --ANK */ - (mroute_do_pim || cache->mfc_un.res.ttls[true_vifi] < 255) && + (net->ipv6.mroute_do_pim || + cache->mfc_un.res.ttls[true_vifi] < 255) && time_after(jiffies, cache->mfc_un.res.last_assert + MFC_ASSERT_THRESH)) { cache->mfc_un.res.last_assert = jiffies; - ip6mr_cache_report(skb, true_vifi, MRT6MSG_WRONGMIF); + ip6mr_cache_report(net, skb, true_vifi, MRT6MSG_WRONGMIF); } goto dont_forward; } - vif6_table[vif].pkt_in++; - vif6_table[vif].bytes_in += skb->len; + net->ipv6.vif6_table[vif].pkt_in++; + net->ipv6.vif6_table[vif].bytes_in += skb->len; /* * Forward the frame @@ -1543,9 +1635,11 @@ dont_forward: int ip6_mr_input(struct sk_buff *skb) { struct mfc6_cache *cache; + struct net *net = dev_net(skb->dev); read_lock(&mrt_lock); - cache = ip6mr_cache_find(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); + cache = ip6mr_cache_find(net, + &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr); /* * No usable cache entry @@ -1555,7 +1649,7 @@ int ip6_mr_input(struct sk_buff *skb) vif = ip6mr_find_vif(skb->dev); if (vif >= 0) { - int err = ip6mr_cache_unresolved(vif, skb); + int err = ip6mr_cache_unresolved(net, vif, skb); read_unlock(&mrt_lock); return err; @@ -1578,7 +1672,8 @@ ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm) { int ct; struct rtnexthop *nhp; - struct net_device *dev = vif6_table[c->mf6c_parent].dev; + struct net *net = mfc6_net(c); + struct net_device *dev = net->ipv6.vif6_table[c->mf6c_parent].dev; u8 *b = skb_tail_pointer(skb); struct rtattr *mp_head; @@ -1594,7 +1689,7 @@ ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm) nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp))); nhp->rtnh_flags = 0; nhp->rtnh_hops = c->mfc_un.res.ttls[ct]; - nhp->rtnh_ifindex = vif6_table[ct].dev->ifindex; + nhp->rtnh_ifindex = net->ipv6.vif6_table[ct].dev->ifindex; nhp->rtnh_len = sizeof(*nhp); } } @@ -1608,14 +1703,15 @@ rtattr_failure: return -EMSGSIZE; } -int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait) +int ip6mr_get_route(struct net *net, + struct sk_buff *skb, struct rtmsg *rtm, int nowait) { int err; struct mfc6_cache *cache; struct rt6_info *rt = (struct rt6_info *)skb->dst; read_lock(&mrt_lock); - cache = ip6mr_cache_find(&rt->rt6i_src.addr, &rt->rt6i_dst.addr); + cache = ip6mr_cache_find(net, &rt->rt6i_src.addr, &rt->rt6i_dst.addr); if (!cache) { struct sk_buff *skb2; @@ -1658,7 +1754,7 @@ int ip6mr_get_route(struct sk_buff *skb, struct rtmsg *rtm, int nowait) ipv6_addr_copy(&iph->saddr, &rt->rt6i_src.addr); ipv6_addr_copy(&iph->daddr, &rt->rt6i_dst.addr); - err = ip6mr_cache_unresolved(vif, skb2); + err = ip6mr_cache_unresolved(net, vif, skb2); read_unlock(&mrt_lock); return err; diff --git a/net/ipv6/ipcomp6.c b/net/ipv6/ipcomp6.c index 4545e4306862b104217aa5189eac1d4b64c1b43e..3a0b3be7ece525d6d7230c2fd2c79340a025c4f2 100644 --- a/net/ipv6/ipcomp6.c +++ b/net/ipv6/ipcomp6.c @@ -63,12 +63,12 @@ static void ipcomp6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, return; spi = htonl(ntohs(ipcomph->cpi)); - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); + x = xfrm_state_lookup(&init_net, (xfrm_address_t *)&iph->daddr, spi, IPPROTO_COMP, AF_INET6); if (!x) return; - printk(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/" NIP6_FMT "\n", - spi, NIP6(iph->daddr)); + printk(KERN_DEBUG "pmtu discovery on SA IPCOMP/%08x/%pI6\n", + spi, &iph->daddr); xfrm_state_put(x); } @@ -76,7 +76,7 @@ static struct xfrm_state *ipcomp6_tunnel_create(struct xfrm_state *x) { struct xfrm_state *t = NULL; - t = xfrm_state_alloc(); + t = xfrm_state_alloc(&init_net); if (!t) goto out; @@ -114,7 +114,7 @@ static int ipcomp6_tunnel_attach(struct xfrm_state *x) spi = xfrm6_tunnel_spi_lookup((xfrm_address_t *)&x->props.saddr); if (spi) - t = xfrm_state_lookup((xfrm_address_t *)&x->id.daddr, + t = xfrm_state_lookup(&init_net, (xfrm_address_t *)&x->id.daddr, spi, IPPROTO_IPV6, AF_INET6); if (!t) { t = ipcomp6_tunnel_create(x); diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index 2aa294be0c790043bbc148a71ce030e4e5fbcc4c..eeeaad2e8b5ca7f64d69f31cdf3a7b9852a2a113 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -395,6 +395,28 @@ sticky_done: break; } + case IPV6_PKTINFO: + { + struct in6_pktinfo pkt; + + if (optlen == 0) + goto e_inval; + else if (optlen < sizeof(struct in6_pktinfo) || optval == NULL) + goto e_inval; + + if (copy_from_user(&pkt, optval, optlen)) { + retv = -EFAULT; + break; + } + if (sk->sk_bound_dev_if && pkt.ipi6_ifindex != sk->sk_bound_dev_if) + goto e_inval; + + np->sticky_pktinfo.ipi6_ifindex = pkt.ipi6_ifindex; + ipv6_addr_copy(&np->sticky_pktinfo.ipi6_addr, &pkt.ipi6_addr); + retv = 0; + break; + } + case IPV6_2292PKTOPTIONS: { struct ipv6_txoptions *opt = NULL; @@ -916,8 +938,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, } else { if (np->rxopt.bits.rxinfo) { struct in6_pktinfo src_info; - src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : sk->sk_bound_dev_if; - ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr); + src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : + np->sticky_pktinfo.ipi6_ifindex; + np->mcast_oif? ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr) : + ipv6_addr_copy(&src_info.ipi6_addr, &(np->sticky_pktinfo.ipi6_addr)); put_cmsg(&msg, SOL_IPV6, IPV6_PKTINFO, sizeof(src_info), &src_info); } if (np->rxopt.bits.rxhlim) { @@ -926,8 +950,10 @@ static int do_ipv6_getsockopt(struct sock *sk, int level, int optname, } if (np->rxopt.bits.rxoinfo) { struct in6_pktinfo src_info; - src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : sk->sk_bound_dev_if; - ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr); + src_info.ipi6_ifindex = np->mcast_oif ? np->mcast_oif : + np->sticky_pktinfo.ipi6_ifindex; + np->mcast_oif? ipv6_addr_copy(&src_info.ipi6_addr, &np->daddr) : + ipv6_addr_copy(&src_info.ipi6_addr, &(np->sticky_pktinfo.ipi6_addr)); put_cmsg(&msg, SOL_IPV6, IPV6_2292PKTINFO, sizeof(src_info), &src_info); } if (np->rxopt.bits.rxohlim) { diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index d7b3c6d398ae382e1342dba28b86575c03f9fd6d..a51fb33e6864f7d588c8ed81821378d710081411 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -303,20 +303,23 @@ static struct inet6_dev *ip6_mc_find_dev(struct net *net, dev = dev_get_by_index(net, ifindex); if (!dev) - return NULL; + goto nodev; idev = in6_dev_get(dev); - if (!idev) { - dev_put(dev); - return NULL; - } + if (!idev) + goto release; read_lock_bh(&idev->lock); - if (idev->dead) { - read_unlock_bh(&idev->lock); - in6_dev_put(idev); - dev_put(dev); - return NULL; - } + if (idev->dead) + goto unlock_release; + return idev; + +unlock_release: + read_unlock_bh(&idev->lock); + in6_dev_put(idev); +release: + dev_put(dev); +nodev: + return NULL; } void ipv6_sock_mc_close(struct sock *sk) @@ -1466,7 +1469,7 @@ static void mld_sendpack(struct sk_buff *skb) &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev->ifindex); - err = xfrm_lookup(&skb->dst, &fl, NULL, 0); + err = xfrm_lookup(net, &skb->dst, &fl, NULL, 0); if (err) goto err_out; @@ -1817,7 +1820,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) hdr->icmp6_cksum = csum_ipv6_magic(saddr, snd_addr, len, IPPROTO_ICMPV6, - csum_partial((__u8 *) hdr, len, 0)); + csum_partial(hdr, len, 0)); idev = in6_dev_get(skb->dev); @@ -1831,7 +1834,7 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) &ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr, skb->dev->ifindex); - err = xfrm_lookup(&skb->dst, &fl, NULL, 0); + err = xfrm_lookup(net, &skb->dst, &fl, NULL, 0); if (err) goto err_out; @@ -2430,9 +2433,9 @@ static int igmp6_mc_seq_show(struct seq_file *seq, void *v) struct igmp6_mc_iter_state *state = igmp6_mc_seq_private(seq); seq_printf(seq, - "%-4d %-15s " NIP6_SEQFMT " %5d %08X %ld\n", + "%-4d %-15s %pi6 %5d %08X %ld\n", state->dev->ifindex, state->dev->name, - NIP6(im->mca_addr), + &im->mca_addr, im->mca_users, im->mca_flags, (im->mca_flags&MAF_TIMER_RUNNING) ? jiffies_to_clock_t(im->mca_timer.expires-jiffies) : 0); @@ -2591,10 +2594,10 @@ static int igmp6_mcf_seq_show(struct seq_file *seq, void *v) "Source Address", "INC", "EXC"); } else { seq_printf(seq, - "%3d %6.6s " NIP6_SEQFMT " " NIP6_SEQFMT " %6lu %6lu\n", + "%3d %6.6s %pi6 %pi6 %6lu %6lu\n", state->dev->ifindex, state->dev->name, - NIP6(state->im->mca_addr), - NIP6(psf->sf_addr), + &state->im->mca_addr, + &psf->sf_addr, psf->sf_count[MCAST_INCLUDE], psf->sf_count[MCAST_EXCLUDE]); } diff --git a/net/ipv6/mip6.c b/net/ipv6/mip6.c index 31295c8f619688099477dd5e230c61f8199d51da..f995e19c87a96d29995d7de530e0f996160ff980 100644 --- a/net/ipv6/mip6.c +++ b/net/ipv6/mip6.c @@ -205,6 +205,7 @@ static inline int mip6_report_rl_allow(struct timeval *stamp, static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, struct flowi *fl) { + struct net *net = xs_net(x); struct inet6_skb_parm *opt = (struct inet6_skb_parm *)skb->cb; struct ipv6_destopt_hao *hao = NULL; struct xfrm_selector sel; @@ -247,7 +248,7 @@ static int mip6_destopt_reject(struct xfrm_state *x, struct sk_buff *skb, struct sel.sport_mask = htons(~0); sel.ifindex = fl->oif; - err = km_report(IPPROTO_DSTOPTS, &sel, + err = km_report(net, IPPROTO_DSTOPTS, &sel, (hao ? (xfrm_address_t *)&hao->addr : NULL)); out: diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index d0f54d18e19b92de1407eb9a36fed5344363d01d..3e2970841bd825f6d4c7286d9a5163e2da2084fe 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -437,38 +437,20 @@ static void pndisc_destructor(struct pneigh_entry *n) ipv6_dev_mc_dec(dev, &maddr); } -/* - * Send a Neighbour Advertisement - */ -static void __ndisc_send(struct net_device *dev, - struct neighbour *neigh, - const struct in6_addr *daddr, - const struct in6_addr *saddr, - struct icmp6hdr *icmp6h, const struct in6_addr *target, - int llinfo) +struct sk_buff *ndisc_build_skb(struct net_device *dev, + const struct in6_addr *daddr, + const struct in6_addr *saddr, + struct icmp6hdr *icmp6h, + const struct in6_addr *target, + int llinfo) { - struct flowi fl; - struct dst_entry *dst; struct net *net = dev_net(dev); struct sock *sk = net->ipv6.ndisc_sk; struct sk_buff *skb; struct icmp6hdr *hdr; - struct inet6_dev *idev; int len; int err; - u8 *opt, type; - - type = icmp6h->icmp6_type; - - icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex); - - dst = icmp6_dst_alloc(dev, neigh, daddr); - if (!dst) - return; - - err = xfrm_lookup(&dst, &fl, NULL, 0); - if (err < 0) - return; + u8 *opt; if (!dev->addr_len) llinfo = 0; @@ -485,8 +467,7 @@ static void __ndisc_send(struct net_device *dev, ND_PRINTK0(KERN_ERR "ICMPv6 ND: %s() failed to allocate an skb.\n", __func__); - dst_release(dst); - return; + return NULL; } skb_reserve(skb, LL_RESERVED_SPACE(dev)); @@ -510,9 +491,45 @@ static void __ndisc_send(struct net_device *dev, hdr->icmp6_cksum = csum_ipv6_magic(saddr, daddr, len, IPPROTO_ICMPV6, - csum_partial((__u8 *) hdr, + csum_partial(hdr, len, 0)); + return skb; +} + +EXPORT_SYMBOL(ndisc_build_skb); + +void ndisc_send_skb(struct sk_buff *skb, + struct net_device *dev, + struct neighbour *neigh, + const struct in6_addr *daddr, + const struct in6_addr *saddr, + struct icmp6hdr *icmp6h) +{ + struct flowi fl; + struct dst_entry *dst; + struct net *net = dev_net(dev); + struct sock *sk = net->ipv6.ndisc_sk; + struct inet6_dev *idev; + int err; + u8 type; + + type = icmp6h->icmp6_type; + + icmpv6_flow_init(sk, &fl, type, saddr, daddr, dev->ifindex); + + dst = icmp6_dst_alloc(dev, neigh, daddr); + if (!dst) { + kfree_skb(skb); + return; + } + + err = xfrm_lookup(net, &dst, &fl, NULL, 0); + if (err < 0) { + kfree_skb(skb); + return; + } + skb->dst = dst; idev = in6_dev_get(dst->dev); @@ -529,6 +546,27 @@ static void __ndisc_send(struct net_device *dev, in6_dev_put(idev); } +EXPORT_SYMBOL(ndisc_send_skb); + +/* + * Send a Neighbour Discover packet + */ +static void __ndisc_send(struct net_device *dev, + struct neighbour *neigh, + const struct in6_addr *daddr, + const struct in6_addr *saddr, + struct icmp6hdr *icmp6h, const struct in6_addr *target, + int llinfo) +{ + struct sk_buff *skb; + + skb = ndisc_build_skb(dev, daddr, saddr, icmp6h, target, llinfo); + if (!skb) + return; + + ndisc_send_skb(skb, dev, neigh, daddr, saddr, icmp6h); +} + static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, const struct in6_addr *daddr, const struct in6_addr *solicited_addr, @@ -647,11 +685,8 @@ static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb) if ((probes -= neigh->parms->ucast_probes) < 0) { if (!(neigh->nud_state & NUD_VALID)) { - ND_PRINTK1(KERN_DEBUG - "%s(): trying to ucast probe in NUD_INVALID: " - NIP6_FMT "\n", - __func__, - NIP6(*target)); + ND_PRINTK1(KERN_DEBUG "%s(): trying to ucast probe in NUD_INVALID: %pI6\n", + __func__, target); } ndisc_send_ns(dev, neigh, target, target, saddr); } else if ((probes -= neigh->parms->app_probes) < 0) { @@ -1494,7 +1529,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, if (dst == NULL) return; - err = xfrm_lookup(&dst, &fl, NULL, 0); + err = xfrm_lookup(net, &dst, &fl, NULL, 0); if (err) return; @@ -1582,7 +1617,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, icmph->icmp6_cksum = csum_ipv6_magic(&saddr_buf, &ipv6_hdr(skb)->saddr, len, IPPROTO_ICMPV6, - csum_partial((u8 *) icmph, len, 0)); + csum_partial(icmph, len, 0)); buff->dst = dst; idev = in6_dev_get(dst->dev); diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index fd5b3a4e332988056119748ae1c636dff72b53b9..834cea69fb53b1a081be1de8368f1b9cec8921dd 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -29,7 +29,7 @@ int ip6_route_me_harder(struct sk_buff *skb) #ifdef CONFIG_XFRM if (!(IP6CB(skb)->flags & IP6SKB_XFRM_TRANSFORMED) && xfrm_decode_session(skb, &fl, AF_INET6) == 0) - if (xfrm_lookup(&skb->dst, &fl, skb->sk, 0)) + if (xfrm_lookup(net, &skb->dst, &fl, skb->sk, 0)) return -1; #endif @@ -56,6 +56,7 @@ EXPORT_SYMBOL(ip6_route_me_harder); struct ip6_rt_info { struct in6_addr daddr; struct in6_addr saddr; + u_int32_t mark; }; static void nf_ip6_saveroute(const struct sk_buff *skb, @@ -68,6 +69,7 @@ static void nf_ip6_saveroute(const struct sk_buff *skb, rt_info->daddr = iph->daddr; rt_info->saddr = iph->saddr; + rt_info->mark = skb->mark; } } @@ -79,7 +81,8 @@ static int nf_ip6_reroute(struct sk_buff *skb, if (entry->hook == NF_INET_LOCAL_OUT) { struct ipv6hdr *iph = ipv6_hdr(skb); if (!ipv6_addr_equal(&iph->daddr, &rt_info->daddr) || - !ipv6_addr_equal(&iph->saddr, &rt_info->saddr)) + !ipv6_addr_equal(&iph->saddr, &rt_info->saddr) || + skb->mark != rt_info->mark) return ip6_route_me_harder(skb); } return 0; diff --git a/net/ipv6/netfilter/ip6t_LOG.c b/net/ipv6/netfilter/ip6t_LOG.c index 871d157cec4eabde6d13fd8a4f1266651eccb368..37adf5abc51e85bb9d07ab4a668307b9b316da77 100644 --- a/net/ipv6/netfilter/ip6t_LOG.c +++ b/net/ipv6/netfilter/ip6t_LOG.c @@ -61,7 +61,7 @@ static void dump_packet(const struct nf_loginfo *info, } /* Max length: 88 "SRC=0000.0000.0000.0000.0000.0000.0000.0000 DST=0000.0000.0000.0000.0000.0000.0000.0000 " */ - printk("SRC=" NIP6_FMT " DST=" NIP6_FMT " ", NIP6(ih->saddr), NIP6(ih->daddr)); + printk("SRC=%pI6 DST=%pI6 ", &ih->saddr, &ih->daddr); /* Max length: 44 "LEN=65535 TC=255 HOPLIMIT=255 FLOWLBL=FFFFF " */ printk("LEN=%Zu TC=%u HOPLIMIT=%u FLOWLBL=%u ", @@ -424,9 +424,8 @@ ip6t_log_packet(u_int8_t pf, if (skb->dev->type == ARPHRD_SIT) { const struct iphdr *iph = (struct iphdr *)skb_mac_header(skb); - printk("TUNNEL=%u.%u.%u.%u->%u.%u.%u.%u ", - NIPQUAD(iph->saddr), - NIPQUAD(iph->daddr)); + printk("TUNNEL=%pI4->%pI4 ", + &iph->saddr, &iph->daddr); } } else printk(" "); diff --git a/net/ipv6/netfilter/ip6t_REJECT.c b/net/ipv6/netfilter/ip6t_REJECT.c index 0981b4ccb8b1c2c20ec4592dd6d0fc27b24f5514..5a2d0a41694a77791c97eef8e1063b40502029ca 100644 --- a/net/ipv6/netfilter/ip6t_REJECT.c +++ b/net/ipv6/netfilter/ip6t_REJECT.c @@ -97,7 +97,7 @@ static void send_reset(struct net *net, struct sk_buff *oldskb) dst = ip6_route_output(net, NULL, &fl); if (dst == NULL) return; - if (dst->error || xfrm_lookup(&dst, &fl, NULL, 0)) + if (dst->error || xfrm_lookup(net, &dst, &fl, NULL, 0)) return; hh_len = (dst->dev->hard_header_len + 15)&~15; diff --git a/net/ipv6/netfilter/ip6table_filter.c b/net/ipv6/netfilter/ip6table_filter.c index b110a8a85a1480855fb6bdea238c82dccd29cc7a..40d2e36d8fac292b8fdf8663717d3eaf505108c5 100644 --- a/net/ipv6/netfilter/ip6table_filter.c +++ b/net/ipv6/netfilter/ip6table_filter.c @@ -61,7 +61,7 @@ static struct xt_table packet_filter = { /* The work comes in here from netfilter.c. */ static unsigned int -ip6t_local_in_hook(unsigned int hook, +ip6t_in_hook(unsigned int hook, struct sk_buff *skb, const struct net_device *in, const struct net_device *out, @@ -71,17 +71,6 @@ ip6t_local_in_hook(unsigned int hook, dev_net(in)->ipv6.ip6table_filter); } -static unsigned int -ip6t_forward_hook(unsigned int hook, - struct sk_buff *skb, - const struct net_device *in, - const struct net_device *out, - int (*okfn)(struct sk_buff *)) -{ - return ip6t_do_table(skb, hook, in, out, - dev_net(in)->ipv6.ip6table_filter); -} - static unsigned int ip6t_local_out_hook(unsigned int hook, struct sk_buff *skb, @@ -105,14 +94,14 @@ ip6t_local_out_hook(unsigned int hook, static struct nf_hook_ops ip6t_ops[] __read_mostly = { { - .hook = ip6t_local_in_hook, + .hook = ip6t_in_hook, .owner = THIS_MODULE, .pf = PF_INET6, .hooknum = NF_INET_LOCAL_IN, .priority = NF_IP6_PRI_FILTER, }, { - .hook = ip6t_forward_hook, + .hook = ip6t_in_hook, .owner = THIS_MODULE, .pf = PF_INET6, .hooknum = NF_INET_FORWARD, diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c index e91db16611d902092b956c63031ee1c39a723d66..727b9530448a5fd42562a8163eaadc067da4b5d6 100644 --- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c +++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c @@ -56,9 +56,8 @@ static bool ipv6_invert_tuple(struct nf_conntrack_tuple *tuple, static int ipv6_print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple) { - return seq_printf(s, "src=" NIP6_FMT " dst=" NIP6_FMT " ", - NIP6(*((struct in6_addr *)tuple->src.u3.ip6)), - NIP6(*((struct in6_addr *)tuple->dst.u3.ip6))); + return seq_printf(s, "src=%pI6 dst=%pI6 ", + tuple->src.u3.ip6, tuple->dst.u3.ip6); } /* diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c index 05726177903f91a6f460fb41123dbf9f73660305..bd52151d31e92f19146b96dfa324259d46670a0e 100644 --- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c +++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c @@ -253,7 +253,7 @@ static struct ctl_table icmpv6_sysctl_table[] = { .data = &nf_ct_icmpv6_timeout, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index 9967ac7a01a87f49323b7e5f0d4ed9ff1ff283b6..ed4d79a9e4a6263225a83f4874692fbca1911754 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -80,7 +80,7 @@ struct ctl_table nf_ct_ipv6_sysctl_table[] = { .data = &nf_init_frags.timeout, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = NET_NF_CONNTRACK_FRAG6_LOW_THRESH, @@ -88,7 +88,7 @@ struct ctl_table nf_ct_ipv6_sysctl_table[] = { .data = &nf_init_frags.low_thresh, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NF_CONNTRACK_FRAG6_HIGH_THRESH, @@ -96,7 +96,7 @@ struct ctl_table nf_ct_ipv6_sysctl_table[] = { .data = &nf_init_frags.high_thresh, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = 0 } }; diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 2ba04d41dc250c11a08e7b4cb95c96e33792c560..61f6827e59067f82fbca8c00db67ecd64b0ed521 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -860,7 +860,8 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) { + err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT); + if (err < 0) { if (err == -EREMOTE) err = ip6_dst_blackhole(sk, &dst, &fl); if (err < 0) diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c index af12de071f4c524c3f6349d982d7fd3dbb97e5a6..3c575118fca51d05d73c35968a0960b1b92a6005 100644 --- a/net/ipv6/reassembly.c +++ b/net/ipv6/reassembly.c @@ -642,7 +642,7 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = { .data = &init_net.ipv6.frags.high_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV6_IP6FRAG_LOW_THRESH, @@ -650,7 +650,7 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = { .data = &init_net.ipv6.frags.low_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IPV6_IP6FRAG_TIME, @@ -658,8 +658,8 @@ static struct ctl_table ip6_frags_ns_ctl_table[] = { .data = &init_net.ipv6.frags.timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { } }; @@ -671,8 +671,8 @@ static struct ctl_table ip6_frags_ctl_table[] = { .data = &ip6_frags.secret_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies }, { } }; diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 89dc699243404669dc53aba051d2b1c1cb014d92..18c486cf498756b5a4536d17798854ba137ba37f 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -108,7 +108,6 @@ static struct dst_ops ip6_dst_ops_template = { .link_failure = ip6_link_failure, .update_pmtu = ip6_rt_update_pmtu, .local_out = __ip6_local_out, - .entry_size = sizeof(struct rt6_info), .entries = ATOMIC_INIT(0), }; @@ -122,7 +121,6 @@ static struct dst_ops ip6_dst_blackhole_ops = { .destroy = ip6_dst_destroy, .check = ip6_dst_check, .update_pmtu = ip6_rt_blackhole_update_pmtu, - .entry_size = sizeof(struct rt6_info), .entries = ATOMIC_INIT(0), }; @@ -2196,7 +2194,7 @@ static int rt6_fill_node(struct net *net, if (iif) { #ifdef CONFIG_IPV6_MROUTE if (ipv6_addr_is_multicast(&rt->rt6i_dst.addr)) { - int err = ip6mr_get_route(skb, rtm, nowait); + int err = ip6mr_get_route(net, skb, rtm, nowait); if (err <= 0) { if (!nowait) { if (err == 0) @@ -2408,19 +2406,16 @@ static int rt6_info_route(struct rt6_info *rt, void *p_arg) { struct seq_file *m = p_arg; - seq_printf(m, NIP6_SEQFMT " %02x ", NIP6(rt->rt6i_dst.addr), - rt->rt6i_dst.plen); + seq_printf(m, "%pi6 %02x ", &rt->rt6i_dst.addr, rt->rt6i_dst.plen); #ifdef CONFIG_IPV6_SUBTREES - seq_printf(m, NIP6_SEQFMT " %02x ", NIP6(rt->rt6i_src.addr), - rt->rt6i_src.plen); + seq_printf(m, "%pi6 %02x ", &rt->rt6i_src.addr, rt->rt6i_src.plen); #else seq_puts(m, "00000000000000000000000000000000 00 "); #endif if (rt->rt6i_nexthop) { - seq_printf(m, NIP6_SEQFMT, - NIP6(*((struct in6_addr *)rt->rt6i_nexthop->primary_key))); + seq_printf(m, "%pi6", rt->rt6i_nexthop->primary_key); } else { seq_puts(m, "00000000000000000000000000000000"); } @@ -2502,7 +2497,7 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.flush_delay, .maxlen = sizeof(int), .mode = 0200, - .proc_handler = &ipv6_sysctl_rtcache_flush + .proc_handler = ipv6_sysctl_rtcache_flush }, { .ctl_name = NET_IPV6_ROUTE_GC_THRESH, @@ -2510,7 +2505,7 @@ ctl_table ipv6_route_table_template[] = { .data = &ip6_dst_ops_template.gc_thresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_ROUTE_MAX_SIZE, @@ -2518,7 +2513,7 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_max_size, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV6_ROUTE_GC_MIN_INTERVAL, @@ -2526,8 +2521,8 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV6_ROUTE_GC_TIMEOUT, @@ -2535,8 +2530,8 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_gc_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV6_ROUTE_GC_INTERVAL, @@ -2544,8 +2539,8 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_gc_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV6_ROUTE_GC_ELASTICITY, @@ -2553,8 +2548,8 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_gc_elasticity, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV6_ROUTE_MTU_EXPIRES, @@ -2562,8 +2557,8 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_mtu_expires, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV6_ROUTE_MIN_ADVMSS, @@ -2571,8 +2566,8 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_min_advmss, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_IPV6_ROUTE_GC_MIN_INTERVAL_MS, @@ -2580,8 +2575,8 @@ ctl_table ipv6_route_table_template[] = { .data = &init_net.ipv6.sysctl.ip6_rt_gc_min_interval, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_ms_jiffies, - .strategy = &sysctl_ms_jiffies, + .proc_handler = proc_dointvec_ms_jiffies, + .strategy = sysctl_ms_jiffies, }, { .ctl_name = 0 } }; diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index b7a50e968506b193081017efcbf2756be68161d8..d3467e563f0232c3bc1f6879e43c6ef99c80c3a4 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -62,8 +62,8 @@ #define HASH_SIZE 16 #define HASH(addr) (((__force u32)addr^((__force u32)addr>>4))&0xF) -static int ipip6_fb_tunnel_init(struct net_device *dev); -static int ipip6_tunnel_init(struct net_device *dev); +static void ipip6_fb_tunnel_init(struct net_device *dev); +static void ipip6_tunnel_init(struct net_device *dev); static void ipip6_tunnel_setup(struct net_device *dev); static int sit_net_id; @@ -188,7 +188,8 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net, } nt = netdev_priv(dev); - dev->init = ipip6_tunnel_init; + ipip6_tunnel_init(dev); + nt->parms = *parms; if (parms->i_flags & SIT_ISATAP) @@ -926,13 +927,17 @@ static int ipip6_tunnel_change_mtu(struct net_device *dev, int new_mtu) return 0; } +static const struct net_device_ops ipip6_netdev_ops = { + .ndo_uninit = ipip6_tunnel_uninit, + .ndo_start_xmit = ipip6_tunnel_xmit, + .ndo_do_ioctl = ipip6_tunnel_ioctl, + .ndo_change_mtu = ipip6_tunnel_change_mtu, +}; + static void ipip6_tunnel_setup(struct net_device *dev) { - dev->uninit = ipip6_tunnel_uninit; + dev->netdev_ops = &ipip6_netdev_ops; dev->destructor = free_netdev; - dev->hard_start_xmit = ipip6_tunnel_xmit; - dev->do_ioctl = ipip6_tunnel_ioctl; - dev->change_mtu = ipip6_tunnel_change_mtu; dev->type = ARPHRD_SIT; dev->hard_header_len = LL_MAX_HEADER + sizeof(struct iphdr); @@ -943,11 +948,9 @@ static void ipip6_tunnel_setup(struct net_device *dev) dev->features |= NETIF_F_NETNS_LOCAL; } -static int ipip6_tunnel_init(struct net_device *dev) +static void ipip6_tunnel_init(struct net_device *dev) { - struct ip_tunnel *tunnel; - - tunnel = netdev_priv(dev); + struct ip_tunnel *tunnel = netdev_priv(dev); tunnel->dev = dev; strcpy(tunnel->parms.name, dev->name); @@ -956,11 +959,9 @@ static int ipip6_tunnel_init(struct net_device *dev) memcpy(dev->broadcast, &tunnel->parms.iph.daddr, 4); ipip6_tunnel_bind_dev(dev); - - return 0; } -static int ipip6_fb_tunnel_init(struct net_device *dev) +static void ipip6_fb_tunnel_init(struct net_device *dev) { struct ip_tunnel *tunnel = netdev_priv(dev); struct iphdr *iph = &tunnel->parms.iph; @@ -977,7 +978,6 @@ static int ipip6_fb_tunnel_init(struct net_device *dev) dev_hold(dev); sitn->tunnels_wc[0] = tunnel; - return 0; } static struct xfrm_tunnel sit_handler = { @@ -1025,16 +1025,17 @@ static int sit_init_net(struct net *net) err = -ENOMEM; goto err_alloc_dev; } - - sitn->fb_tunnel_dev->init = ipip6_fb_tunnel_init; dev_net_set(sitn->fb_tunnel_dev, net); + ipip6_fb_tunnel_init(sitn->fb_tunnel_dev); + if ((err = register_netdev(sitn->fb_tunnel_dev))) goto err_reg_dev; return 0; err_reg_dev: + dev_put(sitn->fb_tunnel_dev); free_netdev(sitn->fb_tunnel_dev); err_alloc_dev: /* nothing */ diff --git a/net/ipv6/syncookies.c b/net/ipv6/syncookies.c index 676c80b5b14b8d13a518ce3a7d7b5f0c48208c5b..711175e0571f754539f5bc74975ebb5b83e1f54a 100644 --- a/net/ipv6/syncookies.c +++ b/net/ipv6/syncookies.c @@ -259,7 +259,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb) if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0) + if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) goto out_free; } diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 587f8f60c489644d3d6dc5a9748fd85963912ae3..9048fe7e7ea76dd2a62baa8955da06e30577f2e1 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c @@ -35,7 +35,7 @@ static ctl_table ipv6_table_template[] = { .data = &init_net.ipv6.sysctl.bindv6only, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = 0 } }; @@ -47,7 +47,7 @@ static ctl_table ipv6_table[] = { .data = &sysctl_mld_max_msf, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = 0 } }; diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index b6b356b7912a57c298a542731c2c9daf24a77bbc..8702b06cb60a9dbe6b1d7490bd30656ed79e141c 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -260,7 +260,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) { + err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT); + if (err < 0) { if (err == -EREMOTE) err = ip6_dst_blackhole(sk, &dst, &fl); if (err < 0) @@ -390,7 +391,7 @@ static void tcp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, goto out; } - if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) { + if ((err = xfrm_lookup(net, &dst, &fl, sk, 0)) < 0) { sk->sk_err_soft = -err; goto out; } @@ -492,7 +493,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req) goto done; if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 0)) < 0) + if ((err = xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) goto done; skb = tcp_make_synack(sk, dst, req); @@ -501,7 +502,7 @@ static int tcp_v6_send_synack(struct sock *sk, struct request_sock *req) th->check = tcp_v6_check(th, skb->len, &treq->loc_addr, &treq->rmt_addr, - csum_partial((char *)th, skb->len, skb->csum)); + csum_partial(th, skb->len, skb->csum)); ipv6_addr_copy(&fl.fl6_dst, &treq->rmt_addr); err = ip6_xmit(sk, skb, &fl, opt, 0); @@ -872,12 +873,10 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) if (genhash || memcmp(hash_location, newhash, 16) != 0) { if (net_ratelimit()) { - printk(KERN_INFO "MD5 Hash %s for " - "(" NIP6_FMT ", %u)->" - "(" NIP6_FMT ", %u)\n", + printk(KERN_INFO "MD5 Hash %s for (%pI6, %u)->(%pI6, %u)\n", genhash ? "failed" : "mismatch", - NIP6(ip6h->saddr), ntohs(th->source), - NIP6(ip6h->daddr), ntohs(th->dest)); + &ip6h->saddr, ntohs(th->source), + &ip6h->daddr, ntohs(th->dest)); } return 1; } @@ -917,7 +916,7 @@ static void tcp_v6_send_check(struct sock *sk, int len, struct sk_buff *skb) skb->csum_offset = offsetof(struct tcphdr, check); } else { th->check = csum_ipv6_magic(&np->saddr, &np->daddr, len, IPPROTO_TCP, - csum_partial((char *)th, th->doff<<2, + csum_partial(th, th->doff<<2, skb->csum)); } } @@ -999,7 +998,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, } #endif - buff->csum = csum_partial((char *)t1, tot_len, 0); + buff->csum = csum_partial(t1, tot_len, 0); memset(&fl, 0, sizeof(fl)); ipv6_addr_copy(&fl.fl6_dst, &ipv6_hdr(skb)->saddr); @@ -1020,7 +1019,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, * namespace */ if (!ip6_dst_lookup(ctl_sk, &buff->dst, &fl)) { - if (xfrm_lookup(&buff->dst, &fl, NULL, 0) >= 0) { + if (xfrm_lookup(net, &buff->dst, &fl, NULL, 0) >= 0) { ip6_xmit(ctl_sk, buff, &fl, NULL, 0); TCP_INC_STATS_BH(net, TCP_MIB_OUTSEGS); if (rst) @@ -1318,7 +1317,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((xfrm_lookup(&dst, &fl, sk, 0)) < 0) + if ((xfrm_lookup(sock_net(sk), &dst, &fl, sk, 0)) < 0) goto out; } @@ -1831,7 +1830,7 @@ static int tcp_v6_init_sock(struct sock *sk) sk->sk_sndbuf = sysctl_tcp_wmem[1]; sk->sk_rcvbuf = sysctl_tcp_rmem[1]; - atomic_inc(&tcp_sockets_allocated); + percpu_counter_inc(&tcp_sockets_allocated); return 0; } @@ -2045,6 +2044,7 @@ struct proto tcpv6_prot = { .sysctl_rmem = sysctl_tcp_rmem, .max_header = MAX_TCP_HEADER, .obj_size = sizeof(struct tcp6_sock), + .slab_flags = SLAB_DESTROY_BY_RCU, .twsk_prot = &tcp6_timewait_sock_ops, .rsk_prot = &tcp6_request_sock_ops, .h.hashinfo = &tcp_hashinfo, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 8b48512ebf6ac98ce279a7ca69daa6639970f1e3..84b1a296eecb3723cc0ddd79982aaf9ff1539f40 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -54,62 +54,91 @@ int udp_v6_get_port(struct sock *sk, unsigned short snum) return udp_lib_get_port(sk, snum, ipv6_rcv_saddr_equal); } +static inline int compute_score(struct sock *sk, struct net *net, + unsigned short hnum, + struct in6_addr *saddr, __be16 sport, + struct in6_addr *daddr, __be16 dport, + int dif) +{ + int score = -1; + + if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && + sk->sk_family == PF_INET6) { + struct ipv6_pinfo *np = inet6_sk(sk); + struct inet_sock *inet = inet_sk(sk); + + score = 0; + if (inet->dport) { + if (inet->dport != sport) + return -1; + score++; + } + if (!ipv6_addr_any(&np->rcv_saddr)) { + if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) + return -1; + score++; + } + if (!ipv6_addr_any(&np->daddr)) { + if (!ipv6_addr_equal(&np->daddr, saddr)) + return -1; + score++; + } + if (sk->sk_bound_dev_if) { + if (sk->sk_bound_dev_if != dif) + return -1; + score++; + } + } + return score; +} + static struct sock *__udp6_lib_lookup(struct net *net, struct in6_addr *saddr, __be16 sport, struct in6_addr *daddr, __be16 dport, - int dif, struct hlist_head udptable[]) + int dif, struct udp_table *udptable) { - struct sock *sk, *result = NULL; - struct hlist_node *node; + struct sock *sk, *result; + struct hlist_nulls_node *node; unsigned short hnum = ntohs(dport); - int badness = -1; - - read_lock(&udp_hash_lock); - sk_for_each(sk, node, &udptable[udp_hashfn(net, hnum)]) { - struct inet_sock *inet = inet_sk(sk); - - if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && - sk->sk_family == PF_INET6) { - struct ipv6_pinfo *np = inet6_sk(sk); - int score = 0; - if (inet->dport) { - if (inet->dport != sport) - continue; - score++; - } - if (!ipv6_addr_any(&np->rcv_saddr)) { - if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) - continue; - score++; - } - if (!ipv6_addr_any(&np->daddr)) { - if (!ipv6_addr_equal(&np->daddr, saddr)) - continue; - score++; - } - if (sk->sk_bound_dev_if) { - if (sk->sk_bound_dev_if != dif) - continue; - score++; - } - if (score == 4) { - result = sk; - break; - } else if (score > badness) { - result = sk; - badness = score; - } + unsigned int hash = udp_hashfn(net, hnum); + struct udp_hslot *hslot = &udptable->hash[hash]; + int score, badness; + + rcu_read_lock(); +begin: + result = NULL; + badness = -1; + sk_nulls_for_each_rcu(sk, node, &hslot->head) { + score = compute_score(sk, net, hnum, saddr, sport, daddr, dport, dif); + if (score > badness) { + result = sk; + badness = score; } } - if (result) - sock_hold(result); - read_unlock(&udp_hash_lock); + /* + * if the nulls value we got at the end of this lookup is + * not the expected one, we must restart lookup. + * We probably met an item that was moved to another chain. + */ + if (get_nulls_value(node) != hash) + goto begin; + + if (result) { + if (unlikely(!atomic_inc_not_zero(&result->sk_refcnt))) + result = NULL; + else if (unlikely(compute_score(result, net, hnum, saddr, sport, + daddr, dport, dif) < badness)) { + sock_put(result); + goto begin; + } + } + rcu_read_unlock(); return result; } static struct sock *__udp6_lib_lookup_skb(struct sk_buff *skb, __be16 sport, __be16 dport, - struct hlist_head udptable[]) + struct udp_table *udptable) { struct sock *sk; struct ipv6hdr *iph = ipv6_hdr(skb); @@ -253,7 +282,7 @@ csum_copy_err: void __udp6_lib_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __be32 info, - struct hlist_head udptable[] ) + struct udp_table *udptable) { struct ipv6_pinfo *np; struct ipv6hdr *hdr = (struct ipv6hdr*)skb->data; @@ -289,7 +318,7 @@ static __inline__ void udpv6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __be32 info ) { - __udp6_lib_err(skb, opt, type, code, offset, info, udp_hash); + __udp6_lib_err(skb, opt, type, code, offset, info, &udp_table); } int udpv6_queue_rcv_skb(struct sock * sk, struct sk_buff *skb) @@ -347,11 +376,11 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, __be16 rmt_port, struct in6_addr *rmt_addr, int dif) { - struct hlist_node *node; + struct hlist_nulls_node *node; struct sock *s = sk; unsigned short num = ntohs(loc_port); - sk_for_each_from(s, node) { + sk_nulls_for_each_from(s, node) { struct inet_sock *inet = inet_sk(s); if (!net_eq(sock_net(s), net)) @@ -388,14 +417,15 @@ static struct sock *udp_v6_mcast_next(struct net *net, struct sock *sk, */ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, struct in6_addr *saddr, struct in6_addr *daddr, - struct hlist_head udptable[]) + struct udp_table *udptable) { struct sock *sk, *sk2; const struct udphdr *uh = udp_hdr(skb); + struct udp_hslot *hslot = &udptable->hash[udp_hashfn(net, ntohs(uh->dest))]; int dif; - read_lock(&udp_hash_lock); - sk = sk_head(&udptable[udp_hashfn(net, ntohs(uh->dest))]); + spin_lock(&hslot->lock); + sk = sk_nulls_head(&hslot->head); dif = inet6_iif(skb); sk = udp_v6_mcast_next(net, sk, uh->dest, daddr, uh->source, saddr, dif); if (!sk) { @@ -404,7 +434,7 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, } sk2 = sk; - while ((sk2 = udp_v6_mcast_next(net, sk_next(sk2), uh->dest, daddr, + while ((sk2 = udp_v6_mcast_next(net, sk_nulls_next(sk2), uh->dest, daddr, uh->source, saddr, dif))) { struct sk_buff *buff = skb_clone(skb, GFP_ATOMIC); if (buff) { @@ -423,7 +453,7 @@ static int __udp6_lib_mcast_deliver(struct net *net, struct sk_buff *skb, sk_add_backlog(sk, skb); bh_unlock_sock(sk); out: - read_unlock(&udp_hash_lock); + spin_unlock(&hslot->lock); return 0; } @@ -461,7 +491,7 @@ static inline int udp6_csum_init(struct sk_buff *skb, struct udphdr *uh, return 0; } -int __udp6_lib_rcv(struct sk_buff *skb, struct hlist_head udptable[], +int __udp6_lib_rcv(struct sk_buff *skb, struct udp_table *udptable, int proto) { struct sock *sk; @@ -558,7 +588,7 @@ discard: static __inline__ int udpv6_rcv(struct sk_buff *skb) { - return __udp6_lib_rcv(skb, udp_hash, IPPROTO_UDP); + return __udp6_lib_rcv(skb, &udp_table, IPPROTO_UDP); } /* @@ -763,6 +793,9 @@ do_udp_sendmsg: if (!fl.oif) fl.oif = sk->sk_bound_dev_if; + if (!fl.oif) + fl.oif = np->sticky_pktinfo.ipi6_ifindex; + if (msg->msg_controllen) { opt = &opt_space; memset(opt, 0, sizeof(struct ipv6_txoptions)); @@ -819,7 +852,8 @@ do_udp_sendmsg: if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = __xfrm_lookup(&dst, &fl, sk, XFRM_LOOKUP_WAIT)) < 0) { + err = __xfrm_lookup(sock_net(sk), &dst, &fl, sk, XFRM_LOOKUP_WAIT); + if (err < 0) { if (err == -EREMOTE) err = ip6_dst_blackhole(sk, &dst, &fl); if (err < 0) @@ -1022,7 +1056,7 @@ int udp6_seq_show(struct seq_file *seq, void *v) static struct udp_seq_afinfo udp6_seq_afinfo = { .name = "udp6", .family = AF_INET6, - .hashtable = udp_hash, + .udp_table = &udp_table, .seq_fops = { .owner = THIS_MODULE, }, @@ -1064,7 +1098,8 @@ struct proto udpv6_prot = { .sysctl_wmem = &sysctl_udp_wmem_min, .sysctl_rmem = &sysctl_udp_rmem_min, .obj_size = sizeof(struct udp6_sock), - .h.udp_hash = udp_hash, + .slab_flags = SLAB_DESTROY_BY_RCU, + .h.udp_table = &udp_table, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_udpv6_setsockopt, .compat_getsockopt = compat_udpv6_getsockopt, diff --git a/net/ipv6/udp_impl.h b/net/ipv6/udp_impl.h index 92dd7da766d8c9855a71afd863a39f90418fde46..23779208c334e90aa1bad9100a1d8c84f6b452df 100644 --- a/net/ipv6/udp_impl.h +++ b/net/ipv6/udp_impl.h @@ -7,9 +7,9 @@ #include #include -extern int __udp6_lib_rcv(struct sk_buff *, struct hlist_head [], int ); +extern int __udp6_lib_rcv(struct sk_buff *, struct udp_table *, int ); extern void __udp6_lib_err(struct sk_buff *, struct inet6_skb_parm *, - int , int , int , __be32 , struct hlist_head []); + int , int , int , __be32 , struct udp_table *); extern int udp_v6_get_port(struct sock *sk, unsigned short snum); diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 3cd1a1ac3d6c7c8dfb686f9b7992a5be9e3095de..ba162a824585b8fcecd2c1022c0c64d09faa68bc 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -15,14 +15,14 @@ static int udplitev6_rcv(struct sk_buff *skb) { - return __udp6_lib_rcv(skb, udplite_hash, IPPROTO_UDPLITE); + return __udp6_lib_rcv(skb, &udplite_table, IPPROTO_UDPLITE); } static void udplitev6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __be32 info) { - __udp6_lib_err(skb, opt, type, code, offset, info, udplite_hash); + __udp6_lib_err(skb, opt, type, code, offset, info, &udplite_table); } static struct inet6_protocol udplitev6_protocol = { @@ -49,7 +49,8 @@ struct proto udplitev6_prot = { .unhash = udp_lib_unhash, .get_port = udp_v6_get_port, .obj_size = sizeof(struct udp6_sock), - .h.udp_hash = udplite_hash, + .slab_flags = SLAB_DESTROY_BY_RCU, + .h.udp_table = &udplite_table, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_udpv6_setsockopt, .compat_getsockopt = compat_udpv6_getsockopt, @@ -95,7 +96,7 @@ void udplitev6_exit(void) static struct udp_seq_afinfo udplite6_seq_afinfo = { .name = "udplite6", .family = AF_INET6, - .hashtable = udplite_hash, + .udp_table = &udplite_table, .seq_fops = { .owner = THIS_MODULE, }, diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index a71c7ddcb41e0a7119a874c1c83e860453f2a4b5..9084582d236bc97f7da39e6f1090f954cb63e94f 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -58,6 +58,7 @@ EXPORT_SYMBOL(xfrm6_rcv); int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto) { + struct net *net = dev_net(skb->dev); struct xfrm_state *x = NULL; int i = 0; @@ -67,7 +68,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, sp = secpath_dup(skb->sp); if (!sp) { - XFRM_INC_STATS(LINUX_MIB_XFRMINERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); goto drop; } if (skb->sp) @@ -76,7 +77,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, } if (1 + skb->sp->len == XFRM_MAX_DEPTH) { - XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); goto drop; } @@ -100,7 +101,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, break; } - x = xfrm_state_lookup_byaddr(dst, src, proto, AF_INET6); + x = xfrm_state_lookup_byaddr(net, dst, src, proto, AF_INET6); if (!x) continue; @@ -122,7 +123,7 @@ int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, } if (!x) { - XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); xfrm_audit_state_notfound_simple(skb, AF_INET6); goto drop; } diff --git a/net/ipv6/xfrm6_policy.c b/net/ipv6/xfrm6_policy.c index 08e4cbbe3f04e5f64e6d91f8b7864c8108d5e0ef..97ab068e8ccc10be9d1ee27ec3b4a081322bb307 100644 --- a/net/ipv6/xfrm6_policy.c +++ b/net/ipv6/xfrm6_policy.c @@ -27,7 +27,8 @@ static struct dst_ops xfrm6_dst_ops; static struct xfrm_policy_afinfo xfrm6_policy_afinfo; -static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr, +static struct dst_entry *xfrm6_dst_lookup(struct net *net, int tos, + xfrm_address_t *saddr, xfrm_address_t *daddr) { struct flowi fl = {}; @@ -38,7 +39,7 @@ static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr, if (saddr) memcpy(&fl.fl6_src, saddr, sizeof(fl.fl6_src)); - dst = ip6_route_output(&init_net, NULL, &fl); + dst = ip6_route_output(net, NULL, &fl); err = dst->error; if (dst->error) { @@ -49,12 +50,13 @@ static struct dst_entry *xfrm6_dst_lookup(int tos, xfrm_address_t *saddr, return dst; } -static int xfrm6_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) +static int xfrm6_get_saddr(struct net *net, + xfrm_address_t *saddr, xfrm_address_t *daddr) { struct dst_entry *dst; struct net_device *dev; - dst = xfrm6_dst_lookup(0, NULL, daddr); + dst = xfrm6_dst_lookup(net, 0, NULL, daddr); if (IS_ERR(dst)) return -EHOSTUNREACH; @@ -144,6 +146,7 @@ static int xfrm6_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) static inline void _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) { + int onlyproto = 0; u16 offset = skb_network_header_len(skb); struct ipv6hdr *hdr = ipv6_hdr(skb); struct ipv6_opt_hdr *exthdr; @@ -159,6 +162,8 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) exthdr = (struct ipv6_opt_hdr *)(nh + offset); switch (nexthdr) { + case NEXTHDR_FRAGMENT: + onlyproto = 1; case NEXTHDR_ROUTING: case NEXTHDR_HOP: case NEXTHDR_DEST: @@ -172,7 +177,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) case IPPROTO_TCP: case IPPROTO_SCTP: case IPPROTO_DCCP: - if (pskb_may_pull(skb, nh + offset + 4 - skb->data)) { + if (!onlyproto && pskb_may_pull(skb, nh + offset + 4 - skb->data)) { __be16 *ports = (__be16 *)exthdr; fl->fl_ip_sport = ports[!!reverse]; @@ -182,7 +187,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) return; case IPPROTO_ICMPV6: - if (pskb_may_pull(skb, nh + offset + 2 - skb->data)) { + if (!onlyproto && pskb_may_pull(skb, nh + offset + 2 - skb->data)) { u8 *icmp = (u8 *)exthdr; fl->fl_icmp_type = icmp[0]; @@ -193,7 +198,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) #if defined(CONFIG_IPV6_MIP6) || defined(CONFIG_IPV6_MIP6_MODULE) case IPPROTO_MH: - if (pskb_may_pull(skb, nh + offset + 3 - skb->data)) { + if (!onlyproto && pskb_may_pull(skb, nh + offset + 3 - skb->data)) { struct ip6_mh *mh; mh = (struct ip6_mh *)exthdr; @@ -217,7 +222,7 @@ _decode_session6(struct sk_buff *skb, struct flowi *fl, int reverse) static inline int xfrm6_garbage_collect(struct dst_ops *ops) { - xfrm6_policy_afinfo.garbage_collect(); + xfrm6_policy_afinfo.garbage_collect(&init_net); return (atomic_read(&xfrm6_dst_ops.entries) > xfrm6_dst_ops.gc_thresh*2); } @@ -274,7 +279,6 @@ static struct dst_ops xfrm6_dst_ops = { .ifdown = xfrm6_dst_ifdown, .local_out = __ip6_local_out, .gc_thresh = 1024, - .entry_size = sizeof(struct xfrm_dst), .entries = ATOMIC_INIT(0), }; diff --git a/net/ipv6/xfrm6_state.c b/net/ipv6/xfrm6_state.c index 60c78cfc273797247312c6846727fc7b10b9db21..0e685b05496ee6456e5b2d7ab2d5feddd2b52e07 100644 --- a/net/ipv6/xfrm6_state.c +++ b/net/ipv6/xfrm6_state.c @@ -19,8 +19,6 @@ #include #include -static struct xfrm_state_afinfo xfrm6_state_afinfo; - static void __xfrm6_init_tempsel(struct xfrm_state *x, struct flowi *fl, struct xfrm_tmpl *tmpl, diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index c2b278138604c15507cf074a185df295c1b9d2e8..80193db224d9070e2ca57982122fdf8384ba5d9f 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -345,24 +345,23 @@ static struct xfrm6_tunnel xfrm46_tunnel_handler = { static int __init xfrm6_tunnel_init(void) { if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) - return -EAGAIN; - - if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) { - xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); - return -EAGAIN; - } - if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) { - xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); - xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); - return -EAGAIN; - } - if (xfrm6_tunnel_spi_init() < 0) { - xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); - xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); - xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); - return -EAGAIN; - } + goto err; + if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) + goto unreg; + if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) + goto dereg6; + if (xfrm6_tunnel_spi_init() < 0) + goto dereg46; return 0; + +dereg46: + xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); +dereg6: + xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); +unreg: + xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); +err: + return -EAGAIN; } static void __exit xfrm6_tunnel_fini(void) diff --git a/net/ipx/sysctl_net_ipx.c b/net/ipx/sysctl_net_ipx.c index 92fef864e85225a142fc778c8da4afc9e94cb5b9..633fcab355800d782cd6805df9931efbc95bf5c8 100644 --- a/net/ipx/sysctl_net_ipx.c +++ b/net/ipx/sysctl_net_ipx.c @@ -23,7 +23,7 @@ static struct ctl_table ipx_table[] = { .data = &sysctl_ipx_pprop_broadcasting, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { 0 }, }; diff --git a/net/irda/irlan/irlan_client.c b/net/irda/irlan/irlan_client.c index 6be1ec26b30cc81cca52309d241dd515105b4cf2..42f7d960d055ca7d8ab0784ddde43ad183943dd2 100644 --- a/net/irda/irlan/irlan_client.c +++ b/net/irda/irlan/irlan_client.c @@ -436,7 +436,6 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param, __u16 tmp_cpu; /* Temporary value in host order */ __u8 *bytes; int i; - DECLARE_MAC_BUF(mac); IRDA_DEBUG(4, "%s(), parm=%s\n", __func__ , param); @@ -521,8 +520,7 @@ static void irlan_check_response_param(struct irlan_cb *self, char *param, /* FILTER_ENTRY, have we got an ethernet address? */ if (strcmp(param, "FILTER_ENTRY") == 0) { bytes = value; - IRDA_DEBUG(4, "Ethernet address = %s\n", - print_mac(mac, bytes)); + IRDA_DEBUG(4, "Ethernet address = %pM\n", bytes); for (i = 0; i < 6; i++) self->dev->dev_addr[i] = bytes[i]; } diff --git a/net/irda/irlan/irlan_common.c b/net/irda/irlan/irlan_common.c index 9a1cd87e71426aaa1c8f4d22318c090a39976683..774d73a76852e1ce63262f8d2a1af343668473d5 100644 --- a/net/irda/irlan/irlan_common.c +++ b/net/irda/irlan/irlan_common.c @@ -207,7 +207,7 @@ static struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr) if (!dev) return NULL; - self = dev->priv; + self = netdev_priv(dev); self->dev = dev; /* diff --git a/net/irda/irlap_frame.c b/net/irda/irlap_frame.c index f17b65af9c9b4b28a90aa722feba24b1c2d9a688..2562ebc1b22c0f2d109b26aca2d43ee576477622 100644 --- a/net/irda/irlap_frame.c +++ b/net/irda/irlap_frame.c @@ -1325,6 +1325,7 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, struct irlap_cb *self; int command; __u8 control; + int ret = -1; if (!net_eq(dev_net(dev), &init_net)) goto out; @@ -1333,25 +1334,21 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, self = (struct irlap_cb *) dev->atalk_ptr; /* If the net device is down, then IrLAP is gone! */ - if (!self || self->magic != LAP_MAGIC) { - dev_kfree_skb(skb); - return -1; - } + if (!self || self->magic != LAP_MAGIC) + goto err; /* We are no longer an "old" protocol, so we need to handle * 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", __func__); - dev_kfree_skb(skb); - return -1; + goto err; } /* Check if frame is large enough for parsing */ if (!pskb_may_pull(skb, 2)) { IRDA_ERROR("%s: frame too short!\n", __func__); - dev_kfree_skb(skb); - return -1; + goto err; } command = skb->data[0] & CMD_FRAME; @@ -1442,7 +1439,9 @@ int irlap_driver_rcv(struct sk_buff *skb, struct net_device *dev, break; } out: + ret = 0; +err: /* Always drop our reference on the skb */ dev_kfree_skb(skb); - return 0; + return ret; } diff --git a/net/irda/irsysctl.c b/net/irda/irsysctl.c index 9ab3df15425db06014e0a2bb3e337cd687a8e729..57f8817c3979029a38a680d1ea65d948766d2ef9 100644 --- a/net/irda/irsysctl.c +++ b/net/irda/irsysctl.c @@ -118,8 +118,8 @@ static ctl_table irda_table[] = { .data = &sysctl_discovery, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &do_discovery, - .strategy = &sysctl_intvec + .proc_handler = do_discovery, + .strategy = sysctl_intvec }, { .ctl_name = NET_IRDA_DEVNAME, @@ -127,8 +127,8 @@ static ctl_table irda_table[] = { .data = sysctl_devname, .maxlen = 65, .mode = 0644, - .proc_handler = &do_devname, - .strategy = &sysctl_string + .proc_handler = do_devname, + .strategy = sysctl_string }, #ifdef CONFIG_IRDA_DEBUG { @@ -137,7 +137,7 @@ static ctl_table irda_table[] = { .data = &irda_debug, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, #endif #ifdef CONFIG_IRDA_FAST_RR @@ -147,7 +147,7 @@ static ctl_table irda_table[] = { .data = &sysctl_fast_poll_increase, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, #endif { @@ -156,8 +156,8 @@ static ctl_table irda_table[] = { .data = &sysctl_discovery_slots, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_discovery_slots, .extra2 = &max_discovery_slots }, @@ -167,7 +167,7 @@ static ctl_table irda_table[] = { .data = &sysctl_discovery_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = NET_IRDA_SLOT_TIMEOUT, @@ -175,8 +175,8 @@ static ctl_table irda_table[] = { .data = &sysctl_slot_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_slot_timeout, .extra2 = &max_slot_timeout }, @@ -186,8 +186,8 @@ static ctl_table irda_table[] = { .data = &sysctl_max_baud_rate, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_max_baud_rate, .extra2 = &max_max_baud_rate }, @@ -197,8 +197,8 @@ static ctl_table irda_table[] = { .data = &sysctl_min_tx_turn_time, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_min_tx_turn_time, .extra2 = &max_min_tx_turn_time }, @@ -208,8 +208,8 @@ static ctl_table irda_table[] = { .data = &sysctl_max_tx_data_size, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_max_tx_data_size, .extra2 = &max_max_tx_data_size }, @@ -219,8 +219,8 @@ static ctl_table irda_table[] = { .data = &sysctl_max_tx_window, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_max_tx_window, .extra2 = &max_max_tx_window }, @@ -230,8 +230,8 @@ static ctl_table irda_table[] = { .data = &sysctl_max_noreply_time, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_max_noreply_time, .extra2 = &max_max_noreply_time }, @@ -241,8 +241,8 @@ static ctl_table irda_table[] = { .data = &sysctl_warn_noreply_time, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_warn_noreply_time, .extra2 = &max_warn_noreply_time }, @@ -252,8 +252,8 @@ static ctl_table irda_table[] = { .data = &sysctl_lap_keepalive_time, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_lap_keepalive_time, .extra2 = &max_lap_keepalive_time }, diff --git a/net/irda/irttp.c b/net/irda/irttp.c index 74e439e808238e8f1af8b2223ea427623a8e1060..ecf4eb2717cb0c4d75b77aa006c8d15235c7d867 100644 --- a/net/irda/irttp.c +++ b/net/irda/irttp.c @@ -201,7 +201,7 @@ static void irttp_todo_expired(unsigned long data) * * Flushes (removes all frames) in transitt-buffer (tx_list) */ -void irttp_flush_queues(struct tsap_cb *self) +static void irttp_flush_queues(struct tsap_cb *self) { struct sk_buff* skb; @@ -1266,9 +1266,9 @@ static void irttp_connect_confirm(void *instance, void *sap, * Some other device is connecting to this TSAP * */ -void irttp_connect_indication(void *instance, void *sap, struct qos_info *qos, - __u32 max_seg_size, __u8 max_header_size, - struct sk_buff *skb) +static void irttp_connect_indication(void *instance, void *sap, + struct qos_info *qos, __u32 max_seg_size, __u8 max_header_size, + struct sk_buff *skb) { struct tsap_cb *self; struct lsap_cb *lsap; @@ -1579,8 +1579,8 @@ EXPORT_SYMBOL(irttp_disconnect_request); * Disconnect indication, TSAP disconnected by peer? * */ -void irttp_disconnect_indication(void *instance, void *sap, LM_REASON reason, - struct sk_buff *skb) +static void irttp_disconnect_indication(void *instance, void *sap, + LM_REASON reason, struct sk_buff *skb) { struct tsap_cb *self; @@ -1664,7 +1664,7 @@ static void irttp_do_data_indication(struct tsap_cb *self, struct sk_buff *skb) * Check if we have any frames to be transmitted, or if we have any * available credit to give away. */ -void irttp_run_rx_queue(struct tsap_cb *self) +static void irttp_run_rx_queue(struct tsap_cb *self) { struct sk_buff *skb; int more = 0; diff --git a/net/irda/timer.c b/net/irda/timer.c index d730099080a28acabb81957840c11e5be7e10445..0335ba0cc5939d19d317563a3ffad6bcca1e0b2d 100644 --- a/net/irda/timer.c +++ b/net/irda/timer.c @@ -219,7 +219,7 @@ static void irlap_backoff_timer_expired(void *data) * * */ -void irlap_media_busy_expired(void* data) +static void irlap_media_busy_expired(void *data) { struct irlap_cb *self = (struct irlap_cb *) data; diff --git a/net/key/af_key.c b/net/key/af_key.c index 5b22e011653b3d54620090028762435559f2a696..f8bd8df5e2575a713f487a2573ba65b7cd5863b8 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -34,15 +35,16 @@ #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x)) #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x)) - -/* List of all pfkey sockets. */ -static HLIST_HEAD(pfkey_table); +static int pfkey_net_id; +struct netns_pfkey { + /* List of all pfkey sockets. */ + struct hlist_head table; + atomic_t socks_nr; +}; static DECLARE_WAIT_QUEUE_HEAD(pfkey_table_wait); static DEFINE_RWLOCK(pfkey_table_lock); static atomic_t pfkey_table_users = ATOMIC_INIT(0); -static atomic_t pfkey_socks_nr = ATOMIC_INIT(0); - struct pfkey_sock { /* struct sock must be the first member of struct pfkey_sock */ struct sock sk; @@ -89,6 +91,9 @@ static void pfkey_terminate_dump(struct pfkey_sock *pfk) static void pfkey_sock_destruct(struct sock *sk) { + struct net *net = sock_net(sk); + struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); + pfkey_terminate_dump(pfkey_sk(sk)); skb_queue_purge(&sk->sk_receive_queue); @@ -100,7 +105,7 @@ static void pfkey_sock_destruct(struct sock *sk) WARN_ON(atomic_read(&sk->sk_rmem_alloc)); WARN_ON(atomic_read(&sk->sk_wmem_alloc)); - atomic_dec(&pfkey_socks_nr); + atomic_dec(&net_pfkey->socks_nr); } static void pfkey_table_grab(void) @@ -151,8 +156,11 @@ static const struct proto_ops pfkey_ops; static void pfkey_insert(struct sock *sk) { + struct net *net = sock_net(sk); + struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); + pfkey_table_grab(); - sk_add_node(sk, &pfkey_table); + sk_add_node(sk, &net_pfkey->table); pfkey_table_ungrab(); } @@ -171,12 +179,10 @@ static struct proto key_proto = { static int pfkey_create(struct net *net, struct socket *sock, int protocol) { + struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); struct sock *sk; int err; - if (net != &init_net) - return -EAFNOSUPPORT; - if (!capable(CAP_NET_ADMIN)) return -EPERM; if (sock->type != SOCK_RAW) @@ -195,7 +201,7 @@ static int pfkey_create(struct net *net, struct socket *sock, int protocol) sk->sk_family = PF_KEY; sk->sk_destruct = pfkey_sock_destruct; - atomic_inc(&pfkey_socks_nr); + atomic_inc(&net_pfkey->socks_nr); pfkey_insert(sk); @@ -255,8 +261,10 @@ static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, #define BROADCAST_REGISTERED 2 #define BROADCAST_PROMISC_ONLY 4 static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, - int broadcast_flags, struct sock *one_sk) + int broadcast_flags, struct sock *one_sk, + struct net *net) { + struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); struct sock *sk; struct hlist_node *node; struct sk_buff *skb2 = NULL; @@ -269,7 +277,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, return -ENOMEM; pfkey_lock_table(); - sk_for_each(sk, node, &pfkey_table) { + sk_for_each(sk, node, &net_pfkey->table) { struct pfkey_sock *pfk = pfkey_sk(sk); int err2; @@ -328,7 +336,7 @@ static int pfkey_do_dump(struct pfkey_sock *pfk) hdr->sadb_msg_seq = 0; hdr->sadb_msg_errno = rc; pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, - &pfk->sk); + &pfk->sk, sock_net(&pfk->sk)); pfk->dump.skb = NULL; } @@ -367,7 +375,7 @@ static int pfkey_error(struct sadb_msg *orig, int err, struct sock *sk) hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); - pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk); + pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk, sock_net(sk)); return 0; } @@ -645,7 +653,7 @@ int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr, xfrm_address_t *xaddr) xaddr); } -static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **ext_hdrs) +static struct xfrm_state *pfkey_xfrm_state_lookup(struct net *net, struct sadb_msg *hdr, void **ext_hdrs) { struct sadb_sa *sa; struct sadb_address *addr; @@ -683,7 +691,7 @@ static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void ** if (!xaddr) return NULL; - return xfrm_state_lookup(xaddr, sa->sadb_sa_spi, proto, family); + return xfrm_state_lookup(net, xaddr, sa->sadb_sa_spi, proto, family); } #define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1))) @@ -1058,7 +1066,8 @@ static inline struct sk_buff *pfkey_xfrm_state2msg_expire(struct xfrm_state *x, return __pfkey_xfrm_state2msg(x, 0, hsc); } -static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, +static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, + struct sadb_msg *hdr, void **ext_hdrs) { struct xfrm_state *x; @@ -1122,7 +1131,7 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) return ERR_PTR(-EINVAL); - x = xfrm_state_alloc(); + x = xfrm_state_alloc(net); if (x == NULL) return ERR_PTR(-ENOBUFS); @@ -1298,6 +1307,7 @@ static int pfkey_reserved(struct sock *sk, struct sk_buff *skb, struct sadb_msg static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { + struct net *net = sock_net(sk); struct sk_buff *resp_skb; struct sadb_x_sa2 *sa2; struct sadb_address *saddr, *daddr; @@ -1348,7 +1358,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h } if (hdr->sadb_msg_seq) { - x = xfrm_find_acq_byseq(hdr->sadb_msg_seq); + x = xfrm_find_acq_byseq(net, hdr->sadb_msg_seq); if (x && xfrm_addr_cmp(&x->id.daddr, xdaddr, family)) { xfrm_state_put(x); x = NULL; @@ -1356,7 +1366,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h } if (!x) - x = xfrm_find_acq(mode, reqid, proto, xdaddr, xsaddr, 1, family); + x = xfrm_find_acq(net, mode, reqid, proto, xdaddr, xsaddr, 1, family); if (x == NULL) return -ENOENT; @@ -1389,13 +1399,14 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h xfrm_state_put(x); - pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk); + pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk, net); return 0; } static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { + struct net *net = sock_net(sk); struct xfrm_state *x; if (hdr->sadb_msg_len != sizeof(struct sadb_msg)/8) @@ -1404,14 +1415,14 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg * if (hdr->sadb_msg_seq == 0 || hdr->sadb_msg_errno == 0) return 0; - x = xfrm_find_acq_byseq(hdr->sadb_msg_seq); + x = xfrm_find_acq_byseq(net, hdr->sadb_msg_seq); if (x == NULL) return 0; spin_lock_bh(&x->lock); if (x->km.state == XFRM_STATE_ACQ) { x->km.state = XFRM_STATE_ERROR; - wake_up(&km_waitq); + wake_up(&net->xfrm.km_waitq); } spin_unlock_bh(&x->lock); xfrm_state_put(x); @@ -1476,18 +1487,19 @@ static int key_notify_sa(struct xfrm_state *x, struct km_event *c) hdr->sadb_msg_seq = c->seq; hdr->sadb_msg_pid = c->pid; - pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); + pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xs_net(x)); return 0; } static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { + struct net *net = sock_net(sk); struct xfrm_state *x; int err; struct km_event c; - x = pfkey_msg2xfrm_state(hdr, ext_hdrs); + x = pfkey_msg2xfrm_state(net, hdr, ext_hdrs); if (IS_ERR(x)) return PTR_ERR(x); @@ -1521,6 +1533,7 @@ out: static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { + struct net *net = sock_net(sk); struct xfrm_state *x; struct km_event c; int err; @@ -1530,7 +1543,7 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h ext_hdrs[SADB_EXT_ADDRESS_DST-1])) return -EINVAL; - x = pfkey_xfrm_state_lookup(hdr, ext_hdrs); + x = pfkey_xfrm_state_lookup(net, hdr, ext_hdrs); if (x == NULL) return -ESRCH; @@ -1562,6 +1575,7 @@ out: static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { + struct net *net = sock_net(sk); __u8 proto; struct sk_buff *out_skb; struct sadb_msg *out_hdr; @@ -1572,7 +1586,7 @@ static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, ext_hdrs[SADB_EXT_ADDRESS_DST-1])) return -EINVAL; - x = pfkey_xfrm_state_lookup(hdr, ext_hdrs); + x = pfkey_xfrm_state_lookup(net, hdr, ext_hdrs); if (x == NULL) return -ESRCH; @@ -1590,7 +1604,7 @@ static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, out_hdr->sadb_msg_reserved = 0; out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; - pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk); + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk)); return 0; } @@ -1691,7 +1705,7 @@ static int pfkey_register(struct sock *sk, struct sk_buff *skb, struct sadb_msg return -ENOBUFS; } - pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk); + pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk, sock_net(sk)); return 0; } @@ -1713,13 +1727,14 @@ static int key_notify_sa_flush(struct km_event *c) hdr->sadb_msg_errno = (uint8_t) 0; hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); - pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); + pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); return 0; } static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { + struct net *net = sock_net(sk); unsigned proto; struct km_event c; struct xfrm_audit audit_info; @@ -1732,13 +1747,14 @@ static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hd audit_info.loginuid = audit_get_loginuid(current); audit_info.sessionid = audit_get_sessionid(current); audit_info.secid = 0; - err = xfrm_state_flush(proto, &audit_info); + err = xfrm_state_flush(net, proto, &audit_info); if (err) return err; c.data.proto = proto; c.seq = hdr->sadb_msg_seq; c.pid = hdr->sadb_msg_pid; c.event = XFRM_MSG_FLUSHSA; + c.net = net; km_state_notify(NULL, &c); return 0; @@ -1768,7 +1784,7 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr) if (pfk->dump.skb) pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, - &pfk->sk); + &pfk->sk, sock_net(&pfk->sk)); pfk->dump.skb = out_skb; return 0; @@ -1776,7 +1792,8 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr) static int pfkey_dump_sa(struct pfkey_sock *pfk) { - return xfrm_state_walk(&pfk->dump.u.state, dump_sa, (void *) pfk); + struct net *net = sock_net(&pfk->sk); + return xfrm_state_walk(net, &pfk->dump.u.state, dump_sa, (void *) pfk); } static void pfkey_dump_sa_done(struct pfkey_sock *pfk) @@ -1817,7 +1834,7 @@ static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg * return -EINVAL; pfk->promisc = satype; } - pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, BROADCAST_ALL, NULL); + pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, BROADCAST_ALL, NULL, sock_net(sk)); return 0; } @@ -1833,7 +1850,7 @@ static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr) return 0; } -static u32 gen_reqid(void) +static u32 gen_reqid(struct net *net) { struct xfrm_policy_walk walk; u32 start; @@ -1846,7 +1863,7 @@ static u32 gen_reqid(void) if (reqid == 0) reqid = IPSEC_MANUAL_REQID_MAX+1; xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); - rc = xfrm_policy_walk(&walk, check_reqid, (void*)&reqid); + rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid); xfrm_policy_walk_done(&walk); if (rc != -EEXIST) return reqid; @@ -1857,6 +1874,7 @@ static u32 gen_reqid(void) static int parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) { + struct net *net = xp_net(xp); struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr; int mode; @@ -1876,7 +1894,7 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) t->reqid = rq->sadb_x_ipsecrequest_reqid; if (t->reqid > IPSEC_MANUAL_REQID_MAX) t->reqid = 0; - if (!t->reqid && !(t->reqid = gen_reqid())) + if (!t->reqid && !(t->reqid = gen_reqid(net))) return -ENOBUFS; } @@ -2147,7 +2165,7 @@ static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c out_hdr->sadb_msg_errno = 0; out_hdr->sadb_msg_seq = c->seq; out_hdr->sadb_msg_pid = c->pid; - pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL); + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xp_net(xp)); out: return 0; @@ -2155,6 +2173,7 @@ out: static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { + struct net *net = sock_net(sk); int err = 0; struct sadb_lifetime *lifetime; struct sadb_address *sa; @@ -2174,7 +2193,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) return -EINVAL; - xp = xfrm_policy_alloc(GFP_KERNEL); + xp = xfrm_policy_alloc(net, GFP_KERNEL); if (xp == NULL) return -ENOBUFS; @@ -2275,6 +2294,7 @@ out: static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { + struct net *net = sock_net(sk); int err; struct sadb_address *sa; struct sadb_x_policy *pol; @@ -2324,7 +2344,7 @@ static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg return err; } - xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, + xp = xfrm_policy_bysel_ctx(net, XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir - 1, &sel, pol_ctx, 1, &err); security_xfrm_policy_free(pol_ctx); @@ -2372,7 +2392,7 @@ static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, struct sadb out_hdr->sadb_msg_errno = 0; out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; - pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk); + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, xp_net(xp)); err = 0; out: @@ -2557,6 +2577,7 @@ static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { + struct net *net = sock_net(sk); unsigned int dir; int err = 0, delete; struct sadb_x_policy *pol; @@ -2571,8 +2592,8 @@ static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h return -EINVAL; delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2); - xp = xfrm_policy_byid(XFRM_POLICY_TYPE_MAIN, dir, pol->sadb_x_policy_id, - delete, &err); + xp = xfrm_policy_byid(net, XFRM_POLICY_TYPE_MAIN, dir, + pol->sadb_x_policy_id, delete, &err); if (xp == NULL) return -ENOENT; @@ -2625,7 +2646,7 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) if (pfk->dump.skb) pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, - &pfk->sk); + &pfk->sk, sock_net(&pfk->sk)); pfk->dump.skb = out_skb; return 0; @@ -2633,7 +2654,8 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) static int pfkey_dump_sp(struct pfkey_sock *pfk) { - return xfrm_policy_walk(&pfk->dump.u.policy, dump_sp, (void *) pfk); + struct net *net = sock_net(&pfk->sk); + return xfrm_policy_walk(net, &pfk->dump.u.policy, dump_sp, (void *) pfk); } static void pfkey_dump_sp_done(struct pfkey_sock *pfk) @@ -2672,13 +2694,14 @@ static int key_notify_policy_flush(struct km_event *c) hdr->sadb_msg_version = PF_KEY_V2; hdr->sadb_msg_errno = (uint8_t) 0; hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); - pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL); + pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); return 0; } static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) { + struct net *net = sock_net(sk); struct km_event c; struct xfrm_audit audit_info; int err; @@ -2686,13 +2709,14 @@ static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg audit_info.loginuid = audit_get_loginuid(current); audit_info.sessionid = audit_get_sessionid(current); audit_info.secid = 0; - err = xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info); + err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); if (err) return err; c.data.type = XFRM_POLICY_TYPE_MAIN; c.event = XFRM_MSG_FLUSHPOLICY; c.pid = hdr->sadb_msg_pid; c.seq = hdr->sadb_msg_seq; + c.net = net; km_policy_notify(NULL, 0, &c); return 0; @@ -2732,7 +2756,7 @@ static int pfkey_process(struct sock *sk, struct sk_buff *skb, struct sadb_msg * int err; pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, - BROADCAST_PROMISC_ONLY, NULL); + BROADCAST_PROMISC_ONLY, NULL, sock_net(sk)); memset(ext_hdrs, 0, sizeof(ext_hdrs)); err = parse_exthdrs(skb, hdr, ext_hdrs); @@ -2935,13 +2959,16 @@ static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c) out_hdr->sadb_msg_seq = 0; out_hdr->sadb_msg_pid = 0; - pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); + pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x)); return 0; } static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c) { - if (atomic_read(&pfkey_socks_nr) == 0) + struct net *net = x ? xs_net(x) : c->net; + struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); + + if (atomic_read(&net_pfkey->socks_nr) == 0) return 0; switch (c->event) { @@ -3103,12 +3130,13 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_ctx->ctx_len); } - return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); + return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x)); } static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, u8 *data, int len, int *dir) { + struct net *net = sock_net(sk); struct xfrm_policy *xp; struct sadb_x_policy *pol = (struct sadb_x_policy*)data; struct sadb_x_sec_ctx *sec_ctx; @@ -3141,7 +3169,7 @@ static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOUND)) return NULL; - xp = xfrm_policy_alloc(GFP_ATOMIC); + xp = xfrm_policy_alloc(net, GFP_ATOMIC); if (xp == NULL) { *dir = -ENOBUFS; return NULL; @@ -3300,7 +3328,7 @@ static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, n_port->sadb_x_nat_t_port_port = sport; n_port->sadb_x_nat_t_port_reserved = 0; - return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); + return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x)); } #ifdef CONFIG_NET_KEY_MIGRATE @@ -3491,7 +3519,7 @@ static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, } /* broadcast migrate message to sockets */ - pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); + pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, &init_net); return 0; @@ -3645,6 +3673,8 @@ static int pfkey_seq_show(struct seq_file *f, void *v) static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos) { + struct net *net = seq_file_net(f); + struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); struct sock *s; struct hlist_node *node; loff_t pos = *ppos; @@ -3653,7 +3683,7 @@ static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos) if (pos == 0) return SEQ_START_TOKEN; - sk_for_each(s, node, &pfkey_table) + sk_for_each(s, node, &net_pfkey->table) if (pos-- == 1) return s; @@ -3662,9 +3692,12 @@ static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos) static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos) { + struct net *net = seq_file_net(f); + struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); + ++*ppos; return (v == SEQ_START_TOKEN) ? - sk_head(&pfkey_table) : + sk_head(&net_pfkey->table) : sk_next((struct sock *)v); } @@ -3682,38 +3715,39 @@ static struct seq_operations pfkey_seq_ops = { static int pfkey_seq_open(struct inode *inode, struct file *file) { - return seq_open(file, &pfkey_seq_ops); + return seq_open_net(inode, file, &pfkey_seq_ops, + sizeof(struct seq_net_private)); } static struct file_operations pfkey_proc_ops = { .open = pfkey_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = seq_release, + .release = seq_release_net, }; -static int pfkey_init_proc(void) +static int __net_init pfkey_init_proc(struct net *net) { struct proc_dir_entry *e; - e = proc_net_fops_create(&init_net, "pfkey", 0, &pfkey_proc_ops); + e = proc_net_fops_create(net, "pfkey", 0, &pfkey_proc_ops); if (e == NULL) return -ENOMEM; return 0; } -static void pfkey_exit_proc(void) +static void pfkey_exit_proc(struct net *net) { - proc_net_remove(&init_net, "pfkey"); + proc_net_remove(net, "pfkey"); } #else -static inline int pfkey_init_proc(void) +static int __net_init pfkey_init_proc(struct net *net) { return 0; } -static inline void pfkey_exit_proc(void) +static void pfkey_exit_proc(struct net *net) { } #endif @@ -3729,10 +3763,51 @@ static struct xfrm_mgr pfkeyv2_mgr = .migrate = pfkey_send_migrate, }; +static int __net_init pfkey_net_init(struct net *net) +{ + struct netns_pfkey *net_pfkey; + int rv; + + net_pfkey = kmalloc(sizeof(struct netns_pfkey), GFP_KERNEL); + if (!net_pfkey) { + rv = -ENOMEM; + goto out_kmalloc; + } + INIT_HLIST_HEAD(&net_pfkey->table); + atomic_set(&net_pfkey->socks_nr, 0); + rv = net_assign_generic(net, pfkey_net_id, net_pfkey); + if (rv < 0) + goto out_assign; + rv = pfkey_init_proc(net); + if (rv < 0) + goto out_proc; + return 0; + +out_proc: +out_assign: + kfree(net_pfkey); +out_kmalloc: + return rv; +} + +static void __net_exit pfkey_net_exit(struct net *net) +{ + struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); + + pfkey_exit_proc(net); + BUG_ON(!hlist_empty(&net_pfkey->table)); + kfree(net_pfkey); +} + +static struct pernet_operations pfkey_net_ops = { + .init = pfkey_net_init, + .exit = pfkey_net_exit, +}; + static void __exit ipsec_pfkey_exit(void) { + unregister_pernet_gen_subsys(pfkey_net_id, &pfkey_net_ops); xfrm_unregister_km(&pfkeyv2_mgr); - pfkey_exit_proc(); sock_unregister(PF_KEY); proto_unregister(&key_proto); } @@ -3747,16 +3822,16 @@ static int __init ipsec_pfkey_init(void) err = sock_register(&pfkey_family_ops); if (err != 0) goto out_unregister_key_proto; - err = pfkey_init_proc(); + err = xfrm_register_km(&pfkeyv2_mgr); if (err != 0) goto out_sock_unregister; - err = xfrm_register_km(&pfkeyv2_mgr); + err = register_pernet_gen_subsys(&pfkey_net_id, &pfkey_net_ops); if (err != 0) - goto out_remove_proc_entry; + goto out_xfrm_unregister_km; out: return err; -out_remove_proc_entry: - pfkey_exit_proc(); +out_xfrm_unregister_km: + xfrm_unregister_km(&pfkeyv2_mgr); out_sock_unregister: sock_unregister(PF_KEY); out_unregister_key_proto: diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c index 5bcc452a247fb54338dc1fac77563df7d6c49f4a..56fd85ab358e3b9c93bf2ff811acd4a9499491ea 100644 --- a/net/llc/af_llc.c +++ b/net/llc/af_llc.c @@ -103,7 +103,6 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr) * llc_ui_send_data - send data via reliable llc2 connection * @sk: Connection the socket is using. * @skb: Data the user wishes to send. - * @addr: Source and destination fields provided by the user. * @noblock: can we block waiting for data? * * Send data via reliable llc2 connection. diff --git a/net/llc/llc_proc.c b/net/llc/llc_proc.c index 48212c0a961ca2f5f73d77a239203c4a206562dc..b58bd7c6cdf8b5323df957c1bc113b8970aa9762 100644 --- a/net/llc/llc_proc.c +++ b/net/llc/llc_proc.c @@ -27,8 +27,7 @@ static void llc_ui_format_mac(struct seq_file *seq, u8 *addr) { - DECLARE_MAC_BUF(mac); - seq_printf(seq, "%s", print_mac(mac, addr)); + seq_printf(seq, "%pM", addr); } static struct sock *llc_get_sk_idx(loff_t pos) diff --git a/net/llc/sysctl_net_llc.c b/net/llc/sysctl_net_llc.c index 5bef1dcf18e3c1ec060dcdb4f4047376d2a0f417..57b9304d444c115d2e6ef00c17c1f25d41b0f50d 100644 --- a/net/llc/sysctl_net_llc.c +++ b/net/llc/sysctl_net_llc.c @@ -20,8 +20,8 @@ static struct ctl_table llc2_timeout_table[] = { .data = &sysctl_llc2_ack_timeout, .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_LLC2_BUSY_TIMEOUT, @@ -29,8 +29,8 @@ static struct ctl_table llc2_timeout_table[] = { .data = &sysctl_llc2_busy_timeout, .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_LLC2_P_TIMEOUT, @@ -38,8 +38,8 @@ static struct ctl_table llc2_timeout_table[] = { .data = &sysctl_llc2_p_timeout, .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { .ctl_name = NET_LLC2_REJ_TIMEOUT, @@ -47,8 +47,8 @@ static struct ctl_table llc2_timeout_table[] = { .data = &sysctl_llc2_rej_timeout, .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { 0 }, }; @@ -60,8 +60,8 @@ static struct ctl_table llc_station_table[] = { .data = &sysctl_llc_station_ack_timeout, .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, - .strategy = &sysctl_jiffies, + .proc_handler = proc_dointvec_jiffies, + .strategy = sysctl_jiffies, }, { 0 }, }; diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig index 7f710a27e91c9feac7681e0272de95bd3cf0bf55..60c16162474c23edbcfe4e338f9e00b4a6b6a0df 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -16,20 +16,20 @@ menu "Rate control algorithm selection" config MAC80211_RC_PID bool "PID controller based rate control algorithm" if EMBEDDED - default y ---help--- This option enables a TX rate control algorithm for mac80211 that uses a PID controller to select the TX rate. config MAC80211_RC_MINSTREL - bool "Minstrel" + bool "Minstrel" if EMBEDDED + default y ---help--- This option enables the 'minstrel' TX rate control algorithm choice prompt "Default rate control algorithm" - default MAC80211_RC_DEFAULT_PID + default MAC80211_RC_DEFAULT_MINSTREL ---help--- This option selects the default rate control algorithm mac80211 will use. Note that this default can still be @@ -55,8 +55,8 @@ endchoice config MAC80211_RC_DEFAULT string - default "pid" if MAC80211_RC_DEFAULT_PID default "minstrel" if MAC80211_RC_DEFAULT_MINSTREL + default "pid" if MAC80211_RC_DEFAULT_PID default "" endmenu diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile index 31cfd1f89a72457a4f3c241a8a5500aefbce21bb..7d4971aa443f177a692bd909a9dbef8c50e682d5 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -46,3 +46,5 @@ rc80211_minstrel-$(CONFIG_MAC80211_DEBUGFS) += rc80211_minstrel_debugfs.o mac80211-$(CONFIG_MAC80211_RC_PID) += $(rc80211_pid-y) mac80211-$(CONFIG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c index 855126a3039daa16ae64ca60c8087e0439a0d61f..9d4e4d846ec16ec978af0c95f1487e2e846f5841 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c @@ -17,13 +17,6 @@ #include "rate.h" #include "mesh.h" -struct ieee80211_hw *wiphy_to_hw(struct wiphy *wiphy) -{ - struct ieee80211_local *local = wiphy_priv(wiphy); - return &local->hw; -} -EXPORT_SYMBOL(wiphy_to_hw); - static bool nl80211_type_check(enum nl80211_iftype type) { switch (type) { @@ -33,6 +26,8 @@ static bool nl80211_type_check(enum nl80211_iftype type) #ifdef CONFIG_MAC80211_MESH case NL80211_IFTYPE_MESH_POINT: #endif + case NL80211_IFTYPE_AP: + case NL80211_IFTYPE_AP_VLAN: case NL80211_IFTYPE_WDS: return true; default: @@ -315,12 +310,35 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo) sinfo->filled = STATION_INFO_INACTIVE_TIME | STATION_INFO_RX_BYTES | - STATION_INFO_TX_BYTES; + STATION_INFO_TX_BYTES | + STATION_INFO_TX_BITRATE; sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx); sinfo->rx_bytes = sta->rx_bytes; sinfo->tx_bytes = sta->tx_bytes; + if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) { + sinfo->filled |= STATION_INFO_SIGNAL; + sinfo->signal = (s8)sta->last_signal; + } + + sinfo->txrate.flags = 0; + if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) + sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS; + if (sta->last_tx_rate.flags & IEEE80211_TX_RC_40_MHZ_WIDTH) + sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH; + if (sta->last_tx_rate.flags & IEEE80211_TX_RC_SHORT_GI) + sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI; + + if (!(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) { + struct ieee80211_supported_band *sband; + sband = sta->local->hw.wiphy->bands[ + sta->local->hw.conf.channel->band]; + sinfo->txrate.legacy = + sband->bitrates[sta->last_tx_rate.idx].bitrate; + } else + sinfo->txrate.mcs = sta->last_tx_rate.idx; + if (ieee80211_vif_is_mesh(&sdata->vif)) { #ifdef CONFIG_MAC80211_MESH sinfo->filled |= STATION_INFO_LLID | @@ -401,8 +419,10 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata, */ if (params->interval) { sdata->local->hw.conf.beacon_int = params->interval; - if (ieee80211_hw_config(sdata->local)) - return -EINVAL; + err = ieee80211_hw_config(sdata->local, + IEEE80211_CONF_CHANGE_BEACON_INTERVAL); + if (err < 0) + return err; /* * We updated some parameter so if below bails out * it's not an error. @@ -589,6 +609,8 @@ static void sta_apply_parameters(struct ieee80211_local *local, struct ieee80211_supported_band *sband; struct ieee80211_sub_if_data *sdata = sta->sdata; + sband = local->hw.wiphy->bands[local->oper_channel->band]; + /* * FIXME: updating the flags is racy when this function is * called from ieee80211_change_station(), this will @@ -629,7 +651,6 @@ static void sta_apply_parameters(struct ieee80211_local *local, if (params->supported_rates) { rates = 0; - 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; @@ -641,10 +662,10 @@ static void sta_apply_parameters(struct ieee80211_local *local, sta->sta.supp_rates[local->oper_channel->band] = rates; } - if (params->ht_capa) { - ieee80211_ht_cap_ie_to_ht_info(params->ht_capa, - &sta->sta.ht_info); - } + if (params->ht_capa) + ieee80211_ht_cap_ie_to_sta_ht_cap(sband, + params->ht_capa, + &sta->sta.ht_cap); if (ieee80211_vif_is_mesh(&sdata->vif) && params->plink_action) { switch (params->plink_action) { @@ -665,6 +686,7 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, struct sta_info *sta; struct ieee80211_sub_if_data *sdata; int err; + int layer2_update; /* Prevent a race with changing the rate control algorithm */ if (!netif_running(dev)) @@ -695,17 +717,25 @@ static int ieee80211_add_station(struct wiphy *wiphy, struct net_device *dev, rate_control_rate_init(sta); + layer2_update = sdata->vif.type == NL80211_IFTYPE_AP_VLAN || + sdata->vif.type == NL80211_IFTYPE_AP; + rcu_read_lock(); err = sta_info_insert(sta); if (err) { /* STA has been freed */ + if (err == -EEXIST && layer2_update) { + /* Need to update layer 2 devices on reassociation */ + sta = sta_info_get(local, mac); + if (sta) + ieee80211_send_layer2_update(sta); + } rcu_read_unlock(); return err; } - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN || - sdata->vif.type == NL80211_IFTYPE_AP) + if (layer2_update) ieee80211_send_layer2_update(sta); rcu_read_unlock(); @@ -957,6 +987,72 @@ static int ieee80211_dump_mpath(struct wiphy *wiphy, struct net_device *dev, rcu_read_unlock(); return 0; } + +static int ieee80211_get_mesh_params(struct wiphy *wiphy, + struct net_device *dev, + struct mesh_config *conf) +{ + struct ieee80211_sub_if_data *sdata; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) + return -ENOTSUPP; + memcpy(conf, &(sdata->u.mesh.mshcfg), sizeof(struct mesh_config)); + return 0; +} + +static inline bool _chg_mesh_attr(enum nl80211_meshconf_params parm, u32 mask) +{ + return (mask >> (parm-1)) & 0x1; +} + +static int ieee80211_set_mesh_params(struct wiphy *wiphy, + struct net_device *dev, + const struct mesh_config *nconf, u32 mask) +{ + struct mesh_config *conf; + struct ieee80211_sub_if_data *sdata; + sdata = IEEE80211_DEV_TO_SUB_IF(dev); + + if (sdata->vif.type != NL80211_IFTYPE_MESH_POINT) + return -ENOTSUPP; + + /* Set the config options which we are interested in setting */ + conf = &(sdata->u.mesh.mshcfg); + if (_chg_mesh_attr(NL80211_MESHCONF_RETRY_TIMEOUT, mask)) + conf->dot11MeshRetryTimeout = nconf->dot11MeshRetryTimeout; + if (_chg_mesh_attr(NL80211_MESHCONF_CONFIRM_TIMEOUT, mask)) + conf->dot11MeshConfirmTimeout = nconf->dot11MeshConfirmTimeout; + if (_chg_mesh_attr(NL80211_MESHCONF_HOLDING_TIMEOUT, mask)) + conf->dot11MeshHoldingTimeout = nconf->dot11MeshHoldingTimeout; + if (_chg_mesh_attr(NL80211_MESHCONF_MAX_PEER_LINKS, mask)) + conf->dot11MeshMaxPeerLinks = nconf->dot11MeshMaxPeerLinks; + if (_chg_mesh_attr(NL80211_MESHCONF_MAX_RETRIES, mask)) + conf->dot11MeshMaxRetries = nconf->dot11MeshMaxRetries; + if (_chg_mesh_attr(NL80211_MESHCONF_TTL, mask)) + conf->dot11MeshTTL = nconf->dot11MeshTTL; + if (_chg_mesh_attr(NL80211_MESHCONF_AUTO_OPEN_PLINKS, mask)) + conf->auto_open_plinks = nconf->auto_open_plinks; + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, mask)) + conf->dot11MeshHWMPmaxPREQretries = + nconf->dot11MeshHWMPmaxPREQretries; + if (_chg_mesh_attr(NL80211_MESHCONF_PATH_REFRESH_TIME, mask)) + conf->path_refresh_time = nconf->path_refresh_time; + if (_chg_mesh_attr(NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, mask)) + conf->min_discovery_timeout = nconf->min_discovery_timeout; + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, mask)) + conf->dot11MeshHWMPactivePathTimeout = + nconf->dot11MeshHWMPactivePathTimeout; + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, mask)) + conf->dot11MeshHWMPpreqMinInterval = + nconf->dot11MeshHWMPpreqMinInterval; + if (_chg_mesh_attr(NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, + mask)) + conf->dot11MeshHWMPnetDiameterTraversalTime = + nconf->dot11MeshHWMPnetDiameterTraversalTime; + return 0; +} + #endif static int ieee80211_change_bss(struct wiphy *wiphy, @@ -972,25 +1068,79 @@ static int ieee80211_change_bss(struct wiphy *wiphy, return -EINVAL; if (params->use_cts_prot >= 0) { - sdata->bss_conf.use_cts_prot = params->use_cts_prot; + sdata->vif.bss_conf.use_cts_prot = params->use_cts_prot; changed |= BSS_CHANGED_ERP_CTS_PROT; } if (params->use_short_preamble >= 0) { - sdata->bss_conf.use_short_preamble = + sdata->vif.bss_conf.use_short_preamble = params->use_short_preamble; changed |= BSS_CHANGED_ERP_PREAMBLE; } if (params->use_short_slot_time >= 0) { - sdata->bss_conf.use_short_slot = + sdata->vif.bss_conf.use_short_slot = params->use_short_slot_time; changed |= BSS_CHANGED_ERP_SLOT; } + if (params->basic_rates) { + int i, j; + u32 rates = 0; + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_supported_band *sband = + wiphy->bands[local->oper_channel->band]; + + for (i = 0; i < params->basic_rates_len; i++) { + int rate = (params->basic_rates[i] & 0x7f) * 5; + for (j = 0; j < sband->n_bitrates; j++) { + if (sband->bitrates[j].bitrate == rate) + rates |= BIT(j); + } + } + sdata->vif.bss_conf.basic_rates = rates; + changed |= BSS_CHANGED_BASIC_RATES; + } + ieee80211_bss_info_change_notify(sdata, changed); return 0; } +static int ieee80211_set_txq_params(struct wiphy *wiphy, + struct ieee80211_txq_params *params) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + struct ieee80211_tx_queue_params p; + + if (!local->ops->conf_tx) + return -EOPNOTSUPP; + + memset(&p, 0, sizeof(p)); + p.aifs = params->aifs; + p.cw_max = params->cwmax; + p.cw_min = params->cwmin; + p.txop = params->txop; + if (local->ops->conf_tx(local_to_hw(local), params->queue, &p)) { + printk(KERN_DEBUG "%s: failed to set TX queue " + "parameters for queue %d\n", local->mdev->name, + params->queue); + return -EINVAL; + } + + return 0; +} + +static int ieee80211_set_channel(struct wiphy *wiphy, + struct ieee80211_channel *chan, + enum nl80211_channel_type channel_type) +{ + struct ieee80211_local *local = wiphy_priv(wiphy); + + local->oper_channel = chan; + local->oper_channel_type = channel_type; + + return ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); +} + struct cfg80211_ops mac80211_config_ops = { .add_virtual_intf = ieee80211_add_iface, .del_virtual_intf = ieee80211_del_iface, @@ -1013,6 +1163,10 @@ struct cfg80211_ops mac80211_config_ops = { .change_mpath = ieee80211_change_mpath, .get_mpath = ieee80211_get_mpath, .dump_mpath = ieee80211_dump_mpath, + .set_mesh_params = ieee80211_set_mesh_params, + .get_mesh_params = ieee80211_get_mesh_params, #endif .change_bss = ieee80211_change_bss, + .set_txq_params = ieee80211_set_txq_params, + .set_channel = ieee80211_set_channel, }; diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c index 24ce544633109c038ee4af718258ddc942311568..2697a2fe608f60978d521acdcb0d90d5ff9ae5b4 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c @@ -47,18 +47,14 @@ static const struct file_operations name## _ops = { \ DEBUGFS_READONLY_FILE(frequency, 20, "%d", 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->hw.conf.antenna_sel_rx); DEBUGFS_READONLY_FILE(rts_threshold, 20, "%d", local->rts_threshold); DEBUGFS_READONLY_FILE(fragmentation_threshold, 20, "%d", local->fragmentation_threshold); DEBUGFS_READONLY_FILE(short_retry_limit, 20, "%d", - local->short_retry_limit); + local->hw.conf.short_frame_max_tx_count); DEBUGFS_READONLY_FILE(long_retry_limit, 20, "%d", - local->long_retry_limit); + local->hw.conf.long_frame_max_tx_count); DEBUGFS_READONLY_FILE(total_ps_buffered, 20, "%d", local->total_ps_buffered); DEBUGFS_READONLY_FILE(wep_iv, 20, "%#06x", @@ -202,8 +198,6 @@ void debugfs_hw_add(struct ieee80211_local *local) local->debugfs.keys = debugfs_create_dir("keys", phyd); DEBUGFS_ADD(frequency); - DEBUGFS_ADD(antenna_sel_tx); - DEBUGFS_ADD(antenna_sel_rx); DEBUGFS_ADD(rts_threshold); DEBUGFS_ADD(fragmentation_threshold); DEBUGFS_ADD(short_retry_limit); @@ -258,8 +252,6 @@ void debugfs_hw_add(struct ieee80211_local *local) void debugfs_hw_del(struct ieee80211_local *local) { DEBUGFS_DEL(frequency); - DEBUGFS_DEL(antenna_sel_tx); - DEBUGFS_DEL(antenna_sel_rx); DEBUGFS_DEL(rts_threshold); DEBUGFS_DEL(fragmentation_threshold); DEBUGFS_DEL(short_retry_limit); diff --git a/net/mac80211/debugfs_key.c b/net/mac80211/debugfs_key.c index a3294d109322d61583afe0a967260e2cc1236d62..6424ac565ae0e1760697e626c2a875c295f472a4 100644 --- a/net/mac80211/debugfs_key.c +++ b/net/mac80211/debugfs_key.c @@ -188,7 +188,6 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key) { static int keycount; char buf[50]; - DECLARE_MAC_BUF(mac); struct sta_info *sta; if (!key->local->debugfs.keys) @@ -206,8 +205,7 @@ void ieee80211_debugfs_key_add(struct ieee80211_key *key) rcu_read_lock(); sta = rcu_dereference(key->sta); if (sta) - sprintf(buf, "../../stations/%s", - print_mac(mac, sta->sta.addr)); + sprintf(buf, "../../stations/%pM", sta->sta.addr); rcu_read_unlock(); /* using sta as a boolean is fine outside RCU lock */ diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c index 2ad504fc3414e19eb1b43cef909af2a68214de4b..c54219301724e1198c824294550edf77d7cc6bdb 100644 --- a/net/mac80211/debugfs_netdev.c +++ b/net/mac80211/debugfs_netdev.c @@ -41,29 +41,6 @@ static ssize_t ieee80211_if_read( 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)); - if (copy_from_user(buf, userbuf, buf_size)) - return count; - read_lock(&dev_base_lock); - if (sdata->dev->reg_state == NETREG_REGISTERED) - (*format)(sdata, buf); - 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, \ @@ -71,19 +48,6 @@ static ssize_t ieee80211_if_fmt_##name( \ { \ 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) \ @@ -104,8 +68,7 @@ static ssize_t ieee80211_if_fmt_##name( \ const struct ieee80211_sub_if_data *sdata, char *buf, \ int buflen) \ { \ - DECLARE_MAC_BUF(mac); \ - return scnprintf(buf, buflen, "%s\n", print_mac(mac, sdata->field));\ + return scnprintf(buf, buflen, "%pM\n", sdata->field); \ } #define __IEEE80211_IF_FILE(name) \ @@ -126,34 +89,6 @@ static const struct file_operations name##_ops = { \ 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(drop_unencrypted, drop_unencrypted, DEC); IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC); @@ -184,7 +119,7 @@ static ssize_t ieee80211_if_fmt_flags( sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "", sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "", sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "", - sdata->bss_conf.use_cts_prot ? "CTS prot\n" : ""); + sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : ""); } __IEEE80211_IF_FILE(flags); @@ -212,30 +147,30 @@ IEEE80211_IF_FILE(dropped_frames_no_route, IEEE80211_IF_FILE(estab_plinks, u.mesh.mshstats.estab_plinks, ATOMIC); /* Mesh parameters */ -IEEE80211_IF_WFILE(dot11MeshMaxRetries, - u.mesh.mshcfg.dot11MeshMaxRetries, DEC, u8); -IEEE80211_IF_WFILE(dot11MeshRetryTimeout, - u.mesh.mshcfg.dot11MeshRetryTimeout, DEC, u16); -IEEE80211_IF_WFILE(dot11MeshConfirmTimeout, - u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC, u16); -IEEE80211_IF_WFILE(dot11MeshHoldingTimeout, - u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC, u16); -IEEE80211_IF_WFILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC, u8); -IEEE80211_IF_WFILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC, u8); -IEEE80211_IF_WFILE(dot11MeshMaxPeerLinks, - u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC, u16); -IEEE80211_IF_WFILE(dot11MeshHWMPactivePathTimeout, - u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC, u32); -IEEE80211_IF_WFILE(dot11MeshHWMPpreqMinInterval, - u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC, u16); -IEEE80211_IF_WFILE(dot11MeshHWMPnetDiameterTraversalTime, - u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC, u16); -IEEE80211_IF_WFILE(dot11MeshHWMPmaxPREQretries, - u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC, u8); -IEEE80211_IF_WFILE(path_refresh_time, - u.mesh.mshcfg.path_refresh_time, DEC, u32); -IEEE80211_IF_WFILE(min_discovery_timeout, - u.mesh.mshcfg.min_discovery_timeout, DEC, u16); +IEEE80211_IF_FILE(dot11MeshMaxRetries, + u.mesh.mshcfg.dot11MeshMaxRetries, DEC); +IEEE80211_IF_FILE(dot11MeshRetryTimeout, + u.mesh.mshcfg.dot11MeshRetryTimeout, DEC); +IEEE80211_IF_FILE(dot11MeshConfirmTimeout, + u.mesh.mshcfg.dot11MeshConfirmTimeout, DEC); +IEEE80211_IF_FILE(dot11MeshHoldingTimeout, + u.mesh.mshcfg.dot11MeshHoldingTimeout, DEC); +IEEE80211_IF_FILE(dot11MeshTTL, u.mesh.mshcfg.dot11MeshTTL, DEC); +IEEE80211_IF_FILE(auto_open_plinks, u.mesh.mshcfg.auto_open_plinks, DEC); +IEEE80211_IF_FILE(dot11MeshMaxPeerLinks, + u.mesh.mshcfg.dot11MeshMaxPeerLinks, DEC); +IEEE80211_IF_FILE(dot11MeshHWMPactivePathTimeout, + u.mesh.mshcfg.dot11MeshHWMPactivePathTimeout, DEC); +IEEE80211_IF_FILE(dot11MeshHWMPpreqMinInterval, + u.mesh.mshcfg.dot11MeshHWMPpreqMinInterval, DEC); +IEEE80211_IF_FILE(dot11MeshHWMPnetDiameterTraversalTime, + u.mesh.mshcfg.dot11MeshHWMPnetDiameterTraversalTime, DEC); +IEEE80211_IF_FILE(dot11MeshHWMPmaxPREQretries, + u.mesh.mshcfg.dot11MeshHWMPmaxPREQretries, DEC); +IEEE80211_IF_FILE(path_refresh_time, + u.mesh.mshcfg.path_refresh_time, DEC); +IEEE80211_IF_FILE(min_discovery_timeout, + u.mesh.mshcfg.min_discovery_timeout, DEC); #endif diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c index b85c4f27b3618e4f783f47c328b1b0c5f3e43702..a2fbe0131312dcf23dda4b2ce8600af246f462f7 100644 --- a/net/mac80211/debugfs_sta.c +++ b/net/mac80211/debugfs_sta.c @@ -39,13 +39,6 @@ static const struct file_operations sta_ ##name## _ops = { \ .open = mac80211_open_file_generic, \ } -#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, \ -} - #define STA_FILE(name, field, format) \ STA_READ_##format(name, field) \ STA_OPS(name) @@ -144,7 +137,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, 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_state_rx[i]? + sta->ampdu_mlme.tid_state_rx[i] ? sta->ampdu_mlme.tid_rx[i]->dialog_token : 0); p += scnprintf(p, sizeof(buf)+buf-p, "\n TX :"); @@ -155,84 +148,20 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, 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_state_tx[i]? + sta->ampdu_mlme.tid_state_tx[i] ? sta->ampdu_mlme.tid_tx[i]->dialog_token : 0); 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_state_tx[i]? + sta->ampdu_mlme.tid_state_tx[i] ? sta->ampdu_mlme.tid_tx[i]->ssn : 0); 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 ieee80211_local *local = sta->sdata->local; - struct ieee80211_hw *hw = &local->hw; - u8 *da = sta->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(sta->sdata, da, tid_num, 0, - WLAN_REASON_QSTA_REQUIRE_SETUP); - sta->ampdu_mlme.tid_state_rx[tid_num] |= - HT_AGG_STATE_DEBUGFS_CTL; - tid_static_rx[tid_num] = 0; - } else { - strcpy(state, "on "); - sta->ampdu_mlme.tid_state_rx[tid_num] &= - ~HT_AGG_STATE_DEBUGFS_CTL; - 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); +STA_OPS(agg_status); #define DEBUGFS_ADD(name) \ sta->debugfs.name = debugfs_create_file(#name, 0400, \ @@ -246,15 +175,14 @@ STA_OPS_WR(agg_status); void ieee80211_sta_debugfs_add(struct sta_info *sta) { struct dentry *stations_dir = sta->local->debugfs.stations; - DECLARE_MAC_BUF(mbuf); - u8 *mac; + u8 mac[3*ETH_ALEN]; sta->debugfs.add_has_run = true; if (!stations_dir) return; - mac = print_mac(mbuf, sta->sta.addr); + snprintf(mac, sizeof(mac), "%pM", sta->sta.addr); /* * This might fail due to a race condition: diff --git a/net/mac80211/event.c b/net/mac80211/event.c index 8de60de70bc9bffa32a4fea6dc3b7641f139c563..0d95561c0ee017d72cf3b19986a79fc25ad9a1ae 100644 --- a/net/mac80211/event.c +++ b/net/mac80211/event.c @@ -21,14 +21,13 @@ void mac80211_ev_michael_mic_failure(struct ieee80211_sub_if_data *sdata, int ke { union iwreq_data wrqu; char *buf = kmalloc(128, GFP_ATOMIC); - DECLARE_MAC_BUF(mac); if (buf) { /* TODO: needed parameters: count, key type, TSC */ sprintf(buf, "MLME-MICHAELMICFAILURE.indication(" - "keyid=%d %scast addr=%s)", + "keyid=%d %scast addr=%pM)", keyidx, hdr->addr1[0] & 0x01 ? "broad" : "uni", - print_mac(mac, hdr->addr2)); + hdr->addr2); memset(&wrqu, 0, sizeof(wrqu)); wrqu.data.length = strlen(buf); wireless_send_event(sdata->dev, IWEVCUSTOM, &wrqu, buf); diff --git a/net/mac80211/ht.c b/net/mac80211/ht.c index dc7d9a3d70d5ccc450faa96a4728a3cee7500cd0..5f510a13b9f0a5679d3ed736efa927532fc18f2a 100644 --- a/net/mac80211/ht.c +++ b/net/mac80211/ht.c @@ -20,50 +20,138 @@ #include "sta_info.h" #include "wme.h" -int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, - struct ieee80211_ht_info *ht_info) +void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, + struct ieee80211_ht_cap *ht_cap_ie, + struct ieee80211_sta_ht_cap *ht_cap) { + u8 ampdu_info, tx_mcs_set_cap; + int i, max_tx_streams; - if (ht_info == NULL) - return -EINVAL; + BUG_ON(!ht_cap); + + memset(ht_cap, 0, sizeof(*ht_cap)); + + if (!ht_cap_ie) + return; + + ht_cap->ht_supported = true; - memset(ht_info, 0, sizeof(*ht_info)); + ht_cap->cap = le16_to_cpu(ht_cap_ie->cap_info) & sband->ht_cap.cap; + ht_cap->cap &= ~IEEE80211_HT_CAP_SM_PS; + ht_cap->cap |= sband->ht_cap.cap & IEEE80211_HT_CAP_SM_PS; - if (ht_cap_ie) { - u8 ampdu_info = ht_cap_ie->ampdu_params_info; + ampdu_info = ht_cap_ie->ampdu_params_info; + ht_cap->ampdu_factor = + ampdu_info & IEEE80211_HT_AMPDU_PARM_FACTOR; + ht_cap->ampdu_density = + (ampdu_info & IEEE80211_HT_AMPDU_PARM_DENSITY) >> 2; - ht_info->ht_supported = 1; - ht_info->cap = le16_to_cpu(ht_cap_ie->cap_info); - ht_info->ampdu_factor = - ampdu_info & IEEE80211_HT_CAP_AMPDU_FACTOR; - ht_info->ampdu_density = - (ampdu_info & IEEE80211_HT_CAP_AMPDU_DENSITY) >> 2; - memcpy(ht_info->supp_mcs_set, ht_cap_ie->supp_mcs_set, 16); - } else - ht_info->ht_supported = 0; + /* own MCS TX capabilities */ + tx_mcs_set_cap = sband->ht_cap.mcs.tx_params; - return 0; + /* can we TX with MCS rates? */ + if (!(tx_mcs_set_cap & IEEE80211_HT_MCS_TX_DEFINED)) + return; + + /* Counting from 0, therefore +1 */ + if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_RX_DIFF) + max_tx_streams = + ((tx_mcs_set_cap & IEEE80211_HT_MCS_TX_MAX_STREAMS_MASK) + >> IEEE80211_HT_MCS_TX_MAX_STREAMS_SHIFT) + 1; + else + max_tx_streams = IEEE80211_HT_MCS_TX_MAX_STREAMS; + + /* + * 802.11n D5.0 20.3.5 / 20.6 says: + * - indices 0 to 7 and 32 are single spatial stream + * - 8 to 31 are multiple spatial streams using equal modulation + * [8..15 for two streams, 16..23 for three and 24..31 for four] + * - remainder are multiple spatial streams using unequal modulation + */ + for (i = 0; i < max_tx_streams; i++) + ht_cap->mcs.rx_mask[i] = + sband->ht_cap.mcs.rx_mask[i] & ht_cap_ie->mcs.rx_mask[i]; + + if (tx_mcs_set_cap & IEEE80211_HT_MCS_TX_UNEQUAL_MODULATION) + for (i = IEEE80211_HT_MCS_UNEQUAL_MODULATION_START_BYTE; + i < IEEE80211_HT_MCS_MASK_LEN; i++) + ht_cap->mcs.rx_mask[i] = + sband->ht_cap.mcs.rx_mask[i] & + ht_cap_ie->mcs.rx_mask[i]; + + /* handle MCS rate 32 too */ + if (sband->ht_cap.mcs.rx_mask[32/8] & ht_cap_ie->mcs.rx_mask[32/8] & 1) + ht_cap->mcs.rx_mask[32/8] |= 1; } -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) +/* + * ieee80211_enable_ht should be called only after the operating band + * has been determined as ht configuration depends on the hw's + * HT abilities for a specific band. + */ +u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, + struct ieee80211_ht_info *hti, + u16 ap_ht_cap_flags) { - if (bss_info == NULL) - return -EINVAL; + struct ieee80211_local *local = sdata->local; + struct ieee80211_supported_band *sband; + struct ieee80211_bss_ht_conf ht; + u32 changed = 0; + bool enable_ht = true, ht_changed; + enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; + + memset(&ht, 0, sizeof(ht)); + + /* HT is not supported */ + if (!sband->ht_cap.ht_supported) + enable_ht = false; + + /* check that channel matches the right operating channel */ + if (local->hw.conf.channel->center_freq != + ieee80211_channel_to_frequency(hti->control_chan)) + enable_ht = false; + + if (enable_ht) { + channel_type = NL80211_CHAN_HT20; + + if (!(ap_ht_cap_flags & IEEE80211_HT_CAP_40MHZ_INTOLERANT) && + (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) && + (hti->ht_param & IEEE80211_HT_PARAM_CHAN_WIDTH_ANY)) { + switch(hti->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: + channel_type = NL80211_CHAN_HT40PLUS; + break; + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: + channel_type = NL80211_CHAN_HT40MINUS; + break; + } + } + } + + ht_changed = local->hw.conf.ht.enabled != enable_ht || + channel_type != local->hw.conf.ht.channel_type; + + local->oper_channel_type = channel_type; + local->hw.conf.ht.enabled = enable_ht; - memset(bss_info, 0, sizeof(*bss_info)); + if (ht_changed) + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_HT); - if (ht_add_info_ie) { - u16 op_mode; - op_mode = le16_to_cpu(ht_add_info_ie->operation_mode); + /* disable HT */ + if (!enable_ht) + return 0; - bss_info->primary_channel = ht_add_info_ie->control_chan; - bss_info->bss_cap = ht_add_info_ie->ht_param; - bss_info->bss_op_mode = (u8)(op_mode & 0xff); + ht.operation_mode = le16_to_cpu(hti->operation_mode); + + /* if bss configuration changed store the new one */ + if (memcmp(&sdata->vif.bss_conf.ht, &ht, sizeof(ht))) { + changed |= BSS_CHANGED_HT; + sdata->vif.bss_conf.ht = ht; } - return 0; + return changed; } static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata, @@ -241,7 +329,6 @@ void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *r struct ieee80211_hw *hw = &local->hw; struct sta_info *sta; int ret, i; - DECLARE_MAC_BUF(mac); rcu_read_lock(); @@ -269,8 +356,8 @@ void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *r BUG_ON(!local->ops->ampdu_action); #ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Rx BA session stop requested for %s tid %u\n", - print_mac(mac, ra), tid); + printk(KERN_DEBUG "Rx BA session stop requested for %pM tid %u\n", + ra, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_RX_STOP, @@ -383,14 +470,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) u16 start_seq_num; u8 *state; int ret; - DECLARE_MAC_BUF(mac); - if (tid >= STA_TID_NUM) + if ((tid >= STA_TID_NUM) || !(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION)) return -EINVAL; #ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Open BA session requested for %s tid %u\n", - print_mac(mac, ra), tid); + printk(KERN_DEBUG "Open BA session requested for %pM tid %u\n", + ra, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ rcu_read_lock(); @@ -442,17 +528,19 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) (unsigned long)&sta->timer_to_tid[tid]; init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer); - /* create a new queue for this aggregation */ - ret = ieee80211_ht_agg_queue_add(local, sta, tid); + if (hw->ampdu_queues) { + /* 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) { + /* 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 - queue unavailable for" - " tid %d\n", tid); + printk(KERN_DEBUG "BA request denied - " + "queue unavailable for tid %d\n", tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - goto err_unlock_queue; + goto err_unlock_queue; + } } sdata = sta->sdata; @@ -471,7 +559,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) /* 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); + if (hw->ampdu_queues) + ieee80211_ht_agg_queue_remove(local, sta, tid, 0); #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "BA request denied - HW unavailable for" " tid %d\n", tid); @@ -481,7 +570,8 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid) } /* Will put all the packets in the new SW queue */ - ieee80211_requeue(local, ieee802_1d_to_ac[tid]); + if (hw->ampdu_queues) + ieee80211_requeue(local, ieee802_1d_to_ac[tid]); spin_unlock_bh(&sta->lock); /* send an addBA request */ @@ -524,7 +614,6 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, struct sta_info *sta; u8 *state; int ret = 0; - DECLARE_MAC_BUF(mac); if (tid >= STA_TID_NUM) return -EINVAL; @@ -546,11 +635,12 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, } #ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Tx BA session stop requested for %s tid %u\n", - print_mac(mac, ra), tid); + printk(KERN_DEBUG "Tx BA session stop requested for %pM tid %u\n", + ra, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ - ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); + if (hw->ampdu_queues) + ieee80211_stop_queue(hw, sta->tid_to_tx_q[tid]); *state = HT_AGG_STATE_REQ_STOP_BA_MSK | (initiator << HT_AGG_STATE_INITIATOR_SHIFT); @@ -563,7 +653,8 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_hw *hw, if (ret) { WARN_ON(ret != -EBUSY); *state = HT_AGG_STATE_OPERATIONAL; - ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + if (hw->ampdu_queues) + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); goto stop_BA_exit; } @@ -579,7 +670,6 @@ 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) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -594,8 +684,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) if (!sta) { rcu_read_unlock(); #ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Could not find station: %s\n", - print_mac(mac, ra)); + printk(KERN_DEBUG "Could not find station: %pM\n", ra); #endif return; } @@ -621,7 +710,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid) #ifdef CONFIG_MAC80211_HT_DEBUG printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid); #endif - ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + if (hw->ampdu_queues) + ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); } spin_unlock_bh(&sta->lock); rcu_read_unlock(); @@ -634,7 +724,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) struct sta_info *sta; u8 *state; int agg_queue; - DECLARE_MAC_BUF(mac); if (tid >= STA_TID_NUM) { #ifdef CONFIG_MAC80211_HT_DEBUG @@ -645,16 +734,15 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) } #ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Stopping Tx BA session for %s tid %d\n", - print_mac(mac, ra), tid); + printk(KERN_DEBUG "Stopping Tx BA session for %pM tid %d\n", + ra, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ rcu_read_lock(); sta = sta_info_get(local, ra); if (!sta) { #ifdef CONFIG_MAC80211_HT_DEBUG - printk(KERN_DEBUG "Could not find station: %s\n", - print_mac(mac, ra)); + printk(KERN_DEBUG "Could not find station: %pM\n", ra); #endif rcu_read_unlock(); return; @@ -677,16 +765,18 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid) ieee80211_send_delba(sta->sdata, ra, tid, WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE); - agg_queue = sta->tid_to_tx_q[tid]; - - ieee80211_ht_agg_queue_remove(local, sta, tid, 1); - - /* We just requeued the all the frames that were in the - * removed queue, and since we might miss a softirq we do - * netif_schedule_queue. ieee80211_wake_queue is not used - * here as this queue is not necessarily stopped - */ - netif_schedule_queue(netdev_get_tx_queue(local->mdev, agg_queue)); + if (hw->ampdu_queues) { + agg_queue = sta->tid_to_tx_q[tid]; + ieee80211_ht_agg_queue_remove(local, sta, tid, 1); + + /* We just requeued the all the frames that were in the + * removed queue, and since we might miss a softirq we do + * netif_schedule_queue. ieee80211_wake_queue is not used + * here as this queue is not necessarily stopped + */ + netif_schedule_queue(netdev_get_tx_queue(local->mdev, + agg_queue)); + } spin_lock_bh(&sta->lock); *state = HT_AGG_STATE_IDLE; sta->ampdu_mlme.addba_req_num[tid] = 0; @@ -783,7 +873,6 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, u16 capab, tid, timeout, ba_policy, buf_size, start_seq_num, status; u8 dialog_token; int ret = -EOPNOTSUPP; - DECLARE_MAC_BUF(mac); /* extract session parameters from addba request frame */ dialog_token = mgmt->u.action.u.addba_req.dialog_token; @@ -801,15 +890,16 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, /* sanity check for incoming parameters: * check if configuration can support the BA policy * and if buffer size does not exceeds max value */ + /* XXX: check own ht delayed BA capability?? */ if (((ba_policy != 1) - && (!(conf->ht_conf.cap & IEEE80211_HT_CAP_DELAY_BA))) + && (!(sta->sta.ht_cap.cap & IEEE80211_HT_CAP_DELAY_BA))) || (buf_size > IEEE80211_MAX_AMPDU_BUF)) { status = WLAN_STATUS_INVALID_QOS_PARAM; #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "AddBA Req with bad params from " - "%s on tid %u. policy %d, buffer size %d\n", - print_mac(mac, mgmt->sa), tid, ba_policy, + "%pM on tid %u. policy %d, buffer size %d\n", + mgmt->sa, tid, ba_policy, buf_size); #endif /* CONFIG_MAC80211_HT_DEBUG */ goto end_no_lock; @@ -820,7 +910,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, sband = local->hw.wiphy->bands[conf->channel->band]; buf_size = IEEE80211_MIN_AMPDU_BUF; - buf_size = buf_size << sband->ht_info.ampdu_factor; + buf_size = buf_size << sband->ht_cap.ampdu_factor; } @@ -831,8 +921,8 @@ void ieee80211_process_addba_request(struct ieee80211_local *local, #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) printk(KERN_DEBUG "unexpected AddBA Req from " - "%s on tid %u\n", - print_mac(mac, mgmt->sa), tid); + "%pM on tid %u\n", + mgmt->sa, tid); #endif /* CONFIG_MAC80211_HT_DEBUG */ goto end; } @@ -910,7 +1000,7 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, { struct ieee80211_hw *hw = &local->hw; u16 capab; - u16 tid; + u16 tid, start_seq_num; u8 *state; capab = le16_to_cpu(mgmt->u.action.u.addba_resp.capab); @@ -943,9 +1033,18 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local, *state |= HT_ADDBA_RECEIVED_MSK; sta->ampdu_mlme.addba_req_num[tid] = 0; - if (*state == HT_AGG_STATE_OPERATIONAL) + if (*state == HT_AGG_STATE_OPERATIONAL && + local->hw.ampdu_queues) ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]); + if (local->ops->ampdu_action) { + (void)local->ops->ampdu_action(hw, + IEEE80211_AMPDU_TX_RESUME, + &sta->sta, tid, &start_seq_num); + } +#ifdef CONFIG_MAC80211_HT_DEBUG + printk(KERN_DEBUG "Resuming TX aggregation for tid %d\n", tid); +#endif /* CONFIG_MAC80211_HT_DEBUG */ spin_unlock_bh(&sta->lock); } else { sta->ampdu_mlme.addba_req_num[tid]++; @@ -964,7 +1063,6 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; u16 tid, params; u16 initiator; - DECLARE_MAC_BUF(mac); params = le16_to_cpu(mgmt->u.action.u.delba.params); tid = (params & IEEE80211_DELBA_PARAM_TID_MASK) >> 12; @@ -972,9 +1070,8 @@ void ieee80211_process_delba(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_HT_DEBUG if (net_ratelimit()) - printk(KERN_DEBUG "delba from %s (%s) tid %d reason code %d\n", - print_mac(mac, mgmt->sa), - initiator ? "initiator" : "recipient", tid, + printk(KERN_DEBUG "delba from %pM (%s) tid %d reason code %d\n", + mgmt->sa, initiator ? "initiator" : "recipient", tid, mgmt->u.action.u.delba.reason_code); #endif /* CONFIG_MAC80211_HT_DEBUG */ diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h index 156e42a003ae77ac38e77aa1e047d58575e87eec..f3eec989662bebb2523d4df393f608546308cc94 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -142,7 +143,6 @@ typedef unsigned __bitwise__ ieee80211_tx_result; #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) struct ieee80211_tx_data { struct sk_buff *skb; @@ -153,11 +153,6 @@ struct ieee80211_tx_data { struct ieee80211_key *key; struct ieee80211_channel *channel; - s8 rate_idx; - /* 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. */ - s8 last_frag_rate_idx; /* Extra fragments (in addition to the first fragment * in skb) */ @@ -192,7 +187,6 @@ struct ieee80211_rx_data { struct ieee80211_rx_status *status; struct ieee80211_rate *rate; - u16 ethertype; unsigned int flags; int sent_ps_buffered; int queue; @@ -203,9 +197,7 @@ struct ieee80211_rx_data { struct ieee80211_tx_stored_packet { struct sk_buff *skb; struct sk_buff **extra_frag; - s8 last_frag_rate_idx; int num_extra_frag; - bool last_frag_rate_ctrl_probe; }; struct beacon_data { @@ -219,9 +211,6 @@ struct ieee80211_if_ap { struct list_head vlans; - u8 ssid[IEEE80211_MAX_SSID_LEN]; - size_t ssid_len; - /* yes, this looks ugly, but guarantees that we can later use * bitmap_empty :) * NB: don't touch this bitmap, use sta_info_{set,clear}_tim_bit */ @@ -255,26 +244,6 @@ struct mesh_preq_queue { 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 */ - u8 dot11MeshHWMPmaxPREQretries; - u32 path_refresh_time; - u16 min_discovery_timeout; - u32 dot11MeshHWMPactivePathTimeout; - u16 dot11MeshHWMPpreqMinInterval; - u16 dot11MeshHWMPnetDiameterTraversalTime; -}; - - /* flags used in struct ieee80211_if_sta.flags */ #define IEEE80211_STA_SSID_SET BIT(0) #define IEEE80211_STA_BSSID_SET BIT(1) @@ -438,8 +407,7 @@ struct ieee80211_sub_if_data { struct ieee80211_key *keys[NUM_DEFAULT_KEYS]; struct ieee80211_key *default_key; - /* BSS configuration for this interface. */ - struct ieee80211_bss_conf bss_conf; + u16 sequence_number; /* * AP this belongs to: self in AP mode and @@ -570,6 +538,11 @@ enum { IEEE80211_ADDBA_MSG = 4, }; +enum queue_stop_reason { + IEEE80211_QUEUE_STOP_REASON_DRIVER, + IEEE80211_QUEUE_STOP_REASON_PS, +}; + /* maximum number of hardware queues we support. */ #define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES) @@ -586,7 +559,8 @@ struct ieee80211_local { const struct ieee80211_ops *ops; unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)]; - + unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES]; + spinlock_t queue_stop_reason_lock; struct net_device *mdev; /* wmaster# - "master" 802.11 device */ int open_count; int monitors, cooked_mntrs; @@ -633,8 +607,6 @@ struct ieee80211_local { int rts_threshold; int fragmentation_threshold; - int short_retry_limit; /* dot11ShortRetryLimit */ - int long_retry_limit; /* dot11LongRetryLimit */ struct crypto_blkcipher *wep_tx_tfm; struct crypto_blkcipher *wep_rx_tfm; @@ -659,6 +631,7 @@ struct ieee80211_local { struct delayed_work scan_work; struct ieee80211_sub_if_data *scan_sdata; struct ieee80211_channel *oper_channel, *scan_channel; + enum nl80211_channel_type oper_channel_type; u8 scan_ssid[IEEE80211_MAX_SSID_LEN]; size_t scan_ssid_len; struct list_head bss_list; @@ -722,13 +695,17 @@ struct ieee80211_local { int wifi_wme_noack_test; unsigned int wmm_acm; /* bit field of ACM bits (BIT(802.1D tag)) */ + bool powersave; + int dynamic_ps_timeout; + struct work_struct dynamic_ps_enable_work; + struct work_struct dynamic_ps_disable_work; + struct timer_list dynamic_ps_timer; + #ifdef CONFIG_MAC80211_DEBUGFS struct local_debugfsdentries { struct dentry *rcdir; struct dentry *rcname; struct dentry *frequency; - struct dentry *antenna_sel_tx; - struct dentry *antenna_sel_rx; struct dentry *rts_threshold; struct dentry *fragmentation_threshold; struct dentry *short_retry_limit; @@ -817,7 +794,7 @@ struct ieee802_11_elems { u8 *wmm_info; u8 *wmm_param; struct ieee80211_ht_cap *ht_cap_elem; - struct ieee80211_ht_addt_info *ht_info_elem; + struct ieee80211_ht_info *ht_info_elem; u8 *mesh_config; u8 *mesh_id; u8 *peer_link; @@ -869,11 +846,6 @@ static inline struct ieee80211_hw *local_to_hw( return &local->hw; } -struct sta_attribute { - struct attribute attr; - ssize_t (*show)(const struct sta_info *, char *buf); - ssize_t (*store)(struct sta_info *, const char *buf, size_t count); -}; static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) { @@ -882,12 +854,9 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr) } -int ieee80211_hw_config(struct ieee80211_local *local); +int ieee80211_hw_config(struct ieee80211_local *local, u32 changed); int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed); void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx); -u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, - struct ieee80211_ht_info *req_ht_cap, - struct ieee80211_ht_bss_info *req_bss_cap); void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, u32 changed); void ieee80211_configure_filter(struct ieee80211_local *local); @@ -906,8 +875,7 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid); void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_sta *ifsta); struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, u8 *bssid, - u8 *addr, u64 supp_rates); + u8 *bssid, u8 *addr, u64 supp_rates); int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason); int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason); u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata); @@ -968,11 +936,12 @@ int ieee80211_monitor_start_xmit(struct sk_buff *skb, struct net_device *dev); int ieee80211_subif_start_xmit(struct sk_buff *skb, struct net_device *dev); /* HT */ -int ieee80211_ht_cap_ie_to_ht_info(struct ieee80211_ht_cap *ht_cap_ie, - struct ieee80211_ht_info *ht_info); -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_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband, + struct ieee80211_ht_cap *ht_cap_ie, + struct ieee80211_sta_ht_cap *ht_cap); +u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata, + struct ieee80211_ht_info *hti, + u16 ap_ht_cap_flags); void ieee80211_send_bar(struct ieee80211_sub_if_data *sdata, u8 *ra, u16 tid, u16 ssn); void ieee80211_sta_stop_rx_ba_session(struct ieee80211_sub_if_data *sdata, u8 *da, @@ -1014,6 +983,15 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freq); u64 ieee80211_mandatory_rates(struct ieee80211_local *local, enum ieee80211_band band); +void ieee80211_dynamic_ps_enable_work(struct work_struct *work); +void ieee80211_dynamic_ps_disable_work(struct work_struct *work); +void ieee80211_dynamic_ps_timer(unsigned long data); + +void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, + enum queue_stop_reason reason); +void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, + enum queue_stop_reason reason); + #ifdef CONFIG_MAC80211_NOINLINE #define debug_noinline noinline #else diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c index 8336fee68d3e05b717047e4d8a1ac5f3623542a8..5abbc3f07dd6eb4c035b697698c878450e444c1e 100644 --- a/net/mac80211/iface.c +++ b/net/mac80211/iface.c @@ -65,7 +65,7 @@ static int ieee80211_open(struct net_device *dev) struct ieee80211_if_init_conf conf; u32 changed = 0; int res; - bool need_hw_reconfig = 0; + u32 hw_reconf_flags = 0; u8 null_addr[ETH_ALEN] = {0}; /* fail early if user set an invalid address */ @@ -152,7 +152,8 @@ static int ieee80211_open(struct net_device *dev) res = local->ops->start(local_to_hw(local)); if (res) goto err_del_bss; - need_hw_reconfig = 1; + /* we're brought up, everything changes */ + hw_reconf_flags = ~0; ieee80211_led_radio(local, local->hw.conf.radio_enabled); } @@ -198,8 +199,10 @@ static int ieee80211_open(struct net_device *dev) /* must be before the call to ieee80211_configure_filter */ local->monitors++; - if (local->monitors == 1) + if (local->monitors == 1) { local->hw.conf.flags |= IEEE80211_CONF_RADIOTAP; + hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP; + } if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) local->fif_fcsfail++; @@ -226,8 +229,14 @@ static int ieee80211_open(struct net_device *dev) if (res) goto err_stop; - if (ieee80211_vif_is_mesh(&sdata->vif)) + if (ieee80211_vif_is_mesh(&sdata->vif)) { + local->fif_other_bss++; + netif_addr_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_addr_unlock_bh(local->mdev); + ieee80211_start_mesh(sdata); + } changed |= ieee80211_reset_erp_info(sdata); ieee80211_bss_info_change_notify(sdata, changed); ieee80211_enable_keys(sdata); @@ -279,8 +288,8 @@ static int ieee80211_open(struct net_device *dev) atomic_inc(&local->iff_promiscs); local->open_count++; - if (need_hw_reconfig) { - ieee80211_hw_config(local); + if (hw_reconf_flags) { + ieee80211_hw_config(local, hw_reconf_flags); /* * set default queue parameters so drivers don't * need to initialise the hardware if the hardware @@ -322,6 +331,7 @@ static int ieee80211_stop(struct net_device *dev) struct ieee80211_local *local = sdata->local; struct ieee80211_if_init_conf conf; struct sta_info *sta; + u32 hw_reconf_flags = 0; /* * Stop TX on this interface first. @@ -405,8 +415,10 @@ static int ieee80211_stop(struct net_device *dev) } local->monitors--; - if (local->monitors == 0) + if (local->monitors == 0) { local->hw.conf.flags &= ~IEEE80211_CONF_RADIOTAP; + hw_reconf_flags |= IEEE80211_CONF_CHANGE_RADIOTAP; + } if (sdata->u.mntr_flags & MONITOR_FLAG_FCSFAIL) local->fif_fcsfail--; @@ -423,7 +435,11 @@ static int ieee80211_stop(struct net_device *dev) break; case NL80211_IFTYPE_STATION: case NL80211_IFTYPE_ADHOC: - sdata->u.sta.state = IEEE80211_STA_MLME_DISABLED; + /* Announce that we are leaving the network. */ + if (sdata->u.sta.state != IEEE80211_STA_MLME_DISABLED) + ieee80211_sta_deauthenticate(sdata, + WLAN_REASON_DEAUTH_LEAVING); + memset(sdata->u.sta.bssid, 0, ETH_ALEN); del_timer_sync(&sdata->u.sta.timer); /* @@ -450,8 +466,15 @@ static int ieee80211_stop(struct net_device *dev) /* fall through */ case NL80211_IFTYPE_MESH_POINT: if (ieee80211_vif_is_mesh(&sdata->vif)) { - /* allmulti is always set on mesh ifaces */ + /* other_bss and allmulti are always set on mesh + * ifaces */ + local->fif_other_bss--; atomic_dec(&local->iff_allmultis); + + netif_addr_lock_bh(local->mdev); + ieee80211_configure_filter(local); + netif_addr_unlock_bh(local->mdev); + ieee80211_stop_mesh(sdata); } /* fall through */ @@ -504,8 +527,15 @@ static int ieee80211_stop(struct net_device *dev) tasklet_disable(&local->tx_pending_tasklet); tasklet_disable(&local->tasklet); + + /* no reconfiguring after stop! */ + hw_reconf_flags = 0; } + /* do after stop to avoid reconfiguring when we stop anyway */ + if (hw_reconf_flags) + ieee80211_hw_config(local, hw_reconf_flags); + return 0; } @@ -668,6 +698,10 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, if (type == sdata->vif.type) return 0; + /* Setting ad-hoc mode on non-IBSS channel is not supported. */ + if (sdata->local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS) + return -EOPNOTSUPP; + /* * We could, here, on changes between IBSS/STA/MESH modes, * invoke an MLME function instead that disassociates etc. @@ -682,7 +716,7 @@ int ieee80211_if_change_type(struct ieee80211_sub_if_data *sdata, ieee80211_setup_sdata(sdata, type); /* reset some values that shouldn't be kept across type changes */ - sdata->bss_conf.basic_rates = + sdata->vif.bss_conf.basic_rates = ieee80211_mandatory_rates(sdata->local, sdata->local->hw.conf.channel->band); sdata->drop_unencrypted = 0; diff --git a/net/mac80211/key.c b/net/mac80211/key.c index a5b06fe7198019c5a178f0ac21118e222bcb04d7..999f7aa423267a33c525ee5693244f0c67070a30 100644 --- a/net/mac80211/key.c +++ b/net/mac80211/key.c @@ -132,7 +132,6 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; - DECLARE_MAC_BUF(mac); assert_key_lock(); might_sleep(); @@ -154,16 +153,15 @@ static void ieee80211_key_enable_hw_accel(struct ieee80211_key *key) if (ret && ret != -ENOSPC && ret != -EOPNOTSUPP) printk(KERN_ERR "mac80211-%s: failed to set key " - "(%d, %s) to hardware (%d)\n", + "(%d, %pM) to hardware (%d)\n", wiphy_name(key->local->hw.wiphy), - key->conf.keyidx, print_mac(mac, addr), ret); + key->conf.keyidx, addr, ret); } static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) { const u8 *addr; int ret; - DECLARE_MAC_BUF(mac); assert_key_lock(); might_sleep(); @@ -186,9 +184,9 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) if (ret) printk(KERN_ERR "mac80211-%s: failed to remove key " - "(%d, %s) from hardware (%d)\n", + "(%d, %pM) from hardware (%d)\n", wiphy_name(key->local->hw.wiphy), - key->conf.keyidx, print_mac(mac, addr), ret); + key->conf.keyidx, addr, ret); spin_lock(&todo_lock); key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE; diff --git a/net/mac80211/main.c b/net/mac80211/main.c index ae62ad40ad63715bed2372be5344ce3c4e4889bc..24b14363d6e70c77766c06946ba5407de122dc89 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c @@ -41,6 +41,8 @@ */ struct ieee80211_tx_status_rtap_hdr { struct ieee80211_radiotap_header hdr; + u8 rate; + u8 padding_for_rate; __le16 tx_flags; u8 data_retries; } __attribute__ ((packed)); @@ -169,19 +171,13 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) conf.changed = changed; if (sdata->vif.type == NL80211_IFTYPE_STATION || - sdata->vif.type == NL80211_IFTYPE_ADHOC) { + sdata->vif.type == NL80211_IFTYPE_ADHOC) conf.bssid = sdata->u.sta.bssid; - conf.ssid = sdata->u.sta.ssid; - conf.ssid_len = sdata->u.sta.ssid_len; - } else if (sdata->vif.type == NL80211_IFTYPE_AP) { + else if (sdata->vif.type == NL80211_IFTYPE_AP) conf.bssid = sdata->dev->dev_addr; - conf.ssid = sdata->u.ap.ssid; - conf.ssid_len = sdata->u.ap.ssid_len; - } else if (ieee80211_vif_is_mesh(&sdata->vif)) { + else if (ieee80211_vif_is_mesh(&sdata->vif)) { u8 zero[ETH_ALEN] = { 0 }; conf.bssid = zero; - conf.ssid = zero; - conf.ssid_len = 0; } else { WARN_ON(1); return -EINVAL; @@ -190,136 +186,73 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed) if (WARN_ON(!conf.bssid && (changed & IEEE80211_IFCC_BSSID))) return -EINVAL; - if (WARN_ON(!conf.ssid && (changed & IEEE80211_IFCC_SSID))) - return -EINVAL; - return local->ops->config_interface(local_to_hw(local), &sdata->vif, &conf); } -int ieee80211_hw_config(struct ieee80211_local *local) +int ieee80211_hw_config(struct ieee80211_local *local, u32 changed) { struct ieee80211_channel *chan; int ret = 0; + int power; + enum nl80211_channel_type channel_type; + + might_sleep(); - if (local->sw_scanning) + if (local->sw_scanning) { chan = local->scan_channel; - else + channel_type = NL80211_CHAN_NO_HT; + } else { chan = local->oper_channel; + channel_type = local->oper_channel_type; + } - local->hw.conf.channel = chan; + if (chan != local->hw.conf.channel || + channel_type != local->hw.conf.ht.channel_type) { + local->hw.conf.channel = chan; + local->hw.conf.ht.channel_type = channel_type; + switch (channel_type) { + case NL80211_CHAN_NO_HT: + local->hw.conf.ht.enabled = false; + break; + case NL80211_CHAN_HT20: + case NL80211_CHAN_HT40MINUS: + case NL80211_CHAN_HT40PLUS: + local->hw.conf.ht.enabled = true; + break; + } + changed |= IEEE80211_CONF_CHANGE_CHANNEL; + } if (!local->hw.conf.power_level) - local->hw.conf.power_level = chan->max_power; + power = 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 "%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); - - return ret; -} - -/** - * ieee80211_handle_ht should be used only after legacy configuration - * has been determined namely band, as ht configuration depends upon - * the hardware's HT abilities for a _specific_ band. - */ -u32 ieee80211_handle_ht(struct ieee80211_local *local, int enable_ht, - struct ieee80211_ht_info *req_ht_cap, - struct ieee80211_ht_bss_info *req_bss_cap) -{ - struct ieee80211_conf *conf = &local->hw.conf; - struct ieee80211_supported_band *sband; - struct ieee80211_ht_info ht_conf; - struct ieee80211_ht_bss_info ht_bss_conf; - u32 changed = 0; - int i; - u8 max_tx_streams = IEEE80211_HT_CAP_MAX_STREAMS; - u8 tx_mcs_set_cap; - - sband = local->hw.wiphy->bands[conf->channel->band]; - - memset(&ht_conf, 0, sizeof(struct ieee80211_ht_info)); - memset(&ht_bss_conf, 0, sizeof(struct ieee80211_ht_bss_info)); - - /* HT is not supported */ - if (!sband->ht_info.ht_supported) { - conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - goto out; + power = min(chan->max_power, local->hw.conf.power_level); + if (local->hw.conf.power_level != power) { + changed |= IEEE80211_CONF_CHANGE_POWER; + local->hw.conf.power_level = power; } - /* disable HT */ - if (!enable_ht) { - if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) - changed |= BSS_CHANGED_HT; - conf->flags &= ~IEEE80211_CONF_SUPPORT_HT_MODE; - conf->ht_conf.ht_supported = 0; - goto out; + if (changed && local->open_count) { + ret = local->ops->config(local_to_hw(local), changed); + /* + * Goal: + * HW reconfiguration should never fail, the driver has told + * us what it can support so it should live up to that promise. + * + * Current status: + * rfkill is not integrated with mac80211 and a + * configuration command can thus fail if hardware rfkill + * is enabled + * + * FIXME: integrate rfkill with mac80211 and then add this + * WARN_ON() back + * + */ + /* WARN_ON(ret); */ } - - if (!(conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE)) - changed |= BSS_CHANGED_HT; - - conf->flags |= IEEE80211_CONF_SUPPORT_HT_MODE; - ht_conf.ht_supported = 1; - - ht_conf.cap = req_ht_cap->cap & sband->ht_info.cap; - ht_conf.cap &= ~(IEEE80211_HT_CAP_SM_PS); - ht_conf.cap |= sband->ht_info.cap & IEEE80211_HT_CAP_SM_PS; - ht_bss_conf.primary_channel = req_bss_cap->primary_channel; - ht_bss_conf.bss_cap = req_bss_cap->bss_cap; - ht_bss_conf.bss_op_mode = req_bss_cap->bss_op_mode; - - ht_conf.ampdu_factor = req_ht_cap->ampdu_factor; - ht_conf.ampdu_density = req_ht_cap->ampdu_density; - - /* Bits 96-100 */ - tx_mcs_set_cap = sband->ht_info.supp_mcs_set[12]; - - /* configure suppoerted Tx MCS according to requested MCS - * (based in most cases on Rx capabilities of peer) and self - * Tx MCS capabilities (as defined by low level driver HW - * Tx capabilities) */ - if (!(tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_DEFINED)) - goto check_changed; - - /* Counting from 0 therfore + 1 */ - if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_RX_DIFF) - max_tx_streams = ((tx_mcs_set_cap & - IEEE80211_HT_CAP_MCS_TX_STREAMS) >> 2) + 1; - - for (i = 0; i < max_tx_streams; i++) - ht_conf.supp_mcs_set[i] = - sband->ht_info.supp_mcs_set[i] & - req_ht_cap->supp_mcs_set[i]; - - if (tx_mcs_set_cap & IEEE80211_HT_CAP_MCS_TX_UEQM) - for (i = IEEE80211_SUPP_MCS_SET_UEQM; - i < IEEE80211_SUPP_MCS_SET_LEN; i++) - ht_conf.supp_mcs_set[i] = - sband->ht_info.supp_mcs_set[i] & - req_ht_cap->supp_mcs_set[i]; - -check_changed: - /* if bss configuration changed store the new one */ - if (memcmp(&conf->ht_conf, &ht_conf, sizeof(ht_conf)) || - memcmp(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf))) { - changed |= BSS_CHANGED_HT; - memcpy(&conf->ht_conf, &ht_conf, sizeof(ht_conf)); - memcpy(&conf->ht_bss_conf, &ht_bss_conf, sizeof(ht_bss_conf)); - } -out: - return changed; + return ret; } void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, @@ -336,15 +269,18 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata, if (local->ops->bss_info_changed) local->ops->bss_info_changed(local_to_hw(local), &sdata->vif, - &sdata->bss_conf, + &sdata->vif.bss_conf, changed); } u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata) { - sdata->bss_conf.use_cts_prot = 0; - sdata->bss_conf.use_short_preamble = 0; - return BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE; + sdata->vif.bss_conf.use_cts_prot = false; + sdata->vif.bss_conf.use_short_preamble = false; + sdata->vif.bss_conf.use_short_slot = false; + return BSS_CHANGED_ERP_CTS_PROT | + BSS_CHANGED_ERP_PREAMBLE | + BSS_CHANGED_ERP_SLOT; } void ieee80211_tx_status_irqsafe(struct ieee80211_hw *hw, @@ -405,7 +341,8 @@ static void ieee80211_tasklet_handler(unsigned long data) dev_kfree_skb(skb); break ; default: - WARN_ON(1); + WARN(1, "mac80211: Packet is of unknown type %d\n", + skb->pkt_type); dev_kfree_skb(skb); break; } @@ -466,8 +403,6 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, struct sta_info *sta, struct sk_buff *skb) { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - sta->tx_filtered_count++; /* @@ -514,10 +449,9 @@ static void ieee80211_handle_filtered_frame(struct ieee80211_local *local, return; } - if (!test_sta_flags(sta, WLAN_STA_PS) && - !(info->flags & IEEE80211_TX_CTL_REQUEUE)) { + if (!test_sta_flags(sta, WLAN_STA_PS) && !skb->requeue) { /* Software retry the packet once */ - info->flags |= IEEE80211_TX_CTL_REQUEUE; + skb->requeue = 1; ieee80211_remove_tx_extra(local, sta->key, skb); dev_queue_xmit(skb); return; @@ -547,13 +481,28 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) struct ieee80211_sub_if_data *sdata; struct net_device *prev_dev = NULL; struct sta_info *sta; + int retry_count = -1, i; + + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + /* the HW cannot have attempted that rate */ + if (i >= hw->max_rates) { + info->status.rates[i].idx = -1; + info->status.rates[i].count = 0; + } + + retry_count += info->status.rates[i].count; + } + if (retry_count < 0) + retry_count = 0; rcu_read_lock(); + sband = local->hw.wiphy->bands[info->band]; + sta = sta_info_get(local, hdr->addr1); if (sta) { - if (info->status.excessive_retries && + if (!(info->flags & IEEE80211_TX_STAT_ACK) && test_sta_flags(sta, WLAN_STA_PS)) { /* * The STA is in power save mode, so assume @@ -584,12 +533,11 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) rcu_read_unlock(); return; } else { - if (info->status.excessive_retries) + if (!(info->flags & IEEE80211_TX_STAT_ACK)) sta->tx_retry_failed++; - sta->tx_retry_count += info->status.retry_count; + sta->tx_retry_count += retry_count; } - sband = local->hw.wiphy->bands[info->band]; rate_control_tx_status(local, sband, sta, skb); } @@ -610,9 +558,9 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) local->dot11TransmittedFrameCount++; if (is_multicast_ether_addr(hdr->addr1)) local->dot11MulticastTransmittedFrameCount++; - if (info->status.retry_count > 0) + if (retry_count > 0) local->dot11RetryCount++; - if (info->status.retry_count > 1) + if (retry_count > 1) local->dot11MultipleRetryCount++; } @@ -656,19 +604,30 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) rthdr->hdr.it_len = cpu_to_le16(sizeof(*rthdr)); rthdr->hdr.it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_TX_FLAGS) | - (1 << IEEE80211_RADIOTAP_DATA_RETRIES)); + (1 << IEEE80211_RADIOTAP_DATA_RETRIES) | + (1 << IEEE80211_RADIOTAP_RATE)); if (!(info->flags & IEEE80211_TX_STAT_ACK) && !is_multicast_ether_addr(hdr->addr1)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_FAIL); - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) && - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) + /* + * XXX: Once radiotap gets the bitmap reset thing the vendor + * extensions proposal contains, we can actually report + * the whole set of tries we did. + */ + if ((info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) || + (info->status.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT)) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_CTS); - else if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + else if (info->status.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) rthdr->tx_flags |= cpu_to_le16(IEEE80211_RADIOTAP_F_TX_RTS); + if (info->status.rates[0].idx >= 0 && + !(info->status.rates[0].flags & IEEE80211_TX_RC_MCS)) + rthdr->rate = sband->bitrates[ + info->status.rates[0].idx].bitrate / 5; - rthdr->data_retries = info->status.retry_count; + /* for now report the total retry_count */ + rthdr->data_retries = retry_count; /* XXX: is this sufficient for BPF? */ skb_set_mac_header(skb, 0); @@ -753,20 +712,30 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, BUG_ON(!ops->configure_filter); local->ops = ops; - local->hw.queues = 1; /* default */ - + /* set up some defaults */ + local->hw.queues = 1; + local->hw.max_rates = 1; local->rts_threshold = IEEE80211_MAX_RTS_THRESHOLD; local->fragmentation_threshold = IEEE80211_MAX_FRAG_THRESHOLD; - local->short_retry_limit = 7; - local->long_retry_limit = 4; - local->hw.conf.radio_enabled = 1; + local->hw.conf.long_frame_max_tx_count = 4; + local->hw.conf.short_frame_max_tx_count = 7; + local->hw.conf.radio_enabled = true; INIT_LIST_HEAD(&local->interfaces); spin_lock_init(&local->key_lock); + spin_lock_init(&local->queue_stop_reason_lock); + INIT_DELAYED_WORK(&local->scan_work, ieee80211_scan_work); + INIT_WORK(&local->dynamic_ps_enable_work, + ieee80211_dynamic_ps_enable_work); + INIT_WORK(&local->dynamic_ps_disable_work, + ieee80211_dynamic_ps_disable_work); + setup_timer(&local->dynamic_ps_timer, + ieee80211_dynamic_ps_timer, (unsigned long) local); + sta_info_init(local); tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending, @@ -788,7 +757,6 @@ EXPORT_SYMBOL(ieee80211_alloc_hw); int ieee80211_register_hw(struct ieee80211_hw *hw) { struct ieee80211_local *local = hw_to_local(hw); - const char *name; int result; enum ieee80211_band band; struct net_device *mdev; @@ -853,8 +821,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) mdev->header_ops = &ieee80211_header_ops; mdev->set_multicast_list = ieee80211_master_set_multicast_list; - name = wiphy_dev(local->hw.wiphy)->driver->name; - local->hw.workqueue = create_freezeable_workqueue(name); + local->hw.workqueue = + create_freezeable_workqueue(wiphy_name(local->hw.wiphy)); if (!local->hw.workqueue) { result = -ENOMEM; goto fail_workqueue; @@ -921,12 +889,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) local->mdev->select_queue = ieee80211_select_queue; - /* add one default STA interface */ - result = ieee80211_if_add(local, "wlan%d", NULL, - NL80211_IFTYPE_STATION, NULL); - if (result) - printk(KERN_WARNING "%s: Failed to add default virtual iface\n", - wiphy_name(local->hw.wiphy)); + /* add one default STA interface if supported */ + if (local->hw.wiphy->interface_modes & BIT(NL80211_IFTYPE_STATION)) { + result = ieee80211_if_add(local, "wlan%d", NULL, + NL80211_IFTYPE_STATION, NULL); + if (result) + printk(KERN_WARNING "%s: Failed to add default virtual iface\n", + wiphy_name(local->hw.wiphy)); + } rtnl_unlock(); @@ -1013,7 +983,7 @@ static int __init ieee80211_init(void) BUILD_BUG_ON(sizeof(struct ieee80211_tx_info) > sizeof(skb->cb)); BUILD_BUG_ON(offsetof(struct ieee80211_tx_info, driver_data) + - IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); + IEEE80211_TX_INFO_DRIVER_DATA_SIZE > sizeof(skb->cb)); ret = rc80211_minstrel_init(); if (ret) diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c index 8013277924f2d75fca8acca678cbebb079c0f8a4..82f568e943657c2c5114ef111f57e53292011edc 100644 --- a/net/mac80211/mesh.c +++ b/net/mac80211/mesh.c @@ -238,7 +238,7 @@ void mesh_mgmt_ies_add(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata) pos = skb_put(skb, 21); *pos++ = WLAN_EID_MESH_CONFIG; - *pos++ = MESH_CFG_LEN; + *pos++ = IEEE80211_MESH_CONFIG_LEN; /* Version */ *pos++ = 1; @@ -473,7 +473,7 @@ static void ieee80211_mesh_rx_bcn_presp(struct ieee80211_sub_if_data *sdata, size_t len, struct ieee80211_rx_status *rx_status) { - struct ieee80211_local *local= sdata->local; + struct ieee80211_local *local = sdata->local; struct ieee802_11_elems elems; struct ieee80211_channel *channel; u64 supp_rates = 0; diff --git a/net/mac80211/mesh.h b/net/mac80211/mesh.h index e10471c6ba42457894ebca93db6a7f8c9376323f..c197ab545e54a05e56b46f946d1d2bb8e3f5e5e9 100644 --- a/net/mac80211/mesh.h +++ b/net/mac80211/mesh.h @@ -145,9 +145,6 @@ struct mesh_rmc { }; -/* Mesh IEs constants */ -#define MESH_CFG_LEN 19 - /* * MESH_CFG_COMP_LEN Includes: * - Active path selection protocol ID. @@ -157,7 +154,7 @@ struct mesh_rmc { * Does not include mesh capabilities, which may vary across nodes in the same * mesh */ -#define MESH_CFG_CMP_LEN 17 +#define MESH_CFG_CMP_LEN (IEEE80211_MESH_CONFIG_LEN - 2) /* Default values, timeouts in ms */ #define MESH_TTL 5 diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c index 501c7831adb4469627c8b7cd0a8c3b067478ff3b..71fe609612303a2d9d6fc11e263845df26438256 100644 --- a/net/mac80211/mesh_hwmp.c +++ b/net/mac80211/mesh_hwmp.c @@ -218,12 +218,16 @@ static u32 airtime_link_metric_get(struct ieee80211_local *local, if (sta->fail_avg >= 100) return MAX_METRIC; + + if (sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS) + 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->last_txrate_idx].bitrate; + rate = sband->bitrates[sta->last_tx_rate.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) ; @@ -759,7 +763,6 @@ enddiscovery: * * @skb: 802.11 frame to be sent * @sdata: network subif the frame will be sent through - * @fwd_frame: true if this frame was originally from a different host * * 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 diff --git a/net/mac80211/mesh_plink.c b/net/mac80211/mesh_plink.c index faac101c0f85a2b7001dfc42c068d5e6140557c3..929ba542fd7294fb812983384552cb2fbb869076 100644 --- a/net/mac80211/mesh_plink.c +++ b/net/mac80211/mesh_plink.c @@ -257,9 +257,6 @@ static void mesh_plink_timer(unsigned long data) struct sta_info *sta; __le16 llid, plid, reason; 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 @@ -274,8 +271,8 @@ static void mesh_plink_timer(unsigned long data) spin_unlock_bh(&sta->lock); return; } - mpl_dbg("Mesh plink timer for %s fired on state %d\n", - print_mac(mac, sta->sta.addr), sta->plink_state); + mpl_dbg("Mesh plink timer for %pM fired on state %d\n", + sta->sta.addr, sta->plink_state); reason = 0; llid = sta->llid; plid = sta->plid; @@ -287,9 +284,9 @@ static void mesh_plink_timer(unsigned long data) /* 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->sta.addr), - sta->plink_retries, sta->plink_timeout); + mpl_dbg("Mesh plink for %pM (retry, timeout): %d %d\n", + sta->sta.addr, sta->plink_retries, + sta->plink_timeout); get_random_bytes(&rand, sizeof(u32)); sta->plink_timeout = sta->plink_timeout + rand % sta->plink_timeout; @@ -337,9 +334,6 @@ 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->lock); get_random_bytes(&llid, 2); @@ -351,8 +345,8 @@ int mesh_plink_open(struct sta_info *sta) sta->plink_state = PLINK_OPN_SNT; mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata)); spin_unlock_bh(&sta->lock); - mpl_dbg("Mesh plink: starting establishment with %s\n", - print_mac(mac, sta->sta.addr)); + mpl_dbg("Mesh plink: starting establishment with %pM\n", + sta->sta.addr); return mesh_plink_frame_tx(sdata, PLINK_OPEN, sta->sta.addr, llid, 0, 0); @@ -360,10 +354,6 @@ int mesh_plink_open(struct sta_info *sta) void mesh_plink_block(struct sta_info *sta) { -#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG - DECLARE_MAC_BUF(mac); -#endif - spin_lock_bh(&sta->lock); __mesh_plink_deactivate(sta); sta->plink_state = PLINK_BLOCKED; @@ -374,12 +364,8 @@ 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->sta.addr)); + mpl_dbg("Mesh plink: closing link with %pM\n", sta->sta.addr); spin_lock_bh(&sta->lock); sta->reason = cpu_to_le16(MESH_LINK_CANCELLED); reason = sta->reason; @@ -417,9 +403,6 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m u8 ie_len; u8 *baseaddr; __le16 plid, llid, reason; -#ifdef CONFIG_MAC80211_VERBOSE_MPL_DEBUG - DECLARE_MAC_BUF(mac); -#endif /* need action_code, aux */ if (len < IEEE80211_MIN_ACTION_SIZE + 3) @@ -557,10 +540,10 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m } } - 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); + mpl_dbg("Mesh plink (peer, state, llid, plid, event): %pM %d %d %d %d\n", + 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 */ @@ -660,8 +643,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); spin_unlock_bh(&sta->lock); - mpl_dbg("Mesh plink with %s ESTABLISHED\n", - print_mac(mac, sta->sta.addr)); + mpl_dbg("Mesh plink with %pM ESTABLISHED\n", + sta->sta.addr); break; default: spin_unlock_bh(&sta->lock); @@ -693,8 +676,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m sta->plink_state = PLINK_ESTAB; mesh_plink_inc_estab_count(sdata); spin_unlock_bh(&sta->lock); - mpl_dbg("Mesh plink with %s ESTABLISHED\n", - print_mac(mac, sta->sta.addr)); + mpl_dbg("Mesh plink with %pM ESTABLISHED\n", + sta->sta.addr); mesh_plink_frame_tx(sdata, PLINK_CONFIRM, sta->sta.addr, llid, plid, 0); break; diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c index 409bb771623671c8274fd0e25683665b13e53fdd..5ba721b6a399ddadefc0924ec50ab5531efd1e5c 100644 --- a/net/mac80211/mlme.c +++ b/net/mac80211/mlme.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include @@ -236,7 +235,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sk_buff *skb; struct ieee80211_mgmt *mgmt; - u8 *pos, *ies, *ht_add_ie; + u8 *pos, *ies, *ht_ie; int i, len, count, rates_len, supp_rates_len; u16 capab; struct ieee80211_bss *bss; @@ -310,7 +309,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | IEEE80211_STYPE_ASSOC_REQ); mgmt->u.assoc_req.capab_info = cpu_to_le16(capab); - mgmt->u.reassoc_req.listen_interval = + mgmt->u.assoc_req.listen_interval = cpu_to_le16(local->hw.conf.listen_interval); } @@ -393,24 +392,25 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, /* wmm support is a must to HT */ if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) && - sband->ht_info.ht_supported && - (ht_add_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_EXTRA_INFO))) { - struct ieee80211_ht_addt_info *ht_add_info = - (struct ieee80211_ht_addt_info *)ht_add_ie; - u16 cap = sband->ht_info.cap; + sband->ht_cap.ht_supported && + (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) && + ht_ie[1] >= sizeof(struct ieee80211_ht_info)) { + struct ieee80211_ht_info *ht_info = + (struct ieee80211_ht_info *)(ht_ie + 2); + u16 cap = sband->ht_cap.cap; __le16 tmp; u32 flags = local->hw.conf.channel->flags; - switch (ht_add_info->ht_param & IEEE80211_HT_IE_CHA_SEC_OFFSET) { - case IEEE80211_HT_IE_CHA_SEC_ABOVE: + switch (ht_info->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) { + case IEEE80211_HT_PARAM_CHA_SEC_ABOVE: if (flags & IEEE80211_CHAN_NO_FAT_ABOVE) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; cap &= ~IEEE80211_HT_CAP_SGI_40; } break; - case IEEE80211_HT_IE_CHA_SEC_BELOW: + case IEEE80211_HT_PARAM_CHA_SEC_BELOW: if (flags & IEEE80211_CHAN_NO_FAT_BELOW) { - cap &= ~IEEE80211_HT_CAP_SUP_WIDTH; + cap &= ~IEEE80211_HT_CAP_SUP_WIDTH_20_40; cap &= ~IEEE80211_HT_CAP_SGI_40; } break; @@ -424,9 +424,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata, memcpy(pos, &tmp, sizeof(u16)); pos += sizeof(u16); /* 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); + *pos++ = sband->ht_cap.ampdu_factor | + (sband->ht_cap.ampdu_density << 2); + memcpy(pos, &sband->ht_cap.mcs, sizeof(sband->ht_cap.mcs)); } kfree(ifsta->assocreq_ies); @@ -568,25 +568,35 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local, } } -static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata, - bool use_protection, - bool use_short_preamble) +static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, + u16 capab, bool erp_valid, u8 erp) { - struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; + struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; #ifdef CONFIG_MAC80211_VERBOSE_DEBUG struct ieee80211_if_sta *ifsta = &sdata->u.sta; - DECLARE_MAC_BUF(mac); #endif u32 changed = 0; + bool use_protection; + bool use_short_preamble; + bool use_short_slot; + + if (erp_valid) { + use_protection = (erp & WLAN_ERP_USE_PROTECTION) != 0; + use_short_preamble = (erp & WLAN_ERP_BARKER_PREAMBLE) == 0; + } else { + use_protection = false; + use_short_preamble = !!(capab & WLAN_CAPABILITY_SHORT_PREAMBLE); + } + + use_short_slot = !!(capab & WLAN_CAPABILITY_SHORT_SLOT_TIME); if (use_protection != bss_conf->use_cts_prot) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) { - printk(KERN_DEBUG "%s: CTS protection %s (BSSID=" - "%s)\n", + printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n", sdata->dev->name, use_protection ? "enabled" : "disabled", - print_mac(mac, ifsta->bssid)); + ifsta->bssid); } #endif bss_conf->use_cts_prot = use_protection; @@ -597,40 +607,28 @@ static u32 ieee80211_handle_protect_preamb(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG if (net_ratelimit()) { printk(KERN_DEBUG "%s: switched to %s barker preamble" - " (BSSID=%s)\n", + " (BSSID=%pM)\n", sdata->dev->name, use_short_preamble ? "short" : "long", - print_mac(mac, ifsta->bssid)); + ifsta->bssid); } #endif bss_conf->use_short_preamble = use_short_preamble; changed |= BSS_CHANGED_ERP_PREAMBLE; } - return changed; -} - -static u32 ieee80211_handle_erp_ie(struct ieee80211_sub_if_data *sdata, - u8 erp_value) -{ - bool use_protection = (erp_value & WLAN_ERP_USE_PROTECTION) != 0; - bool use_short_preamble = (erp_value & WLAN_ERP_BARKER_PREAMBLE) == 0; - - return ieee80211_handle_protect_preamb(sdata, - use_protection, use_short_preamble); -} - -static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata, - struct ieee80211_bss *bss) -{ - u32 changed = 0; - - if (bss->has_erp_value) - changed |= ieee80211_handle_erp_ie(sdata, bss->erp_value); - else { - u16 capab = bss->capability; - changed |= ieee80211_handle_protect_preamb(sdata, false, - (capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0); + if (use_short_slot != bss_conf->use_short_slot) { +#ifdef CONFIG_MAC80211_VERBOSE_DEBUG + if (net_ratelimit()) { + printk(KERN_DEBUG "%s: switched to %s slot" + " (BSSID=%s)\n", + sdata->dev->name, + use_short_slot ? "short" : "long", + ifsta->bssid); + } +#endif + bss_conf->use_short_slot = use_short_slot; + changed |= BSS_CHANGED_ERP_SLOT; } return changed; @@ -701,14 +699,15 @@ static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata, static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, - struct ieee80211_if_sta *ifsta) + struct ieee80211_if_sta *ifsta, + u32 bss_info_changed) { struct ieee80211_local *local = sdata->local; struct ieee80211_conf *conf = &local_to_hw(local)->conf; - u32 changed = BSS_CHANGED_ASSOC; struct ieee80211_bss *bss; + bss_info_changed |= BSS_CHANGED_ASSOC; ifsta->flags |= IEEE80211_STA_ASSOCIATED; if (sdata->vif.type != NL80211_IFTYPE_STATION) @@ -719,22 +718,16 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ifsta->ssid, ifsta->ssid_len); if (bss) { /* set timing information */ - sdata->bss_conf.beacon_int = bss->beacon_int; - sdata->bss_conf.timestamp = bss->timestamp; - sdata->bss_conf.dtim_period = bss->dtim_period; + sdata->vif.bss_conf.beacon_int = bss->beacon_int; + sdata->vif.bss_conf.timestamp = bss->timestamp; + sdata->vif.bss_conf.dtim_period = bss->dtim_period; - changed |= ieee80211_handle_bss_capability(sdata, bss); + bss_info_changed |= ieee80211_handle_bss_capability(sdata, + bss->capability, bss->has_erp_value, bss->erp_value); ieee80211_rx_bss_put(local, bss); } - if (conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { - changed |= BSS_CHANGED_HT; - sdata->bss_conf.assoc_ht = 1; - sdata->bss_conf.ht_conf = &conf->ht_conf; - sdata->bss_conf.ht_bss_conf = &conf->ht_bss_conf; - } - ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET; memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN); ieee80211_sta_send_associnfo(sdata, ifsta); @@ -742,14 +735,25 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, ifsta->last_probe = jiffies; ieee80211_led_assoc(local, 1); - sdata->bss_conf.assoc = 1; + sdata->vif.bss_conf.assoc = 1; /* * For now just always ask the driver to update the basic rateset * when we have associated, we aren't checking whether it actually * changed or not. */ - changed |= BSS_CHANGED_BASIC_RATES; - ieee80211_bss_info_change_notify(sdata, changed); + bss_info_changed |= BSS_CHANGED_BASIC_RATES; + ieee80211_bss_info_change_notify(sdata, bss_info_changed); + + if (local->powersave) { + if (local->dynamic_ps_timeout > 0) + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(local->dynamic_ps_timeout)); + else { + conf->flags |= IEEE80211_CONF_PS; + ieee80211_hw_config(local, + IEEE80211_CONF_CHANGE_PS); + } + } netif_tx_start_all_queues(sdata->dev); netif_carrier_on(sdata->dev); @@ -760,18 +764,17 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata, static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_sta *ifsta) { - DECLARE_MAC_BUF(mac); - ifsta->direct_probe_tries++; if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: direct probe to AP %s timed out\n", - sdata->dev->name, print_mac(mac, ifsta->bssid)); + printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n", + sdata->dev->name, ifsta->bssid); ifsta->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_sta_send_apinfo(sdata, ifsta); return; } - printk(KERN_DEBUG "%s: direct probe to AP %s try %d\n", - sdata->dev->name, print_mac(mac, ifsta->bssid), + printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n", + sdata->dev->name, ifsta->bssid, ifsta->direct_probe_tries); ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE; @@ -791,33 +794,36 @@ static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata, static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_sta *ifsta) { - DECLARE_MAC_BUF(mac); - ifsta->auth_tries++; if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) { - printk(KERN_DEBUG "%s: authentication with AP %s" + printk(KERN_DEBUG "%s: authentication with AP %pM" " timed out\n", - sdata->dev->name, print_mac(mac, ifsta->bssid)); + sdata->dev->name, ifsta->bssid); ifsta->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_sta_send_apinfo(sdata, ifsta); return; } ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE; - printk(KERN_DEBUG "%s: authenticate with AP %s\n", - sdata->dev->name, print_mac(mac, ifsta->bssid)); + printk(KERN_DEBUG "%s: authenticate with AP %pM\n", + sdata->dev->name, ifsta->bssid); ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0); mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT); } +/* + * The disassoc 'reason' argument can be either our own reason + * if self disconnected or a reason code from the AP. + */ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_sta *ifsta, bool deauth, bool self_disconnected, u16 reason) { struct ieee80211_local *local = sdata->local; struct sta_info *sta; - u32 changed = BSS_CHANGED_ASSOC; + u32 changed = 0, config_changed = 0; rcu_read_lock(); @@ -851,21 +857,40 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata, ifsta->flags &= ~IEEE80211_STA_ASSOCIATED; changed |= ieee80211_reset_erp_info(sdata); - if (sdata->bss_conf.assoc_ht) - changed |= BSS_CHANGED_HT; - - sdata->bss_conf.assoc_ht = 0; - sdata->bss_conf.ht_conf = NULL; - sdata->bss_conf.ht_bss_conf = NULL; - ieee80211_led_assoc(local, 0); - sdata->bss_conf.assoc = 0; + changed |= BSS_CHANGED_ASSOC; + sdata->vif.bss_conf.assoc = false; ieee80211_sta_send_apinfo(sdata, ifsta); - if (self_disconnected) + if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) ifsta->state = IEEE80211_STA_MLME_DISABLED; + rcu_read_unlock(); + + local->hw.conf.ht.enabled = false; + local->oper_channel_type = NL80211_CHAN_NO_HT; + config_changed |= IEEE80211_CONF_CHANGE_HT; + + del_timer_sync(&local->dynamic_ps_timer); + cancel_work_sync(&local->dynamic_ps_enable_work); + + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->hw.conf.flags &= ~IEEE80211_CONF_PS; + config_changed |= IEEE80211_CONF_CHANGE_PS; + } + + ieee80211_hw_config(local, config_changed); + ieee80211_bss_info_change_notify(sdata, changed); + + rcu_read_lock(); + + sta = sta_info_get(local, ifsta->bssid); + if (!sta) { + rcu_read_unlock(); + return; + } + sta_info_unlink(&sta); rcu_read_unlock(); @@ -914,20 +939,19 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata, static void ieee80211_associate(struct ieee80211_sub_if_data *sdata, struct ieee80211_if_sta *ifsta) { - DECLARE_MAC_BUF(mac); - ifsta->assoc_tries++; if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) { - printk(KERN_DEBUG "%s: association with AP %s" + printk(KERN_DEBUG "%s: association with AP %pM" " timed out\n", - sdata->dev->name, print_mac(mac, ifsta->bssid)); + sdata->dev->name, ifsta->bssid); ifsta->state = IEEE80211_STA_MLME_DISABLED; + ieee80211_sta_send_apinfo(sdata, ifsta); return; } ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; - printk(KERN_DEBUG "%s: associate with AP %s\n", - sdata->dev->name, print_mac(mac, ifsta->bssid)); + printk(KERN_DEBUG "%s: associate with AP %pM\n", + sdata->dev->name, ifsta->bssid); if (ieee80211_privacy_mismatch(sdata, ifsta)) { printk(KERN_DEBUG "%s: mismatch in privacy configuration and " "mixed-cell disabled - abort association\n", sdata->dev->name); @@ -947,7 +971,6 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sta_info *sta; int disassoc; - DECLARE_MAC_BUF(mac); /* TODO: start monitoring current AP signal quality and number of * missed beacons. Scan other channels every now and then and search @@ -960,8 +983,8 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, sta = sta_info_get(local, ifsta->bssid); if (!sta) { - printk(KERN_DEBUG "%s: No STA entry for own AP %s\n", - sdata->dev->name, print_mac(mac, ifsta->bssid)); + printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n", + sdata->dev->name, ifsta->bssid); disassoc = 1; } else { disassoc = 0; @@ -969,9 +992,9 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata, sta->last_rx + IEEE80211_MONITORING_INTERVAL)) { if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) { printk(KERN_DEBUG "%s: No ProbeResp from " - "current AP %s - assume out of " + "current AP %pM - assume out of " "range\n", - sdata->dev->name, print_mac(mac, ifsta->bssid)); + sdata->dev->name, ifsta->bssid); disassoc = 1; } else ieee80211_send_probe_req(sdata, ifsta->bssid, @@ -1032,7 +1055,6 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata, size_t len) { u16 auth_alg, auth_transaction, status_code; - DECLARE_MAC_BUF(mac); if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE && sdata->vif.type != NL80211_IFTYPE_ADHOC) @@ -1125,7 +1147,6 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, size_t len) { u16 reason_code; - DECLARE_MAC_BUF(mac); if (len < 24 + 2) return; @@ -1136,7 +1157,8 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); if (ifsta->flags & IEEE80211_STA_AUTHENTICATED) - printk(KERN_DEBUG "%s: deauthenticated\n", sdata->dev->name); + printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n", + sdata->dev->name, reason_code); if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE || ifsta->state == IEEE80211_STA_MLME_ASSOCIATE || @@ -1157,7 +1179,6 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, size_t len) { u16 reason_code; - DECLARE_MAC_BUF(mac); if (len < 24 + 2) return; @@ -1168,7 +1189,8 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); if (ifsta->flags & IEEE80211_STA_ASSOCIATED) - printk(KERN_DEBUG "%s: disassociated\n", sdata->dev->name); + printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n", + sdata->dev->name, reason_code); if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) { ifsta->state = IEEE80211_STA_MLME_ASSOCIATE; @@ -1176,7 +1198,7 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, IEEE80211_RETRY_AUTH_INTERVAL); } - ieee80211_set_disassoc(sdata, ifsta, false, false, 0); + ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code); } @@ -1192,11 +1214,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, u64 rates, basic_rates; u16 capab_info, status_code, aid; struct ieee802_11_elems elems; - struct ieee80211_bss_conf *bss_conf = &sdata->bss_conf; + struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf; u8 *pos; + u32 changed = 0; int i, j; - DECLARE_MAC_BUF(mac); - bool have_higher_than_11mbit = false; + bool have_higher_than_11mbit = false, newsta = false; + u16 ap_ht_cap_flags; /* AssocResp and ReassocResp have identical structure, so process both * of them in this function. */ @@ -1214,9 +1237,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, status_code = le16_to_cpu(mgmt->u.assoc_resp.status_code); aid = le16_to_cpu(mgmt->u.assoc_resp.aid); - printk(KERN_DEBUG "%s: RX %sssocResp from %s (capab=0x%x " + printk(KERN_DEBUG "%s: RX %sssocResp from %pM (capab=0x%x " "status=%d aid=%d)\n", - sdata->dev->name, reassoc ? "Rea" : "A", print_mac(mac, mgmt->sa), + sdata->dev->name, reassoc ? "Rea" : "A", mgmt->sa, capab_info, status_code, (u16)(aid & ~(BIT(15) | BIT(14)))); if (status_code != WLAN_STATUS_SUCCESS) { @@ -1259,7 +1282,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, sta = sta_info_get(local, ifsta->bssid); if (!sta) { struct ieee80211_bss *bss; - int err; + + newsta = true; sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC); if (!sta) { @@ -1278,13 +1302,6 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, ieee80211_rx_bss_put(local, bss); } - err = sta_info_insert(sta); - if (err) { - printk(KERN_DEBUG "%s: failed to insert STA entry for" - " the AP (error %d)\n", sdata->dev->name, err); - rcu_read_unlock(); - return; - } /* update new sta with its last rx activity */ sta->last_rx = jiffies; } @@ -1308,34 +1325,40 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, for (i = 0; i < elems.supp_rates_len; i++) { int rate = (elems.supp_rates[i] & 0x7f) * 5; + bool is_basic = !!(elems.supp_rates[i] & 0x80); if (rate > 110) have_higher_than_11mbit = true; for (j = 0; j < sband->n_bitrates; j++) { - if (sband->bitrates[j].bitrate == rate) + if (sband->bitrates[j].bitrate == rate) { rates |= BIT(j); - if (elems.supp_rates[i] & 0x80) - basic_rates |= BIT(j); + if (is_basic) + basic_rates |= BIT(j); + break; + } } } for (i = 0; i < elems.ext_supp_rates_len; i++) { int rate = (elems.ext_supp_rates[i] & 0x7f) * 5; + bool is_basic = !!(elems.supp_rates[i] & 0x80); if (rate > 110) have_higher_than_11mbit = true; for (j = 0; j < sband->n_bitrates; j++) { - if (sband->bitrates[j].bitrate == rate) + if (sband->bitrates[j].bitrate == rate) { rates |= BIT(j); - if (elems.ext_supp_rates[i] & 0x80) - basic_rates |= BIT(j); + if (is_basic) + basic_rates |= BIT(j); + break; + } } } sta->sta.supp_rates[local->hw.conf.channel->band] = rates; - sdata->bss_conf.basic_rates = basic_rates; + sdata->vif.bss_conf.basic_rates = basic_rates; /* cf. IEEE 802.11 9.2.12 */ if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ && @@ -1344,31 +1367,43 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata, else sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE; - if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param && - (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) { - struct ieee80211_ht_bss_info bss_info; - ieee80211_ht_cap_ie_to_ht_info( - elems.ht_cap_elem, &sta->sta.ht_info); - ieee80211_ht_addt_info_ie_to_ht_bss_info( - elems.ht_info_elem, &bss_info); - ieee80211_handle_ht(local, 1, &sta->sta.ht_info, &bss_info); - } + if (elems.ht_cap_elem) + ieee80211_ht_cap_ie_to_sta_ht_cap(sband, + elems.ht_cap_elem, &sta->sta.ht_cap); + + ap_ht_cap_flags = sta->sta.ht_cap.cap; rate_control_rate_init(sta); - if (elems.wmm_param) { + if (elems.wmm_param) set_sta_flags(sta, WLAN_STA_WME); - rcu_read_unlock(); + + if (newsta) { + int err = sta_info_insert(sta); + if (err) { + printk(KERN_DEBUG "%s: failed to insert STA entry for" + " the AP (error %d)\n", sdata->dev->name, err); + rcu_read_unlock(); + return; + } + } + + rcu_read_unlock(); + + if (elems.wmm_param) ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, elems.wmm_param_len); - } else - rcu_read_unlock(); + + if (elems.ht_info_elem && elems.wmm_param && + (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) + changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, + ap_ht_cap_flags); /* set AID and assoc capability, * ieee80211_set_associated() will tell the driver */ bss_conf->aid = aid; bss_conf->assoc_capability = capab_info; - ieee80211_set_associated(sdata, ifsta); + ieee80211_set_associated(sdata, ifsta, changed); ieee80211_associated(sdata, ifsta); } @@ -1386,6 +1421,13 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, struct ieee80211_supported_band *sband; union iwreq_data wrqu; + skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); + if (!skb) { + printk(KERN_DEBUG "%s: failed to allocate buffer for probe " + "response\n", sdata->dev->name); + return -ENOMEM; + } + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; /* Remove possible STA entries from other IBSS networks. */ @@ -1411,63 +1453,62 @@ static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata, return res; /* Build IBSS probe response */ - skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400); - if (skb) { - 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 = cpu_to_le16(IEEE80211_FTYPE_MGMT | - IEEE80211_STYPE_PROBE_RESP); - memset(mgmt->da, 0xff, ETH_ALEN); - memcpy(mgmt->sa, sdata->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.timestamp = cpu_to_le64(bss->timestamp); - 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); + skb_reserve(skb, local->hw.extra_tx_headroom); - 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); - } + mgmt = (struct ieee80211_mgmt *) + skb_put(skb, 24 + sizeof(mgmt->u.beacon)); + memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon)); + mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | + IEEE80211_STYPE_PROBE_RESP); + memset(mgmt->da, 0xff, ETH_ALEN); + memcpy(mgmt->sa, sdata->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.timestamp = cpu_to_le64(bss->timestamp); + mgmt->u.beacon.capab_info = cpu_to_le16(bss->capability); - 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; + pos = skb_put(skb, 2 + ifsta->ssid_len); + *pos++ = WLAN_EID_SSID; + *pos++ = ifsta->ssid_len; + memcpy(pos, ifsta->ssid, ifsta->ssid_len); - 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); - } + 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); - ifsta->probe_resp = skb; + 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); + } + + 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; - ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); + 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); } + ifsta->probe_resp = skb; + + ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON); + + rates = 0; sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; for (i = 0; i < bss->supp_rates_len; i++) { @@ -1507,8 +1548,6 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, u64 beacon_timestamp, rx_timestamp; u64 supp_rates = 0; enum ieee80211_band band = rx_status->band; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); if (elems->ds_params && elems->ds_params_len == 1) freq = ieee80211_channel_to_frequency(elems->ds_params[0]); @@ -1538,17 +1577,16 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_IBSS_DEBUG if (sta->sta.supp_rates[band] != prev_rates) printk(KERN_DEBUG "%s: updated supp_rates set " - "for %s based on beacon info (0x%llx | " + "for %pM based on beacon info (0x%llx | " "0x%llx -> 0x%llx)\n", sdata->dev->name, - print_mac(mac, sta->sta.addr), + sta->sta.addr, (unsigned long long) prev_rates, (unsigned long long) supp_rates, (unsigned long long) sta->sta.supp_rates[band]); #endif } else { - ieee80211_ibss_add_sta(sdata, NULL, mgmt->bssid, - mgmt->sa, supp_rates); + ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); } rcu_read_unlock(); @@ -1595,8 +1633,13 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, * 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[band]-> + int rate; + if (rx_status->flag & RX_FLAG_HT) { + rate = 65; /* TODO: HT rates */ + } else { + rate = local->hw.wiphy->bands[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 */ @@ -1605,10 +1648,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, /* 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), + printk(KERN_DEBUG "RX beacon SA=%pM BSSID=" + "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n", + mgmt->sa, mgmt->bssid, (unsigned long long)rx_timestamp, (unsigned long long)beacon_timestamp, (unsigned long long)(rx_timestamp - beacon_timestamp), @@ -1617,13 +1659,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata, if (beacon_timestamp > rx_timestamp) { #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: beacon TSF higher than " - "local TSF - IBSS merge with BSSID %s\n", - sdata->dev->name, print_mac(mac, mgmt->bssid)); + "local TSF - IBSS merge with BSSID %pM\n", + sdata->dev->name, mgmt->bssid); #endif ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss); - ieee80211_ibss_add_sta(sdata, NULL, - mgmt->bssid, mgmt->sa, - supp_rates); + ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates); } } @@ -1671,8 +1711,9 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, size_t baselen; struct ieee802_11_elems elems; struct ieee80211_local *local = sdata->local; - struct ieee80211_conf *conf = &local->hw.conf; u32 changed = 0; + bool erp_valid; + u8 erp_value = 0; /* Process beacon from the current BSS */ baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt; @@ -1694,22 +1735,49 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param, elems.wmm_param_len); - if (elems.erp_info && elems.erp_info_len >= 1) - changed |= ieee80211_handle_erp_ie(sdata, elems.erp_info[0]); - else { - u16 capab = le16_to_cpu(mgmt->u.beacon.capab_info); - changed |= ieee80211_handle_protect_preamb(sdata, false, - (capab & WLAN_CAPABILITY_SHORT_PREAMBLE) != 0); + + if (elems.erp_info && elems.erp_info_len >= 1) { + erp_valid = true; + erp_value = elems.erp_info[0]; + } else { + erp_valid = false; } + changed |= ieee80211_handle_bss_capability(sdata, + le16_to_cpu(mgmt->u.beacon.capab_info), + erp_valid, erp_value); + + + if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) { + struct sta_info *sta; + struct ieee80211_supported_band *sband; + u16 ap_ht_cap_flags; + + rcu_read_lock(); - if (elems.ht_cap_elem && elems.ht_info_elem && - elems.wmm_param && conf->flags & IEEE80211_CONF_SUPPORT_HT_MODE) { - struct ieee80211_ht_bss_info bss_info; + sta = sta_info_get(local, ifsta->bssid); + if (!sta) { + rcu_read_unlock(); + return; + } + + sband = local->hw.wiphy->bands[local->hw.conf.channel->band]; - ieee80211_ht_addt_info_ie_to_ht_bss_info( - elems.ht_info_elem, &bss_info); - changed |= ieee80211_handle_ht(local, 1, &conf->ht_conf, - &bss_info); + ieee80211_ht_cap_ie_to_sta_ht_cap(sband, + elems.ht_cap_elem, &sta->sta.ht_cap); + + ap_ht_cap_flags = sta->sta.ht_cap.cap; + + rcu_read_unlock(); + + changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem, + ap_ht_cap_flags); + } + + if (elems.country_elem) { + /* Note we are only reviewing this on beacons + * for the BSSID we are associated to */ + regulatory_hint_11d(local->hw.wiphy, + elems.country_elem, elems.country_elem_len); } ieee80211_bss_info_change_notify(sdata, changed); @@ -1727,11 +1795,6 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb; struct ieee80211_mgmt *resp; u8 *pos, *end; - DECLARE_MAC_BUF(mac); -#ifdef CONFIG_MAC80211_IBSS_DEBUG - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); -#endif if (sdata->vif.type != NL80211_IFTYPE_ADHOC || ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED || @@ -1744,10 +1807,10 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, tx_last_beacon = 1; #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: RX ProbeReq SA=%s DA=%s BSSID=" - "%s (tx_last_beacon=%d)\n", - sdata->dev->name, print_mac(mac, mgmt->sa), print_mac(mac2, mgmt->da), - print_mac(mac3, mgmt->bssid), tx_last_beacon); + printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM" + " (tx_last_beacon=%d)\n", + sdata->dev->name, mgmt->sa, mgmt->da, + mgmt->bssid, tx_last_beacon); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (!tx_last_beacon) @@ -1763,8 +1826,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, pos + 2 + pos[1] > end) { #ifdef CONFIG_MAC80211_IBSS_DEBUG printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq " - "from %s\n", - sdata->dev->name, print_mac(mac, mgmt->sa)); + "from %pM\n", + sdata->dev->name, mgmt->sa); #endif return; } @@ -1783,8 +1846,8 @@ static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata, resp = (struct ieee80211_mgmt *) skb->data; memcpy(resp->da, mgmt->sa, ETH_ALEN); #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: Sending ProbeResp to %s\n", - sdata->dev->name, print_mac(mac, resp->da)); + printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n", + sdata->dev->name, resp->da); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ ieee80211_tx_skb(sdata, skb, 0); } @@ -1972,7 +2035,7 @@ static int ieee80211_sta_match_ssid(struct ieee80211_if_sta *ifsta, } } - if (hidden_ssid && ifsta->ssid_len == ssid_len) + if (hidden_ssid && (ifsta->ssid_len == ssid_len || ssid_len == 0)) return 1; if (ssid_len == 1 && ssid[0] == ' ') @@ -1990,7 +2053,6 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, u8 bssid[ETH_ALEN], *pos; int i; int ret; - DECLARE_MAC_BUF(mac); #if 0 /* Easier testing, use fixed BSSID. */ @@ -2006,8 +2068,8 @@ static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata, bssid[0] |= 0x02; #endif - printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %s\n", - sdata->dev->name, print_mac(mac, bssid)); + printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n", + sdata->dev->name, bssid); bss = ieee80211_rx_bss_add(local, bssid, local->hw.conf.channel->center_freq, @@ -2050,8 +2112,6 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, int found = 0; u8 bssid[ETH_ALEN]; int active_ibss; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); if (ifsta->ssid_len == 0) return -EINVAL; @@ -2068,8 +2128,7 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, || !(bss->capability & WLAN_CAPABILITY_IBSS)) continue; #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG " bssid=%s found\n", - print_mac(mac, bss->bssid)); + printk(KERN_DEBUG " bssid=%pM found\n", bss->bssid); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ memcpy(bssid, bss->bssid, ETH_ALEN); found = 1; @@ -2080,9 +2139,8 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_IBSS_DEBUG if (found) - printk(KERN_DEBUG " sta_find_ibss: selected %s current " - "%s\n", print_mac(mac, bssid), - print_mac(mac2, ifsta->bssid)); + printk(KERN_DEBUG " sta_find_ibss: selected %pM current " + "%pM\n", bssid, ifsta->bssid); #endif /* CONFIG_MAC80211_IBSS_DEBUG */ if (found && memcmp(ifsta->bssid, bssid, ETH_ALEN) != 0) { @@ -2099,9 +2157,9 @@ static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata, if (!bss) goto dont_join; - printk(KERN_DEBUG "%s: Selected IBSS BSSID %s" + printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM" " based on configured SSID\n", - sdata->dev->name, print_mac(mac, bssid)); + sdata->dev->name, bssid); ret = ieee80211_sta_join_ibss(sdata, ifsta, bss); ieee80211_rx_bss_put(local, bss); return ret; @@ -2338,12 +2396,10 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata) * must be callable in atomic context. */ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, - struct sk_buff *skb, u8 *bssid, - u8 *addr, u64 supp_rates) + u8 *bssid,u8 *addr, u64 supp_rates) { struct ieee80211_local *local = sdata->local; struct sta_info *sta; - DECLARE_MAC_BUF(mac); int band = local->hw.conf.channel->band; /* TODO: Could consider removing the least recently used entry and @@ -2351,7 +2407,7 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) { if (net_ratelimit()) { printk(KERN_DEBUG "%s: No room for a new IBSS STA " - "entry %s\n", sdata->dev->name, print_mac(mac, addr)); + "entry %pM\n", sdata->dev->name, addr); } return NULL; } @@ -2360,8 +2416,8 @@ struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata, return NULL; #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Adding new IBSS station %s (dev=%s)\n", - wiphy_name(local->hw.wiphy), print_mac(mac, addr), sdata->dev->name); + printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n", + wiphy_name(local->hw.wiphy), addr, sdata->dev->name); #endif sta = sta_info_alloc(sdata, addr, GFP_ATOMIC); @@ -2408,7 +2464,6 @@ void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata, int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len) { struct ieee80211_if_sta *ifsta; - int res; if (len > IEEE80211_MAX_SSID_LEN) return -EINVAL; @@ -2420,19 +2475,6 @@ int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size memcpy(ifsta->ssid, ssid, len); ifsta->ssid_len = len; ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET; - - res = 0; - /* - * Hack! MLME code needs to be cleaned up to have different - * entry points for configuration and internal selection change - */ - if (netif_running(sdata->dev)) - res = ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); - if (res) { - printk(KERN_DEBUG "%s: Failed to config new SSID to " - "the low-level driver\n", sdata->dev->name); - return res; - } } if (len) @@ -2560,3 +2602,39 @@ void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local) ieee80211_restart_sta_timer(sdata); rcu_read_unlock(); } + +void ieee80211_dynamic_ps_disable_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, + dynamic_ps_disable_work); + + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + local->hw.conf.flags &= ~IEEE80211_CONF_PS; + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); + } + + ieee80211_wake_queues_by_reason(&local->hw, + IEEE80211_QUEUE_STOP_REASON_PS); +} + +void ieee80211_dynamic_ps_enable_work(struct work_struct *work) +{ + struct ieee80211_local *local = + container_of(work, struct ieee80211_local, + dynamic_ps_enable_work); + + if (local->hw.conf.flags & IEEE80211_CONF_PS) + return; + + local->hw.conf.flags |= IEEE80211_CONF_PS; + + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); +} + +void ieee80211_dynamic_ps_timer(unsigned long data) +{ + struct ieee80211_local *local = (void *) data; + + queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work); +} diff --git a/net/mac80211/rate.c b/net/mac80211/rate.c index 5d786720d9357c8ecd96a027074489d338a30951..3fa7ab285066a46c5200d49c4ca06e4c56ff5456 100644 --- a/net/mac80211/rate.c +++ b/net/mac80211/rate.c @@ -199,48 +199,44 @@ static void rate_control_release(struct kref *kref) } void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, - struct ieee80211_supported_band *sband, - struct sta_info *sta, struct sk_buff *skb, - struct rate_selection *sel) + struct sta_info *sta, + struct ieee80211_tx_rate_control *txrc) { struct rate_control_ref *ref = sdata->local->rate_ctrl; void *priv_sta = NULL; struct ieee80211_sta *ista = NULL; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); int i; - sel->rate_idx = -1; - sel->nonerp_idx = -1; - sel->probe_idx = -1; - sel->max_rate_idx = sdata->max_ratectrl_rateidx; - if (sta) { ista = &sta->sta; priv_sta = sta->rate_ctrl_priv; } + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + info->control.rates[i].idx = -1; + info->control.rates[i].flags = 0; + info->control.rates[i].count = 1; + } + if (sta && sdata->force_unicast_rateidx > -1) - sel->rate_idx = sdata->force_unicast_rateidx; + info->control.rates[0].idx = sdata->force_unicast_rateidx; else - ref->ops->get_rate(ref->priv, sband, ista, priv_sta, skb, sel); - - if (sdata->max_ratectrl_rateidx > -1 && - sel->rate_idx > sdata->max_ratectrl_rateidx) - sel->rate_idx = sdata->max_ratectrl_rateidx; - - BUG_ON(sel->rate_idx < 0); - - /* Select a non-ERP backup rate. */ - if (sel->nonerp_idx < 0) { - for (i = 0; i < sband->n_bitrates; i++) { - struct ieee80211_rate *rate = &sband->bitrates[i]; - if (sband->bitrates[sel->rate_idx].bitrate < rate->bitrate) - break; - - if (rate_supported(ista, sband->band, i) && - !(rate->flags & IEEE80211_RATE_ERP_G)) - sel->nonerp_idx = i; - } + ref->ops->get_rate(ref->priv, ista, priv_sta, txrc); + + /* + * try to enforce the maximum rate the user wanted + */ + if (sdata->max_ratectrl_rateidx > -1) + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) + continue; + info->control.rates[i].idx = + min_t(s8, info->control.rates[i].idx, + sdata->max_ratectrl_rateidx); } + + BUG_ON(info->control.rates[0].idx < 0); } struct rate_control_ref *rate_control_get(struct rate_control_ref *ref) diff --git a/net/mac80211/rate.h b/net/mac80211/rate.h index d0092f847f82775eb19c457874dfc911a12d4795..928da625e281557ccecc0f1923def7b9bfa72415 100644 --- a/net/mac80211/rate.h +++ b/net/mac80211/rate.h @@ -31,9 +31,8 @@ struct rate_control_ref { struct rate_control_ref *rate_control_alloc(const char *name, struct ieee80211_local *local); void rate_control_get_rate(struct ieee80211_sub_if_data *sdata, - struct ieee80211_supported_band *sband, - struct sta_info *sta, struct sk_buff *skb, - struct rate_selection *sel); + struct sta_info *sta, + struct ieee80211_tx_rate_control *txrc); struct rate_control_ref *rate_control_get(struct rate_control_ref *ref); void rate_control_put(struct rate_control_ref *ref); @@ -64,12 +63,6 @@ static inline void rate_control_rate_init(struct sta_info *sta) } -static inline void rate_control_clear(struct ieee80211_local *local) -{ - struct rate_control_ref *ref = local->rate_ctrl; - ref->ops->clear(ref->priv); -} - static inline void *rate_control_alloc_sta(struct rate_control_ref *ref, struct ieee80211_sta *sta, gfp_t gfp) diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c index f6d69dab07a3eba384bfa91baed0e9b4f3a5f287..2b3b490a6073467755e3b83998d1480398864148 100644 --- a/net/mac80211/rc80211_minstrel.c +++ b/net/mac80211/rc80211_minstrel.c @@ -126,7 +126,9 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) mr->adjusted_retry_count = mr->retry_count >> 1; if (mr->adjusted_retry_count > 2) mr->adjusted_retry_count = 2; + mr->sample_limit = 4; } else { + mr->sample_limit = -1; mr->adjusted_retry_count = mr->retry_count; } if (!mr->adjusted_retry_count) @@ -169,30 +171,20 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, { struct minstrel_sta_info *mi = priv_sta; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_tx_altrate *ar = info->status.retries; - struct minstrel_priv *mp = priv; - int i, ndx, tries; - int success = 0; - - if (!info->status.excessive_retries) - success = 1; + struct ieee80211_tx_rate *ar = info->status.rates; + int i, ndx; + int success; - if (!mp->has_mrr || (ar[0].rate_idx < 0)) { - ndx = rix_to_ndx(mi, info->tx_rate_idx); - tries = info->status.retry_count + 1; - mi->r[ndx].success += success; - mi->r[ndx].attempts += tries; - return; - } + success = !!(info->flags & IEEE80211_TX_STAT_ACK); - for (i = 0; i < 4; i++) { - if (ar[i].rate_idx < 0) + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + if (ar[i].idx < 0) break; - ndx = rix_to_ndx(mi, ar[i].rate_idx); - mi->r[ndx].attempts += ar[i].limit + 1; + ndx = rix_to_ndx(mi, ar[i].idx); + mi->r[ndx].attempts += ar[i].count; - if ((i != 3) && (ar[i + 1].rate_idx < 0)) + if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) mi->r[ndx].success += success; } @@ -210,9 +202,9 @@ minstrel_get_retry_count(struct minstrel_rate *mr, { unsigned int retry = mr->adjusted_retry_count; - if (info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) + if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS) retry = max(2U, min(mr->retry_count_rtscts, retry)); - else if (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT) + else if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) retry = max(2U, min(mr->retry_count_cts, retry)); return retry; } @@ -233,15 +225,16 @@ minstrel_get_next_sample(struct minstrel_sta_info *mi) return sample_ndx; } -void -minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, struct rate_selection *sel) +static void +minstrel_get_rate(void *priv, struct ieee80211_sta *sta, + void *priv_sta, struct ieee80211_tx_rate_control *txrc) { + struct sk_buff *skb = txrc->skb; + struct ieee80211_supported_band *sband = txrc->sband; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct minstrel_sta_info *mi = priv_sta; struct minstrel_priv *mp = priv; - struct ieee80211_tx_altrate *ar = info->control.retries; + struct ieee80211_tx_rate *ar = info->control.rates; unsigned int ndx, sample_ndx = 0; bool mrr; bool sample_slower = false; @@ -251,16 +244,12 @@ minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband, int sample_rate; if (!sta || !mi || use_low_rate(skb)) { - sel->rate_idx = rate_lowest_index(sband, sta); + ar[0].idx = rate_lowest_index(sband, sta); + ar[0].count = mp->max_retry; return; } - mrr = mp->has_mrr; - - /* mac80211 does not allow mrr for RTS/CTS */ - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) - mrr = false; + mrr = mp->has_mrr && !txrc->rts && !txrc->bss_conf->use_cts_prot; if (time_after(jiffies, mi->stats_update + (mp->update_interval * HZ) / 1000)) @@ -278,7 +267,8 @@ minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband, (mi->sample_count + mi->sample_deferred / 2); /* delta > 0: sampling required */ - if (delta > 0) { + if ((delta > 0) && (mrr || !mi->prev_sample)) { + struct minstrel_rate *msr; if (mi->packet_count >= 10000) { mi->sample_deferred = 0; mi->sample_count = 0; @@ -297,13 +287,20 @@ minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband, } sample_ndx = minstrel_get_next_sample(mi); + msr = &mi->r[sample_ndx]; sample = true; - sample_slower = mrr && (mi->r[sample_ndx].perfect_tx_time > + sample_slower = mrr && (msr->perfect_tx_time > mi->r[ndx].perfect_tx_time); if (!sample_slower) { - ndx = sample_ndx; - mi->sample_count++; + if (msr->sample_limit != 0) { + ndx = sample_ndx; + mi->sample_count++; + if (msr->sample_limit > 0) + msr->sample_limit--; + } else { + sample = false; + } } else { /* Only use IEEE80211_TX_CTL_RATE_CTRL_PROBE to mark * packets that have the sampling rate deferred to the @@ -315,13 +312,22 @@ minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband, mi->sample_deferred++; } } - sel->rate_idx = mi->r[ndx].rix; - info->control.retry_limit = minstrel_get_retry_count(&mi->r[ndx], info); + mi->prev_sample = sample; + + /* If we're not using MRR and the sampling rate already + * has a probability of >95%, we shouldn't be attempting + * to use it, as this only wastes precious airtime */ + if (!mrr && sample && (mi->r[ndx].probability > 17100)) + ndx = mi->max_tp_rate; + + ar[0].idx = mi->r[ndx].rix; + ar[0].count = minstrel_get_retry_count(&mi->r[ndx], info); if (!mrr) { - ar[0].rate_idx = mi->lowest_rix; - ar[0].limit = mp->max_retry; - ar[1].rate_idx = -1; + if (!sample) + ar[0].count = mp->max_retry; + ar[1].idx = mi->lowest_rix; + ar[1].count = mp->max_retry; return; } @@ -336,9 +342,9 @@ minstrel_get_rate(void *priv, struct ieee80211_supported_band *sband, } mrr_ndx[1] = mi->max_prob_rate; mrr_ndx[2] = 0; - for (i = 0; i < 3; i++) { - ar[i].rate_idx = mi->r[mrr_ndx[i]].rix; - ar[i].limit = mi->r[mrr_ndx[i]].adjusted_retry_count; + for (i = 1; i < 4; i++) { + ar[i].idx = mi->r[mrr_ndx[i - 1]].rix; + ar[i].count = mi->r[mrr_ndx[i - 1]].adjusted_retry_count; } } @@ -415,6 +421,7 @@ minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, /* calculate maximum number of retransmissions before * fallback (based on maximum segment size) */ + mr->sample_limit = -1; mr->retry_count = 1; mr->retry_count_cts = 1; mr->retry_count_rtscts = 1; @@ -500,11 +507,6 @@ minstrel_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) kfree(mi); } -static void -minstrel_clear(void *priv) -{ -} - static void * minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) { @@ -532,13 +534,13 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) /* maximum time that the hw is allowed to stay in one MRR segment */ mp->segment_size = 6000; - if (hw->max_altrate_tries > 0) - mp->max_retry = hw->max_altrate_tries; + if (hw->max_rate_tries > 0) + mp->max_retry = hw->max_rate_tries; else /* safe default, does not necessarily have to match hw properties */ mp->max_retry = 7; - if (hw->max_altrates >= 3) + if (hw->max_rates >= 4) mp->has_mrr = true; mp->hw = hw; @@ -558,7 +560,6 @@ static struct rate_control_ops mac80211_minstrel = { .tx_status = minstrel_tx_status, .get_rate = minstrel_get_rate, .rate_init = minstrel_rate_init, - .clear = minstrel_clear, .alloc = minstrel_alloc, .free = minstrel_free, .alloc_sta = minstrel_alloc_sta, diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h index 9a90a6aee043fbd0aac5469a89a9981c91d4ab0b..869fe0ef951d176a6bf3b5592a3d6e9191a9e8b8 100644 --- a/net/mac80211/rc80211_minstrel.h +++ b/net/mac80211/rc80211_minstrel.h @@ -16,6 +16,7 @@ struct minstrel_rate { unsigned int perfect_tx_time; unsigned int ack_time; + int sample_limit; unsigned int retry_count; unsigned int retry_count_cts; unsigned int retry_count_rtscts; @@ -57,6 +58,7 @@ struct minstrel_sta_info { int n_rates; struct minstrel_rate *r; + bool prev_sample; /* sampling table */ u8 *sample_table; diff --git a/net/mac80211/rc80211_pid.h b/net/mac80211/rc80211_pid.h index 01d64d53f3b9351ead2458fcebf2b1b5301a1f4b..1a873f00691acca56edd1b7c954b9e2f4cde0eb9 100644 --- a/net/mac80211/rc80211_pid.h +++ b/net/mac80211/rc80211_pid.h @@ -49,7 +49,7 @@ /* Arithmetic right shift for positive and negative values for ISO C. */ #define RC_PID_DO_ARITH_RIGHT_SHIFT(x, y) \ - (x) < 0 ? -((-(x)) >> (y)) : (x) >> (y) + ((x) < 0 ? -((-(x)) >> (y)) : (x) >> (y)) enum rc_pid_event_type { RC_PID_EVENT_TYPE_TX_STATUS, @@ -61,6 +61,7 @@ enum rc_pid_event_type { union rc_pid_event_data { /* RC_PID_EVENT_TX_STATUS */ struct { + u32 flags; struct ieee80211_tx_info tx_status; }; /* RC_PID_EVENT_TYPE_RATE_CHANGE */ diff --git a/net/mac80211/rc80211_pid_algo.c b/net/mac80211/rc80211_pid_algo.c index 86eb374e3b87f22338b4697552e0283f897db8aa..b16801cde06f41825b6f0db7fd2f4188ebdbcbf8 100644 --- a/net/mac80211/rc80211_pid_algo.c +++ b/net/mac80211/rc80211_pid_algo.c @@ -241,7 +241,7 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba /* Ignore all frames that were sent with a different rate than the rate * we currently advise mac80211 to use. */ - if (info->tx_rate_idx != spinfo->txrate_idx) + if (info->status.rates[0].idx != spinfo->txrate_idx) return; spinfo->tx_num_xmit++; @@ -253,10 +253,10 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba /* We count frames that totally failed to be transmitted as two bad * frames, those that made it out but had some retries as one good and * one bad frame. */ - if (info->status.excessive_retries) { + if (!(info->flags & IEEE80211_TX_STAT_ACK)) { spinfo->tx_num_failed += 2; spinfo->tx_num_xmit++; - } else if (info->status.retry_count) { + } else if (info->status.rates[0].count > 1) { spinfo->tx_num_failed++; spinfo->tx_num_xmit++; } @@ -270,23 +270,32 @@ static void rate_control_pid_tx_status(void *priv, struct ieee80211_supported_ba } static void -rate_control_pid_get_rate(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_sta *sta, void *priv_sta, - struct sk_buff *skb, - struct rate_selection *sel) +rate_control_pid_get_rate(void *priv, struct ieee80211_sta *sta, + void *priv_sta, + struct ieee80211_tx_rate_control *txrc) { + struct sk_buff *skb = txrc->skb; + struct ieee80211_supported_band *sband = txrc->sband; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct rc_pid_sta_info *spinfo = priv_sta; int rateidx; u16 fc; + if (txrc->rts) + info->control.rates[0].count = + txrc->hw->conf.long_frame_max_tx_count; + else + info->control.rates[0].count = + txrc->hw->conf.short_frame_max_tx_count; + /* Send management frames and broadcast/multicast data using lowest * rate. */ fc = le16_to_cpu(hdr->frame_control); if (!sta || !spinfo || (fc & IEEE80211_FCTL_FTYPE) != IEEE80211_FTYPE_DATA || is_multicast_ether_addr(hdr->addr1)) { - sel->rate_idx = rate_lowest_index(sband, sta); + info->control.rates[0].idx = rate_lowest_index(sband, sta); return; } @@ -295,7 +304,7 @@ rate_control_pid_get_rate(void *priv, struct ieee80211_supported_band *sband, if (rateidx >= sband->n_bitrates) rateidx = sband->n_bitrates - 1; - sel->rate_idx = rateidx; + info->control.rates[0].idx = rateidx; #ifdef CONFIG_MAC80211_DEBUGFS rate_control_pid_event_tx_rate(&spinfo->events, @@ -394,11 +403,11 @@ static void *rate_control_pid_alloc(struct ieee80211_hw *hw, S_IRUSR | S_IWUSR, debugfsdir, &pinfo->sampling_period); de->coeff_p = debugfs_create_u32("coeff_p", S_IRUSR | S_IWUSR, - debugfsdir, &pinfo->coeff_p); + debugfsdir, (u32 *)&pinfo->coeff_p); de->coeff_i = debugfs_create_u32("coeff_i", S_IRUSR | S_IWUSR, - debugfsdir, &pinfo->coeff_i); + debugfsdir, (u32 *)&pinfo->coeff_i); de->coeff_d = debugfs_create_u32("coeff_d", S_IRUSR | S_IWUSR, - debugfsdir, &pinfo->coeff_d); + debugfsdir, (u32 *)&pinfo->coeff_d); de->smoothing_shift = debugfs_create_u32("smoothing_shift", S_IRUSR | S_IWUSR, debugfsdir, &pinfo->smoothing_shift); @@ -437,10 +446,6 @@ static void rate_control_pid_free(void *priv) kfree(pinfo); } -static void rate_control_pid_clear(void *priv) -{ -} - static void *rate_control_pid_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) { @@ -471,7 +476,6 @@ static struct rate_control_ops mac80211_rcpid = { .tx_status = rate_control_pid_tx_status, .get_rate = rate_control_pid_get_rate, .rate_init = rate_control_pid_rate_init, - .clear = rate_control_pid_clear, .alloc = rate_control_pid_alloc, .free = rate_control_pid_free, .alloc_sta = rate_control_pid_alloc_sta, diff --git a/net/mac80211/rc80211_pid_debugfs.c b/net/mac80211/rc80211_pid_debugfs.c index 8121d3bc683585e22443f7621a90697d73edddbe..a08a9b5303474bc304b9f119b31cc4938dfa9acb 100644 --- a/net/mac80211/rc80211_pid_debugfs.c +++ b/net/mac80211/rc80211_pid_debugfs.c @@ -43,6 +43,7 @@ void rate_control_pid_event_tx_status(struct rc_pid_event_buffer *buf, { union rc_pid_event_data evd; + evd.flags = stat->flags; memcpy(&evd.tx_status, stat, sizeof(struct ieee80211_tx_info)); rate_control_pid_event(buf, RC_PID_EVENT_TYPE_TX_STATUS, &evd); } @@ -167,8 +168,8 @@ static ssize_t rate_control_pid_events_read(struct file *file, char __user *buf, switch (ev->type) { case RC_PID_EVENT_TYPE_TX_STATUS: p += snprintf(pb + p, length - p, "tx_status %u %u", - ev->data.tx_status.status.excessive_retries, - ev->data.tx_status.status.retry_count); + !(ev->data.flags & IEEE80211_TX_STAT_ACK), + ev->data.tx_status.status.rates[0].idx); break; case RC_PID_EVENT_TYPE_RATE_CHANGE: p += snprintf(pb + p, length - p, "rate_change %d %d", diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c index cf6b121e1bbf58407608132c24b613c2cbd34129..7175ae80c36a3b3a513fd1f5040643e595401a5c 100644 --- a/net/mac80211/rx.c +++ b/net/mac80211/rx.c @@ -26,10 +26,11 @@ #include "tkip.h" #include "wme.h" -u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, - struct tid_ampdu_rx *tid_agg_rx, - struct sk_buff *skb, u16 mpdu_seq_num, - int bar_req); +static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + struct sk_buff *skb, + u16 mpdu_seq_num, + int bar_req); /* * monitor mode reception * @@ -122,7 +123,6 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, /* radiotap header, set always present flags */ rthdr->it_present = cpu_to_le32((1 << IEEE80211_RADIOTAP_FLAGS) | - (1 << IEEE80211_RADIOTAP_RATE) | (1 << IEEE80211_RADIOTAP_CHANNEL) | (1 << IEEE80211_RADIOTAP_ANTENNA) | (1 << IEEE80211_RADIOTAP_RX_FLAGS)); @@ -148,7 +148,19 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local, pos++; /* IEEE80211_RADIOTAP_RATE */ - *pos = rate->bitrate / 5; + if (status->flag & RX_FLAG_HT) { + /* + * TODO: add following information into radiotap header once + * suitable fields are defined for it: + * - MCS index (status->rate_idx) + * - HT40 (status->flag & RX_FLAG_40MHZ) + * - short-GI (status->flag & RX_FLAG_SHORT_GI) + */ + *pos = 0; + } else { + rthdr->it_present |= (1 << IEEE80211_RADIOTAP_RATE); + *pos = rate->bitrate / 5; + } pos++; /* IEEE80211_RADIOTAP_CHANNEL */ @@ -653,13 +665,16 @@ ieee80211_rx_h_decrypt(struct ieee80211_rx_data *rx) static void ap_sta_ps_start(struct sta_info *sta) { struct ieee80211_sub_if_data *sdata = sta->sdata; - DECLARE_MAC_BUF(mac); + struct ieee80211_local *local = sdata->local; atomic_inc(&sdata->bss->num_sta_ps); set_and_clear_sta_flags(sta, WLAN_STA_PS, WLAN_STA_PSPOLL); + if (local->ops->sta_notify) + local->ops->sta_notify(local_to_hw(local), &sdata->vif, + STA_NOTIFY_SLEEP, &sta->sta); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA %s aid %d enters power save mode\n", - sdata->dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid); + printk(KERN_DEBUG "%s: STA %pM aid %d enters power save mode\n", + sdata->dev->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -669,38 +684,37 @@ static int ap_sta_ps_end(struct sta_info *sta) struct ieee80211_local *local = sdata->local; struct sk_buff *skb; int sent = 0; - struct ieee80211_tx_info *info; - DECLARE_MAC_BUF(mac); atomic_dec(&sdata->bss->num_sta_ps); clear_sta_flags(sta, WLAN_STA_PS | WLAN_STA_PSPOLL); + if (local->ops->sta_notify) + local->ops->sta_notify(local_to_hw(local), &sdata->vif, + STA_NOTIFY_AWAKE, &sta->sta); 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", - sdata->dev->name, print_mac(mac, sta->sta.addr), sta->sta.aid); + printk(KERN_DEBUG "%s: STA %pM aid %d exits power save mode\n", + sdata->dev->name, sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ /* Send all buffered frames to the station */ while ((skb = skb_dequeue(&sta->tx_filtered)) != NULL) { - info = IEEE80211_SKB_CB(skb); sent++; - info->flags |= IEEE80211_TX_CTL_REQUEUE; + skb->requeue = 1; dev_queue_xmit(skb); } while ((skb = skb_dequeue(&sta->ps_tx_buf)) != NULL) { - info = IEEE80211_SKB_CB(skb); local->total_ps_buffered--; sent++; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "%s: STA %s aid %d send PS frame " + printk(KERN_DEBUG "%s: STA %pM aid %d send PS frame " "since STA not sleeping anymore\n", sdata->dev->name, - print_mac(mac, sta->sta.addr), sta->sta.aid); + sta->sta.addr, sta->sta.aid); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ - info->flags |= IEEE80211_TX_CTL_REQUEUE; + skb->requeue = 1; dev_queue_xmit(skb); } @@ -745,17 +759,29 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx) sta->last_qual = rx->status->qual; sta->last_noise = rx->status->noise; + /* + * Change STA power saving mode only at the end of a frame + * exchange sequence. + */ if (!ieee80211_has_morefrags(hdr->frame_control) && (rx->sdata->vif.type == NL80211_IFTYPE_AP || rx->sdata->vif.type == NL80211_IFTYPE_AP_VLAN)) { - /* Change STA power saving mode only in the end of a frame - * exchange sequence */ - if (test_sta_flags(sta, WLAN_STA_PS) && - !ieee80211_has_pm(hdr->frame_control)) - rx->sent_ps_buffered += ap_sta_ps_end(sta); - else if (!test_sta_flags(sta, WLAN_STA_PS) && - ieee80211_has_pm(hdr->frame_control)) - ap_sta_ps_start(sta); + if (test_sta_flags(sta, WLAN_STA_PS)) { + /* + * Ignore doze->wake transitions that are + * indicated by non-data frames, the standard + * is unclear here, but for example going to + * PS mode and then scanning would cause a + * doze->wake transition for the probe request, + * and that is clearly undesirable. + */ + if (ieee80211_is_data(hdr->frame_control) && + !ieee80211_has_pm(hdr->frame_control)) + rx->sent_ps_buffered += ap_sta_ps_end(sta); + } else { + if (ieee80211_has_pm(hdr->frame_control)) + ap_sta_ps_start(sta); + } } /* Drop data::nullfunc frames silently, since they are used only to @@ -789,15 +815,12 @@ ieee80211_reassemble_add(struct ieee80211_sub_if_data *sdata, #ifdef CONFIG_MAC80211_VERBOSE_DEBUG struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) entry->skb_list.next->data; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); printk(KERN_DEBUG "%s: RX reassembly removed oldest " "fragment entry (idx=%d age=%lu seq=%d last_frag=%d " - "addr1=%s addr2=%s\n", + "addr1=%pM addr2=%pM\n", sdata->dev->name, idx, jiffies - entry->first_frag_time, entry->seq, - entry->last_frag, print_mac(mac, hdr->addr1), - print_mac(mac2, hdr->addr2)); + entry->last_frag, hdr->addr1, hdr->addr2); #endif __skb_queue_purge(&entry->skb_list); } @@ -866,7 +889,6 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx) unsigned int frag, seq; struct ieee80211_fragment_entry *entry; struct sk_buff *skb; - DECLARE_MAC_BUF(mac); hdr = (struct ieee80211_hdr *)rx->skb->data; fc = hdr->frame_control; @@ -970,7 +992,6 @@ 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; int no_pending_pkts; - DECLARE_MAC_BUF(mac); __le16 fc = ((struct ieee80211_hdr *)rx->skb->data)->frame_control; if (likely(!rx->sta || !ieee80211_is_pspoll(fc) || @@ -1001,8 +1022,8 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) set_sta_flags(rx->sta, WLAN_STA_PSPOLL); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA %s aid %d: PS Poll (entries after %d)\n", - print_mac(mac, rx->sta->sta.addr), rx->sta->sta.aid, + printk(KERN_DEBUG "STA %pM aid %d: PS Poll (entries after %d)\n", + rx->sta->sta.addr, rx->sta->sta.aid, skb_queue_len(&rx->sta->ps_tx_buf)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ @@ -1025,9 +1046,9 @@ ieee80211_rx_h_ps_poll(struct ieee80211_rx_data *rx) * 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 " + printk(KERN_DEBUG "%s: STA %pM sent PS Poll even " "though there are no buffered frames for it\n", - rx->dev->name, print_mac(mac, rx->sta->sta.addr)); + rx->dev->name, rx->sta->sta.addr); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ } @@ -1097,10 +1118,6 @@ ieee80211_data_to_8023(struct ieee80211_rx_data *rx) u8 src[ETH_ALEN] __aligned(2); struct sk_buff *skb = rx->skb; struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); - DECLARE_MAC_BUF(mac3); - DECLARE_MAC_BUF(mac4); if (unlikely(!ieee80211_is_data_present(hdr->frame_control))) return -1; @@ -1279,7 +1296,6 @@ ieee80211_rx_h_amsdu(struct ieee80211_rx_data *rx) int remaining, err; u8 dst[ETH_ALEN]; u8 src[ETH_ALEN]; - DECLARE_MAC_BUF(mac); if (unlikely(!ieee80211_is_data(fc))) return RX_CONTINUE; @@ -1552,14 +1568,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx) if (len < IEEE80211_MIN_ACTION_SIZE + 1) return RX_DROP_MONITOR; - /* - * FIXME: revisit this, I'm sure we should handle most - * of these frames in other modes as well! - */ - if (sdata->vif.type != NL80211_IFTYPE_STATION && - sdata->vif.type != NL80211_IFTYPE_ADHOC) - return RX_CONTINUE; - switch (mgmt->u.action.category) { case WLAN_CATEGORY_BACK: switch (mgmt->u.action.u.addba_req.action_code) { @@ -1632,8 +1640,6 @@ static void ieee80211_rx_michael_mic_report(struct net_device *dev, { int keyidx; unsigned int hdrlen; - DECLARE_MAC_BUF(mac); - DECLARE_MAC_BUF(mac2); hdrlen = ieee80211_hdrlen(hdr->frame_control); if (rx->skb->len >= hdrlen + 4) @@ -1854,10 +1860,15 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata, if (!(sdata->dev->flags & IFF_PROMISC)) return 0; rx->flags &= ~IEEE80211_RX_RA_MATCH; - } else if (!rx->sta) - rx->sta = ieee80211_ibss_add_sta(sdata, rx->skb, - bssid, hdr->addr2, - BIT(rx->status->rate_idx)); + } else if (!rx->sta) { + int rate_idx; + if (rx->status->flag & RX_FLAG_HT) + rate_idx = 0; /* TODO: HT rates */ + else + rate_idx = rx->status->rate_idx; + rx->sta = ieee80211_ibss_add_sta(sdata, bssid, hdr->addr2, + BIT(rate_idx)); + } break; case NL80211_IFTYPE_MESH_POINT: if (!multicast && @@ -2002,17 +2013,17 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw, static inline int seq_less(u16 sq1, u16 sq2) { - return (((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1)); + return ((sq1 - sq2) & SEQ_MASK) > (SEQ_MODULO >> 1); } static inline u16 seq_inc(u16 sq) { - return ((sq + 1) & SEQ_MASK); + return (sq + 1) & SEQ_MASK; } static inline u16 seq_sub(u16 sq1, u16 sq2) { - return ((sq1 - sq2) & SEQ_MASK); + return (sq1 - sq2) & SEQ_MASK; } @@ -2020,10 +2031,11 @@ static inline u16 seq_sub(u16 sq1, u16 sq2) * As it function blongs to Rx path it must be called with * the proper rcu_read_lock protection for its flow. */ -u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, - struct tid_ampdu_rx *tid_agg_rx, - struct sk_buff *skb, u16 mpdu_seq_num, - int bar_req) +static u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, + struct tid_ampdu_rx *tid_agg_rx, + struct sk_buff *skb, + u16 mpdu_seq_num, + int bar_req) { struct ieee80211_local *local = hw_to_local(hw); struct ieee80211_rx_status status; @@ -2062,7 +2074,13 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, tid_agg_rx->reorder_buf[index]->cb, sizeof(status)); sband = local->hw.wiphy->bands[status.band]; - rate = &sband->bitrates[status.rate_idx]; + if (status.flag & RX_FLAG_HT) { + /* TODO: HT rates */ + rate = sband->bitrates; + } else { + rate = &sband->bitrates + [status.rate_idx]; + } __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], &status, rate); @@ -2106,7 +2124,10 @@ u8 ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw, memcpy(&status, tid_agg_rx->reorder_buf[index]->cb, sizeof(status)); sband = local->hw.wiphy->bands[status.band]; - rate = &sband->bitrates[status.rate_idx]; + if (status.flag & RX_FLAG_HT) + rate = sband->bitrates; /* TODO: HT rates */ + else + rate = &sband->bitrates[status.rate_idx]; __ieee80211_rx_handle_packet(hw, tid_agg_rx->reorder_buf[index], &status, rate); tid_agg_rx->stored_mpdu_num--; @@ -2194,15 +2215,26 @@ void __ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb, } sband = local->hw.wiphy->bands[status->band]; - - if (!sband || - status->rate_idx < 0 || - status->rate_idx >= sband->n_bitrates) { + if (!sband) { WARN_ON(1); return; } - rate = &sband->bitrates[status->rate_idx]; + if (status->flag & RX_FLAG_HT) { + /* rate_idx is MCS index */ + if (WARN_ON(status->rate_idx < 0 || + status->rate_idx >= 76)) + return; + /* HT rates are not in the table - use the highest legacy rate + * for now since other parts of mac80211 may not yet be fully + * MCS aware. */ + rate = &sband->bitrates[sband->n_bitrates - 1]; + } else { + if (WARN_ON(status->rate_idx < 0 || + status->rate_idx >= sband->n_bitrates)) + return; + rate = &sband->bitrates[status->rate_idx]; + } /* * key references and virtual interfaces are protected using RCU diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c index 416bb41099f361159d0bc578533d08a371a7de03..f5c7c3371929a5c41651bcbefa45771149b5c2d4 100644 --- a/net/mac80211/scan.c +++ b/net/mac80211/scan.c @@ -159,7 +159,7 @@ ieee80211_rx_mesh_bss_add(struct ieee80211_local *local, u8 *mesh_id, int mesh_i { struct ieee80211_bss *bss; - if (mesh_config_len != MESH_CFG_LEN) + if (mesh_config_len != IEEE80211_MESH_CONFIG_LEN) return NULL; bss = kzalloc(sizeof(*bss), GFP_ATOMIC); @@ -448,18 +448,17 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw) if (local->hw_scanning) { local->hw_scanning = false; - if (ieee80211_hw_config(local)) - printk(KERN_DEBUG "%s: failed to restore operational " - "channel after scan\n", wiphy_name(local->hw.wiphy)); - + /* + * Somebody might have requested channel change during scan + * that we won't have acted upon, try now. ieee80211_hw_config + * will set the flag based on actual changes. + */ + ieee80211_hw_config(local, 0); goto done; } local->sw_scanning = false; - if (ieee80211_hw_config(local)) - printk(KERN_DEBUG "%s: failed to restore operational " - "channel after scan\n", wiphy_name(local->hw.wiphy)); - + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_CHANNEL); netif_tx_lock_bh(local->mdev); netif_addr_lock(local->mdev); @@ -546,12 +545,9 @@ void ieee80211_scan_work(struct work_struct *work) if (!skip) { local->scan_channel = chan; - if (ieee80211_hw_config(local)) { - printk(KERN_DEBUG "%s: failed to set freq to " - "%d MHz for scan\n", wiphy_name(local->hw.wiphy), - chan->center_freq); + if (ieee80211_hw_config(local, + IEEE80211_CONF_CHANGE_CHANNEL)) skip = 1; - } } /* advance state machine to next channel/band */ diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c index d254446b85b59d76bf3d940fce4364270a2d5bb0..10c5539c20abdcafdd8fc1461914b2b9b43ba3ff 100644 --- a/net/mac80211/sta_info.c +++ b/net/mac80211/sta_info.c @@ -137,14 +137,12 @@ struct sta_info *sta_info_get_by_idx(struct ieee80211_local *local, int idx, static void __sta_info_free(struct ieee80211_local *local, struct sta_info *sta) { - DECLARE_MAC_BUF(mbuf); - rate_control_free_sta(sta); 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->sta.addr)); + printk(KERN_DEBUG "%s: Destroyed STA %pM\n", + wiphy_name(local->hw.wiphy), sta->sta.addr); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ kfree(sta); @@ -222,7 +220,6 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sta_info *sta; int i; - DECLARE_MAC_BUF(mbuf); sta = kzalloc(sizeof(*sta) + local->hw.sta_data_size, gfp); if (!sta) @@ -263,8 +260,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, skb_queue_head_init(&sta->tx_filtered); #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Allocated STA %s\n", - wiphy_name(local->hw.wiphy), print_mac(mbuf, sta->sta.addr)); + printk(KERN_DEBUG "%s: Allocated STA %pM\n", + wiphy_name(local->hw.wiphy), sta->sta.addr); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ #ifdef CONFIG_MAC80211_MESH @@ -281,7 +278,6 @@ int sta_info_insert(struct sta_info *sta) struct ieee80211_sub_if_data *sdata = sta->sdata; unsigned long flags; int err = 0; - DECLARE_MAC_BUF(mac); /* * Can't be a WARN_ON because it can be triggered through a race: @@ -294,7 +290,7 @@ int sta_info_insert(struct sta_info *sta) } if (WARN_ON(compare_ether_addr(sta->sta.addr, sdata->dev->dev_addr) == 0 || - is_multicast_ether_addr(sta->sta.addr))) { + is_multicast_ether_addr(sta->sta.addr))) { err = -EINVAL; goto out_free; } @@ -322,8 +318,8 @@ int sta_info_insert(struct sta_info *sta) } #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Inserted STA %s\n", - wiphy_name(local->hw.wiphy), print_mac(mac, sta->sta.addr)); + printk(KERN_DEBUG "%s: Inserted STA %pM\n", + wiphy_name(local->hw.wiphy), sta->sta.addr); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ spin_unlock_irqrestore(&local->sta_lock, flags); @@ -423,9 +419,6 @@ 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 - DECLARE_MAC_BUF(mbuf); -#endif /* * pull caller's reference if we're already gone. */ @@ -468,8 +461,8 @@ static void __sta_info_unlink(struct sta_info **sta) } #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - printk(KERN_DEBUG "%s: Removed STA %s\n", - wiphy_name(local->hw.wiphy), print_mac(mbuf, (*sta)->sta.addr)); + printk(KERN_DEBUG "%s: Removed STA %pM\n", + wiphy_name(local->hw.wiphy), (*sta)->sta.addr); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ /* @@ -544,7 +537,6 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, 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)) return; @@ -564,8 +556,8 @@ static void sta_info_cleanup_expire_buffered(struct ieee80211_local *local, sdata = sta->sdata; local->total_ps_buffered--; #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "Buffered frame expired (STA " - "%s)\n", print_mac(mac, sta->sta.addr)); + printk(KERN_DEBUG "Buffered frame expired (STA %pM)\n", + sta->sta.addr); #endif dev_kfree_skb(skb); @@ -809,15 +801,14 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, struct ieee80211_local *local = sdata->local; struct sta_info *sta, *tmp; LIST_HEAD(tmp_list); - DECLARE_MAC_BUF(mac); unsigned long flags; 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 + exp_time)) { #ifdef CONFIG_MAC80211_IBSS_DEBUG - printk(KERN_DEBUG "%s: expiring inactive STA %s\n", - sdata->dev->name, print_mac(mac, sta->sta.addr)); + printk(KERN_DEBUG "%s: expiring inactive STA %pM\n", + sdata->dev->name, sta->sta.addr); #endif __sta_info_unlink(&sta); if (sta) @@ -830,7 +821,7 @@ void ieee80211_sta_expire(struct ieee80211_sub_if_data *sdata, } struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw, - const u8 *addr) + const u8 *addr) { struct sta_info *sta = sta_info_get(hw_to_local(hw), addr); diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h index 168a39a298bdc1f754de9ad1d0ac04f311466d33..dc2606d0ae7713fbc850bdaf2339573f22d8a2f2 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h @@ -160,18 +160,17 @@ struct sta_ampdu_mlme { * @list: global linked list entry * @hnext: hash table linked list pointer * @local: pointer to the global information - * @sdata: TBD - * @key: TBD - * @rate_ctrl: TBD - * @rate_ctrl_priv: TBD + * @sdata: virtual interface this station belongs to + * @key: peer key negotiated with this station, if any + * @rate_ctrl: rate control algorithm reference + * @rate_ctrl_priv: rate control private per-STA pointer + * @last_tx_rate: rate used for last transmit, to report to userspace as + * "the" transmit rate * @lock: used for locking all fields that require locking, see comments * in the header file. * @flaglock: spinlock for flags accesses - * @addr: MAC address of this STA - * @aid: STA's unique AID (1..2007, 0 = not assigned yet), - * only used in AP (and IBSS?) mode - * @listen_interval: TBD - * @pin_status: TBD + * @listen_interval: listen interval of this station, when we're acting as AP + * @pin_status: used internally for pinning a STA struct into memory * @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 @@ -180,8 +179,8 @@ struct sta_ampdu_mlme { * power saving state * @rx_packets: Number of MSDUs received from this STA * @rx_bytes: Number of bytes received from this STA - * @wep_weak_iv_count: TBD - * @last_rx: TBD + * @wep_weak_iv_count: number of weak WEP IVs received from this station + * @last_rx: time (in jiffies) when last frame was received from this STA * @num_duplicates: number of duplicate frames received from this STA * @rx_fragments: number of received MPDUs * @rx_dropped: number of dropped MPDUs from this STA @@ -189,26 +188,26 @@ struct sta_ampdu_mlme { * @last_qual: qual of last received frame from this STA * @last_noise: noise of last received frame from this STA * @last_seq_ctrl: last received seq/frag number from this STA (per RX queue) - * @tx_filtered_count: TBD - * @tx_retry_failed: TBD - * @tx_retry_count: TBD + * @tx_filtered_count: number of frames the hardware filtered for this STA + * @tx_retry_failed: number of frames that failed retry + * @tx_retry_count: total number of retries for frames to this STA * @fail_avg: moving percentage of failed MSDUs * @tx_packets: number of RX/TX MSDUs - * @tx_bytes: TBD + * @tx_bytes: number of bytes transmitted to this STA * @tx_fragments: number of transmitted MPDUs - * @last_txrate_idx: Index of the last used transmit rate - * @tid_seq: TBD - * @ampdu_mlme: TBD + * @last_txrate: description of the last used transmit rate + * @tid_seq: per-TID sequence numbers for sending to this STA + * @ampdu_mlme: A-MPDU state machine state * @timer_to_tid: identity mapping to ID timers * @tid_to_tx_q: map tid to tx queue * @llid: Local link ID * @plid: Peer link ID * @reason: Cancel reason on PLINK_HOLDING state * @plink_retries: Retries in establishment - * @ignore_plink_timer: TBD - * @plink_state plink_state: TBD - * @plink_timeout: TBD - * @plink_timer: TBD + * @ignore_plink_timer: ignore the peer-link timer (used internally) + * @plink_state: peer link state + * @plink_timeout: timeout of peer link + * @plink_timer: peer link watch timer * @debugfs: debug filesystem info * @sta: station information we share with the driver */ @@ -267,7 +266,7 @@ struct sta_info { unsigned long tx_packets; unsigned long tx_bytes; unsigned long tx_fragments; - unsigned int last_txrate_idx; + struct ieee80211_tx_rate last_tx_rate; u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1]; /* diff --git a/net/mac80211/tkip.c b/net/mac80211/tkip.c index 34b32bc8f609d84d5a2fb0473d1be05e0f553930..38fa111d2dc6fff3720fd2990777ff75adc75b37 100644 --- a/net/mac80211/tkip.c +++ b/net/mac80211/tkip.c @@ -263,10 +263,9 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, (iv32 == key->u.tkip.rx[queue].iv32 && iv16 <= key->u.tkip.rx[queue].iv16))) { #ifdef CONFIG_MAC80211_TKIP_DEBUG - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "TKIP replay detected for RX frame from " - "%s (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", - print_mac(mac, ta), + "%pM (RX IV (%04x,%02x) <= prev. IV (%04x,%02x)\n", + ta, iv32, iv16, key->u.tkip.rx[queue].iv32, key->u.tkip.rx[queue].iv16); #endif @@ -287,9 +286,8 @@ int ieee80211_tkip_decrypt_data(struct crypto_blkcipher *tfm, { int i; u8 key_offset = NL80211_TKIP_DATA_OFFSET_ENCR_KEY; - DECLARE_MAC_BUF(mac); - printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%s" - " TK=", print_mac(mac, ta)); + printk(KERN_DEBUG "TKIP decrypt: Phase1 TA=%pM" + " TK=", ta); for (i = 0; i < 16; i++) printk("%02x ", key->conf.key[key_offset + i]); diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c index 1460537faf3335c64824ddd61704a212a43655de..a4af3a124cce7d895426b9e49e36ef53a5c54601 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c @@ -46,13 +46,20 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, struct ieee80211_local *local = tx->local; struct ieee80211_supported_band *sband; struct ieee80211_hdr *hdr; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + + /* assume HW handles this */ + if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS) + return 0; + + /* uh huh? */ + if (WARN_ON_ONCE(info->control.rates[0].idx < 0)) + return 0; sband = local->hw.wiphy->bands[tx->channel->band]; - txrate = &sband->bitrates[tx->rate_idx]; + txrate = &sband->bitrates[info->control.rates[0].idx]; - erp = 0; - if (tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) - erp = txrate->flags & IEEE80211_RATE_ERP_G; + erp = txrate->flags & IEEE80211_RATE_ERP_G; /* * data and mgmt (except PS Poll): @@ -116,7 +123,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, if (r->bitrate > txrate->bitrate) break; - if (tx->sdata->bss_conf.basic_rates & BIT(i)) + if (tx->sdata->vif.bss_conf.basic_rates & BIT(i)) rate = r->bitrate; switch (sband->band) { @@ -150,7 +157,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, * to closest integer */ dur = ieee80211_frame_duration(local, 10, rate, erp, - tx->sdata->bss_conf.use_short_preamble); + tx->sdata->vif.bss_conf.use_short_preamble); if (next_frag_len) { /* Frame is fragmented: duration increases with time needed to @@ -159,7 +166,7 @@ static __le16 ieee80211_duration(struct ieee80211_tx_data *tx, int group_addr, /* next fragment */ dur += ieee80211_frame_duration(local, next_frag_len, txrate->bitrate, erp, - tx->sdata->bss_conf.use_short_preamble); + tx->sdata->vif.bss_conf.use_short_preamble); } return cpu_to_le16(dur); @@ -201,10 +208,9 @@ ieee80211_tx_h_check_assoc(struct ieee80211_tx_data *tx) tx->sdata->vif.type != NL80211_IFTYPE_ADHOC && ieee80211_is_data(hdr->frame_control))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - DECLARE_MAC_BUF(mac); printk(KERN_DEBUG "%s: dropped data frame to not " - "associated station %s\n", - tx->dev->name, print_mac(mac, hdr->addr1)); + "associated station %pM\n", + tx->dev->name, hdr->addr1); #endif /* CONFIG_MAC80211_VERBOSE_DEBUG */ I802_DEBUG_INC(tx->local->tx_handlers_drop_not_assoc); return TX_DROP; @@ -331,7 +337,6 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; u32 staflags; - DECLARE_MAC_BUF(mac); if (unlikely(!sta || ieee80211_is_probe_resp(hdr->frame_control))) return TX_CONTINUE; @@ -341,9 +346,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) if (unlikely((staflags & WLAN_STA_PS) && !(staflags & WLAN_STA_PSPOLL))) { #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG - printk(KERN_DEBUG "STA %s aid %d: PS buffer (entries " + printk(KERN_DEBUG "STA %pM aid %d: PS buffer (entries " "before %d)\n", - print_mac(mac, sta->sta.addr), sta->sta.aid, + sta->sta.addr, sta->sta.aid, skb_queue_len(&sta->ps_tx_buf)); #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER) @@ -352,9 +357,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) struct sk_buff *old = skb_dequeue(&sta->ps_tx_buf); #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG if (net_ratelimit()) { - printk(KERN_DEBUG "%s: STA %s TX " + printk(KERN_DEBUG "%s: STA %pM TX " "buffer full - dropping oldest frame\n", - tx->dev->name, print_mac(mac, sta->sta.addr)); + tx->dev->name, sta->sta.addr); } #endif dev_kfree_skb(old); @@ -371,9 +376,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx) } #ifdef CONFIG_MAC80211_VERBOSE_PS_DEBUG else if (unlikely(test_sta_flags(sta, WLAN_STA_PS))) { - printk(KERN_DEBUG "%s: STA %s in PS mode, but pspoll " + printk(KERN_DEBUG "%s: STA %pM in PS mode, but pspoll " "set -> send frame\n", tx->dev->name, - print_mac(mac, sta->sta.addr)); + sta->sta.addr); } #endif /* CONFIG_MAC80211_VERBOSE_PS_DEBUG */ clear_sta_flags(sta, WLAN_STA_PSPOLL); @@ -439,140 +444,154 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) static ieee80211_tx_result debug_noinline ieee80211_tx_h_rate_ctrl(struct ieee80211_tx_data *tx) { - struct rate_selection rsel; - struct ieee80211_supported_band *sband; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + struct ieee80211_hdr *hdr = (void *)tx->skb->data; + struct ieee80211_supported_band *sband; + struct ieee80211_rate *rate; + int i, len; + bool inval = false, rts = false, short_preamble = false; + struct ieee80211_tx_rate_control txrc; - sband = tx->local->hw.wiphy->bands[tx->channel->band]; + memset(&txrc, 0, sizeof(txrc)); - if (likely(tx->rate_idx < 0)) { - rate_control_get_rate(tx->sdata, sband, tx->sta, - tx->skb, &rsel); - if (tx->sta) - tx->sta->last_txrate_idx = rsel.rate_idx; - tx->rate_idx = rsel.rate_idx; - if (unlikely(rsel.probe_idx >= 0)) { - info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; - tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - info->control.retries[0].rate_idx = tx->rate_idx; - info->control.retries[0].limit = tx->local->hw.max_altrate_tries; - tx->rate_idx = rsel.probe_idx; - } else if (info->control.retries[0].limit == 0) - info->control.retries[0].rate_idx = -1; - - if (unlikely(tx->rate_idx < 0)) - return TX_DROP; - } else - info->control.retries[0].rate_idx = -1; + sband = tx->local->hw.wiphy->bands[tx->channel->band]; - if (tx->sdata->bss_conf.use_cts_prot && - (tx->flags & IEEE80211_TX_FRAGMENTED) && (rsel.nonerp_idx >= 0)) { - tx->last_frag_rate_idx = tx->rate_idx; - if (rsel.probe_idx >= 0) - tx->flags &= ~IEEE80211_TX_PROBE_LAST_FRAG; - else - tx->flags |= IEEE80211_TX_PROBE_LAST_FRAG; - tx->rate_idx = rsel.nonerp_idx; - info->tx_rate_idx = rsel.nonerp_idx; - info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; - } else { - tx->last_frag_rate_idx = tx->rate_idx; - info->tx_rate_idx = tx->rate_idx; + len = min_t(int, tx->skb->len + FCS_LEN, + tx->local->fragmentation_threshold); + + /* set up the tx rate control struct we give the RC algo */ + txrc.hw = local_to_hw(tx->local); + txrc.sband = sband; + txrc.bss_conf = &tx->sdata->vif.bss_conf; + txrc.skb = tx->skb; + txrc.reported_rate.idx = -1; + txrc.max_rate_idx = tx->sdata->max_ratectrl_rateidx; + + /* set up RTS protection if desired */ + if (tx->local->rts_threshold < IEEE80211_MAX_RTS_THRESHOLD && + len > tx->local->rts_threshold) { + txrc.rts = rts = true; } - info->tx_rate_idx = tx->rate_idx; - return TX_CONTINUE; -} + /* + * Use short preamble if the BSS can handle it, but not for + * management frames unless we know the receiver can handle + * that -- the management frame might be to a station that + * just wants a probe response. + */ + if (tx->sdata->vif.bss_conf.use_short_preamble && + (ieee80211_is_data(hdr->frame_control) || + (tx->sta && test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE)))) + txrc.short_preamble = short_preamble = true; -static ieee80211_tx_result debug_noinline -ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) -{ - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); - struct ieee80211_supported_band *sband; - sband = tx->local->hw.wiphy->bands[tx->channel->band]; + rate_control_get_rate(tx->sdata, tx->sta, &txrc); + + if (unlikely(info->control.rates[0].idx < 0)) + return TX_DROP; + + if (txrc.reported_rate.idx < 0) + txrc.reported_rate = info->control.rates[0]; if (tx->sta) - info->control.sta = &tx->sta->sta; + tx->sta->last_tx_rate = txrc.reported_rate; - if (!info->control.retry_limit) { - if (!is_multicast_ether_addr(hdr->addr1)) { - int len = min_t(int, tx->skb->len + FCS_LEN, - tx->local->fragmentation_threshold); - if (len > tx->local->rts_threshold - && tx->local->rts_threshold < - IEEE80211_MAX_RTS_THRESHOLD) { - info->flags |= IEEE80211_TX_CTL_USE_RTS_CTS; - info->flags |= - IEEE80211_TX_CTL_LONG_RETRY_LIMIT; - info->control.retry_limit = - tx->local->long_retry_limit; - } else { - info->control.retry_limit = - tx->local->short_retry_limit; - } - } else { - info->control.retry_limit = 1; - } - } + if (unlikely(!info->control.rates[0].count)) + info->control.rates[0].count = 1; - 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. */ - info->control.retries[0].rate_idx = -1; + if (is_multicast_ether_addr(hdr->addr1)) { + /* + * XXX: verify the rate is in the basic rateset + */ + return TX_CONTINUE; } - /* 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 ((tx->sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) && - (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_ERP_G) && - (tx->flags & IEEE80211_TX_UNICAST) && - tx->sdata->bss_conf.use_cts_prot && - !(info->flags & IEEE80211_TX_CTL_USE_RTS_CTS)) - info->flags |= IEEE80211_TX_CTL_USE_CTS_PROTECT; - - /* Transmit data frames using short preambles if the driver supports - * short preambles at the selected rate and short preambles are - * available on the network at the current point in time. */ - if (ieee80211_is_data(hdr->frame_control) && - (sband->bitrates[tx->rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) && - tx->sdata->bss_conf.use_short_preamble && - (!tx->sta || test_sta_flags(tx->sta, WLAN_STA_SHORT_PREAMBLE))) { - info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; + /* + * set up the RTS/CTS rate as the fastest basic rate + * that is not faster than the data rate + * + * XXX: Should this check all retry rates? + */ + if (!(info->control.rates[0].flags & IEEE80211_TX_RC_MCS)) { + s8 baserate = 0; + + rate = &sband->bitrates[info->control.rates[0].idx]; + + for (i = 0; i < sband->n_bitrates; i++) { + /* must be a basic rate */ + if (!(tx->sdata->vif.bss_conf.basic_rates & BIT(i))) + continue; + /* must not be faster than the data rate */ + if (sband->bitrates[i].bitrate > rate->bitrate) + continue; + /* maximum */ + if (sband->bitrates[baserate].bitrate < + sband->bitrates[i].bitrate) + baserate = i; + } + + info->control.rts_cts_rate_idx = baserate; } - if ((info->flags & IEEE80211_TX_CTL_USE_RTS_CTS) || - (info->flags & IEEE80211_TX_CTL_USE_CTS_PROTECT)) { - struct ieee80211_rate *rate; - s8 baserate = -1; - int idx; + for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { + /* + * make sure there's no valid rate following + * an invalid one, just in case drivers don't + * take the API seriously to stop at -1. + */ + if (inval) { + info->control.rates[i].idx = -1; + continue; + } + if (info->control.rates[i].idx < 0) { + inval = true; + continue; + } - /* Do not use multiple retry rates when using RTS/CTS */ - info->control.retries[0].rate_idx = -1; + /* + * For now assume MCS is already set up correctly, this + * needs to be fixed. + */ + if (info->control.rates[i].flags & IEEE80211_TX_RC_MCS) { + WARN_ON(info->control.rates[i].idx > 76); + continue; + } - /* Use min(data rate, max base rate) as CTS/RTS rate */ - rate = &sband->bitrates[tx->rate_idx]; + /* set up RTS protection if desired */ + if (rts) + info->control.rates[i].flags |= + IEEE80211_TX_RC_USE_RTS_CTS; - for (idx = 0; idx < sband->n_bitrates; idx++) { - if (sband->bitrates[idx].bitrate > rate->bitrate) - continue; - if (tx->sdata->bss_conf.basic_rates & BIT(idx) && - (baserate < 0 || - (sband->bitrates[baserate].bitrate - < sband->bitrates[idx].bitrate))) - baserate = idx; + /* RC is busted */ + if (WARN_ON_ONCE(info->control.rates[i].idx >= + sband->n_bitrates)) { + info->control.rates[i].idx = -1; + continue; } - if (baserate >= 0) - info->control.rts_cts_rate_idx = baserate; - else - info->control.rts_cts_rate_idx = 0; + rate = &sband->bitrates[info->control.rates[i].idx]; + + /* set up short preamble */ + if (short_preamble && + rate->flags & IEEE80211_RATE_SHORT_PREAMBLE) + info->control.rates[i].flags |= + IEEE80211_TX_RC_USE_SHORT_PREAMBLE; + + /* set up G protection */ + if (!rts && tx->sdata->vif.bss_conf.use_cts_prot && + rate->flags & IEEE80211_RATE_ERP_G) + info->control.rates[i].flags |= + IEEE80211_TX_RC_USE_CTS_PROTECT; } + return TX_CONTINUE; +} + +static ieee80211_tx_result debug_noinline +ieee80211_tx_h_misc(struct ieee80211_tx_data *tx) +{ + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); + if (tx->sta) info->control.sta = &tx->sta->sta; @@ -602,8 +621,18 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) if (ieee80211_hdrlen(hdr->frame_control) < 24) return TX_CONTINUE; + /* + * Anything but QoS data that has a sequence number field + * (is long enough) gets a sequence number from the global + * counter. + */ if (!ieee80211_is_data_qos(hdr->frame_control)) { + /* driver should assign sequence number */ info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; + /* for pure STA mode without beacons, we can do it */ + hdr->seq_ctrl = cpu_to_le16(tx->sdata->sequence_number); + tx->sdata->sequence_number += 0x10; + tx->sdata->sequence_number &= IEEE80211_SCTL_SEQ; return TX_CONTINUE; } @@ -632,6 +661,7 @@ ieee80211_tx_h_sequence(struct ieee80211_tx_data *tx) static ieee80211_tx_result debug_noinline ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) { + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; size_t hdrlen, per_fragm, num_fragm, payload_len, left; struct sk_buff **frags, *first, *frag; @@ -648,9 +678,7 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) * This scenario is handled in __ieee80211_tx_prepare but extra * caution taken here as fragmented ampdu may cause Tx stop. */ - if (WARN_ON(tx->flags & IEEE80211_TX_CTL_AMPDU || - skb_get_queue_mapping(tx->skb) >= - ieee80211_num_regular_queues(&tx->local->hw))) + if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU)) return TX_DROP; first = tx->skb; @@ -684,20 +712,45 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx) IEEE80211_ENCRYPT_TAILROOM); if (!frag) goto fail; + /* Make sure that all fragments use the same priority so * that they end up using the same TX queue */ frag->priority = first->priority; + skb_reserve(frag, tx->local->tx_headroom + IEEE80211_ENCRYPT_HEADROOM); + + /* copy TX information */ + info = IEEE80211_SKB_CB(frag); + memcpy(info, first->cb, sizeof(frag->cb)); + + /* copy/fill in 802.11 header */ fhdr = (struct ieee80211_hdr *) skb_put(frag, hdrlen); memcpy(fhdr, first->data, hdrlen); - if (i == num_fragm - 2) - fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); fhdr->seq_ctrl = cpu_to_le16(seq | ((i + 1) & IEEE80211_SCTL_FRAG)); + + if (i == num_fragm - 2) { + /* clear MOREFRAGS bit for the last fragment */ + fhdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_MOREFRAGS); + } else { + /* + * No multi-rate retries for fragmented frames, that + * would completely throw off the NAV at other STAs. + */ + info->control.rates[1].idx = -1; + info->control.rates[2].idx = -1; + info->control.rates[3].idx = -1; + info->control.rates[4].idx = -1; + BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); + info->flags &= ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; + } + + /* copy data */ copylen = left > per_fragm ? per_fragm : left; memcpy(skb_put(frag, copylen), pos, copylen); - memcpy(frag->cb, first->cb, sizeof(frag->cb)); + skb_copy_queue_mapping(frag, first); + frag->do_not_encrypt = first->do_not_encrypt; pos += copylen; @@ -757,12 +810,10 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx) tx->extra_frag[0]->len); for (i = 0; i < tx->num_extra_frag; i++) { - if (i + 1 < tx->num_extra_frag) { + if (i + 1 < tx->num_extra_frag) next_len = tx->extra_frag[i + 1]->len; - } else { + else next_len = 0; - tx->rate_idx = tx->last_frag_rate_idx; - } hdr = (struct ieee80211_hdr *)tx->extra_frag[i]->data; hdr->duration_id = ieee80211_duration(tx, 0, next_len); @@ -815,7 +866,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, (struct ieee80211_radiotap_header *) skb->data; struct ieee80211_supported_band *sband; int ret = ieee80211_radiotap_iterator_init(&iterator, rthdr, skb->len); - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); sband = tx->local->hw.wiphy->bands[tx->channel->band]; @@ -829,8 +879,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, */ while (!ret) { - int i, target_rate; - ret = ieee80211_radiotap_iterator_next(&iterator); if (ret) @@ -844,38 +892,6 @@ __ieee80211_parse_tx_radiotap(struct ieee80211_tx_data *tx, * get_unaligned((type *)iterator.this_arg) to dereference * iterator.this_arg for type "type" safely on all arches. */ - case IEEE80211_RADIOTAP_RATE: - /* - * radiotap rate u8 is in 500kbps units eg, 0x02=1Mbps - * ieee80211 rate int is in 100kbps units eg, 0x0a=1Mbps - */ - target_rate = (*iterator.this_arg) * 5; - for (i = 0; i < sband->n_bitrates; i++) { - struct ieee80211_rate *r; - - r = &sband->bitrates[i]; - - if (r->bitrate == target_rate) { - tx->rate_idx = i; - break; - } - } - break; - - case IEEE80211_RADIOTAP_ANTENNA: - /* - * radiotap uses 0 for 1st ant, mac80211 is 1 for - * 1st ant - */ - info->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) { /* @@ -933,7 +949,8 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, struct ieee80211_sub_if_data *sdata; struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - int hdrlen; + int hdrlen, tid; + u8 *qc, *state; memset(tx, 0, sizeof(*tx)); tx->skb = skb; @@ -941,8 +958,6 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, tx->local = local; tx->sdata = IEEE80211_DEV_TO_SUB_IF(dev); tx->channel = local->hw.conf.channel; - tx->rate_idx = -1; - tx->last_frag_rate_idx = -1; /* * Set this flag (used below to indicate "automatic fragmentation"), * it will be cleared/left by radiotap as desired. @@ -966,6 +981,15 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, tx->sta = sta_info_get(local, hdr->addr1); + if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) { + qc = ieee80211_get_qos_ctl(hdr); + tid = *qc & IEEE80211_QOS_CTL_TID_MASK; + + state = &tx->sta->ampdu_mlme.tid_state_tx[tid]; + if (*state == HT_AGG_STATE_OPERATIONAL) + info->flags |= IEEE80211_TX_CTL_AMPDU; + } + if (is_multicast_ether_addr(hdr->addr1)) { tx->flags &= ~IEEE80211_TX_UNICAST; info->flags |= IEEE80211_TX_CTL_NO_ACK; @@ -977,7 +1001,6 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx, if (tx->flags & IEEE80211_TX_FRAGMENTED) { if ((tx->flags & IEEE80211_TX_UNICAST) && skb->len + FCS_LEN > local->fragmentation_threshold && - !local->ops->set_frag_threshold && !(info->flags & IEEE80211_TX_CTL_AMPDU)) tx->flags |= IEEE80211_TX_FRAGMENTED; else @@ -1043,23 +1066,11 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb, if (!tx->extra_frag[i]) continue; info = IEEE80211_SKB_CB(tx->extra_frag[i]); - info->flags &= ~(IEEE80211_TX_CTL_USE_RTS_CTS | - IEEE80211_TX_CTL_USE_CTS_PROTECT | - IEEE80211_TX_CTL_CLEAR_PS_FILT | + info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT | IEEE80211_TX_CTL_FIRST_FRAGMENT); if (netif_subqueue_stopped(local->mdev, tx->extra_frag[i])) return IEEE80211_TX_FRAG_AGAIN; - if (i == tx->num_extra_frag) { - info->tx_rate_idx = tx->last_frag_rate_idx; - - if (tx->flags & IEEE80211_TX_PROBE_LAST_FRAG) - info->flags |= - IEEE80211_TX_CTL_RATE_CTRL_PROBE; - else - info->flags &= - ~IEEE80211_TX_CTL_RATE_CTRL_PROBE; - } ret = local->ops->tx(local_to_hw(local), tx->extra_frag[i]); @@ -1168,7 +1179,7 @@ retry: * queues, there's no reason for a driver to reject * a frame there, warn and drop it. */ - if (WARN_ON(queue >= ieee80211_num_regular_queues(&local->hw))) + if (WARN_ON(info->flags & IEEE80211_TX_CTL_AMPDU)) goto drop; store = &local->pending_packet[queue]; @@ -1196,9 +1207,6 @@ retry: store->skb = skb; store->extra_frag = tx.extra_frag; store->num_extra_frag = tx.num_extra_frag; - store->last_frag_rate_idx = tx.last_frag_rate_idx; - store->last_frag_rate_ctrl_probe = - !!(tx.flags & IEEE80211_TX_PROBE_LAST_FRAG); } out: rcu_read_unlock(); @@ -1465,6 +1473,19 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, goto fail; } + if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) && + local->dynamic_ps_timeout > 0) { + if (local->hw.conf.flags & IEEE80211_CONF_PS) { + ieee80211_stop_queues_by_reason(&local->hw, + IEEE80211_QUEUE_STOP_REASON_PS); + queue_work(local->hw.workqueue, + &local->dynamic_ps_disable_work); + } + + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(local->dynamic_ps_timeout)); + } + nh_pos = skb_network_header(skb) - skb->data; h_pos = skb_transport_header(skb) - skb->data; @@ -1593,12 +1614,10 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb, compare_ether_addr(dev->dev_addr, skb->data + ETH_ALEN) == 0))) { #ifdef CONFIG_MAC80211_VERBOSE_DEBUG - DECLARE_MAC_BUF(mac); - if (net_ratelimit()) - printk(KERN_DEBUG "%s: dropped frame to %s" + printk(KERN_DEBUG "%s: dropped frame to %pM" " (unauthorized port)\n", dev->name, - print_mac(mac, hdr.addr1)); + hdr.addr1); #endif I802_DEBUG_INC(local->tx_handlers_drop_unauth_port); @@ -1757,10 +1776,7 @@ void ieee80211_tx_pending(unsigned long data) store = &local->pending_packet[i]; tx.extra_frag = store->extra_frag; tx.num_extra_frag = store->num_extra_frag; - tx.last_frag_rate_idx = store->last_frag_rate_idx; tx.flags = 0; - if (store->last_frag_rate_ctrl_probe) - tx.flags |= IEEE80211_TX_PROBE_LAST_FRAG; ret = __ieee80211_tx(local, store->skb, &tx); if (ret) { if (ret == IEEE80211_TX_FRAG_AGAIN) @@ -1775,8 +1791,7 @@ void ieee80211_tx_pending(unsigned long data) /* functions for drivers to get certain frames */ -static void ieee80211_beacon_add_tim(struct ieee80211_local *local, - struct ieee80211_if_ap *bss, +static void ieee80211_beacon_add_tim(struct ieee80211_if_ap *bss, struct sk_buff *skb, struct beacon_data *beacon) { @@ -1844,11 +1859,9 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, struct ieee80211_local *local = hw_to_local(hw); struct sk_buff *skb = NULL; struct ieee80211_tx_info *info; - struct net_device *bdev; struct ieee80211_sub_if_data *sdata = NULL; struct ieee80211_if_ap *ap = NULL; struct ieee80211_if_sta *ifsta = NULL; - struct rate_selection rsel; struct beacon_data *beacon; struct ieee80211_supported_band *sband; enum ieee80211_band band = local->hw.conf.channel->band; @@ -1858,7 +1871,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, rcu_read_lock(); sdata = vif_to_sdata(vif); - bdev = sdata->dev; if (sdata->vif.type == NL80211_IFTYPE_AP) { ap = &sdata->u.ap; @@ -1886,12 +1898,12 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, * of the tim bitmap in mac80211 and the driver. */ if (local->tim_in_locked_section) { - ieee80211_beacon_add_tim(local, ap, skb, beacon); + ieee80211_beacon_add_tim(ap, skb, beacon); } else { unsigned long flags; spin_lock_irqsave(&local->sta_lock, flags); - ieee80211_beacon_add_tim(local, ap, skb, beacon); + ieee80211_beacon_add_tim(ap, skb, beacon); spin_unlock_irqrestore(&local->sta_lock, flags); } @@ -1952,33 +1964,23 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw, skb->do_not_encrypt = 1; info->band = band; - rate_control_get_rate(sdata, sband, NULL, skb, &rsel); - - if (unlikely(rsel.rate_idx < 0)) { - if (net_ratelimit()) { - printk(KERN_DEBUG "%s: ieee80211_beacon_get: " - "no rate found\n", - wiphy_name(local->hw.wiphy)); - } - dev_kfree_skb_any(skb); - skb = NULL; - goto out; - } + /* + * XXX: For now, always use the lowest rate + */ + info->control.rates[0].idx = 0; + info->control.rates[0].count = 1; + info->control.rates[1].idx = -1; + info->control.rates[2].idx = -1; + info->control.rates[3].idx = -1; + info->control.rates[4].idx = -1; + BUILD_BUG_ON(IEEE80211_TX_MAX_RATES != 5); info->control.vif = vif; - info->tx_rate_idx = rsel.rate_idx; info->flags |= IEEE80211_TX_CTL_NO_ACK; info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT; info->flags |= IEEE80211_TX_CTL_ASSIGN_SEQ; - if (sdata->bss_conf.use_short_preamble && - sband->bitrates[rsel.rate_idx].flags & IEEE80211_RATE_SHORT_PREAMBLE) - info->flags |= IEEE80211_TX_CTL_SHORT_PREAMBLE; - - info->antenna_sel_tx = local->hw.conf.antenna_sel_tx; - info->control.retry_limit = 1; - -out: + out: rcu_read_unlock(); return skb; } @@ -2023,14 +2025,12 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw, struct sk_buff *skb = NULL; struct sta_info *sta; struct ieee80211_tx_data tx; - struct net_device *bdev; struct ieee80211_sub_if_data *sdata; struct ieee80211_if_ap *bss = NULL; struct beacon_data *beacon; struct ieee80211_tx_info *info; sdata = vif_to_sdata(vif); - bdev = sdata->dev; bss = &sdata->u.ap; if (!bss) diff --git a/net/mac80211/util.c b/net/mac80211/util.c index cee4884b9d06215f86b73630362fae1f9ab87168..fb89e1d0aa0330ad893888c37697e6932bda47ec 100644 --- a/net/mac80211/util.c +++ b/net/mac80211/util.c @@ -239,7 +239,7 @@ __le16 ieee80211_generic_frame_duration(struct ieee80211_hw *hw, erp = 0; if (vif) { sdata = vif_to_sdata(vif); - short_preamble = sdata->bss_conf.use_short_preamble; + short_preamble = sdata->vif.bss_conf.use_short_preamble; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) erp = rate->flags & IEEE80211_RATE_ERP_G; } @@ -272,7 +272,7 @@ __le16 ieee80211_rts_duration(struct ieee80211_hw *hw, erp = 0; if (vif) { sdata = vif_to_sdata(vif); - short_preamble = sdata->bss_conf.use_short_preamble; + short_preamble = sdata->vif.bss_conf.use_short_preamble; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) erp = rate->flags & IEEE80211_RATE_ERP_G; } @@ -312,7 +312,7 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, erp = 0; if (vif) { sdata = vif_to_sdata(vif); - short_preamble = sdata->bss_conf.use_short_preamble; + short_preamble = sdata->vif.bss_conf.use_short_preamble; if (sdata->flags & IEEE80211_SDATA_OPERATING_GMODE) erp = rate->flags & IEEE80211_RATE_ERP_G; } @@ -330,10 +330,20 @@ __le16 ieee80211_ctstoself_duration(struct ieee80211_hw *hw, } EXPORT_SYMBOL(ieee80211_ctstoself_duration); -void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) +static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue, + enum queue_stop_reason reason) { struct ieee80211_local *local = hw_to_local(hw); + /* we don't need to track ampdu queues */ + if (queue < ieee80211_num_regular_queues(hw)) { + __clear_bit(reason, &local->queue_stop_reasons[queue]); + + if (local->queue_stop_reasons[queue] != 0) + /* someone still has this queue stopped */ + return; + } + if (test_bit(queue, local->queues_pending)) { set_bit(queue, local->queues_pending_run); tasklet_schedule(&local->tx_pending_tasklet); @@ -341,22 +351,74 @@ void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) netif_wake_subqueue(local->mdev, queue); } } + +void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue, + enum queue_stop_reason reason) +{ + struct ieee80211_local *local = hw_to_local(hw); + unsigned long flags; + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + __ieee80211_wake_queue(hw, queue, reason); + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); +} + +void ieee80211_wake_queue(struct ieee80211_hw *hw, int queue) +{ + ieee80211_wake_queue_by_reason(hw, queue, + IEEE80211_QUEUE_STOP_REASON_DRIVER); +} EXPORT_SYMBOL(ieee80211_wake_queue); -void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) +static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue, + enum queue_stop_reason reason) { struct ieee80211_local *local = hw_to_local(hw); + /* we don't need to track ampdu queues */ + if (queue < ieee80211_num_regular_queues(hw)) + __set_bit(reason, &local->queue_stop_reasons[queue]); + netif_stop_subqueue(local->mdev, queue); } + +void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue, + enum queue_stop_reason reason) +{ + struct ieee80211_local *local = hw_to_local(hw); + unsigned long flags; + + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + __ieee80211_stop_queue(hw, queue, reason); + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); +} + +void ieee80211_stop_queue(struct ieee80211_hw *hw, int queue) +{ + ieee80211_stop_queue_by_reason(hw, queue, + IEEE80211_QUEUE_STOP_REASON_DRIVER); +} EXPORT_SYMBOL(ieee80211_stop_queue); -void ieee80211_stop_queues(struct ieee80211_hw *hw) +void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw, + enum queue_stop_reason reason) { + struct ieee80211_local *local = hw_to_local(hw); + unsigned long flags; int i; + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (i = 0; i < ieee80211_num_queues(hw); i++) - ieee80211_stop_queue(hw, i); + __ieee80211_stop_queue(hw, i, reason); + + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); +} + +void ieee80211_stop_queues(struct ieee80211_hw *hw) +{ + ieee80211_stop_queues_by_reason(hw, + IEEE80211_QUEUE_STOP_REASON_DRIVER); } EXPORT_SYMBOL(ieee80211_stop_queues); @@ -367,12 +429,24 @@ int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue) } EXPORT_SYMBOL(ieee80211_queue_stopped); -void ieee80211_wake_queues(struct ieee80211_hw *hw) +void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw, + enum queue_stop_reason reason) { + struct ieee80211_local *local = hw_to_local(hw); + unsigned long flags; int i; + spin_lock_irqsave(&local->queue_stop_reason_lock, flags); + for (i = 0; i < hw->queues + hw->ampdu_queues; i++) - ieee80211_wake_queue(hw, i); + __ieee80211_wake_queue(hw, i, reason); + + spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags); +} + +void ieee80211_wake_queues(struct ieee80211_hw *hw) +{ + ieee80211_wake_queues_by_reason(hw, IEEE80211_QUEUE_STOP_REASON_DRIVER); } EXPORT_SYMBOL(ieee80211_wake_queues); @@ -532,8 +606,8 @@ void ieee802_11_parse_elems(u8 *start, size_t len, if (elen >= sizeof(struct ieee80211_ht_cap)) elems->ht_cap_elem = (void *)pos; break; - case WLAN_EID_HT_EXTRA_INFO: - if (elen >= sizeof(struct ieee80211_ht_addt_info)) + case WLAN_EID_HT_INFORMATION: + if (elen >= sizeof(struct ieee80211_ht_info)) elems->ht_info_elem = (void *)pos; break; case WLAN_EID_MESH_ID: @@ -638,19 +712,16 @@ int ieee80211_set_freq(struct ieee80211_sub_if_data *sdata, int freqMHz) if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) { if (sdata->vif.type == NL80211_IFTYPE_ADHOC && - chan->flags & IEEE80211_CHAN_NO_IBSS) { - printk(KERN_DEBUG "%s: IBSS not allowed on frequency " - "%d MHz\n", sdata->dev->name, chan->center_freq); + chan->flags & IEEE80211_CHAN_NO_IBSS) return ret; - } local->oper_channel = chan; + local->oper_channel_type = NL80211_CHAN_NO_HT; if (local->sw_scanning || local->hw_scanning) ret = 0; else - ret = ieee80211_hw_config(local); - - rate_control_clear(local); + ret = ieee80211_hw_config( + local, IEEE80211_CONF_CHANGE_CHANNEL); } return ret; diff --git a/net/mac80211/wep.c b/net/mac80211/wep.c index f0e2d3ecb5c49d5ca1ac6b8752c67bcf48a2350d..7043ddc75498f0f952586c58d4f4371d13984007 100644 --- a/net/mac80211/wep.c +++ b/net/mac80211/wep.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "ieee80211_i.h" @@ -49,17 +50,19 @@ void ieee80211_wep_free(struct ieee80211_local *local) crypto_free_blkcipher(local->wep_rx_tfm); } -static inline int ieee80211_wep_weak_iv(u32 iv, int keylen) +static inline bool ieee80211_wep_weak_iv(u32 iv, int keylen) { - /* Fluhrer, Mantin, and Shamir have reported weaknesses in the + /* + * Fluhrer, Mantin, and Shamir have reported weaknesses in the * key scheduling algorithm of RC4. At least IVs (KeyByte + 3, - * 0xff, N) can be used to speedup attacks, so avoid using them. */ + * 0xff, N) can be used to speedup attacks, so avoid using them. + */ if ((iv & 0xff00) == 0xff00) { u8 B = (iv >> 16) & 0xff; if (B >= 3 && B < 3 + keylen) - return 1; + return true; } - return 0; + return false; } @@ -123,10 +126,10 @@ void ieee80211_wep_encrypt_data(struct crypto_blkcipher *tfm, u8 *rc4key, { struct blkcipher_desc desc = { .tfm = tfm }; struct scatterlist sg; - __le32 *icv; + __le32 icv; - icv = (__le32 *)(data + data_len); - *icv = cpu_to_le32(~crc32_le(~0, data, data_len)); + icv = cpu_to_le32(~crc32_le(~0, data, data_len)); + put_unaligned(icv, (__le32 *)(data + data_len)); crypto_blkcipher_setkey(tfm, rc4key, klen); sg_init_one(&sg, data, data_len + WEP_ICV_LEN); @@ -268,7 +271,7 @@ int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, } -u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) +bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) { struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; unsigned int hdrlen; @@ -276,16 +279,13 @@ u8 * ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key) u32 iv; if (!ieee80211_has_protected(hdr->frame_control)) - return NULL; + return false; hdrlen = ieee80211_hdrlen(hdr->frame_control); ivpos = skb->data + hdrlen; iv = (ivpos[0] << 16) | (ivpos[1] << 8) | ivpos[2]; - if (ieee80211_wep_weak_iv(iv, key->conf.keylen)) - return ivpos; - - return NULL; + return ieee80211_wep_weak_iv(iv, key->conf.keylen); } ieee80211_rx_result @@ -329,6 +329,8 @@ static int wep_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) ieee80211_tx_result ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) { + int i; + ieee80211_tx_set_protected(tx); if (wep_encrypt_skb(tx, tx->skb) < 0) { @@ -337,9 +339,8 @@ ieee80211_crypto_wep_encrypt(struct ieee80211_tx_data *tx) } if (tx->extra_frag) { - int i; for (i = 0; i < tx->num_extra_frag; i++) { - if (wep_encrypt_skb(tx, tx->extra_frag[i]) < 0) { + if (wep_encrypt_skb(tx, tx->extra_frag[i])) { I802_DEBUG_INC(tx->local-> tx_handlers_drop_wep); return TX_DROP; diff --git a/net/mac80211/wep.h b/net/mac80211/wep.h index e587172115b8397acc0ce4f92d401e5b288101a4..d3f0db48314e11f00fed332a046798dcaeff4913 100644 --- a/net/mac80211/wep.h +++ b/net/mac80211/wep.h @@ -26,7 +26,7 @@ int ieee80211_wep_encrypt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); int ieee80211_wep_decrypt(struct ieee80211_local *local, struct sk_buff *skb, struct ieee80211_key *key); -u8 *ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); +bool ieee80211_wep_is_weak_iv(struct sk_buff *skb, struct ieee80211_key *key); ieee80211_rx_result ieee80211_crypto_wep_decrypt(struct ieee80211_rx_data *rx); diff --git a/net/mac80211/wext.c b/net/mac80211/wext.c index ab4ddba874be5ce73cb4ffc0b5e7e1da77053dac..7162d5816f39146adbf65a8fac47d6bd2b11ee86 100644 --- a/net/mac80211/wext.c +++ b/net/mac80211/wext.c @@ -135,48 +135,6 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev, return -EOPNOTSUPP; } -static int ieee80211_ioctl_giwname(struct net_device *dev, - struct iw_request_info *info, - char *name, char *extra) -{ - struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_supported_band *sband; - u8 is_ht = 0, is_a = 0, is_b = 0, is_g = 0; - - - sband = local->hw.wiphy->bands[IEEE80211_BAND_5GHZ]; - if (sband) { - is_a = 1; - is_ht |= sband->ht_info.ht_supported; - } - - sband = local->hw.wiphy->bands[IEEE80211_BAND_2GHZ]; - if (sband) { - int i; - /* Check for mandatory rates */ - for (i = 0; i < sband->n_bitrates; i++) { - if (sband->bitrates[i].bitrate == 10) - is_b = 1; - if (sband->bitrates[i].bitrate == 60) - is_g = 1; - } - is_ht |= sband->ht_info.ht_supported; - } - - strcpy(name, "IEEE 802.11"); - if (is_a) - strcat(name, "a"); - if (is_b) - strcat(name, "b"); - if (is_g) - strcat(name, "g"); - if (is_ht) - strcat(name, "n"); - - return 0; -} - - static int ieee80211_ioctl_giwrange(struct net_device *dev, struct iw_request_info *info, struct iw_point *data, char *extra) @@ -266,78 +224,6 @@ static int ieee80211_ioctl_giwrange(struct net_device *dev, } -static int ieee80211_ioctl_siwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); - struct ieee80211_local *local = sdata->local; - int type; - - if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) - return -EOPNOTSUPP; - - switch (*mode) { - case IW_MODE_INFRA: - type = NL80211_IFTYPE_STATION; - break; - case IW_MODE_ADHOC: - /* Setting ad-hoc mode on non ibss channel is not - * supported. - */ - if (local->oper_channel && - (local->oper_channel->flags & IEEE80211_CHAN_NO_IBSS)) - return -EOPNOTSUPP; - - type = NL80211_IFTYPE_ADHOC; - break; - case IW_MODE_REPEAT: - type = NL80211_IFTYPE_WDS; - break; - case IW_MODE_MONITOR: - type = NL80211_IFTYPE_MONITOR; - break; - default: - return -EINVAL; - } - - return ieee80211_if_change_type(sdata, type); -} - - -static int ieee80211_ioctl_giwmode(struct net_device *dev, - struct iw_request_info *info, - __u32 *mode, char *extra) -{ - struct ieee80211_sub_if_data *sdata; - - sdata = IEEE80211_DEV_TO_SUB_IF(dev); - switch (sdata->vif.type) { - case NL80211_IFTYPE_AP: - *mode = IW_MODE_MASTER; - break; - case NL80211_IFTYPE_STATION: - *mode = IW_MODE_INFRA; - break; - case NL80211_IFTYPE_ADHOC: - *mode = IW_MODE_ADHOC; - break; - case NL80211_IFTYPE_MONITOR: - *mode = IW_MODE_MONITOR; - break; - case NL80211_IFTYPE_WDS: - *mode = IW_MODE_REPEAT; - break; - case NL80211_IFTYPE_AP_VLAN: - *mode = IW_MODE_SECOND; /* FIXME */ - break; - default: - *mode = IW_MODE_AUTO; - break; - } - return 0; -} - static int ieee80211_ioctl_siwfreq(struct net_device *dev, struct iw_request_info *info, struct iw_freq *freq, char *extra) @@ -415,13 +301,6 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev, return 0; } - if (sdata->vif.type == NL80211_IFTYPE_AP) { - memcpy(sdata->u.ap.ssid, ssid, len); - memset(sdata->u.ap.ssid + len, 0, - IEEE80211_MAX_SSID_LEN - len); - sdata->u.ap.ssid_len = len; - return ieee80211_if_config(sdata, IEEE80211_IFCC_SSID); - } return -EOPNOTSUPP; } @@ -445,15 +324,6 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev, return res; } - if (sdata->vif.type == NL80211_IFTYPE_AP) { - len = sdata->u.ap.ssid_len; - if (len > IW_ESSID_MAX_SIZE) - len = IW_ESSID_MAX_SIZE; - memcpy(ssid, sdata->u.ap.ssid, len); - data->length = len; - data->flags = 1; - return 0; - } return -EOPNOTSUPP; } @@ -548,8 +418,7 @@ static int ieee80211_ioctl_siwscan(struct net_device *dev, if (sdata->vif.type != NL80211_IFTYPE_STATION && sdata->vif.type != NL80211_IFTYPE_ADHOC && - sdata->vif.type != NL80211_IFTYPE_MESH_POINT && - sdata->vif.type != NL80211_IFTYPE_AP) + sdata->vif.type != NL80211_IFTYPE_MESH_POINT) return -EOPNOTSUPP; /* if SSID was specified explicitly then use that */ @@ -644,8 +513,8 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev, sta = sta_info_get(local, sdata->u.sta.bssid); - if (sta && sta->last_txrate_idx < sband->n_bitrates) - rate->value = sband->bitrates[sta->last_txrate_idx].bitrate; + if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS)) + rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate; else rate->value = 0; @@ -664,45 +533,35 @@ static int ieee80211_ioctl_siwtxpower(struct net_device *dev, union iwreq_data *data, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - bool need_reconfig = 0; + struct ieee80211_channel* chan = local->hw.conf.channel; + u32 reconf_flags = 0; int new_power_level; if ((data->txpower.flags & IW_TXPOW_TYPE) != IW_TXPOW_DBM) return -EINVAL; if (data->txpower.flags & IW_TXPOW_RANGE) return -EINVAL; + if (!chan) + return -EINVAL; - if (data->txpower.fixed) { - new_power_level = data->txpower.value; - } else { - /* - * 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; - + if (data->txpower.fixed) + new_power_level = min(data->txpower.value, chan->max_power); + else /* Automatic power level setting */ new_power_level = chan->max_power; - } if (local->hw.conf.power_level != new_power_level) { local->hw.conf.power_level = new_power_level; - need_reconfig = 1; + reconf_flags |= IEEE80211_CONF_CHANGE_POWER; } if (local->hw.conf.radio_enabled != !(data->txpower.disabled)) { local->hw.conf.radio_enabled = !(data->txpower.disabled); - need_reconfig = 1; + reconf_flags |= IEEE80211_CONF_CHANGE_RADIO_ENABLED; ieee80211_led_radio(local, local->hw.conf.radio_enabled); } - if (need_reconfig) { - ieee80211_hw_config(local); - /* The return value of hw_config is not of big interest here, - * as it doesn't say that it failed because of _this_ config - * change or something else. Ignore it. */ - } + if (reconf_flags) + ieee80211_hw_config(local, reconf_flags); return 0; } @@ -779,14 +638,6 @@ static int ieee80211_ioctl_siwfrag(struct net_device *dev, local->fragmentation_threshold = frag->value & ~0x1; } - /* If the wlan card performs fragmentation in hardware/firmware, - * configure it here */ - - if (local->ops->set_frag_threshold) - return local->ops->set_frag_threshold( - local_to_hw(local), - local->fragmentation_threshold); - return 0; } @@ -814,21 +665,16 @@ static int ieee80211_ioctl_siwretry(struct net_device *dev, (retry->flags & IW_RETRY_TYPE) != IW_RETRY_LIMIT) return -EINVAL; - if (retry->flags & IW_RETRY_MAX) - local->long_retry_limit = retry->value; - else if (retry->flags & IW_RETRY_MIN) - local->short_retry_limit = retry->value; - else { - local->long_retry_limit = retry->value; - local->short_retry_limit = retry->value; + if (retry->flags & IW_RETRY_MAX) { + local->hw.conf.long_frame_max_tx_count = retry->value; + } else if (retry->flags & IW_RETRY_MIN) { + local->hw.conf.short_frame_max_tx_count = retry->value; + } else { + local->hw.conf.long_frame_max_tx_count = retry->value; + local->hw.conf.short_frame_max_tx_count = retry->value; } - if (local->ops->set_retry_limit) { - return local->ops->set_retry_limit( - local_to_hw(local), - local->short_retry_limit, - local->long_retry_limit); - } + ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS); return 0; } @@ -845,14 +691,15 @@ static int ieee80211_ioctl_giwretry(struct net_device *dev, /* first return min value, iwconfig will ask max value * later if needed */ retry->flags |= IW_RETRY_LIMIT; - retry->value = local->short_retry_limit; - if (local->long_retry_limit != local->short_retry_limit) + retry->value = local->hw.conf.short_frame_max_tx_count; + if (local->hw.conf.long_frame_max_tx_count != + local->hw.conf.short_frame_max_tx_count) retry->flags |= IW_RETRY_MIN; return 0; } if (retry->flags & IW_RETRY_MAX) { retry->flags = IW_RETRY_LIMIT | IW_RETRY_MAX; - retry->value = local->long_retry_limit; + retry->value = local->hw.conf.long_frame_max_tx_count; } return 0; @@ -983,25 +830,56 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev, struct iw_param *wrq, char *extra) { + struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev); struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); struct ieee80211_conf *conf = &local->hw.conf; + int ret = 0, timeout = 0; + bool ps; + + if (sdata->vif.type != NL80211_IFTYPE_STATION) + return -EINVAL; if (wrq->disabled) { - conf->flags &= ~IEEE80211_CONF_PS; - return ieee80211_hw_config(local); + ps = false; + timeout = 0; + goto set; } switch (wrq->flags & IW_POWER_MODE) { case IW_POWER_ON: /* If not specified */ case IW_POWER_MODE: /* If set all mask */ case IW_POWER_ALL_R: /* If explicitely state all */ - conf->flags |= IEEE80211_CONF_PS; + ps = true; break; - default: /* Otherwise we don't support it */ - return -EINVAL; + default: /* Otherwise we ignore */ + break; + } + + if (wrq->flags & IW_POWER_TIMEOUT) + timeout = wrq->value / 1000; + +set: + if (ps == local->powersave && timeout == local->dynamic_ps_timeout) + return ret; + + local->powersave = ps; + local->dynamic_ps_timeout = timeout; + + if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) { + if (!(local->hw.flags & IEEE80211_HW_NO_STACK_DYNAMIC_PS) && + local->dynamic_ps_timeout > 0) + mod_timer(&local->dynamic_ps_timer, jiffies + + msecs_to_jiffies(local->dynamic_ps_timeout)); + else { + if (local->powersave) + conf->flags |= IEEE80211_CONF_PS; + else + conf->flags &= ~IEEE80211_CONF_PS; + } + ret = ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_PS); } - return ieee80211_hw_config(local); + return ret; } static int ieee80211_ioctl_giwpower(struct net_device *dev, @@ -1010,9 +888,8 @@ static int ieee80211_ioctl_giwpower(struct net_device *dev, char *extra) { struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr); - struct ieee80211_conf *conf = &local->hw.conf; - wrqu->power.disabled = !(conf->flags & IEEE80211_CONF_PS); + wrqu->power.disabled = !local->powersave; return 0; } @@ -1176,13 +1053,13 @@ static int ieee80211_ioctl_siwencodeext(struct net_device *dev, static const iw_handler ieee80211_handler[] = { (iw_handler) NULL, /* SIOCSIWCOMMIT */ - (iw_handler) ieee80211_ioctl_giwname, /* SIOCGIWNAME */ + (iw_handler) cfg80211_wext_giwname, /* SIOCGIWNAME */ (iw_handler) NULL, /* SIOCSIWNWID */ (iw_handler) NULL, /* SIOCGIWNWID */ (iw_handler) ieee80211_ioctl_siwfreq, /* SIOCSIWFREQ */ (iw_handler) ieee80211_ioctl_giwfreq, /* SIOCGIWFREQ */ - (iw_handler) ieee80211_ioctl_siwmode, /* SIOCSIWMODE */ - (iw_handler) ieee80211_ioctl_giwmode, /* SIOCGIWMODE */ + (iw_handler) cfg80211_wext_siwmode, /* SIOCSIWMODE */ + (iw_handler) cfg80211_wext_giwmode, /* SIOCGIWMODE */ (iw_handler) NULL, /* SIOCSIWSENS */ (iw_handler) NULL, /* SIOCGIWSENS */ (iw_handler) NULL /* not used */, /* SIOCSIWRANGE */ diff --git a/net/mac80211/wme.c b/net/mac80211/wme.c index 139b5f267b34b4e38d2925996936ab7f389061a9..ac71b38f7cb5cb217180bb2cef3bcfa4b6540b40 100644 --- a/net/mac80211/wme.c +++ b/net/mac80211/wme.c @@ -114,8 +114,8 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) { struct ieee80211_master_priv *mpriv = netdev_priv(dev); struct ieee80211_local *local = mpriv->local; + struct ieee80211_hw *hw = &local->hw; struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); struct sta_info *sta; u16 queue; u8 tid; @@ -124,21 +124,19 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) if (unlikely(queue >= local->hw.queues)) queue = local->hw.queues - 1; - if (info->flags & IEEE80211_TX_CTL_REQUEUE) { + if (skb->requeue) { + if (!hw->ampdu_queues) + return queue; + rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK; if (sta) { - struct ieee80211_hw *hw = &local->hw; int ampdu_queue = sta->tid_to_tx_q[tid]; if ((ampdu_queue < ieee80211_num_queues(hw)) && - test_bit(ampdu_queue, local->queue_pool)) { + test_bit(ampdu_queue, local->queue_pool)) queue = ampdu_queue; - info->flags |= IEEE80211_TX_CTL_AMPDU; - } else { - info->flags &= ~IEEE80211_TX_CTL_AMPDU; - } } rcu_read_unlock(); @@ -159,20 +157,18 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb) *p++ = ack_policy | tid; *p = 0; + if (!hw->ampdu_queues) + return queue; + rcu_read_lock(); sta = sta_info_get(local, hdr->addr1); if (sta) { int ampdu_queue = sta->tid_to_tx_q[tid]; - struct ieee80211_hw *hw = &local->hw; if ((ampdu_queue < ieee80211_num_queues(hw)) && - test_bit(ampdu_queue, local->queue_pool)) { + test_bit(ampdu_queue, local->queue_pool)) queue = ampdu_queue; - info->flags |= IEEE80211_TX_CTL_AMPDU; - } else { - info->flags &= ~IEEE80211_TX_CTL_AMPDU; - } } rcu_read_unlock(); @@ -206,13 +202,11 @@ int ieee80211_ht_agg_queue_add(struct ieee80211_local *local, * on the previous queue * since HT is strict in order */ #ifdef CONFIG_MAC80211_HT_DEBUG - if (net_ratelimit()) { - DECLARE_MAC_BUF(mac); + if (net_ratelimit()) printk(KERN_DEBUG "allocated aggregation queue" - " %d tid %d addr %s pool=0x%lX\n", - i, tid, print_mac(mac, sta->sta.addr), + " %d tid %d addr %pM pool=0x%lX\n", + i, tid, sta->sta.addr, local->queue_pool[0]); - } #endif /* CONFIG_MAC80211_HT_DEBUG */ return 0; } diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 6db649480e8ff2ae1aa8369be77c2e1e7220b562..7aa63caf8d50c3c7c8b2b87b77b9a3515fd5a4ca 100644 --- a/net/mac80211/wpa.c +++ b/net/mac80211/wpa.c @@ -49,8 +49,7 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) !(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 - */ + /* hwaccel - with no need for preallocated room for MMIC */ return TX_CONTINUE; } @@ -67,8 +66,6 @@ ieee80211_tx_h_michael_mic_add(struct ieee80211_tx_data *tx) #else authenticator = 1; #endif - /* At this point we know we're using ALG_TKIP. To get the MIC key - * we now will rely on the offset from the ieee80211_key_conf::key */ key_offset = authenticator ? NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY : NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY; @@ -90,11 +87,8 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) u8 mic[MICHAEL_MIC_LEN]; struct sk_buff *skb = rx->skb; int authenticator = 1, wpa_test = 0; - DECLARE_MAC_BUF(mac); - /* - * No way to verify the MIC if the hardware stripped it - */ + /* No way to verify the MIC if the hardware stripped it */ if (rx->status->flag & RX_FLAG_MMIC_STRIPPED) return RX_CONTINUE; @@ -116,8 +110,6 @@ ieee80211_rx_h_michael_mic_verify(struct ieee80211_rx_data *rx) #else authenticator = 1; #endif - /* At this point we know we're using ALG_TKIP. To get the MIC key - * we now will rely on the offset from the ieee80211_key_conf::key */ key_offset = authenticator ? NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY : NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY; @@ -202,6 +194,7 @@ ieee80211_tx_result ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; + int i; ieee80211_tx_set_protected(tx); @@ -209,9 +202,8 @@ ieee80211_crypto_tkip_encrypt(struct ieee80211_tx_data *tx) return TX_DROP; if (tx->extra_frag) { - int i; for (i = 0; i < tx->num_extra_frag; i++) { - if (tkip_encrypt_skb(tx, tx->extra_frag[i]) < 0) + if (tkip_encrypt_skb(tx, tx->extra_frag[i])) return TX_DROP; } } @@ -227,7 +219,6 @@ ieee80211_crypto_tkip_decrypt(struct ieee80211_rx_data *rx) int hdrlen, res, hwaccel = 0, wpa_test = 0; struct ieee80211_key *key = rx->key; struct sk_buff *skb = rx->skb; - DECLARE_MAC_BUF(mac); hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -350,7 +341,7 @@ static inline void ccmp_pn2hdr(u8 *hdr, u8 *pn, int key_id) } -static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr) +static inline void ccmp_hdr2pn(u8 *pn, u8 *hdr) { pn[0] = hdr[7]; pn[1] = hdr[6]; @@ -358,7 +349,6 @@ static inline int ccmp_hdr2pn(u8 *pn, u8 *hdr) pn[3] = hdr[4]; pn[4] = hdr[1]; pn[5] = hdr[0]; - return (hdr[3] >> 6) & 0x03; } @@ -373,7 +363,7 @@ static int ccmp_encrypt_skb(struct ieee80211_tx_data *tx, struct sk_buff *skb) 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 " + /* hwaccel - with no need for preallocated room for CCMP * header or MIC fields */ info->control.hw_key = &tx->key->conf; return 0; @@ -426,6 +416,7 @@ ieee80211_tx_result ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) { struct sk_buff *skb = tx->skb; + int i; ieee80211_tx_set_protected(tx); @@ -433,9 +424,8 @@ ieee80211_crypto_ccmp_encrypt(struct ieee80211_tx_data *tx) return TX_DROP; if (tx->extra_frag) { - int i; for (i = 0; i < tx->num_extra_frag; i++) { - if (ccmp_encrypt_skb(tx, tx->extra_frag[i]) < 0) + if (ccmp_encrypt_skb(tx, tx->extra_frag[i])) return TX_DROP; } } @@ -453,7 +443,6 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) struct sk_buff *skb = rx->skb; u8 pn[CCMP_PN_LEN]; int data_len; - DECLARE_MAC_BUF(mac); hdrlen = ieee80211_hdrlen(hdr->frame_control); @@ -468,7 +457,7 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) (rx->status->flag & RX_FLAG_IV_STRIPPED)) return RX_CONTINUE; - (void) ccmp_hdr2pn(pn, skb->data + hdrlen); + ccmp_hdr2pn(pn, skb->data + hdrlen); if (memcmp(pn, key->u.ccmp.rx_pn[rx->queue], CCMP_PN_LEN) <= 0) { key->u.ccmp.replays++; @@ -483,9 +472,8 @@ ieee80211_crypto_ccmp_decrypt(struct ieee80211_rx_data *rx) key->u.ccmp.tfm, key->u.ccmp.rx_crypto_buf, skb->data + hdrlen + CCMP_HDR_LEN, data_len, skb->data + skb->len - CCMP_MIC_LEN, - skb->data + hdrlen + CCMP_HDR_LEN)) { + skb->data + hdrlen + CCMP_HDR_LEN)) return RX_DROP_UNUSABLE; - } } memcpy(key->u.ccmp.rx_pn[rx->queue], pn, CCMP_PN_LEN); diff --git a/net/netfilter/Kconfig b/net/netfilter/Kconfig index 25dcef9f219493a597511c157efc9c2fe4f343e6..c2bac9cd0cafe6861a43ae619a9087eeba8ed1d5 100644 --- a/net/netfilter/Kconfig +++ b/net/netfilter/Kconfig @@ -373,11 +373,10 @@ config NETFILTER_XT_TARGET_MARK config NETFILTER_XT_TARGET_NFLOG tristate '"NFLOG" target support' default m if NETFILTER_ADVANCED=n + select NETFILTER_NETLINK_LOG help This option enables the NFLOG target, which allows to LOG - messages through the netfilter logging API, which can use - either the old LOG target, the old ULOG target or nfnetlink_log - as backend. + messages through nfnetlink_log. To compile it as a module, choose M here. If unsure, say N. diff --git a/net/netfilter/ipvs/ip_vs_conn.c b/net/netfilter/ipvs/ip_vs_conn.c index 9a24332fbed878ec43c54a7db45dee81108a9be2..60aba45023ff7e9d687d356c1aaf4edfebde7e2d 100644 --- a/net/netfilter/ipvs/ip_vs_conn.c +++ b/net/netfilter/ipvs/ip_vs_conn.c @@ -820,13 +820,11 @@ static int ip_vs_conn_seq_show(struct seq_file *seq, void *v) #ifdef CONFIG_IP_VS_IPV6 if (cp->af == AF_INET6) - seq_printf(seq, - "%-3s " NIP6_FMT " %04X " NIP6_FMT - " %04X " NIP6_FMT " %04X %-11s %7lu\n", + seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X %pI6 %04X %-11s %7lu\n", ip_vs_proto_name(cp->protocol), - NIP6(cp->caddr.in6), ntohs(cp->cport), - NIP6(cp->vaddr.in6), ntohs(cp->vport), - NIP6(cp->daddr.in6), ntohs(cp->dport), + &cp->caddr.in6, ntohs(cp->cport), + &cp->vaddr.in6, ntohs(cp->vport), + &cp->daddr.in6, ntohs(cp->dport), ip_vs_state_name(cp->protocol, cp->state), (cp->timer.expires-jiffies)/HZ); else @@ -883,13 +881,11 @@ static int ip_vs_conn_sync_seq_show(struct seq_file *seq, void *v) #ifdef CONFIG_IP_VS_IPV6 if (cp->af == AF_INET6) - seq_printf(seq, - "%-3s " NIP6_FMT " %04X " NIP6_FMT - " %04X " NIP6_FMT " %04X %-11s %-6s %7lu\n", + seq_printf(seq, "%-3s %pI6 %04X %pI6 %04X %pI6 %04X %-11s %-6s %7lu\n", ip_vs_proto_name(cp->protocol), - NIP6(cp->caddr.in6), ntohs(cp->cport), - NIP6(cp->vaddr.in6), ntohs(cp->vport), - NIP6(cp->daddr.in6), ntohs(cp->dport), + &cp->caddr.in6, ntohs(cp->cport), + &cp->vaddr.in6, ntohs(cp->vport), + &cp->daddr.in6, ntohs(cp->dport), ip_vs_state_name(cp->protocol, cp->state), ip_vs_origin_name(cp->flags), (cp->timer.expires-jiffies)/HZ); diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 958abf3e5f8cd3baceb46fedb6ec4b2f0cd4a15e..cb3e031335ebc4af9a95e5a359c10c3805c8754d 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -730,9 +730,9 @@ static int ip_vs_out_icmp(struct sk_buff *skb, int *related) if (ic == NULL) return NF_DROP; - IP_VS_DBG(12, "Outgoing ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n", + IP_VS_DBG(12, "Outgoing ICMP (%d,%d) %pI4->%pI4\n", ic->type, ntohs(icmp_id(ic)), - NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); + &iph->saddr, &iph->daddr); /* * Work through seeing if this is for us. @@ -805,9 +805,9 @@ static int ip_vs_out_icmp_v6(struct sk_buff *skb, int *related) if (ic == NULL) return NF_DROP; - IP_VS_DBG(12, "Outgoing ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n", + IP_VS_DBG(12, "Outgoing ICMPv6 (%d,%d) %pI6->%pI6\n", ic->icmp6_type, ntohs(icmpv6_id(ic)), - NIP6(iph->saddr), NIP6(iph->daddr)); + &iph->saddr, &iph->daddr); /* * Work through seeing if this is for us. @@ -1070,9 +1070,9 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) if (ic == NULL) return NF_DROP; - IP_VS_DBG(12, "Incoming ICMP (%d,%d) %u.%u.%u.%u->%u.%u.%u.%u\n", + IP_VS_DBG(12, "Incoming ICMP (%d,%d) %pI4->%pI4\n", ic->type, ntohs(icmp_id(ic)), - NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); + &iph->saddr, &iph->daddr); /* * Work through seeing if this is for us. @@ -1127,8 +1127,8 @@ ip_vs_in_icmp(struct sk_buff *skb, int *related, unsigned int hooknum) /* Ensure the checksum is correct */ if (!skb_csum_unnecessary(skb) && ip_vs_checksum_complete(skb, ihl)) { /* Failed checksum! */ - IP_VS_DBG(1, "Incoming ICMP: failed checksum from %d.%d.%d.%d!\n", - NIPQUAD(iph->saddr)); + IP_VS_DBG(1, "Incoming ICMP: failed checksum from %pI4!\n", + &iph->saddr); goto out; } @@ -1175,9 +1175,9 @@ ip_vs_in_icmp_v6(struct sk_buff *skb, int *related, unsigned int hooknum) if (ic == NULL) return NF_DROP; - IP_VS_DBG(12, "Incoming ICMPv6 (%d,%d) " NIP6_FMT "->" NIP6_FMT "\n", + IP_VS_DBG(12, "Incoming ICMPv6 (%d,%d) %pI6->%pI6\n", ic->icmp6_type, ntohs(icmpv6_id(ic)), - NIP6(iph->saddr), NIP6(iph->daddr)); + &iph->saddr, &iph->daddr); /* * Work through seeing if this is for us. diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 0302cf3e503968f5a4a2b8a89b3828b536e71871..e01061f49cdc644b0fe99d48457795458f55aa91 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -1168,15 +1168,9 @@ ip_vs_add_service(struct ip_vs_service_user_kern *u, } #ifdef CONFIG_IP_VS_IPV6 - if (u->af == AF_INET6) { - if (!sched->supports_ipv6) { - ret = -EAFNOSUPPORT; - goto out_err; - } - if ((u->netmask < 1) || (u->netmask > 128)) { - ret = -EINVAL; - goto out_err; - } + if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) { + ret = -EINVAL; + goto out_err; } #endif @@ -1272,15 +1266,9 @@ ip_vs_edit_service(struct ip_vs_service *svc, struct ip_vs_service_user_kern *u) old_sched = sched; #ifdef CONFIG_IP_VS_IPV6 - if (u->af == AF_INET6) { - if (!sched->supports_ipv6) { - ret = -EAFNOSUPPORT; - goto out; - } - if ((u->netmask < 1) || (u->netmask > 128)) { - ret = -EINVAL; - goto out; - } + if (u->af == AF_INET6 && (u->netmask < 1 || u->netmask > 128)) { + ret = -EINVAL; + goto out; } #endif @@ -1557,7 +1545,7 @@ static struct ctl_table vs_vars[] = { .data = &sysctl_ip_vs_amemthresh, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, #ifdef CONFIG_IP_VS_DEBUG { @@ -1565,7 +1553,7 @@ static struct ctl_table vs_vars[] = { .data = &sysctl_ip_vs_debug_level, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, #endif { @@ -1573,28 +1561,28 @@ static struct ctl_table vs_vars[] = { .data = &sysctl_ip_vs_am_droprate, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .procname = "drop_entry", .data = &sysctl_ip_vs_drop_entry, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_do_defense_mode, + .proc_handler = proc_do_defense_mode, }, { .procname = "drop_packet", .data = &sysctl_ip_vs_drop_packet, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_do_defense_mode, + .proc_handler = proc_do_defense_mode, }, { .procname = "secure_tcp", .data = &sysctl_ip_vs_secure_tcp, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_do_defense_mode, + .proc_handler = proc_do_defense_mode, }, #if 0 { @@ -1602,84 +1590,84 @@ static struct ctl_table vs_vars[] = { .data = &vs_timeout_table_dos.timeout[IP_VS_S_ESTABLISHED], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "timeout_synsent", .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYN_SENT], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "timeout_synrecv", .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYN_RECV], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "timeout_finwait", .data = &vs_timeout_table_dos.timeout[IP_VS_S_FIN_WAIT], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "timeout_timewait", .data = &vs_timeout_table_dos.timeout[IP_VS_S_TIME_WAIT], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "timeout_close", .data = &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "timeout_closewait", .data = &vs_timeout_table_dos.timeout[IP_VS_S_CLOSE_WAIT], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "timeout_lastack", .data = &vs_timeout_table_dos.timeout[IP_VS_S_LAST_ACK], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "timeout_listen", .data = &vs_timeout_table_dos.timeout[IP_VS_S_LISTEN], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "timeout_synack", .data = &vs_timeout_table_dos.timeout[IP_VS_S_SYNACK], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "timeout_udp", .data = &vs_timeout_table_dos.timeout[IP_VS_S_UDP], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "timeout_icmp", .data = &vs_timeout_table_dos.timeout[IP_VS_S_ICMP], .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, #endif { @@ -1687,35 +1675,35 @@ static struct ctl_table vs_vars[] = { .data = &sysctl_ip_vs_cache_bypass, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .procname = "expire_nodest_conn", .data = &sysctl_ip_vs_expire_nodest_conn, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .procname = "expire_quiescent_template", .data = &sysctl_ip_vs_expire_quiescent_template, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .procname = "sync_threshold", .data = &sysctl_ip_vs_sync_threshold, .maxlen = sizeof(sysctl_ip_vs_sync_threshold), .mode = 0644, - .proc_handler = &proc_do_sync_threshold, + .proc_handler = proc_do_sync_threshold, }, { .procname = "nat_icmp_send", .data = &sysctl_ip_vs_nat_icmp_send, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = 0 } }; @@ -1867,9 +1855,9 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v) if (iter->table == ip_vs_svc_table) { #ifdef CONFIG_IP_VS_IPV6 if (svc->af == AF_INET6) - seq_printf(seq, "%s [" NIP6_FMT "]:%04X %s ", + seq_printf(seq, "%s [%pI6]:%04X %s ", ip_vs_proto_name(svc->protocol), - NIP6(svc->addr.in6), + &svc->addr.in6, ntohs(svc->port), svc->scheduler->name); else @@ -1895,9 +1883,9 @@ static int ip_vs_info_seq_show(struct seq_file *seq, void *v) #ifdef CONFIG_IP_VS_IPV6 if (dest->af == AF_INET6) seq_printf(seq, - " -> [" NIP6_FMT "]:%04X" + " -> [%pI6]:%04X" " %-7s %-6d %-10d %-10d\n", - NIP6(dest->addr.in6), + &dest->addr.in6, ntohs(dest->port), ip_vs_fwd_name(atomic_read(&dest->conn_flags)), atomic_read(&dest->weight), @@ -2141,8 +2129,8 @@ do_ip_vs_set_ctl(struct sock *sk, int cmd, void __user *user, unsigned int len) /* Check for valid protocol: TCP or UDP, even for fwmark!=0 */ if (usvc.protocol != IPPROTO_TCP && usvc.protocol != IPPROTO_UDP) { - IP_VS_ERR("set_ctl: invalid protocol: %d %d.%d.%d.%d:%d %s\n", - usvc.protocol, NIPQUAD(usvc.addr.ip), + IP_VS_ERR("set_ctl: invalid protocol: %d %pI4:%d %s\n", + usvc.protocol, &usvc.addr.ip, ntohs(usvc.port), usvc.sched_name); ret = -EFAULT; goto out_unlock; diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c index a16943fd72f175646ffa8406ac741ca56a2015db..a9dac74bb13f7550a4aa9c6b95a84566d4e1fd68 100644 --- a/net/netfilter/ipvs/ip_vs_dh.c +++ b/net/netfilter/ipvs/ip_vs_dh.c @@ -64,9 +64,16 @@ struct ip_vs_dh_bucket { /* * Returns hash value for IPVS DH entry */ -static inline unsigned ip_vs_dh_hashkey(__be32 addr) +static inline unsigned ip_vs_dh_hashkey(int af, const union nf_inet_addr *addr) { - return (ntohl(addr)*2654435761UL) & IP_VS_DH_TAB_MASK; + __be32 addr_fold = addr->ip; + +#ifdef CONFIG_IP_VS_IPV6 + if (af == AF_INET6) + addr_fold = addr->ip6[0]^addr->ip6[1]^ + addr->ip6[2]^addr->ip6[3]; +#endif + return (ntohl(addr_fold)*2654435761UL) & IP_VS_DH_TAB_MASK; } @@ -74,9 +81,10 @@ static inline unsigned ip_vs_dh_hashkey(__be32 addr) * Get ip_vs_dest associated with supplied parameters. */ static inline struct ip_vs_dest * -ip_vs_dh_get(struct ip_vs_dh_bucket *tbl, __be32 addr) +ip_vs_dh_get(int af, struct ip_vs_dh_bucket *tbl, + const union nf_inet_addr *addr) { - return (tbl[ip_vs_dh_hashkey(addr)]).dest; + return (tbl[ip_vs_dh_hashkey(af, addr)]).dest; } @@ -202,12 +210,14 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) { struct ip_vs_dest *dest; struct ip_vs_dh_bucket *tbl; - struct iphdr *iph = ip_hdr(skb); + struct ip_vs_iphdr iph; + + ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); IP_VS_DBG(6, "ip_vs_dh_schedule(): Scheduling...\n"); tbl = (struct ip_vs_dh_bucket *)svc->sched_data; - dest = ip_vs_dh_get(tbl, iph->daddr); + dest = ip_vs_dh_get(svc->af, tbl, &iph.daddr); if (!dest || !(dest->flags & IP_VS_DEST_F_AVAILABLE) || atomic_read(&dest->weight) <= 0 @@ -215,11 +225,10 @@ ip_vs_dh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) return NULL; } - IP_VS_DBG(6, "DH: destination IP address %u.%u.%u.%u " - "--> server %u.%u.%u.%u:%d\n", - NIPQUAD(iph->daddr), - NIPQUAD(dest->addr.ip), - ntohs(dest->port)); + IP_VS_DBG_BUF(6, "DH: destination IP address %s --> server %s:%d\n", + IP_VS_DBG_ADDR(svc->af, &iph.daddr), + IP_VS_DBG_ADDR(svc->af, &dest->addr), + ntohs(dest->port)); return dest; } @@ -234,9 +243,6 @@ static struct ip_vs_scheduler ip_vs_dh_scheduler = .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, .n_list = LIST_HEAD_INIT(ip_vs_dh_scheduler.n_list), -#ifdef CONFIG_IP_VS_IPV6 - .supports_ipv6 = 0, -#endif .init_service = ip_vs_dh_init_svc, .done_service = ip_vs_dh_done_svc, .update_service = ip_vs_dh_update_svc, diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 2e7dbd8b73a431fd4ef2b4cdb2346e497e853854..428edbf481cce9814ac860ca20ee3b89aeb38ab3 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c @@ -178,10 +178,8 @@ static int ip_vs_ftp_out(struct ip_vs_app *app, struct ip_vs_conn *cp, &start, &end) != 1) return 1; - IP_VS_DBG(7, "PASV response (%u.%u.%u.%u:%d) -> " - "%u.%u.%u.%u:%d detected\n", - NIPQUAD(from.ip), ntohs(port), - NIPQUAD(cp->caddr.ip), 0); + IP_VS_DBG(7, "PASV response (%pI4:%d) -> %pI4:%d detected\n", + &from.ip, ntohs(port), &cp->caddr.ip, 0); /* * Now update or create an connection entry for it @@ -312,8 +310,7 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, &start, &end) != 1) return 1; - IP_VS_DBG(7, "PORT %u.%u.%u.%u:%d detected\n", - NIPQUAD(to.ip), ntohs(port)); + IP_VS_DBG(7, "PORT %pI4:%d detected\n", &to.ip, ntohs(port)); /* Passive mode off */ cp->app_data = NULL; @@ -321,9 +318,9 @@ static int ip_vs_ftp_in(struct ip_vs_app *app, struct ip_vs_conn *cp, /* * Now update or create a connection entry for it */ - IP_VS_DBG(7, "protocol %s %u.%u.%u.%u:%d %u.%u.%u.%u:%d\n", + IP_VS_DBG(7, "protocol %s %pI4:%d %pI4:%d\n", ip_vs_proto_name(iph->protocol), - NIPQUAD(to.ip), ntohs(port), NIPQUAD(cp->vaddr.ip), 0); + &to.ip, ntohs(port), &cp->vaddr.ip, 0); n_cp = ip_vs_conn_in_get(AF_INET, iph->protocol, &to, port, diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c index 6ecef3518cac190090e3748039c7aa4e4f2053c6..9394f539966aea9f91dd37a6165969d31b5a8ee8 100644 --- a/net/netfilter/ipvs/ip_vs_lblc.c +++ b/net/netfilter/ipvs/ip_vs_lblc.c @@ -86,7 +86,8 @@ static int sysctl_ip_vs_lblc_expiration = 24*60*60*HZ; */ struct ip_vs_lblc_entry { struct list_head list; - __be32 addr; /* destination IP address */ + int af; /* address family */ + union nf_inet_addr addr; /* destination IP address */ struct ip_vs_dest *dest; /* real server (cache) */ unsigned long lastuse; /* last used time */ }; @@ -115,7 +116,7 @@ static ctl_table vs_vars_table[] = { .data = &sysctl_ip_vs_lblc_expiration, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 } }; @@ -137,9 +138,17 @@ static inline void ip_vs_lblc_free(struct ip_vs_lblc_entry *en) /* * Returns hash value for IPVS LBLC entry */ -static inline unsigned ip_vs_lblc_hashkey(__be32 addr) +static inline unsigned +ip_vs_lblc_hashkey(int af, const union nf_inet_addr *addr) { - return (ntohl(addr)*2654435761UL) & IP_VS_LBLC_TAB_MASK; + __be32 addr_fold = addr->ip; + +#ifdef CONFIG_IP_VS_IPV6 + if (af == AF_INET6) + addr_fold = addr->ip6[0]^addr->ip6[1]^ + addr->ip6[2]^addr->ip6[3]; +#endif + return (ntohl(addr_fold)*2654435761UL) & IP_VS_LBLC_TAB_MASK; } @@ -150,7 +159,7 @@ static inline unsigned ip_vs_lblc_hashkey(__be32 addr) static void ip_vs_lblc_hash(struct ip_vs_lblc_table *tbl, struct ip_vs_lblc_entry *en) { - unsigned hash = ip_vs_lblc_hashkey(en->addr); + unsigned hash = ip_vs_lblc_hashkey(en->af, &en->addr); list_add(&en->list, &tbl->bucket[hash]); atomic_inc(&tbl->entries); @@ -162,13 +171,14 @@ ip_vs_lblc_hash(struct ip_vs_lblc_table *tbl, struct ip_vs_lblc_entry *en) * lock */ static inline struct ip_vs_lblc_entry * -ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __be32 addr) +ip_vs_lblc_get(int af, struct ip_vs_lblc_table *tbl, + const union nf_inet_addr *addr) { - unsigned hash = ip_vs_lblc_hashkey(addr); + unsigned hash = ip_vs_lblc_hashkey(af, addr); struct ip_vs_lblc_entry *en; list_for_each_entry(en, &tbl->bucket[hash], list) - if (en->addr == addr) + if (ip_vs_addr_equal(af, &en->addr, addr)) return en; return NULL; @@ -180,12 +190,12 @@ ip_vs_lblc_get(struct ip_vs_lblc_table *tbl, __be32 addr) * address to a server. Called under write lock. */ static inline struct ip_vs_lblc_entry * -ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, __be32 daddr, +ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr, struct ip_vs_dest *dest) { struct ip_vs_lblc_entry *en; - en = ip_vs_lblc_get(tbl, daddr); + en = ip_vs_lblc_get(dest->af, tbl, daddr); if (!en) { en = kmalloc(sizeof(*en), GFP_ATOMIC); if (!en) { @@ -193,7 +203,8 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, __be32 daddr, return NULL; } - en->addr = daddr; + en->af = dest->af; + ip_vs_addr_copy(dest->af, &en->addr, daddr); en->lastuse = jiffies; atomic_inc(&dest->refcnt); @@ -369,7 +380,7 @@ static int ip_vs_lblc_done_svc(struct ip_vs_service *svc) static inline struct ip_vs_dest * -__ip_vs_lblc_schedule(struct ip_vs_service *svc, struct iphdr *iph) +__ip_vs_lblc_schedule(struct ip_vs_service *svc) { struct ip_vs_dest *dest, *least; int loh, doh; @@ -420,12 +431,13 @@ __ip_vs_lblc_schedule(struct ip_vs_service *svc, struct iphdr *iph) } } - IP_VS_DBG(6, "LBLC: server %d.%d.%d.%d:%d " - "activeconns %d refcnt %d weight %d overhead %d\n", - NIPQUAD(least->addr.ip), ntohs(least->port), - atomic_read(&least->activeconns), - atomic_read(&least->refcnt), - atomic_read(&least->weight), loh); + IP_VS_DBG_BUF(6, "LBLC: server %s:%d " + "activeconns %d refcnt %d weight %d overhead %d\n", + IP_VS_DBG_ADDR(least->af, &least->addr), + ntohs(least->port), + atomic_read(&least->activeconns), + atomic_read(&least->refcnt), + atomic_read(&least->weight), loh); return least; } @@ -459,15 +471,17 @@ static struct ip_vs_dest * ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) { struct ip_vs_lblc_table *tbl = svc->sched_data; - struct iphdr *iph = ip_hdr(skb); + struct ip_vs_iphdr iph; struct ip_vs_dest *dest = NULL; struct ip_vs_lblc_entry *en; + ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); + IP_VS_DBG(6, "ip_vs_lblc_schedule(): Scheduling...\n"); /* First look in our cache */ read_lock(&svc->sched_lock); - en = ip_vs_lblc_get(tbl, iph->daddr); + en = ip_vs_lblc_get(svc->af, tbl, &iph.daddr); if (en) { /* We only hold a read lock, but this is atomic */ en->lastuse = jiffies; @@ -491,7 +505,7 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) goto out; /* No cache entry or it is invalid, time to schedule */ - dest = __ip_vs_lblc_schedule(svc, iph); + dest = __ip_vs_lblc_schedule(svc); if (!dest) { IP_VS_DBG(1, "no destination available\n"); return NULL; @@ -499,15 +513,13 @@ ip_vs_lblc_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) /* If we fail to create a cache entry, we'll just use the valid dest */ write_lock(&svc->sched_lock); - ip_vs_lblc_new(tbl, iph->daddr, dest); + ip_vs_lblc_new(tbl, &iph.daddr, dest); write_unlock(&svc->sched_lock); out: - IP_VS_DBG(6, "LBLC: destination IP address %u.%u.%u.%u " - "--> server %u.%u.%u.%u:%d\n", - NIPQUAD(iph->daddr), - NIPQUAD(dest->addr.ip), - ntohs(dest->port)); + IP_VS_DBG_BUF(6, "LBLC: destination IP address %s --> server %s:%d\n", + IP_VS_DBG_ADDR(svc->af, &iph.daddr), + IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port)); return dest; } @@ -522,9 +534,6 @@ static struct ip_vs_scheduler ip_vs_lblc_scheduler = .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, .n_list = LIST_HEAD_INIT(ip_vs_lblc_scheduler.n_list), -#ifdef CONFIG_IP_VS_IPV6 - .supports_ipv6 = 0, -#endif .init_service = ip_vs_lblc_init_svc, .done_service = ip_vs_lblc_done_svc, .schedule = ip_vs_lblc_schedule, diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c index 1f75ea83bcf8654256912317a4d8c4d8ce92e77a..92dc76a6842cc101a1f14afed07ae65841d10440 100644 --- a/net/netfilter/ipvs/ip_vs_lblcr.c +++ b/net/netfilter/ipvs/ip_vs_lblcr.c @@ -202,12 +202,13 @@ static inline struct ip_vs_dest *ip_vs_dest_set_min(struct ip_vs_dest_set *set) } } - IP_VS_DBG(6, "ip_vs_dest_set_min: server %d.%d.%d.%d:%d " - "activeconns %d refcnt %d weight %d overhead %d\n", - NIPQUAD(least->addr.ip), ntohs(least->port), - atomic_read(&least->activeconns), - atomic_read(&least->refcnt), - atomic_read(&least->weight), loh); + IP_VS_DBG_BUF(6, "ip_vs_dest_set_min: server %s:%d " + "activeconns %d refcnt %d weight %d overhead %d\n", + IP_VS_DBG_ADDR(least->af, &least->addr), + ntohs(least->port), + atomic_read(&least->activeconns), + atomic_read(&least->refcnt), + atomic_read(&least->weight), loh); return least; } @@ -248,12 +249,12 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set) } } - IP_VS_DBG(6, "ip_vs_dest_set_max: server %d.%d.%d.%d:%d " - "activeconns %d refcnt %d weight %d overhead %d\n", - NIPQUAD(most->addr.ip), ntohs(most->port), - atomic_read(&most->activeconns), - atomic_read(&most->refcnt), - atomic_read(&most->weight), moh); + IP_VS_DBG_BUF(6, "ip_vs_dest_set_max: server %s:%d " + "activeconns %d refcnt %d weight %d overhead %d\n", + IP_VS_DBG_ADDR(most->af, &most->addr), ntohs(most->port), + atomic_read(&most->activeconns), + atomic_read(&most->refcnt), + atomic_read(&most->weight), moh); return most; } @@ -264,7 +265,8 @@ static inline struct ip_vs_dest *ip_vs_dest_set_max(struct ip_vs_dest_set *set) */ struct ip_vs_lblcr_entry { struct list_head list; - __be32 addr; /* destination IP address */ + int af; /* address family */ + union nf_inet_addr addr; /* destination IP address */ struct ip_vs_dest_set set; /* destination server set */ unsigned long lastuse; /* last used time */ }; @@ -293,7 +295,7 @@ static ctl_table vs_vars_table[] = { .data = &sysctl_ip_vs_lblcr_expiration, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 } }; @@ -311,9 +313,17 @@ static inline void ip_vs_lblcr_free(struct ip_vs_lblcr_entry *en) /* * Returns hash value for IPVS LBLCR entry */ -static inline unsigned ip_vs_lblcr_hashkey(__be32 addr) +static inline unsigned +ip_vs_lblcr_hashkey(int af, const union nf_inet_addr *addr) { - return (ntohl(addr)*2654435761UL) & IP_VS_LBLCR_TAB_MASK; + __be32 addr_fold = addr->ip; + +#ifdef CONFIG_IP_VS_IPV6 + if (af == AF_INET6) + addr_fold = addr->ip6[0]^addr->ip6[1]^ + addr->ip6[2]^addr->ip6[3]; +#endif + return (ntohl(addr_fold)*2654435761UL) & IP_VS_LBLCR_TAB_MASK; } @@ -324,7 +334,7 @@ static inline unsigned ip_vs_lblcr_hashkey(__be32 addr) static void ip_vs_lblcr_hash(struct ip_vs_lblcr_table *tbl, struct ip_vs_lblcr_entry *en) { - unsigned hash = ip_vs_lblcr_hashkey(en->addr); + unsigned hash = ip_vs_lblcr_hashkey(en->af, &en->addr); list_add(&en->list, &tbl->bucket[hash]); atomic_inc(&tbl->entries); @@ -336,13 +346,14 @@ ip_vs_lblcr_hash(struct ip_vs_lblcr_table *tbl, struct ip_vs_lblcr_entry *en) * read lock. */ static inline struct ip_vs_lblcr_entry * -ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __be32 addr) +ip_vs_lblcr_get(int af, struct ip_vs_lblcr_table *tbl, + const union nf_inet_addr *addr) { - unsigned hash = ip_vs_lblcr_hashkey(addr); + unsigned hash = ip_vs_lblcr_hashkey(af, addr); struct ip_vs_lblcr_entry *en; list_for_each_entry(en, &tbl->bucket[hash], list) - if (en->addr == addr) + if (ip_vs_addr_equal(af, &en->addr, addr)) return en; return NULL; @@ -354,12 +365,12 @@ ip_vs_lblcr_get(struct ip_vs_lblcr_table *tbl, __be32 addr) * IP address to a server. Called under write lock. */ static inline struct ip_vs_lblcr_entry * -ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, __be32 daddr, +ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr, struct ip_vs_dest *dest) { struct ip_vs_lblcr_entry *en; - en = ip_vs_lblcr_get(tbl, daddr); + en = ip_vs_lblcr_get(dest->af, tbl, daddr); if (!en) { en = kmalloc(sizeof(*en), GFP_ATOMIC); if (!en) { @@ -367,7 +378,8 @@ ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, __be32 daddr, return NULL; } - en->addr = daddr; + en->af = dest->af; + ip_vs_addr_copy(dest->af, &en->addr, daddr); en->lastuse = jiffies; /* initilize its dest set */ @@ -544,7 +556,7 @@ static int ip_vs_lblcr_done_svc(struct ip_vs_service *svc) static inline struct ip_vs_dest * -__ip_vs_lblcr_schedule(struct ip_vs_service *svc, struct iphdr *iph) +__ip_vs_lblcr_schedule(struct ip_vs_service *svc) { struct ip_vs_dest *dest, *least; int loh, doh; @@ -596,12 +608,13 @@ __ip_vs_lblcr_schedule(struct ip_vs_service *svc, struct iphdr *iph) } } - IP_VS_DBG(6, "LBLCR: server %d.%d.%d.%d:%d " - "activeconns %d refcnt %d weight %d overhead %d\n", - NIPQUAD(least->addr.ip), ntohs(least->port), - atomic_read(&least->activeconns), - atomic_read(&least->refcnt), - atomic_read(&least->weight), loh); + IP_VS_DBG_BUF(6, "LBLCR: server %s:%d " + "activeconns %d refcnt %d weight %d overhead %d\n", + IP_VS_DBG_ADDR(least->af, &least->addr), + ntohs(least->port), + atomic_read(&least->activeconns), + atomic_read(&least->refcnt), + atomic_read(&least->weight), loh); return least; } @@ -635,15 +648,17 @@ static struct ip_vs_dest * ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) { struct ip_vs_lblcr_table *tbl = svc->sched_data; - struct iphdr *iph = ip_hdr(skb); + struct ip_vs_iphdr iph; struct ip_vs_dest *dest = NULL; struct ip_vs_lblcr_entry *en; + ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); + IP_VS_DBG(6, "ip_vs_lblcr_schedule(): Scheduling...\n"); /* First look in our cache */ read_lock(&svc->sched_lock); - en = ip_vs_lblcr_get(tbl, iph->daddr); + en = ip_vs_lblcr_get(svc->af, tbl, &iph.daddr); if (en) { /* We only hold a read lock, but this is atomic */ en->lastuse = jiffies; @@ -673,7 +688,7 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) } /* The cache entry is invalid, time to schedule */ - dest = __ip_vs_lblcr_schedule(svc, iph); + dest = __ip_vs_lblcr_schedule(svc); if (!dest) { IP_VS_DBG(1, "no destination available\n"); read_unlock(&svc->sched_lock); @@ -691,7 +706,7 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) goto out; /* No cache entry, time to schedule */ - dest = __ip_vs_lblcr_schedule(svc, iph); + dest = __ip_vs_lblcr_schedule(svc); if (!dest) { IP_VS_DBG(1, "no destination available\n"); return NULL; @@ -699,15 +714,13 @@ ip_vs_lblcr_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) /* If we fail to create a cache entry, we'll just use the valid dest */ write_lock(&svc->sched_lock); - ip_vs_lblcr_new(tbl, iph->daddr, dest); + ip_vs_lblcr_new(tbl, &iph.daddr, dest); write_unlock(&svc->sched_lock); out: - IP_VS_DBG(6, "LBLCR: destination IP address %u.%u.%u.%u " - "--> server %u.%u.%u.%u:%d\n", - NIPQUAD(iph->daddr), - NIPQUAD(dest->addr.ip), - ntohs(dest->port)); + IP_VS_DBG_BUF(6, "LBLCR: destination IP address %s --> server %s:%d\n", + IP_VS_DBG_ADDR(svc->af, &iph.daddr), + IP_VS_DBG_ADDR(svc->af, &dest->addr), ntohs(dest->port)); return dest; } @@ -722,9 +735,6 @@ static struct ip_vs_scheduler ip_vs_lblcr_scheduler = .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, .n_list = LIST_HEAD_INIT(ip_vs_lblcr_scheduler.n_list), -#ifdef CONFIG_IP_VS_IPV6 - .supports_ipv6 = 0, -#endif .init_service = ip_vs_lblcr_init_svc, .done_service = ip_vs_lblcr_done_svc, .schedule = ip_vs_lblcr_schedule, diff --git a/net/netfilter/ipvs/ip_vs_lc.c b/net/netfilter/ipvs/ip_vs_lc.c index b69f808ac461215f0f07be0556e355e4b5e27707..51912cab777bb5349012709639c1efa1ff774005 100644 --- a/net/netfilter/ipvs/ip_vs_lc.c +++ b/net/netfilter/ipvs/ip_vs_lc.c @@ -81,9 +81,6 @@ static struct ip_vs_scheduler ip_vs_lc_scheduler = { .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, .n_list = LIST_HEAD_INIT(ip_vs_lc_scheduler.n_list), -#ifdef CONFIG_IP_VS_IPV6 - .supports_ipv6 = 1, -#endif .schedule = ip_vs_lc_schedule, }; diff --git a/net/netfilter/ipvs/ip_vs_nq.c b/net/netfilter/ipvs/ip_vs_nq.c index 9a2d8033f08f1f2b0d8707d3650361f231d3500a..6758ad2ceaaf66130f881ff672cc0d9444d1416a 100644 --- a/net/netfilter/ipvs/ip_vs_nq.c +++ b/net/netfilter/ipvs/ip_vs_nq.c @@ -116,9 +116,6 @@ static struct ip_vs_scheduler ip_vs_nq_scheduler = .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, .n_list = LIST_HEAD_INIT(ip_vs_nq_scheduler.n_list), -#ifdef CONFIG_IP_VS_IPV6 - .supports_ipv6 = 1, -#endif .schedule = ip_vs_nq_schedule, }; diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c index 0791f9e08feb7f04d8e2ea56aa08f1064fe6232f..a01520e3d6b8266c671f57aedfb251f70bba61f4 100644 --- a/net/netfilter/ipvs/ip_vs_proto.c +++ b/net/netfilter/ipvs/ip_vs_proto.c @@ -164,26 +164,21 @@ ip_vs_tcpudp_debug_packet_v4(struct ip_vs_protocol *pp, if (ih == NULL) sprintf(buf, "%s TRUNCATED", pp->name); else if (ih->frag_off & htons(IP_OFFSET)) - sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag", - pp->name, NIPQUAD(ih->saddr), - NIPQUAD(ih->daddr)); + sprintf(buf, "%s %pI4->%pI4 frag", + pp->name, &ih->saddr, &ih->daddr); else { __be16 _ports[2], *pptr ; pptr = skb_header_pointer(skb, offset + ih->ihl*4, sizeof(_ports), _ports); if (pptr == NULL) - sprintf(buf, "%s TRUNCATED %u.%u.%u.%u->%u.%u.%u.%u", - pp->name, - NIPQUAD(ih->saddr), - NIPQUAD(ih->daddr)); + sprintf(buf, "%s TRUNCATED %pI4->%pI4", + pp->name, &ih->saddr, &ih->daddr); else - sprintf(buf, "%s %u.%u.%u.%u:%u->%u.%u.%u.%u:%u", + sprintf(buf, "%s %pI4:%u->%pI4:%u", pp->name, - NIPQUAD(ih->saddr), - ntohs(pptr[0]), - NIPQUAD(ih->daddr), - ntohs(pptr[1])); + &ih->saddr, ntohs(pptr[0]), + &ih->daddr, ntohs(pptr[1])); } printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); @@ -203,26 +198,21 @@ ip_vs_tcpudp_debug_packet_v6(struct ip_vs_protocol *pp, if (ih == NULL) sprintf(buf, "%s TRUNCATED", pp->name); else if (ih->nexthdr == IPPROTO_FRAGMENT) - sprintf(buf, "%s " NIP6_FMT "->" NIP6_FMT " frag", - pp->name, NIP6(ih->saddr), - NIP6(ih->daddr)); + sprintf(buf, "%s %pI6->%pI6 frag", + pp->name, &ih->saddr, &ih->daddr); else { __be16 _ports[2], *pptr; pptr = skb_header_pointer(skb, offset + sizeof(struct ipv6hdr), sizeof(_ports), _ports); if (pptr == NULL) - sprintf(buf, "%s TRUNCATED " NIP6_FMT "->" NIP6_FMT, - pp->name, - NIP6(ih->saddr), - NIP6(ih->daddr)); + sprintf(buf, "%s TRUNCATED %pI6->%pI6", + pp->name, &ih->saddr, &ih->daddr); else - sprintf(buf, "%s " NIP6_FMT ":%u->" NIP6_FMT ":%u", + sprintf(buf, "%s %pI6:%u->%pI6:%u", pp->name, - NIP6(ih->saddr), - ntohs(pptr[0]), - NIP6(ih->daddr), - ntohs(pptr[1])); + &ih->saddr, ntohs(pptr[0]), + &ih->daddr, ntohs(pptr[1])); } printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); diff --git a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c index 80ab0c8e5b4af113e7a67fa0f4032a808d248119..79f56c1e7c19b0ef771ed553ea90d743e736b9f8 100644 --- a/net/netfilter/ipvs/ip_vs_proto_ah_esp.c +++ b/net/netfilter/ipvs/ip_vs_proto_ah_esp.c @@ -135,9 +135,8 @@ ah_esp_debug_packet_v4(struct ip_vs_protocol *pp, const struct sk_buff *skb, if (ih == NULL) sprintf(buf, "%s TRUNCATED", pp->name); else - sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u", - pp->name, NIPQUAD(ih->saddr), - NIPQUAD(ih->daddr)); + sprintf(buf, "%s %pI4->%pI4", + pp->name, &ih->saddr, &ih->daddr); printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); } @@ -154,9 +153,8 @@ ah_esp_debug_packet_v6(struct ip_vs_protocol *pp, const struct sk_buff *skb, if (ih == NULL) sprintf(buf, "%s TRUNCATED", pp->name); else - sprintf(buf, "%s " NIP6_FMT "->" NIP6_FMT, - pp->name, NIP6(ih->saddr), - NIP6(ih->daddr)); + sprintf(buf, "%s %pI6->%pI6", + pp->name, &ih->saddr, &ih->daddr); printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf); } diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index dd4566ea2bff7bce68baabf916eb4b9ae25c9a6f..8cba41802850b041e5062c38f786da00f3ed6697 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c @@ -192,8 +192,8 @@ tcp_snat_handler(struct sk_buff *skb, /* Adjust TCP checksums */ if (skb->ip_summed == CHECKSUM_PARTIAL) { tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr, - htonl(oldlen), - htonl(skb->len - tcphoff)); + htons(oldlen), + htons(skb->len - tcphoff)); } else if (!cp->app) { /* Only port and addr are changed, do fast csum update */ tcp_fast_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr, @@ -267,8 +267,8 @@ tcp_dnat_handler(struct sk_buff *skb, */ if (skb->ip_summed == CHECKSUM_PARTIAL) { tcp_partial_csum_update(cp->af, tcph, &cp->daddr, &cp->vaddr, - htonl(oldlen), - htonl(skb->len - tcphoff)); + htons(oldlen), + htons(skb->len - tcphoff)); } else if (!cp->app) { /* Only port and addr are changed, do fast csum update */ tcp_fast_csum_update(cp->af, tcph, &cp->vaddr, &cp->daddr, diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index 6eb6039d63434f6ecc4bd511edb390e0e91bbd6a..d2930a71084bd3079e980ba7af0ecdb4d00204fa 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c @@ -203,8 +203,8 @@ udp_snat_handler(struct sk_buff *skb, */ if (skb->ip_summed == CHECKSUM_PARTIAL) { udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr, - htonl(oldlen), - htonl(skb->len - udphoff)); + htons(oldlen), + htons(skb->len - udphoff)); } else if (!cp->app && (udph->check != 0)) { /* Only port and addr are changed, do fast csum update */ udp_fast_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr, @@ -279,8 +279,8 @@ udp_dnat_handler(struct sk_buff *skb, */ if (skb->ip_summed == CHECKSUM_PARTIAL) { udp_partial_csum_update(cp->af, udph, &cp->daddr, &cp->vaddr, - htonl(oldlen), - htonl(skb->len - udphoff)); + htons(oldlen), + htons(skb->len - udphoff)); } else if (!cp->app && (udph->check != 0)) { /* Only port and addr are changed, do fast csum update */ udp_fast_csum_update(cp->af, udph, &cp->vaddr, &cp->daddr, diff --git a/net/netfilter/ipvs/ip_vs_rr.c b/net/netfilter/ipvs/ip_vs_rr.c index a22195f68ac4cf102b536be9d1a40354eab76723..8fb51c169eb852daeb9e1117fde96f07a9d2b595 100644 --- a/net/netfilter/ipvs/ip_vs_rr.c +++ b/net/netfilter/ipvs/ip_vs_rr.c @@ -89,9 +89,6 @@ static struct ip_vs_scheduler ip_vs_rr_scheduler = { .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, .n_list = LIST_HEAD_INIT(ip_vs_rr_scheduler.n_list), -#ifdef CONFIG_IP_VS_IPV6 - .supports_ipv6 = 1, -#endif .init_service = ip_vs_rr_init_svc, .update_service = ip_vs_rr_update_svc, .schedule = ip_vs_rr_schedule, diff --git a/net/netfilter/ipvs/ip_vs_sed.c b/net/netfilter/ipvs/ip_vs_sed.c index 7d2f22f04b8389f2cd2f1ba8b20f72e49e7f511f..691a6a0086e18c90f2b0548951b1218fc9a4958f 100644 --- a/net/netfilter/ipvs/ip_vs_sed.c +++ b/net/netfilter/ipvs/ip_vs_sed.c @@ -118,9 +118,6 @@ static struct ip_vs_scheduler ip_vs_sed_scheduler = .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, .n_list = LIST_HEAD_INIT(ip_vs_sed_scheduler.n_list), -#ifdef CONFIG_IP_VS_IPV6 - .supports_ipv6 = 1, -#endif .schedule = ip_vs_sed_schedule, }; diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c index 1d96de27fefdbaab3022f0178218a7207e8a2fc5..0e53955ef1396ec0d157163eb66ab00f2e590506 100644 --- a/net/netfilter/ipvs/ip_vs_sh.c +++ b/net/netfilter/ipvs/ip_vs_sh.c @@ -61,9 +61,16 @@ struct ip_vs_sh_bucket { /* * Returns hash value for IPVS SH entry */ -static inline unsigned ip_vs_sh_hashkey(__be32 addr) +static inline unsigned ip_vs_sh_hashkey(int af, const union nf_inet_addr *addr) { - return (ntohl(addr)*2654435761UL) & IP_VS_SH_TAB_MASK; + __be32 addr_fold = addr->ip; + +#ifdef CONFIG_IP_VS_IPV6 + if (af == AF_INET6) + addr_fold = addr->ip6[0]^addr->ip6[1]^ + addr->ip6[2]^addr->ip6[3]; +#endif + return (ntohl(addr_fold)*2654435761UL) & IP_VS_SH_TAB_MASK; } @@ -71,9 +78,10 @@ static inline unsigned ip_vs_sh_hashkey(__be32 addr) * Get ip_vs_dest associated with supplied parameters. */ static inline struct ip_vs_dest * -ip_vs_sh_get(struct ip_vs_sh_bucket *tbl, __be32 addr) +ip_vs_sh_get(int af, struct ip_vs_sh_bucket *tbl, + const union nf_inet_addr *addr) { - return (tbl[ip_vs_sh_hashkey(addr)]).dest; + return (tbl[ip_vs_sh_hashkey(af, addr)]).dest; } @@ -199,12 +207,14 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) { struct ip_vs_dest *dest; struct ip_vs_sh_bucket *tbl; - struct iphdr *iph = ip_hdr(skb); + struct ip_vs_iphdr iph; + + ip_vs_fill_iphdr(svc->af, skb_network_header(skb), &iph); IP_VS_DBG(6, "ip_vs_sh_schedule(): Scheduling...\n"); tbl = (struct ip_vs_sh_bucket *)svc->sched_data; - dest = ip_vs_sh_get(tbl, iph->saddr); + dest = ip_vs_sh_get(svc->af, tbl, &iph.saddr); if (!dest || !(dest->flags & IP_VS_DEST_F_AVAILABLE) || atomic_read(&dest->weight) <= 0 @@ -212,11 +222,10 @@ ip_vs_sh_schedule(struct ip_vs_service *svc, const struct sk_buff *skb) return NULL; } - IP_VS_DBG(6, "SH: source IP address %u.%u.%u.%u " - "--> server %u.%u.%u.%u:%d\n", - NIPQUAD(iph->saddr), - NIPQUAD(dest->addr.ip), - ntohs(dest->port)); + IP_VS_DBG_BUF(6, "SH: source IP address %s --> server %s:%d\n", + IP_VS_DBG_ADDR(svc->af, &iph.saddr), + IP_VS_DBG_ADDR(svc->af, &dest->addr), + ntohs(dest->port)); return dest; } @@ -231,9 +240,6 @@ static struct ip_vs_scheduler ip_vs_sh_scheduler = .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, .n_list = LIST_HEAD_INIT(ip_vs_sh_scheduler.n_list), -#ifdef CONFIG_IP_VS_IPV6 - .supports_ipv6 = 0, -#endif .init_service = ip_vs_sh_init_svc, .done_service = ip_vs_sh_done_svc, .update_service = ip_vs_sh_update_svc, diff --git a/net/netfilter/ipvs/ip_vs_sync.c b/net/netfilter/ipvs/ip_vs_sync.c index de5e7e118eed51e9b10be8f9c76cc91e9f7ed9d0..6be5d4efa51ba58c9f13bb40b475bcb58c6795ca 100644 --- a/net/netfilter/ipvs/ip_vs_sync.c +++ b/net/netfilter/ipvs/ip_vs_sync.c @@ -580,8 +580,8 @@ static int bind_mcastif_addr(struct socket *sock, char *ifname) IP_VS_ERR("You probably need to specify IP address on " "multicast interface.\n"); - IP_VS_DBG(7, "binding socket with (%s) %u.%u.%u.%u\n", - ifname, NIPQUAD(addr)); + IP_VS_DBG(7, "binding socket with (%s) %pI4\n", + ifname, &addr); /* Now bind the socket with the address of multicast interface */ sin.sin_family = AF_INET; diff --git a/net/netfilter/ipvs/ip_vs_wlc.c b/net/netfilter/ipvs/ip_vs_wlc.c index 8c596e712599fd12ff4b03edceae590d22226325..57b452bbb4eab71f106e5e56f23259b3df7b18d8 100644 --- a/net/netfilter/ipvs/ip_vs_wlc.c +++ b/net/netfilter/ipvs/ip_vs_wlc.c @@ -106,9 +106,6 @@ static struct ip_vs_scheduler ip_vs_wlc_scheduler = .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, .n_list = LIST_HEAD_INIT(ip_vs_wlc_scheduler.n_list), -#ifdef CONFIG_IP_VS_IPV6 - .supports_ipv6 = 1, -#endif .schedule = ip_vs_wlc_schedule, }; diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c index 7ea92fed50bf86c21ec75abfa779d9db1bf3d71f..2f618dc29c5b69468b21ded446b13f18c1efebab 100644 --- a/net/netfilter/ipvs/ip_vs_wrr.c +++ b/net/netfilter/ipvs/ip_vs_wrr.c @@ -213,9 +213,6 @@ static struct ip_vs_scheduler ip_vs_wrr_scheduler = { .refcnt = ATOMIC_INIT(0), .module = THIS_MODULE, .n_list = LIST_HEAD_INIT(ip_vs_wrr_scheduler.n_list), -#ifdef CONFIG_IP_VS_IPV6 - .supports_ipv6 = 1, -#endif .init_service = ip_vs_wrr_init_svc, .done_service = ip_vs_wrr_done_svc, .update_service = ip_vs_wrr_update_svc, diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index e90d52f199bc1d98d3cf8e2c8fe93008d60b02f6..425ab144f15d4e29d90a9c6078d5221588b18fbb 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -82,14 +82,13 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos) if (ip_route_output_key(&init_net, &rt, &fl)) { spin_unlock(&dest->dst_lock); - IP_VS_DBG_RL("ip_route_output error, " - "dest: %u.%u.%u.%u\n", - NIPQUAD(dest->addr.ip)); + IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", + &dest->addr.ip); return NULL; } __ip_vs_dst_set(dest, rtos, dst_clone(&rt->u.dst)); - IP_VS_DBG(10, "new dst %u.%u.%u.%u, refcnt=%d, rtos=%X\n", - NIPQUAD(dest->addr.ip), + IP_VS_DBG(10, "new dst %pI4, refcnt=%d, rtos=%X\n", + &dest->addr.ip, atomic_read(&rt->u.dst.__refcnt), rtos); } spin_unlock(&dest->dst_lock); @@ -104,8 +103,8 @@ __ip_vs_get_out_rt(struct ip_vs_conn *cp, u32 rtos) }; if (ip_route_output_key(&init_net, &rt, &fl)) { - IP_VS_DBG_RL("ip_route_output error, dest: " - "%u.%u.%u.%u\n", NIPQUAD(cp->daddr.ip)); + IP_VS_DBG_RL("ip_route_output error, dest: %pI4\n", + &cp->daddr.ip); return NULL; } } @@ -141,14 +140,13 @@ __ip_vs_get_out_rt_v6(struct ip_vs_conn *cp) NULL, &fl); if (!rt) { spin_unlock(&dest->dst_lock); - IP_VS_DBG_RL("ip6_route_output error, " - "dest: " NIP6_FMT "\n", - NIP6(dest->addr.in6)); + IP_VS_DBG_RL("ip6_route_output error, dest: %pI6\n", + &dest->addr.in6); return NULL; } __ip_vs_dst_set(dest, 0, dst_clone(&rt->u.dst)); - IP_VS_DBG(10, "new dst " NIP6_FMT ", refcnt=%d\n", - NIP6(dest->addr.in6), + IP_VS_DBG(10, "new dst %pI6, refcnt=%d\n", + &dest->addr.in6, atomic_read(&rt->u.dst.__refcnt)); } spin_unlock(&dest->dst_lock); @@ -167,8 +165,8 @@ __ip_vs_get_out_rt_v6(struct ip_vs_conn *cp) rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl); if (!rt) { - IP_VS_DBG_RL("ip6_route_output error, dest: " - NIP6_FMT "\n", NIP6(cp->daddr.in6)); + IP_VS_DBG_RL("ip6_route_output error, dest: %pI6\n", + &cp->daddr.in6); return NULL; } } @@ -237,8 +235,8 @@ ip_vs_bypass_xmit(struct sk_buff *skb, struct ip_vs_conn *cp, EnterFunction(10); if (ip_route_output_key(&init_net, &rt, &fl)) { - IP_VS_DBG_RL("ip_vs_bypass_xmit(): ip_route_output error, " - "dest: %u.%u.%u.%u\n", NIPQUAD(iph->daddr)); + IP_VS_DBG_RL("ip_vs_bypass_xmit(): ip_route_output error, dest: %pI4\n", + &iph->daddr); goto tx_error_icmp; } @@ -301,8 +299,8 @@ ip_vs_bypass_xmit_v6(struct sk_buff *skb, struct ip_vs_conn *cp, rt = (struct rt6_info *)ip6_route_output(&init_net, NULL, &fl); if (!rt) { - IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): ip6_route_output error, " - "dest: " NIP6_FMT "\n", NIP6(iph->daddr)); + IP_VS_DBG_RL("ip_vs_bypass_xmit_v6(): ip6_route_output error, dest: %pI6\n", + &iph->daddr); goto tx_error_icmp; } diff --git a/net/netfilter/nf_conntrack_acct.c b/net/netfilter/nf_conntrack_acct.c index b92df5c1dfcf395078ca2f766f57206f2ffad047..9fe8982bd7c905d67086b5073fd72df407dade7a 100644 --- a/net/netfilter/nf_conntrack_acct.c +++ b/net/netfilter/nf_conntrack_acct.c @@ -35,7 +35,7 @@ static struct ctl_table acct_sysctl_table[] = { .data = &init_net.ct.sysctl_acct, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, {} }; diff --git a/net/netfilter/nf_conntrack_amanda.c b/net/netfilter/nf_conntrack_amanda.c index 38aedeeaf4e1cb71100c726d42a9f21b3618ef74..4f8fcf498545f302105535bfebaf34b9755908fe 100644 --- a/net/netfilter/nf_conntrack_amanda.c +++ b/net/netfilter/nf_conntrack_amanda.c @@ -30,6 +30,7 @@ MODULE_AUTHOR("Brian J. Murrell "); MODULE_DESCRIPTION("Amanda connection tracking module"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ip_conntrack_amanda"); +MODULE_ALIAS_NFCT_HELPER("amanda"); module_param(master_timeout, uint, 0600); MODULE_PARM_DESC(master_timeout, "timeout for the master connection"); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 233fdd2d7d2186b03fd6bac169d4090dbab562a3..7e83f74cd5de3dea8f3ba32a2feea84f12cbe359 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -39,13 +39,13 @@ #include #include #include +#include #define NF_CONNTRACK_VERSION "0.5.0" -unsigned int -(*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, - enum nf_nat_manip_type manip, - struct nlattr *attr) __read_mostly; +int (*nfnetlink_parse_nat_setup_hook)(struct nf_conn *ct, + enum nf_nat_manip_type manip, + struct nlattr *attr) __read_mostly; EXPORT_SYMBOL_GPL(nfnetlink_parse_nat_setup_hook); DEFINE_SPINLOCK(nf_conntrack_lock); @@ -181,7 +181,8 @@ destroy_conntrack(struct nf_conntrack *nfct) NF_CT_ASSERT(atomic_read(&nfct->use) == 0); NF_CT_ASSERT(!timer_pending(&ct->timeout)); - nf_conntrack_event(IPCT_DESTROY, ct); + if (!test_bit(IPS_DYING_BIT, &ct->status)) + nf_conntrack_event(IPCT_DESTROY, ct); set_bit(IPS_DYING_BIT, &ct->status); /* To make sure we don't get any weird locking issues here: @@ -586,14 +587,7 @@ init_conntrack(struct net *net, nf_conntrack_get(&ct->master->ct_general); NF_CT_STAT_INC(net, expect_new); } else { - struct nf_conntrack_helper *helper; - - helper = __nf_ct_helper_find(&repl_tuple); - if (helper) { - help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); - if (help) - rcu_assign_pointer(help->helper, helper); - } + __nf_ct_try_assign_helper(ct, GFP_ATOMIC); NF_CT_STAT_INC(net, new); } @@ -770,7 +764,6 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, const struct nf_conntrack_tuple *newreply) { struct nf_conn_help *help = nfct_help(ct); - struct nf_conntrack_helper *helper; /* Should be unconfirmed, so not in hash table yet */ NF_CT_ASSERT(!nf_ct_is_confirmed(ct)); @@ -783,23 +776,7 @@ void nf_conntrack_alter_reply(struct nf_conn *ct, return; rcu_read_lock(); - helper = __nf_ct_helper_find(newreply); - if (helper == NULL) { - if (help) - rcu_assign_pointer(help->helper, NULL); - goto out; - } - - if (help == NULL) { - help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); - if (help == NULL) - goto out; - } else { - memset(&help->help, 0, sizeof(help->help)); - } - - rcu_assign_pointer(help->helper, helper); -out: + __nf_ct_try_assign_helper(ct, GFP_ATOMIC); rcu_read_unlock(); } EXPORT_SYMBOL_GPL(nf_conntrack_alter_reply); @@ -994,8 +971,20 @@ void nf_ct_iterate_cleanup(struct net *net, } EXPORT_SYMBOL_GPL(nf_ct_iterate_cleanup); +struct __nf_ct_flush_report { + u32 pid; + int report; +}; + static int kill_all(struct nf_conn *i, void *data) { + struct __nf_ct_flush_report *fr = (struct __nf_ct_flush_report *)data; + + /* get_next_corpse sets the dying bit for us */ + nf_conntrack_event_report(IPCT_DESTROY, + i, + fr->pid, + fr->report); return 1; } @@ -1009,9 +998,13 @@ void nf_ct_free_hashtable(struct hlist_head *hash, int vmalloced, unsigned int s } EXPORT_SYMBOL_GPL(nf_ct_free_hashtable); -void nf_conntrack_flush(struct net *net) +void nf_conntrack_flush(struct net *net, u32 pid, int report) { - nf_ct_iterate_cleanup(net, kill_all, NULL); + struct __nf_ct_flush_report fr = { + .pid = pid, + .report = report, + }; + nf_ct_iterate_cleanup(net, kill_all, &fr); } EXPORT_SYMBOL_GPL(nf_conntrack_flush); @@ -1027,7 +1020,7 @@ static void nf_conntrack_cleanup_net(struct net *net) nf_ct_event_cache_flush(net); nf_conntrack_ecache_fini(net); i_see_dead_people: - nf_conntrack_flush(net); + nf_conntrack_flush(net, 0, 0); if (atomic_read(&net->ct.count) != 0) { schedule(); goto i_see_dead_people; diff --git a/net/netfilter/nf_conntrack_ecache.c b/net/netfilter/nf_conntrack_ecache.c index a5f5e2e65d13770bf62a419e94962986f8c21a56..dee4190209ccc2420709bcbcab29527270625730 100644 --- a/net/netfilter/nf_conntrack_ecache.c +++ b/net/netfilter/nf_conntrack_ecache.c @@ -35,9 +35,17 @@ static inline void __nf_ct_deliver_cached_events(struct nf_conntrack_ecache *ecache) { if (nf_ct_is_confirmed(ecache->ct) && !nf_ct_is_dying(ecache->ct) - && ecache->events) - atomic_notifier_call_chain(&nf_conntrack_chain, ecache->events, - ecache->ct); + && ecache->events) { + struct nf_ct_event item = { + .ct = ecache->ct, + .pid = 0, + .report = 0 + }; + + atomic_notifier_call_chain(&nf_conntrack_chain, + ecache->events, + &item); + } ecache->events = 0; nf_ct_put(ecache->ct); diff --git a/net/netfilter/nf_conntrack_expect.c b/net/netfilter/nf_conntrack_expect.c index 37a703bc3b8ee0556fedbeccb6a89a72ce39750c..3a8a34a6d37c807bd995eb0a43f3498ddf567662 100644 --- a/net/netfilter/nf_conntrack_expect.c +++ b/net/netfilter/nf_conntrack_expect.c @@ -362,7 +362,7 @@ static inline int refresh_timer(struct nf_conntrack_expect *i) return 1; } -int nf_ct_expect_related(struct nf_conntrack_expect *expect) +static inline int __nf_ct_expect_check(struct nf_conntrack_expect *expect) { const struct nf_conntrack_expect_policy *p; struct nf_conntrack_expect *i; @@ -371,11 +371,8 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect) struct net *net = nf_ct_exp_net(expect); struct hlist_node *n; unsigned int h; - int ret; - - NF_CT_ASSERT(master_help); + int ret = 0; - spin_lock_bh(&nf_conntrack_lock); if (!master_help->helper) { ret = -ESHUTDOWN; goto out; @@ -409,18 +406,50 @@ int nf_ct_expect_related(struct nf_conntrack_expect *expect) printk(KERN_WARNING "nf_conntrack: expectation table full\n"); ret = -EMFILE; - goto out; } +out: + return ret; +} + +int nf_ct_expect_related(struct nf_conntrack_expect *expect) +{ + int ret; + + spin_lock_bh(&nf_conntrack_lock); + ret = __nf_ct_expect_check(expect); + if (ret < 0) + goto out; nf_ct_expect_insert(expect); + atomic_inc(&expect->use); + spin_unlock_bh(&nf_conntrack_lock); nf_ct_expect_event(IPEXP_NEW, expect); - ret = 0; + nf_ct_expect_put(expect); + return ret; out: spin_unlock_bh(&nf_conntrack_lock); return ret; } EXPORT_SYMBOL_GPL(nf_ct_expect_related); +int nf_ct_expect_related_report(struct nf_conntrack_expect *expect, + u32 pid, int report) +{ + int ret; + + spin_lock_bh(&nf_conntrack_lock); + ret = __nf_ct_expect_check(expect); + if (ret < 0) + goto out; + nf_ct_expect_insert(expect); +out: + spin_unlock_bh(&nf_conntrack_lock); + if (ret == 0) + nf_ct_expect_event_report(IPEXP_NEW, expect, pid, report); + return ret; +} +EXPORT_SYMBOL_GPL(nf_ct_expect_related_report); + #ifdef CONFIG_PROC_FS struct ct_expect_iter_state { struct seq_net_private p; diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 4f7107107e9974655a47fa7715615774a2259bc1..00fecc385f9b55e9aa6edb2452a7c6025f043618 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -29,6 +29,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Rusty Russell "); MODULE_DESCRIPTION("ftp connection tracking helper"); MODULE_ALIAS("ip_conntrack_ftp"); +MODULE_ALIAS_NFCT_HELPER("ftp"); /* This is slow, but it's simple. --RR */ static char *ftp_buffer; @@ -357,7 +358,7 @@ static int help(struct sk_buff *skb, int ret; u32 seq; int dir = CTINFO2DIR(ctinfo); - unsigned int matchlen, matchoff; + unsigned int uninitialized_var(matchlen), uninitialized_var(matchoff); struct nf_ct_ftp_master *ct_ftp_info = &nfct_help(ct)->help.ct_ftp_info; struct nf_conntrack_expect *exp; union nf_inet_addr *daddr; @@ -427,10 +428,8 @@ static int help(struct sk_buff *skb, connection tracking, not packet filtering. However, it is necessary for accurate tracking in this case. */ - if (net_ratelimit()) - printk("conntrack_ftp: partial %s %u+%u\n", - search[dir][i].pattern, - ntohl(th->seq), datalen); + pr_debug("conntrack_ftp: partial %s %u+%u\n", + search[dir][i].pattern, ntohl(th->seq), datalen); ret = NF_DROP; goto out; } else if (found == 0) { /* No match */ @@ -462,16 +461,13 @@ static int help(struct sk_buff *skb, different IP address. Simply don't record it for NAT. */ if (cmd.l3num == PF_INET) { - pr_debug("conntrack_ftp: NOT RECORDING: " NIPQUAD_FMT - " != " NIPQUAD_FMT "\n", - NIPQUAD(cmd.u3.ip), - NIPQUAD(ct->tuplehash[dir].tuple.src.u3.ip)); + pr_debug("conntrack_ftp: NOT RECORDING: %pI4 != %pI4\n", + &cmd.u3.ip, + &ct->tuplehash[dir].tuple.src.u3.ip); } else { - pr_debug("conntrack_ftp: NOT RECORDING: " NIP6_FMT - " != " NIP6_FMT "\n", - NIP6(*((struct in6_addr *)cmd.u3.ip6)), - NIP6(*((struct in6_addr *) - ct->tuplehash[dir].tuple.src.u3.ip6))); + pr_debug("conntrack_ftp: NOT RECORDING: %pI6 != %pI6\n", + cmd.u3.ip6, + ct->tuplehash[dir].tuple.src.u3.ip6); } /* Thanks to Cristiano Lincoln Mattos diff --git a/net/netfilter/nf_conntrack_h323_main.c b/net/netfilter/nf_conntrack_h323_main.c index c1504f71cdff08d8ad98685d73b2bba4e5a6c10f..687bd633c3d7020c277ba0f25b6e3033fd5053c7 100644 --- a/net/netfilter/nf_conntrack_h323_main.c +++ b/net/netfilter/nf_conntrack_h323_main.c @@ -850,10 +850,8 @@ static int process_setup(struct sk_buff *skb, struct nf_conn *ct, get_h225_addr(ct, *data, &setup->destCallSignalAddress, &addr, &port) && memcmp(&addr, &ct->tuplehash[!dir].tuple.src.u3, sizeof(addr))) { - pr_debug("nf_ct_q931: set destCallSignalAddress " - NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n", - NIP6(*(struct in6_addr *)&addr), ntohs(port), - NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.src.u3), + pr_debug("nf_ct_q931: set destCallSignalAddress %pI6:%hu->%pI6:%hu\n", + &addr, ntohs(port), &ct->tuplehash[!dir].tuple.src.u3, ntohs(ct->tuplehash[!dir].tuple.src.u.tcp.port)); ret = set_h225_addr(skb, data, dataoff, &setup->destCallSignalAddress, @@ -868,10 +866,8 @@ static int process_setup(struct sk_buff *skb, struct nf_conn *ct, get_h225_addr(ct, *data, &setup->sourceCallSignalAddress, &addr, &port) && memcmp(&addr, &ct->tuplehash[!dir].tuple.dst.u3, sizeof(addr))) { - pr_debug("nf_ct_q931: set sourceCallSignalAddress " - NIP6_FMT ":%hu->" NIP6_FMT ":%hu\n", - NIP6(*(struct in6_addr *)&addr), ntohs(port), - NIP6(*(struct in6_addr *)&ct->tuplehash[!dir].tuple.dst.u3), + pr_debug("nf_ct_q931: set sourceCallSignalAddress %pI6:%hu->%pI6:%hu\n", + &addr, ntohs(port), &ct->tuplehash[!dir].tuple.dst.u3, ntohs(ct->tuplehash[!dir].tuple.dst.u.tcp.port)); ret = set_h225_addr(skb, data, dataoff, &setup->sourceCallSignalAddress, @@ -1831,3 +1827,4 @@ MODULE_AUTHOR("Jing Min Zhao "); MODULE_DESCRIPTION("H.323 connection tracking helper"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ip_conntrack_h323"); +MODULE_ALIAS_NFCT_HELPER("h323"); diff --git a/net/netfilter/nf_conntrack_helper.c b/net/netfilter/nf_conntrack_helper.c index c39b6a9941331c8fe6c6fe2a80130f04bd1b1129..a51bdac9f3a0682a442d833d44a82c813cd19eff 100644 --- a/net/netfilter/nf_conntrack_helper.c +++ b/net/netfilter/nf_conntrack_helper.c @@ -45,7 +45,7 @@ static unsigned int helper_hash(const struct nf_conntrack_tuple *tuple) (__force __u16)tuple->src.u.all) % nf_ct_helper_hsize; } -struct nf_conntrack_helper * +static struct nf_conntrack_helper * __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) { struct nf_conntrack_helper *helper; @@ -63,7 +63,6 @@ __nf_ct_helper_find(const struct nf_conntrack_tuple *tuple) } return NULL; } -EXPORT_SYMBOL_GPL(__nf_ct_helper_find); struct nf_conntrack_helper * __nf_conntrack_helper_find_byname(const char *name) @@ -95,6 +94,35 @@ struct nf_conn_help *nf_ct_helper_ext_add(struct nf_conn *ct, gfp_t gfp) } EXPORT_SYMBOL_GPL(nf_ct_helper_ext_add); +int __nf_ct_try_assign_helper(struct nf_conn *ct, gfp_t flags) +{ + int ret = 0; + struct nf_conntrack_helper *helper; + struct nf_conn_help *help = nfct_help(ct); + + helper = __nf_ct_helper_find(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); + if (helper == NULL) { + if (help) + rcu_assign_pointer(help->helper, NULL); + goto out; + } + + if (help == NULL) { + help = nf_ct_helper_ext_add(ct, flags); + if (help == NULL) { + ret = -ENOMEM; + goto out; + } + } else { + memset(&help->help, 0, sizeof(help->help)); + } + + rcu_assign_pointer(help->helper, helper); +out: + return ret; +} +EXPORT_SYMBOL_GPL(__nf_ct_try_assign_helper); + static inline int unhelp(struct nf_conntrack_tuple_hash *i, const struct nf_conntrack_helper *me) { diff --git a/net/netfilter/nf_conntrack_irc.c b/net/netfilter/nf_conntrack_irc.c index 20633fdf7e6bb48b48e485b9ba0d110ab1f8459b..409c8be58e7c3fe097ceacc47c37ffb8092a155a 100644 --- a/net/netfilter/nf_conntrack_irc.c +++ b/net/netfilter/nf_conntrack_irc.c @@ -41,6 +41,7 @@ MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("IRC (DCC) connection tracking helper"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ip_conntrack_irc"); +MODULE_ALIAS_NFCT_HELPER("irc"); module_param_array(ports, ushort, &ports_c, 0400); MODULE_PARM_DESC(ports, "port numbers of IRC servers"); @@ -156,9 +157,9 @@ static int help(struct sk_buff *skb, unsigned int protoff, /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */ iph = ip_hdr(skb); - pr_debug("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u\n", - NIPQUAD(iph->saddr), ntohs(th->source), - NIPQUAD(iph->daddr), ntohs(th->dest)); + pr_debug("DCC found in master %pI4:%u %pI4:%u\n", + &iph->saddr, ntohs(th->source), + &iph->daddr, ntohs(th->dest)); for (i = 0; i < ARRAY_SIZE(dccprotos); i++) { if (memcmp(data, dccprotos[i], strlen(dccprotos[i]))) { @@ -185,10 +186,9 @@ static int help(struct sk_buff *skb, unsigned int protoff, tuple->dst.u3.ip != htonl(dcc_ip)) { if (net_ratelimit()) printk(KERN_WARNING - "Forged DCC command from " - "%u.%u.%u.%u: %u.%u.%u.%u:%u\n", - NIPQUAD(tuple->src.u3.ip), - HIPQUAD(dcc_ip), dcc_port); + "Forged DCC command from %pI4: %pI4:%u\n", + &tuple->src.u3.ip, + &dcc_ip, dcc_port); continue; } diff --git a/net/netfilter/nf_conntrack_netbios_ns.c b/net/netfilter/nf_conntrack_netbios_ns.c index 08404e6755fb15064ab086d3229a34cc9139ce3d..5af4273b4668c3bf53b0ea1dc1937ed973831610 100644 --- a/net/netfilter/nf_conntrack_netbios_ns.c +++ b/net/netfilter/nf_conntrack_netbios_ns.c @@ -37,6 +37,7 @@ MODULE_AUTHOR("Patrick McHardy "); MODULE_DESCRIPTION("NetBIOS name service broadcast connection tracking helper"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ip_conntrack_netbios_ns"); +MODULE_ALIAS_NFCT_HELPER("netbios_ns"); static unsigned int timeout __read_mostly = 3; module_param(timeout, uint, 0400); diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 5f4a6516b3b6b6f935e677f774c22de1c038dccb..00e8c27130ff6ad6fa345b860948ddb8dca2bf4e 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -105,16 +105,14 @@ ctnetlink_dump_tuples(struct sk_buff *skb, struct nf_conntrack_l3proto *l3proto; struct nf_conntrack_l4proto *l4proto; - l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); + l3proto = __nf_ct_l3proto_find(tuple->src.l3num); ret = ctnetlink_dump_tuples_ip(skb, tuple, l3proto); - nf_ct_l3proto_put(l3proto); if (unlikely(ret < 0)) return ret; - l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); + l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); ret = ctnetlink_dump_tuples_proto(skb, tuple, l4proto); - nf_ct_l4proto_put(l4proto); return ret; } @@ -151,11 +149,9 @@ ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) struct nlattr *nest_proto; int ret; - l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct)); - if (!l4proto->to_nlattr) { - nf_ct_l4proto_put(l4proto); + l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); + if (!l4proto->to_nlattr) return 0; - } nest_proto = nla_nest_start(skb, CTA_PROTOINFO | NLA_F_NESTED); if (!nest_proto) @@ -163,14 +159,11 @@ ctnetlink_dump_protoinfo(struct sk_buff *skb, const struct nf_conn *ct) ret = l4proto->to_nlattr(skb, nest_proto, ct); - nf_ct_l4proto_put(l4proto); - nla_nest_end(skb, nest_proto); return ret; nla_put_failure: - nf_ct_l4proto_put(l4proto); return -1; } @@ -184,7 +177,6 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) if (!help) return 0; - rcu_read_lock(); helper = rcu_dereference(help->helper); if (!helper) goto out; @@ -199,11 +191,9 @@ ctnetlink_dump_helpinfo(struct sk_buff *skb, const struct nf_conn *ct) nla_nest_end(skb, nest_helper); out: - rcu_read_unlock(); return 0; nla_put_failure: - rcu_read_unlock(); return -1; } @@ -420,7 +410,8 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; struct nlattr *nest_parms; - struct nf_conn *ct = (struct nf_conn *)ptr; + struct nf_ct_event *item = (struct nf_ct_event *)ptr; + struct nf_conn *ct = item->ct; struct sk_buff *skb; unsigned int type; sk_buff_data_t b; @@ -453,7 +444,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, b = skb->tail; type |= NFNL_SUBSYS_CTNETLINK << 8; - nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); + nlh = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg)); nfmsg = NLMSG_DATA(nlh); nlh->nlmsg_flags = flags; @@ -461,6 +452,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; + rcu_read_lock(); nest_parms = nla_nest_start(skb, CTA_TUPLE_ORIG | NLA_F_NESTED); if (!nest_parms) goto nla_put_failure; @@ -517,13 +509,15 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, && ctnetlink_dump_mark(skb, ct) < 0) goto nla_put_failure; #endif + rcu_read_unlock(); nlh->nlmsg_len = skb->tail - b; - nfnetlink_send(skb, 0, group, 0); + nfnetlink_send(skb, item->pid, group, item->report); return NOTIFY_DONE; -nlmsg_failure: nla_put_failure: + rcu_read_unlock(); +nlmsg_failure: kfree_skb(skb); return NOTIFY_DONE; } @@ -729,7 +723,9 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, err = ctnetlink_parse_tuple(cda, &tuple, CTA_TUPLE_REPLY, u3); else { /* Flush the whole table */ - nf_conntrack_flush(&init_net); + nf_conntrack_flush(&init_net, + NETLINK_CB(skb).pid, + nlmsg_report(nlh)); return 0; } @@ -750,6 +746,14 @@ ctnetlink_del_conntrack(struct sock *ctnl, struct sk_buff *skb, } } + nf_conntrack_event_report(IPCT_DESTROY, + ct, + NETLINK_CB(skb).pid, + nlmsg_report(nlh)); + + /* death_by_timeout would report the event again */ + set_bit(IPS_DYING_BIT, &ct->status); + nf_ct_kill(ct); nf_ct_put(ct); @@ -795,8 +799,10 @@ ctnetlink_get_conntrack(struct sock *ctnl, struct sk_buff *skb, return -ENOMEM; } + rcu_read_lock(); err = ctnetlink_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_CT_NEW, 1, ct); + rcu_read_unlock(); nf_ct_put(ct); if (err <= 0) goto free; @@ -922,8 +928,22 @@ ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *cda[]) } helper = __nf_conntrack_helper_find_byname(helpname); - if (helper == NULL) + if (helper == NULL) { +#ifdef CONFIG_MODULES + spin_unlock_bh(&nf_conntrack_lock); + + if (request_module("nfct-helper-%s", helpname) < 0) { + spin_lock_bh(&nf_conntrack_lock); + return -EOPNOTSUPP; + } + + spin_lock_bh(&nf_conntrack_lock); + helper = __nf_conntrack_helper_find_byname(helpname); + if (helper) + return -EAGAIN; +#endif return -EOPNOTSUPP; + } if (help) { if (help->helper == helper) @@ -1079,15 +1099,38 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) return 0; } +static inline void +ctnetlink_event_report(struct nf_conn *ct, u32 pid, int report) +{ + unsigned int events = 0; + + if (test_bit(IPS_EXPECTED_BIT, &ct->status)) + events |= IPCT_RELATED; + else + events |= IPCT_NEW; + + nf_conntrack_event_report(IPCT_STATUS | + IPCT_HELPER | + IPCT_REFRESH | + IPCT_PROTOINFO | + IPCT_NATSEQADJ | + IPCT_MARK | + events, + ct, + pid, + report); +} + static int ctnetlink_create_conntrack(struct nlattr *cda[], struct nf_conntrack_tuple *otuple, struct nf_conntrack_tuple *rtuple, - struct nf_conn *master_ct) + struct nf_conn *master_ct, + u32 pid, + int report) { struct nf_conn *ct; int err = -EINVAL; - struct nf_conn_help *help; struct nf_conntrack_helper *helper; ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC); @@ -1102,16 +1145,55 @@ ctnetlink_create_conntrack(struct nlattr *cda[], ct->status |= IPS_CONFIRMED; rcu_read_lock(); - helper = __nf_ct_helper_find(rtuple); - if (helper) { - help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); - if (help == NULL) { + if (cda[CTA_HELP]) { + char *helpname; + + err = ctnetlink_parse_help(cda[CTA_HELP], &helpname); + if (err < 0) { + rcu_read_unlock(); + goto err; + } + + helper = __nf_conntrack_helper_find_byname(helpname); + if (helper == NULL) { + rcu_read_unlock(); +#ifdef CONFIG_MODULES + if (request_module("nfct-helper-%s", helpname) < 0) { + err = -EOPNOTSUPP; + goto err; + } + + rcu_read_lock(); + helper = __nf_conntrack_helper_find_byname(helpname); + if (helper) { + rcu_read_unlock(); + err = -EAGAIN; + goto err; + } + rcu_read_unlock(); +#endif + err = -EOPNOTSUPP; + goto err; + } else { + struct nf_conn_help *help; + + help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); + if (help == NULL) { + rcu_read_unlock(); + err = -ENOMEM; + goto err; + } + + /* not in hash table yet so not strictly necessary */ + rcu_assign_pointer(help->helper, helper); + } + } else { + /* try an implicit helper assignation */ + err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC); + if (err < 0) { rcu_read_unlock(); - err = -ENOMEM; goto err; } - /* not in hash table yet so not strictly necessary */ - rcu_assign_pointer(help->helper, helper); } if (cda[CTA_STATUS]) { @@ -1151,9 +1233,12 @@ ctnetlink_create_conntrack(struct nlattr *cda[], ct->master = master_ct; } + nf_conntrack_get(&ct->ct_general); add_timer(&ct->timeout); nf_conntrack_hash_insert(ct); rcu_read_unlock(); + ctnetlink_event_report(ct, pid, report); + nf_ct_put(ct); return 0; @@ -1209,7 +1294,7 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, goto out_unlock; } master_ct = nf_ct_tuplehash_to_ctrack(master_h); - atomic_inc(&master_ct->ct_general.use); + nf_conntrack_get(&master_ct->ct_general); } err = -ENOENT; @@ -1217,9 +1302,10 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, err = ctnetlink_create_conntrack(cda, &otuple, &rtuple, - master_ct); + master_ct, + NETLINK_CB(skb).pid, + nlmsg_report(nlh)); spin_unlock_bh(&nf_conntrack_lock); - if (err < 0 && master_ct) nf_ct_put(master_ct); @@ -1231,6 +1317,8 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, * so there's no need to increase the refcount */ err = -EEXIST; if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { + struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); + /* we only allow nat config for new conntracks */ if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { err = -EOPNOTSUPP; @@ -1241,8 +1329,19 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, err = -EOPNOTSUPP; goto out_unlock; } - err = ctnetlink_change_conntrack(nf_ct_tuplehash_to_ctrack(h), - cda); + + err = ctnetlink_change_conntrack(ct, cda); + if (err == 0) { + nf_conntrack_get(&ct->ct_general); + spin_unlock_bh(&nf_conntrack_lock); + ctnetlink_event_report(ct, + NETLINK_CB(skb).pid, + nlmsg_report(nlh)); + nf_ct_put(ct); + } else + spin_unlock_bh(&nf_conntrack_lock); + + return err; } out_unlock: @@ -1293,16 +1392,14 @@ ctnetlink_exp_dump_mask(struct sk_buff *skb, if (!nest_parms) goto nla_put_failure; - l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); + l3proto = __nf_ct_l3proto_find(tuple->src.l3num); ret = ctnetlink_dump_tuples_ip(skb, &m, l3proto); - nf_ct_l3proto_put(l3proto); if (unlikely(ret < 0)) goto nla_put_failure; - l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); + l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); ret = ctnetlink_dump_tuples_proto(skb, &m, l4proto); - nf_ct_l4proto_put(l4proto); if (unlikely(ret < 0)) goto nla_put_failure; @@ -1379,7 +1476,8 @@ static int ctnetlink_expect_event(struct notifier_block *this, { struct nlmsghdr *nlh; struct nfgenmsg *nfmsg; - struct nf_conntrack_expect *exp = (struct nf_conntrack_expect *)ptr; + struct nf_exp_event *item = (struct nf_exp_event *)ptr; + struct nf_conntrack_expect *exp = item->exp; struct sk_buff *skb; unsigned int type; sk_buff_data_t b; @@ -1401,7 +1499,7 @@ static int ctnetlink_expect_event(struct notifier_block *this, b = skb->tail; type |= NFNL_SUBSYS_CTNETLINK_EXP << 8; - nlh = NLMSG_PUT(skb, 0, 0, type, sizeof(struct nfgenmsg)); + nlh = NLMSG_PUT(skb, item->pid, 0, type, sizeof(struct nfgenmsg)); nfmsg = NLMSG_DATA(nlh); nlh->nlmsg_flags = flags; @@ -1409,15 +1507,18 @@ static int ctnetlink_expect_event(struct notifier_block *this, nfmsg->version = NFNETLINK_V0; nfmsg->res_id = 0; + rcu_read_lock(); if (ctnetlink_exp_dump_expect(skb, exp) < 0) goto nla_put_failure; + rcu_read_unlock(); nlh->nlmsg_len = skb->tail - b; - nfnetlink_send(skb, 0, NFNLGRP_CONNTRACK_EXP_NEW, 0); + nfnetlink_send(skb, item->pid, NFNLGRP_CONNTRACK_EXP_NEW, item->report); return NOTIFY_DONE; -nlmsg_failure: nla_put_failure: + rcu_read_unlock(); +nlmsg_failure: kfree_skb(skb); return NOTIFY_DONE; } @@ -1521,9 +1622,11 @@ ctnetlink_get_expect(struct sock *ctnl, struct sk_buff *skb, if (!skb2) goto out; + rcu_read_lock(); err = ctnetlink_exp_fill_info(skb2, NETLINK_CB(skb).pid, nlh->nlmsg_seq, IPCTNL_MSG_EXP_NEW, 1, exp); + rcu_read_unlock(); if (err <= 0) goto free; @@ -1624,7 +1727,7 @@ ctnetlink_change_expect(struct nf_conntrack_expect *x, struct nlattr *cda[]) } static int -ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3) +ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3, u32 pid, int report) { struct nf_conntrack_tuple tuple, mask, master_tuple; struct nf_conntrack_tuple_hash *h = NULL; @@ -1653,7 +1756,7 @@ ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3) if (!help || !help->helper) { /* such conntrack hasn't got any helper, abort */ - err = -EINVAL; + err = -EOPNOTSUPP; goto out; } @@ -1671,7 +1774,7 @@ ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3) memcpy(&exp->mask.src.u3, &mask.src.u3, sizeof(exp->mask.src.u3)); exp->mask.src.u.all = mask.src.u.all; - err = nf_ct_expect_related(exp); + err = nf_ct_expect_related_report(exp, pid, report); nf_ct_expect_put(exp); out: @@ -1704,8 +1807,12 @@ ctnetlink_new_expect(struct sock *ctnl, struct sk_buff *skb, if (!exp) { spin_unlock_bh(&nf_conntrack_lock); err = -ENOENT; - if (nlh->nlmsg_flags & NLM_F_CREATE) - err = ctnetlink_create_expect(cda, u3); + if (nlh->nlmsg_flags & NLM_F_CREATE) { + err = ctnetlink_create_expect(cda, + u3, + NETLINK_CB(skb).pid, + nlmsg_report(nlh)); + } return err; } diff --git a/net/netfilter/nf_conntrack_pptp.c b/net/netfilter/nf_conntrack_pptp.c index 1bc3001d182773e33872081d4b40fc7bf6f4e95d..9e169ef2e85443eaff5c8224ccbeaad1d0f4a202 100644 --- a/net/netfilter/nf_conntrack_pptp.c +++ b/net/netfilter/nf_conntrack_pptp.c @@ -37,6 +37,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Harald Welte "); MODULE_DESCRIPTION("Netfilter connection tracking helper module for PPTP"); MODULE_ALIAS("ip_conntrack_pptp"); +MODULE_ALIAS_NFCT_HELPER("pptp"); static DEFINE_SPINLOCK(nf_pptp_lock); diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c index dbe680af85d2daa2aa3aaceb2c668e48847de643..4be80d7b87958253f16e86bc550686544e06385d 100644 --- a/net/netfilter/nf_conntrack_proto_generic.c +++ b/net/netfilter/nf_conntrack_proto_generic.c @@ -67,7 +67,7 @@ static struct ctl_table generic_sysctl_table[] = { .data = &nf_ct_generic_timeout, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 @@ -80,7 +80,7 @@ static struct ctl_table generic_compat_sysctl_table[] = { .data = &nf_ct_generic_timeout, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c index 4ab62ad85dd493e473b68bc2affa5eb63783fbfb..1b279f9d6bf3a81d90205b5dd06cb158fdbf4829 100644 --- a/net/netfilter/nf_conntrack_proto_gre.c +++ b/net/netfilter/nf_conntrack_proto_gre.c @@ -341,7 +341,7 @@ static int __init nf_ct_proto_gre_init(void) return rv; } -static void nf_ct_proto_gre_fini(void) +static void __exit nf_ct_proto_gre_fini(void) { nf_conntrack_l4proto_unregister(&nf_conntrack_l4proto_gre4); unregister_pernet_gen_subsys(proto_gre_net_id, &proto_gre_net_ops); diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c index ae8c2609e230b6323598521f8cc606bac7c5074e..74e03790119989df87cd1a95e8a80280f1c85764 100644 --- a/net/netfilter/nf_conntrack_proto_sctp.c +++ b/net/netfilter/nf_conntrack_proto_sctp.c @@ -317,7 +317,7 @@ static int sctp_packet(struct nf_conn *ct, goto out; } - old_state = new_state = SCTP_CONNTRACK_MAX; + old_state = new_state = SCTP_CONNTRACK_NONE; write_lock_bh(&sctp_lock); for_each_sctp_chunk (skb, sch, _sch, offset, dataoff, count) { /* Special cases of Verification tag check (Sec 8.5.1) */ @@ -548,49 +548,49 @@ static struct ctl_table sctp_sysctl_table[] = { .data = &sctp_timeouts[SCTP_CONNTRACK_CLOSED], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_sctp_timeout_cookie_wait", .data = &sctp_timeouts[SCTP_CONNTRACK_COOKIE_WAIT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_sctp_timeout_cookie_echoed", .data = &sctp_timeouts[SCTP_CONNTRACK_COOKIE_ECHOED], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_sctp_timeout_established", .data = &sctp_timeouts[SCTP_CONNTRACK_ESTABLISHED], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_sctp_timeout_shutdown_sent", .data = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_sctp_timeout_shutdown_recd", .data = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_sctp_timeout_shutdown_ack_sent", .data = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 @@ -604,49 +604,49 @@ static struct ctl_table sctp_compat_sysctl_table[] = { .data = &sctp_timeouts[SCTP_CONNTRACK_CLOSED], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_sctp_timeout_cookie_wait", .data = &sctp_timeouts[SCTP_CONNTRACK_COOKIE_WAIT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_sctp_timeout_cookie_echoed", .data = &sctp_timeouts[SCTP_CONNTRACK_COOKIE_ECHOED], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_sctp_timeout_established", .data = &sctp_timeouts[SCTP_CONNTRACK_ESTABLISHED], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_sctp_timeout_shutdown_sent", .data = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_SENT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_sctp_timeout_shutdown_recd", .data = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_RECD], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_sctp_timeout_shutdown_ack_sent", .data = &sctp_timeouts[SCTP_CONNTRACK_SHUTDOWN_ACK_SENT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index f947ec41e391f7ae565f6017ae51feae29b0487a..a1edb9c1adee8625e5d81800c0fa8bb96ec483cc 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c @@ -1192,70 +1192,70 @@ static struct ctl_table tcp_sysctl_table[] = { .data = &tcp_timeouts[TCP_CONNTRACK_SYN_SENT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_tcp_timeout_syn_recv", .data = &tcp_timeouts[TCP_CONNTRACK_SYN_RECV], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_tcp_timeout_established", .data = &tcp_timeouts[TCP_CONNTRACK_ESTABLISHED], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_tcp_timeout_fin_wait", .data = &tcp_timeouts[TCP_CONNTRACK_FIN_WAIT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_tcp_timeout_close_wait", .data = &tcp_timeouts[TCP_CONNTRACK_CLOSE_WAIT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_tcp_timeout_last_ack", .data = &tcp_timeouts[TCP_CONNTRACK_LAST_ACK], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_tcp_timeout_time_wait", .data = &tcp_timeouts[TCP_CONNTRACK_TIME_WAIT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_tcp_timeout_close", .data = &tcp_timeouts[TCP_CONNTRACK_CLOSE], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_tcp_timeout_max_retrans", .data = &nf_ct_tcp_timeout_max_retrans, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_tcp_timeout_unacknowledged", .data = &nf_ct_tcp_timeout_unacknowledged, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = NET_NF_CONNTRACK_TCP_LOOSE, @@ -1263,7 +1263,7 @@ static struct ctl_table tcp_sysctl_table[] = { .data = &nf_ct_tcp_loose, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NF_CONNTRACK_TCP_BE_LIBERAL, @@ -1271,7 +1271,7 @@ static struct ctl_table tcp_sysctl_table[] = { .data = &nf_ct_tcp_be_liberal, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NF_CONNTRACK_TCP_MAX_RETRANS, @@ -1279,7 +1279,7 @@ static struct ctl_table tcp_sysctl_table[] = { .data = &nf_ct_tcp_max_retrans, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = 0 @@ -1293,63 +1293,63 @@ static struct ctl_table tcp_compat_sysctl_table[] = { .data = &tcp_timeouts[TCP_CONNTRACK_SYN_SENT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_tcp_timeout_syn_recv", .data = &tcp_timeouts[TCP_CONNTRACK_SYN_RECV], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_tcp_timeout_established", .data = &tcp_timeouts[TCP_CONNTRACK_ESTABLISHED], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_tcp_timeout_fin_wait", .data = &tcp_timeouts[TCP_CONNTRACK_FIN_WAIT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_tcp_timeout_close_wait", .data = &tcp_timeouts[TCP_CONNTRACK_CLOSE_WAIT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_tcp_timeout_last_ack", .data = &tcp_timeouts[TCP_CONNTRACK_LAST_ACK], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_tcp_timeout_time_wait", .data = &tcp_timeouts[TCP_CONNTRACK_TIME_WAIT], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_tcp_timeout_close", .data = &tcp_timeouts[TCP_CONNTRACK_CLOSE], .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_tcp_timeout_max_retrans", .data = &nf_ct_tcp_timeout_max_retrans, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_LOOSE, @@ -1357,7 +1357,7 @@ static struct ctl_table tcp_compat_sysctl_table[] = { .data = &nf_ct_tcp_loose, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_BE_LIBERAL, @@ -1365,7 +1365,7 @@ static struct ctl_table tcp_compat_sysctl_table[] = { .data = &nf_ct_tcp_be_liberal, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_IPV4_NF_CONNTRACK_TCP_MAX_RETRANS, @@ -1373,7 +1373,7 @@ static struct ctl_table tcp_compat_sysctl_table[] = { .data = &nf_ct_tcp_max_retrans, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = 0 diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c index 7c2ca48698bed1d4ea1ea2b54375e9aa4aecbb89..2b8b1f579f930f523e4733073a176a95ef29549b 100644 --- a/net/netfilter/nf_conntrack_proto_udp.c +++ b/net/netfilter/nf_conntrack_proto_udp.c @@ -143,14 +143,14 @@ static struct ctl_table udp_sysctl_table[] = { .data = &nf_ct_udp_timeout, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "nf_conntrack_udp_timeout_stream", .data = &nf_ct_udp_timeout_stream, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 @@ -163,14 +163,14 @@ static struct ctl_table udp_compat_sysctl_table[] = { .data = &nf_ct_udp_timeout, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .procname = "ip_conntrack_udp_timeout_stream", .data = &nf_ct_udp_timeout_stream, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c index d22d839e4f94b9f3f1466e666c5f1fe3a425f9a2..4579d8de13b15d75f69181c7e4bd36ed3d7e39db 100644 --- a/net/netfilter/nf_conntrack_proto_udplite.c +++ b/net/netfilter/nf_conntrack_proto_udplite.c @@ -151,7 +151,7 @@ static struct ctl_table udplite_sysctl_table[] = { .data = &nf_ct_udplite_timeout, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = CTL_UNNUMBERED, @@ -159,7 +159,7 @@ static struct ctl_table udplite_sysctl_table[] = { .data = &nf_ct_udplite_timeout_stream, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_jiffies, + .proc_handler = proc_dointvec_jiffies, }, { .ctl_name = 0 diff --git a/net/netfilter/nf_conntrack_sane.c b/net/netfilter/nf_conntrack_sane.c index a94294b2b23ca71f2bfc30e3b88dc7dea962c373..dcfecbb81c4617784178009bc02de37b9a32cb00 100644 --- a/net/netfilter/nf_conntrack_sane.c +++ b/net/netfilter/nf_conntrack_sane.c @@ -30,6 +30,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Michal Schmidt "); MODULE_DESCRIPTION("SANE connection tracking helper"); +MODULE_ALIAS_NFCT_HELPER("sane"); static char *sane_buffer; diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c index 6813f1c8863f245ac84ffc7ad3a1b9e36c8e5cd3..4b572163784b338b1efa430713e1ae73d5da38b2 100644 --- a/net/netfilter/nf_conntrack_sip.c +++ b/net/netfilter/nf_conntrack_sip.c @@ -28,6 +28,7 @@ MODULE_LICENSE("GPL"); MODULE_AUTHOR("Christian Hentschel "); MODULE_DESCRIPTION("SIP connection tracking helper"); MODULE_ALIAS("ip_conntrack_sip"); +MODULE_ALIAS_NFCT_HELPER("sip"); #define MAX_PORTS 8 static unsigned short ports[MAX_PORTS]; diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c index 98106d4e89f033f5d6e22b17a0de9b2d6a709b5d..f37b9b74c6a8c78ea372569d4ffba09f69be9f9d 100644 --- a/net/netfilter/nf_conntrack_standalone.c +++ b/net/netfilter/nf_conntrack_standalone.c @@ -336,7 +336,7 @@ static ctl_table nf_ct_sysctl_table[] = { .data = &nf_conntrack_max, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NF_CONNTRACK_COUNT, @@ -344,7 +344,7 @@ static ctl_table nf_ct_sysctl_table[] = { .data = &init_net.ct.count, .maxlen = sizeof(int), .mode = 0444, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NF_CONNTRACK_BUCKETS, @@ -352,7 +352,7 @@ static ctl_table nf_ct_sysctl_table[] = { .data = &nf_conntrack_htable_size, .maxlen = sizeof(unsigned int), .mode = 0444, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NF_CONNTRACK_CHECKSUM, @@ -360,7 +360,7 @@ static ctl_table nf_ct_sysctl_table[] = { .data = &init_net.ct.sysctl_checksum, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = NET_NF_CONNTRACK_LOG_INVALID, @@ -368,8 +368,8 @@ static ctl_table nf_ct_sysctl_table[] = { .data = &init_net.ct.sysctl_log_invalid, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &log_invalid_proto_min, .extra2 = &log_invalid_proto_max, }, @@ -379,7 +379,7 @@ static ctl_table nf_ct_sysctl_table[] = { .data = &nf_ct_expect_max, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = 0 } }; @@ -393,7 +393,7 @@ static ctl_table nf_ct_netfilter_table[] = { .data = &nf_conntrack_max, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = 0 } }; diff --git a/net/netfilter/nf_conntrack_tftp.c b/net/netfilter/nf_conntrack_tftp.c index f57f6e7a71ee4e9e6913d7646dddfc8607ebe746..46e646b2e9b922ff1210ff06c835f32538f0d0c7 100644 --- a/net/netfilter/nf_conntrack_tftp.c +++ b/net/netfilter/nf_conntrack_tftp.c @@ -22,6 +22,7 @@ MODULE_AUTHOR("Magnus Boden "); MODULE_DESCRIPTION("TFTP connection tracking helper"); MODULE_LICENSE("GPL"); MODULE_ALIAS("ip_conntrack_tftp"); +MODULE_ALIAS_NFCT_HELPER("tftp"); #define MAX_PORTS 8 static unsigned short ports[MAX_PORTS]; diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 38f9efd90e8d5ccdd68668e4df57d71ea4453a66..fa49dc7fe100ffb0cd7a48e1b626c87019903197 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -534,7 +535,7 @@ static struct nf_loginfo default_loginfo = { }; /* log handler for internal netfilter logging api */ -static void +void nfulnl_log_packet(u_int8_t pf, unsigned int hooknum, const struct sk_buff *skb, @@ -649,6 +650,7 @@ alloc_failure: /* FIXME: statistics */ goto unlock_and_release; } +EXPORT_SYMBOL_GPL(nfulnl_log_packet); static int nfulnl_rcv_nl_event(struct notifier_block *this, diff --git a/net/netfilter/xt_NFLOG.c b/net/netfilter/xt_NFLOG.c index 50e3a52d3b31006421bd4ad32f6a63d1305c5925..a57c5cf018ec04871d07a4f4c948c78b08ddb443 100644 --- a/net/netfilter/xt_NFLOG.c +++ b/net/netfilter/xt_NFLOG.c @@ -13,6 +13,7 @@ #include #include #include +#include MODULE_AUTHOR("Patrick McHardy "); MODULE_DESCRIPTION("Xtables: packet logging to netlink using NFLOG"); @@ -31,8 +32,8 @@ nflog_tg(struct sk_buff *skb, const struct xt_target_param *par) li.u.ulog.group = info->group; li.u.ulog.qthreshold = info->threshold; - nf_log_packet(par->family, par->hooknum, skb, par->in, - par->out, &li, "%s", info->prefix); + nfulnl_log_packet(par->family, par->hooknum, skb, par->in, + par->out, &li, info->prefix); return XT_CONTINUE; } diff --git a/net/netfilter/xt_dccp.c b/net/netfilter/xt_dccp.c index e5d3e867328790f59f18fd630595520406ca5c48..0989f29ade2ea0e559b53e7afac854a2bb09d54a 100644 --- a/net/netfilter/xt_dccp.c +++ b/net/netfilter/xt_dccp.c @@ -45,10 +45,8 @@ dccp_find_option(u_int8_t option, unsigned int optlen = dh->dccph_doff*4 - __dccp_hdr_len(dh); unsigned int i; - if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) { - *hotdrop = true; - return false; - } + if (dh->dccph_doff * 4 < __dccp_hdr_len(dh)) + goto invalid; if (!optlen) return false; @@ -57,9 +55,7 @@ dccp_find_option(u_int8_t option, op = skb_header_pointer(skb, protoff + optoff, optlen, dccp_optbuf); if (op == NULL) { /* If we don't have the whole header, drop packet. */ - spin_unlock_bh(&dccp_buflock); - *hotdrop = true; - return false; + goto partial; } for (i = 0; i < optlen; ) { @@ -76,6 +72,12 @@ dccp_find_option(u_int8_t option, spin_unlock_bh(&dccp_buflock); return false; + +partial: + spin_unlock_bh(&dccp_buflock); +invalid: + *hotdrop = true; + return false; } diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 6fc4292d46e6b33e18863878285af99ef34af3e7..f97fded024c46d5d8c28c57b2146b0c2c5e14c67 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -893,23 +893,21 @@ static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family, switch (family) { case NFPROTO_IPV4: - return seq_printf(s, "%ld %u.%u.%u.%u:%u->" - "%u.%u.%u.%u:%u %u %u %u\n", + return seq_printf(s, "%ld %pI4:%u->%pI4:%u %u %u %u\n", (long)(ent->expires - jiffies)/HZ, - NIPQUAD(ent->dst.ip.src), + &ent->dst.ip.src, ntohs(ent->dst.src_port), - NIPQUAD(ent->dst.ip.dst), + &ent->dst.ip.dst, ntohs(ent->dst.dst_port), ent->rateinfo.credit, ent->rateinfo.credit_cap, ent->rateinfo.cost); #if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE) case NFPROTO_IPV6: - return seq_printf(s, "%ld " NIP6_FMT ":%u->" - NIP6_FMT ":%u %u %u %u\n", + return seq_printf(s, "%ld %pI6:%u->%pI6:%u %u %u %u\n", (long)(ent->expires - jiffies)/HZ, - NIP6(*(struct in6_addr *)&ent->dst.ip6.src), + &ent->dst.ip6.src, ntohs(ent->dst.src_port), - NIP6(*(struct in6_addr *)&ent->dst.ip6.dst), + &ent->dst.ip6.dst, ntohs(ent->dst.dst_port), ent->rateinfo.credit, ent->rateinfo.credit_cap, ent->rateinfo.cost); diff --git a/net/netfilter/xt_iprange.c b/net/netfilter/xt_iprange.c index 7ac54eab0b00a6a0249afcc43ca6afea807410a0..501f9b6231886cb21fcf112f8fbbf01ed8ca2a76 100644 --- a/net/netfilter/xt_iprange.c +++ b/net/netfilter/xt_iprange.c @@ -26,12 +26,11 @@ iprange_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) if ((ntohl(iph->saddr) < ntohl(info->src.min_ip) || ntohl(iph->saddr) > ntohl(info->src.max_ip)) ^ !!(info->flags & IPRANGE_SRC_INV)) { - pr_debug("src IP %u.%u.%u.%u NOT in range %s" - "%u.%u.%u.%u-%u.%u.%u.%u\n", - NIPQUAD(iph->saddr), + pr_debug("src IP %pI4 NOT in range %s%pI4-%pI4\n", + &iph->saddr, info->flags & IPRANGE_SRC_INV ? "(INV) " : "", - NIPQUAD(info->src.min_ip), - NIPQUAD(info->src.max_ip)); + &info->src.min_ip, + &info->src.max_ip); return false; } } @@ -39,12 +38,11 @@ iprange_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) if ((ntohl(iph->daddr) < ntohl(info->dst.min_ip) || ntohl(iph->daddr) > ntohl(info->dst.max_ip)) ^ !!(info->flags & IPRANGE_DST_INV)) { - pr_debug("dst IP %u.%u.%u.%u NOT in range %s" - "%u.%u.%u.%u-%u.%u.%u.%u\n", - NIPQUAD(iph->daddr), + pr_debug("dst IP %pI4 NOT in range %s%pI4-%pI4\n", + &iph->daddr, info->flags & IPRANGE_DST_INV ? "(INV) " : "", - NIPQUAD(info->dst.min_ip), - NIPQUAD(info->dst.max_ip)); + &info->dst.min_ip, + &info->dst.max_ip); return false; } } @@ -63,12 +61,11 @@ iprange_mt4(const struct sk_buff *skb, const struct xt_match_param *par) m |= ntohl(iph->saddr) > ntohl(info->src_max.ip); m ^= !!(info->flags & IPRANGE_SRC_INV); if (m) { - pr_debug("src IP " NIPQUAD_FMT " NOT in range %s" - NIPQUAD_FMT "-" NIPQUAD_FMT "\n", - NIPQUAD(iph->saddr), + pr_debug("src IP %pI4 NOT in range %s%pI4-%pI4\n", + &iph->saddr, (info->flags & IPRANGE_SRC_INV) ? "(INV) " : "", - NIPQUAD(info->src_max.ip), - NIPQUAD(info->src_max.ip)); + &info->src_max.ip, + &info->src_max.ip); return false; } } @@ -77,12 +74,11 @@ iprange_mt4(const struct sk_buff *skb, const struct xt_match_param *par) m |= ntohl(iph->daddr) > ntohl(info->dst_max.ip); m ^= !!(info->flags & IPRANGE_DST_INV); if (m) { - pr_debug("dst IP " NIPQUAD_FMT " NOT in range %s" - NIPQUAD_FMT "-" NIPQUAD_FMT "\n", - NIPQUAD(iph->daddr), + pr_debug("dst IP %pI4 NOT in range %s%pI4-%pI4\n", + &iph->daddr, (info->flags & IPRANGE_DST_INV) ? "(INV) " : "", - NIPQUAD(info->dst_min.ip), - NIPQUAD(info->dst_max.ip)); + &info->dst_min.ip, + &info->dst_max.ip); return false; } } diff --git a/net/netfilter/xt_recent.c b/net/netfilter/xt_recent.c index 280c471bcdf444fdc2228a46895c2b44baf8d549..fe80b614a40033014f48cfe1fad26f3806af85c2 100644 --- a/net/netfilter/xt_recent.c +++ b/net/netfilter/xt_recent.c @@ -72,9 +72,6 @@ struct recent_entry { struct recent_table { struct list_head list; char name[XT_RECENT_NAME_LEN]; -#ifdef CONFIG_PROC_FS - struct proc_dir_entry *proc_old, *proc; -#endif unsigned int refcnt; unsigned int entries; struct list_head lru_list; @@ -284,6 +281,9 @@ static bool recent_mt_check(const struct xt_mtchk_param *par) { const struct xt_recent_mtinfo *info = par->matchinfo; struct recent_table *t; +#ifdef CONFIG_PROC_FS + struct proc_dir_entry *pde; +#endif unsigned i; bool ret = false; @@ -318,25 +318,25 @@ static bool recent_mt_check(const struct xt_mtchk_param *par) for (i = 0; i < ip_list_hash_size; i++) INIT_LIST_HEAD(&t->iphash[i]); #ifdef CONFIG_PROC_FS - t->proc = proc_create_data(t->name, ip_list_perms, recent_proc_dir, + pde = proc_create_data(t->name, ip_list_perms, recent_proc_dir, &recent_mt_fops, t); - if (t->proc == NULL) { + if (pde == NULL) { kfree(t); goto out; } + pde->uid = ip_list_uid; + pde->gid = ip_list_gid; #ifdef CONFIG_NETFILTER_XT_MATCH_RECENT_PROC_COMPAT - t->proc_old = proc_create_data(t->name, ip_list_perms, proc_old_dir, + pde = proc_create_data(t->name, ip_list_perms, proc_old_dir, &recent_old_fops, t); - if (t->proc_old == NULL) { + if (pde == NULL) { remove_proc_entry(t->name, proc_old_dir); kfree(t); goto out; } - t->proc_old->uid = ip_list_uid; - t->proc_old->gid = ip_list_gid; + pde->uid = ip_list_uid; + pde->gid = ip_list_gid; #endif - t->proc->uid = ip_list_uid; - t->proc->gid = ip_list_gid; #endif spin_lock_bh(&recent_lock); list_add_tail(&t->list, &tables); @@ -422,13 +422,11 @@ static int recent_seq_show(struct seq_file *seq, void *v) i = (e->index - 1) % ip_pkt_list_tot; if (e->family == NFPROTO_IPV4) - seq_printf(seq, "src=" NIPQUAD_FMT " ttl: %u last_seen: %lu " - "oldest_pkt: %u", NIPQUAD(e->addr.ip), e->ttl, - e->stamps[i], e->index); + seq_printf(seq, "src=%pI4 ttl: %u last_seen: %lu oldest_pkt: %u", + &e->addr.ip, e->ttl, e->stamps[i], e->index); else - seq_printf(seq, "src=" NIP6_FMT " ttl: %u last_seen: %lu " - "oldest_pkt: %u", NIP6(e->addr.in6), e->ttl, - e->stamps[i], e->index); + seq_printf(seq, "src=%pI6 ttl: %u last_seen: %lu oldest_pkt: %u", + &e->addr.in6, e->ttl, e->stamps[i], e->index); for (i = 0; i < e->nstamps; i++) seq_printf(seq, "%s %lu", i ? "," : "", e->stamps[i]); seq_printf(seq, "\n"); diff --git a/net/netlabel/netlabel_addrlist.c b/net/netlabel/netlabel_addrlist.c index 249f6b92f153b675cb7895b0b3b4f57b8fb74799..834c6eb7f484cfe9ccab1523ac4f8733d6c6dda8 100644 --- a/net/netlabel/netlabel_addrlist.c +++ b/net/netlabel/netlabel_addrlist.c @@ -337,7 +337,7 @@ void netlbl_af4list_audit_addr(struct audit_buffer *audit_buf, if (dev != NULL) audit_log_format(audit_buf, " netif=%s", dev); - audit_log_format(audit_buf, " %s=" NIPQUAD_FMT, dir, NIPQUAD(addr)); + audit_log_format(audit_buf, " %s=%pI4", dir, &addr); if (mask_val != 0xffffffff) { u32 mask_len = 0; while (mask_val > 0) { @@ -371,7 +371,7 @@ void netlbl_af6list_audit_addr(struct audit_buffer *audit_buf, if (dev != NULL) audit_log_format(audit_buf, " netif=%s", dev); - audit_log_format(audit_buf, " %s=" NIP6_FMT, dir, NIP6(*addr)); + audit_log_format(audit_buf, " %s=%pI6", dir, addr); if (ntohl(mask->s6_addr32[3]) != 0xffffffff) { u32 mask_len = 0; u32 mask_val; diff --git a/net/netlabel/netlabel_mgmt.c b/net/netlabel/netlabel_mgmt.c index 0a0ef17b2a401bf4afb1385b5eb5173dd0c38d7b..1821c5d50fb8ec448374c04619c30eab07baa15f 100644 --- a/net/netlabel/netlabel_mgmt.c +++ b/net/netlabel/netlabel_mgmt.c @@ -596,7 +596,6 @@ listdef_failure: /** * netlbl_mgmt_protocols_cb - Write an individual PROTOCOL message response * @skb: the skb to write to - * @seq: the NETLINK sequence number * @cb: the NETLINK callback * @protocol: the NetLabel protocol to use in the message * diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index 480184a857d21abdf72886d795679b64996399b1..9eb895c7a2a97bb87076f715ce5c692f74e51505 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -452,6 +452,10 @@ static int netlink_create(struct net *net, struct socket *sock, int protocol) if (err < 0) goto out_module; + local_bh_disable(); + sock_prot_inuse_add(net, &netlink_proto, 1); + local_bh_enable(); + nlk = nlk_sk(sock->sk); nlk->module = module; out: @@ -511,6 +515,9 @@ static int netlink_release(struct socket *sock) kfree(nlk->groups); nlk->groups = NULL; + local_bh_disable(); + sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1); + local_bh_enable(); sock_put(sk); return 0; } diff --git a/net/netlink/attr.c b/net/netlink/attr.c index 2d106cfe1d276bf5e234195753eb091cba7b7f1e..56c3ce7fe29af8b2bf47dd8bdc41edb93576c70a 100644 --- a/net/netlink/attr.c +++ b/net/netlink/attr.c @@ -83,6 +83,12 @@ static int validate_nla(struct nlattr *nla, int maxtype, if (attrlen < NLA_ALIGN(pt->len) + NLA_HDRLEN + nla_len(nla)) return -ERANGE; break; + case NLA_NESTED: + /* a nested attributes is allowed to be empty; if its not, + * it must have a size of at least NLA_HDRLEN. + */ + if (attrlen == 0) + break; default: if (pt->len) minlen = pt->len; @@ -233,7 +239,7 @@ size_t nla_strlcpy(char *dst, const struct nlattr *nla, size_t dstsize) * * Returns the number of bytes copied. */ -int nla_memcpy(void *dest, struct nlattr *src, int count) +int nla_memcpy(void *dest, const struct nlattr *src, int count) { int minlen = min_t(int, count, nla_len(src)); diff --git a/net/netrom/sysctl_net_netrom.c b/net/netrom/sysctl_net_netrom.c index 34c96c9674dfd838c9061d2a0afde9211ea4bed3..7b49591fe87c7e4dccdfb521db62cf306f641266 100644 --- a/net/netrom/sysctl_net_netrom.c +++ b/net/netrom/sysctl_net_netrom.c @@ -41,8 +41,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_default_path_quality, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_quality, .extra2 = &max_quality }, @@ -52,8 +52,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_obsolescence_count_initialiser, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_obs, .extra2 = &max_obs }, @@ -63,8 +63,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_network_ttl_initialiser, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_ttl, .extra2 = &max_ttl }, @@ -74,8 +74,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_transport_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_t1, .extra2 = &max_t1 }, @@ -85,8 +85,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_transport_maximum_tries, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_n2, .extra2 = &max_n2 }, @@ -96,8 +96,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_transport_acknowledge_delay, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_t2, .extra2 = &max_t2 }, @@ -107,8 +107,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_transport_busy_delay, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_t4, .extra2 = &max_t4 }, @@ -118,8 +118,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_transport_requested_window_size, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_window, .extra2 = &max_window }, @@ -129,8 +129,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_transport_no_activity_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_idle, .extra2 = &max_idle }, @@ -140,8 +140,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_routing_control, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_route, .extra2 = &max_route }, @@ -151,8 +151,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_link_fails_count, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_fails, .extra2 = &max_fails }, @@ -162,8 +162,8 @@ static ctl_table nr_table[] = { .data = &sysctl_netrom_reset_circuit, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_reset, .extra2 = &max_reset }, diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index c718e7e3f7dea66facd1483b0b27dd5b4ef974bc..5f94db2f3e9ed410e58f660f3ab3c0468e68ff92 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -872,6 +872,7 @@ static int packet_release(struct socket *sock) write_lock_bh(&net->packet.sklist_lock); sk_del_node_init(sk); + sock_prot_inuse_add(net, sk->sk_prot, -1); write_unlock_bh(&net->packet.sklist_lock); /* @@ -1084,6 +1085,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol) write_lock_bh(&net->packet.sklist_lock); sk_add_node(sk, &net->packet.sklist); + sock_prot_inuse_add(net, &packet_proto, 1); write_unlock_bh(&net->packet.sklist_lock); return(0); out: diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c index 9d211f12582ba90882ae9f272a6896b716d83af4..13cb323f8c382bad79f287bb5636ed0ee34271df 100644 --- a/net/phonet/af_phonet.c +++ b/net/phonet/af_phonet.c @@ -67,9 +67,6 @@ static int pn_socket_create(struct net *net, struct socket *sock, int protocol) struct phonet_protocol *pnp; int err; - if (net != &init_net) - return -EAFNOSUPPORT; - if (!capable(CAP_SYS_ADMIN)) return -EPERM; @@ -352,9 +349,6 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev, struct sockaddr_pn sa; u16 len; - if (dev_net(dev) != &init_net) - goto out; - /* check we have at least a full Phonet header */ if (!pskb_pull(skb, sizeof(struct phonethdr))) goto out; @@ -373,7 +367,7 @@ static int phonet_rcv(struct sk_buff *skb, struct net_device *dev, if (pn_sockaddr_get_addr(&sa) == 0) goto out; /* currently, we cannot be device 0 */ - sk = pn_find_sock_by_sa(&sa); + sk = pn_find_sock_by_sa(dev_net(dev), &sa); if (sk == NULL) { if (can_respond(skb)) { send_obj_unreachable(skb); diff --git a/net/phonet/pep-gprs.c b/net/phonet/pep-gprs.c index 803eeef0aa856877ddced0e45fc283f4641da2ab..b0ceac2d6cd1022d568c48efd85ede0568882da8 100644 --- a/net/phonet/pep-gprs.c +++ b/net/phonet/pep-gprs.c @@ -40,23 +40,17 @@ struct gprs_dev { void (*old_data_ready)(struct sock *, int); void (*old_write_space)(struct sock *); - struct net_device *net; - struct net_device_stats stats; - - struct sk_buff_head tx_queue; - struct work_struct tx_work; - spinlock_t tx_lock; - unsigned tx_max; + struct net_device *dev; }; -static int gprs_type_trans(struct sk_buff *skb) +static __be16 gprs_type_trans(struct sk_buff *skb) { const u8 *pvfc; u8 buf; pvfc = skb_header_pointer(skb, 0, 1, &buf); if (!pvfc) - return 0; + return htons(0); /* Look at IP version field */ switch (*pvfc >> 4) { case 4: @@ -64,7 +58,15 @@ static int gprs_type_trans(struct sk_buff *skb) case 6: return htons(ETH_P_IPV6); } - return 0; + return htons(0); +} + +static void gprs_writeable(struct gprs_dev *gp) +{ + struct net_device *dev = gp->dev; + + if (pep_writeable(gp->sk)) + netif_wake_queue(dev); } /* @@ -73,18 +75,21 @@ static int gprs_type_trans(struct sk_buff *skb) static void gprs_state_change(struct sock *sk) { - struct gprs_dev *dev = sk->sk_user_data; + struct gprs_dev *gp = sk->sk_user_data; if (sk->sk_state == TCP_CLOSE_WAIT) { - netif_stop_queue(dev->net); - netif_carrier_off(dev->net); + struct net_device *dev = gp->dev; + + netif_stop_queue(dev); + netif_carrier_off(dev); } } -static int gprs_recv(struct gprs_dev *dev, struct sk_buff *skb) +static int gprs_recv(struct gprs_dev *gp, struct sk_buff *skb) { + struct net_device *dev = gp->dev; int err = 0; - u16 protocol = gprs_type_trans(skb); + __be16 protocol = gprs_type_trans(skb); if (!protocol) { err = -EINVAL; @@ -99,7 +104,7 @@ static int gprs_recv(struct gprs_dev *dev, struct sk_buff *skb) * so wrap the IP packet as a single fragment of an head-less * socket buffer. The network stack will pull what it needs, * but at least, the whole IP payload is not memcpy'd. */ - rskb = netdev_alloc_skb(dev->net, 0); + rskb = netdev_alloc_skb(dev, 0); if (!rskb) { err = -ENOBUFS; goto drop; @@ -123,9 +128,9 @@ static int gprs_recv(struct gprs_dev *dev, struct sk_buff *skb) skb->protocol = protocol; skb_reset_mac_header(skb); - skb->dev = dev->net; + skb->dev = dev; - if (likely(dev->net->flags & IFF_UP)) { + if (likely(dev->flags & IFF_UP)) { dev->stats.rx_packets++; dev->stats.rx_bytes += skb->len; netif_rx(skb); @@ -143,26 +148,21 @@ drop: static void gprs_data_ready(struct sock *sk, int len) { - struct gprs_dev *dev = sk->sk_user_data; + struct gprs_dev *gp = sk->sk_user_data; struct sk_buff *skb; while ((skb = pep_read(sk)) != NULL) { skb_orphan(skb); - gprs_recv(dev, skb); + gprs_recv(gp, skb); } } static void gprs_write_space(struct sock *sk) { - struct gprs_dev *dev = sk->sk_user_data; - struct net_device *net = dev->net; - unsigned credits = pep_writeable(sk); - - spin_lock_bh(&dev->tx_lock); - dev->tx_max = credits; - if (credits > skb_queue_len(&dev->tx_queue) && netif_running(net)) - netif_wake_queue(net); - spin_unlock_bh(&dev->tx_lock); + struct gprs_dev *gp = sk->sk_user_data; + + if (netif_running(gp->dev)) + gprs_writeable(gp); } /* @@ -173,22 +173,21 @@ static int gprs_open(struct net_device *dev) { struct gprs_dev *gp = netdev_priv(dev); - gprs_write_space(gp->sk); + gprs_writeable(gp); return 0; } static int gprs_close(struct net_device *dev) { - struct gprs_dev *gp = netdev_priv(dev); - netif_stop_queue(dev); - flush_work(&gp->tx_work); return 0; } -static int gprs_xmit(struct sk_buff *skb, struct net_device *net) +static int gprs_xmit(struct sk_buff *skb, struct net_device *dev) { - struct gprs_dev *dev = netdev_priv(net); + struct gprs_dev *gp = netdev_priv(dev); + struct sock *sk = gp->sk; + int len, err; switch (skb->protocol) { case htons(ETH_P_IP): @@ -199,84 +198,50 @@ static int gprs_xmit(struct sk_buff *skb, struct net_device *net) return 0; } - spin_lock(&dev->tx_lock); - if (likely(skb_queue_len(&dev->tx_queue) < dev->tx_max)) { - skb_queue_tail(&dev->tx_queue, skb); - skb = NULL; - } - if (skb_queue_len(&dev->tx_queue) >= dev->tx_max) - netif_stop_queue(net); - spin_unlock(&dev->tx_lock); - - schedule_work(&dev->tx_work); - if (unlikely(skb)) + skb_orphan(skb); + skb_set_owner_w(skb, sk); + len = skb->len; + err = pep_write(sk, skb); + if (err) { + LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n", + dev->name, err); + dev->stats.tx_aborted_errors++; + dev->stats.tx_errors++; dev_kfree_skb(skb); - return 0; -} - -static void gprs_tx(struct work_struct *work) -{ - struct gprs_dev *dev = container_of(work, struct gprs_dev, tx_work); - struct sock *sk = dev->sk; - struct sk_buff *skb; - - while ((skb = skb_dequeue(&dev->tx_queue)) != NULL) { - int err; - - dev->stats.tx_bytes += skb->len; + } else { dev->stats.tx_packets++; - - skb_orphan(skb); - skb_set_owner_w(skb, sk); - - lock_sock(sk); - err = pep_write(sk, skb); - if (err) { - LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n", - dev->net->name, err); - dev->stats.tx_aborted_errors++; - dev->stats.tx_errors++; - } - release_sock(sk); + dev->stats.tx_bytes += len; } - lock_sock(sk); - gprs_write_space(sk); - release_sock(sk); + if (!pep_writeable(sk)) + netif_stop_queue(dev); + return 0; } -static int gprs_set_mtu(struct net_device *net, int new_mtu) +static int gprs_set_mtu(struct net_device *dev, int new_mtu) { if ((new_mtu < 576) || (new_mtu > (PHONET_MAX_MTU - 11))) return -EINVAL; - net->mtu = new_mtu; + dev->mtu = new_mtu; return 0; } -static struct net_device_stats *gprs_get_stats(struct net_device *net) +static void gprs_setup(struct net_device *dev) { - struct gprs_dev *dev = netdev_priv(net); - - return &dev->stats; -} - -static void gprs_setup(struct net_device *net) -{ - net->features = NETIF_F_FRAGLIST; - net->type = ARPHRD_NONE; - net->flags = IFF_POINTOPOINT | IFF_NOARP; - net->mtu = GPRS_DEFAULT_MTU; - net->hard_header_len = 0; - net->addr_len = 0; - net->tx_queue_len = 10; - - net->destructor = free_netdev; - net->open = gprs_open; - net->stop = gprs_close; - net->hard_start_xmit = gprs_xmit; /* mandatory */ - net->change_mtu = gprs_set_mtu; - net->get_stats = gprs_get_stats; + dev->features = NETIF_F_FRAGLIST; + dev->type = ARPHRD_PHONET_PIPE; + dev->flags = IFF_POINTOPOINT | IFF_NOARP; + dev->mtu = GPRS_DEFAULT_MTU; + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->tx_queue_len = 10; + + dev->destructor = free_netdev; + dev->open = gprs_open; + dev->stop = gprs_close; + dev->hard_start_xmit = gprs_xmit; /* mandatory */ + dev->change_mtu = gprs_set_mtu; } /* @@ -290,28 +255,25 @@ static void gprs_setup(struct net_device *net) int gprs_attach(struct sock *sk) { static const char ifname[] = "gprs%d"; - struct gprs_dev *dev; - struct net_device *net; + struct gprs_dev *gp; + struct net_device *dev; int err; if (unlikely(sk->sk_type == SOCK_STREAM)) return -EINVAL; /* need packet boundaries */ /* Create net device */ - net = alloc_netdev(sizeof(*dev), ifname, gprs_setup); - if (!net) + dev = alloc_netdev(sizeof(*gp), ifname, gprs_setup); + if (!dev) return -ENOMEM; - dev = netdev_priv(net); - dev->net = net; - dev->tx_max = 0; - spin_lock_init(&dev->tx_lock); - skb_queue_head_init(&dev->tx_queue); - INIT_WORK(&dev->tx_work, gprs_tx); - - netif_stop_queue(net); - err = register_netdev(net); + gp = netdev_priv(dev); + gp->sk = sk; + gp->dev = dev; + + netif_stop_queue(dev); + err = register_netdev(dev); if (err) { - free_netdev(net); + free_netdev(dev); return err; } @@ -325,40 +287,38 @@ int gprs_attach(struct sock *sk) err = -EINVAL; goto out_rel; } - sk->sk_user_data = dev; - dev->old_state_change = sk->sk_state_change; - dev->old_data_ready = sk->sk_data_ready; - dev->old_write_space = sk->sk_write_space; + sk->sk_user_data = gp; + gp->old_state_change = sk->sk_state_change; + gp->old_data_ready = sk->sk_data_ready; + gp->old_write_space = sk->sk_write_space; sk->sk_state_change = gprs_state_change; sk->sk_data_ready = gprs_data_ready; sk->sk_write_space = gprs_write_space; release_sock(sk); - sock_hold(sk); - dev->sk = sk; - printk(KERN_DEBUG"%s: attached\n", net->name); - return net->ifindex; + printk(KERN_DEBUG"%s: attached\n", dev->name); + return dev->ifindex; out_rel: release_sock(sk); - unregister_netdev(net); + unregister_netdev(dev); return err; } void gprs_detach(struct sock *sk) { - struct gprs_dev *dev = sk->sk_user_data; - struct net_device *net = dev->net; + struct gprs_dev *gp = sk->sk_user_data; + struct net_device *dev = gp->dev; lock_sock(sk); sk->sk_user_data = NULL; - sk->sk_state_change = dev->old_state_change; - sk->sk_data_ready = dev->old_data_ready; - sk->sk_write_space = dev->old_write_space; + sk->sk_state_change = gp->old_state_change; + sk->sk_data_ready = gp->old_data_ready; + sk->sk_write_space = gp->old_write_space; release_sock(sk); - printk(KERN_DEBUG"%s: detached\n", net->name); - unregister_netdev(net); + printk(KERN_DEBUG"%s: detached\n", dev->name); + unregister_netdev(dev); sock_put(sk); } diff --git a/net/phonet/pep.c b/net/phonet/pep.c index bc6d50f83249fb9aa5db766d71fb95e3147fd237..bb3e67849b38c562129b37292837d687b5d19b5b 100644 --- a/net/phonet/pep.c +++ b/net/phonet/pep.c @@ -225,6 +225,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) { struct pep_sock *pn = pep_sk(sk); struct pnpipehdr *hdr = pnp_hdr(skb); + int wake = 0; if (!pskb_may_pull(skb, sizeof(*hdr) + 4)) return -EINVAL; @@ -241,16 +242,16 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) case PN_LEGACY_FLOW_CONTROL: switch (hdr->data[4]) { case PEP_IND_BUSY: - pn->tx_credits = 0; + atomic_set(&pn->tx_credits, 0); break; case PEP_IND_READY: - pn->tx_credits = 1; + atomic_set(&pn->tx_credits, wake = 1); break; } break; case PN_ONE_CREDIT_FLOW_CONTROL: if (hdr->data[4] == PEP_IND_READY) - pn->tx_credits = 1; + atomic_set(&pn->tx_credits, wake = 1); break; } break; @@ -258,10 +259,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) case PN_PEP_IND_ID_MCFC_GRANT_CREDITS: if (pn->tx_fc != PN_MULTI_CREDIT_FLOW_CONTROL) break; - if (pn->tx_credits + hdr->data[4] > 0xff) - pn->tx_credits = 0xff; - else - pn->tx_credits += hdr->data[4]; + atomic_add(wake = hdr->data[4], &pn->tx_credits); break; default: @@ -269,7 +267,7 @@ static int pipe_rcv_status(struct sock *sk, struct sk_buff *skb) (unsigned)hdr->data[1]); return -EOPNOTSUPP; } - if (pn->tx_credits) + if (wake) sk->sk_write_space(sk); return 0; } @@ -343,7 +341,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) } /* fall through */ case PNS_PEP_DISABLE_REQ: - pn->tx_credits = 0; + atomic_set(&pn->tx_credits, 0); pep_reply(sk, skb, PN_PIPE_NO_ERROR, NULL, 0, GFP_ATOMIC); break; @@ -390,7 +388,7 @@ static int pipe_do_rcv(struct sock *sk, struct sk_buff *skb) /* fall through */ case PNS_PIPE_ENABLED_IND: if (!pn_flow_safe(pn->tx_fc)) { - pn->tx_credits = 1; + atomic_set(&pn->tx_credits, 1); sk->sk_write_space(sk); } if (sk->sk_state == TCP_ESTABLISHED) @@ -504,8 +502,9 @@ static int pep_connreq_rcv(struct sock *sk, struct sk_buff *skb) newpn->pn_sk.resource = pn->pn_sk.resource; skb_queue_head_init(&newpn->ctrlreq_queue); newpn->pipe_handle = pipe_handle; + atomic_set(&newpn->tx_credits, 0); newpn->peer_type = peer_type; - newpn->rx_credits = newpn->tx_credits = 0; + newpn->rx_credits = 0; newpn->rx_fc = newpn->tx_fc = PN_LEGACY_FLOW_CONTROL; newpn->init_enable = enabled; @@ -821,14 +820,18 @@ static int pipe_skb_send(struct sock *sk, struct sk_buff *skb) struct pep_sock *pn = pep_sk(sk); struct pnpipehdr *ph; + if (pn_flow_safe(pn->tx_fc) && + !atomic_add_unless(&pn->tx_credits, -1, 0)) { + kfree_skb(skb); + return -ENOBUFS; + } + skb_push(skb, 3); skb_reset_transport_header(skb); ph = pnp_hdr(skb); ph->utid = 0; ph->message_id = PNS_PIPE_DATA; ph->pipe_handle = pn->pipe_handle; - if (pn_flow_safe(pn->tx_fc) && pn->tx_credits) - pn->tx_credits--; return pn_skb_send(sk, skb, &pipe_srv); } @@ -866,7 +869,7 @@ disabled: BUG_ON(sk->sk_state != TCP_ESTABLISHED); /* Wait until flow control allows TX */ - done = pn->tx_credits > 0; + done = atomic_read(&pn->tx_credits); while (!done) { DEFINE_WAIT(wait); @@ -881,7 +884,7 @@ disabled: prepare_to_wait(&sk->sk_socket->wait, &wait, TASK_INTERRUPTIBLE); - done = sk_wait_event(sk, &timeo, pn->tx_credits > 0); + done = sk_wait_event(sk, &timeo, atomic_read(&pn->tx_credits)); finish_wait(&sk->sk_socket->wait, &wait); if (sk->sk_state != TCP_ESTABLISHED) @@ -895,7 +898,8 @@ disabled: goto out; skb_reserve(skb, MAX_PHONET_HEADER + 3); - if (sk->sk_state != TCP_ESTABLISHED || !pn->tx_credits) + if (sk->sk_state != TCP_ESTABLISHED || + !atomic_read(&pn->tx_credits)) goto disabled; /* sock_alloc_send_skb might sleep */ } @@ -917,7 +921,7 @@ int pep_writeable(struct sock *sk) { struct pep_sock *pn = pep_sk(sk); - return (sk->sk_state == TCP_ESTABLISHED) ? pn->tx_credits : 0; + return atomic_read(&pn->tx_credits); } int pep_write(struct sock *sk, struct sk_buff *skb) diff --git a/net/phonet/pn_dev.c b/net/phonet/pn_dev.c index f93ff8ef47d0f8d47635af976c4fab46b8fcd1ce..5491bf5e354bbe20b7eb33a078e2a710e4d10d0b 100644 --- a/net/phonet/pn_dev.c +++ b/net/phonet/pn_dev.c @@ -76,7 +76,7 @@ struct net_device *phonet_device_get(struct net *net) dev = pnd->netdev; BUG_ON(!dev); - if (dev_net(dev) == net && + if (net_eq(dev_net(dev), net) && (dev->reg_state == NETREG_REGISTERED) && ((pnd->netdev->flags & IFF_UP)) == IFF_UP) break; @@ -140,12 +140,14 @@ u8 phonet_address_get(struct net_device *dev, u8 addr) return addr; } -int phonet_address_lookup(u8 addr) +int phonet_address_lookup(struct net *net, u8 addr) { struct phonet_device *pnd; spin_lock_bh(&pndevs.lock); list_for_each_entry(pnd, &pndevs.list, list) { + if (!net_eq(dev_net(pnd->netdev), net)) + continue; /* Don't allow unregistering devices! */ if ((pnd->netdev->reg_state != NETREG_REGISTERED) || ((pnd->netdev->flags & IFF_UP)) != IFF_UP) diff --git a/net/phonet/socket.c b/net/phonet/socket.c index d81740187fb4982981490ba6718c6081513af1f0..ada2a35bf7a2382f49c49f771403e70d6b5d0359 100644 --- a/net/phonet/socket.c +++ b/net/phonet/socket.c @@ -57,7 +57,7 @@ static struct { * Find address based on socket address, match only certain fields. * Also grab sock if it was found. Remember to sock_put it later. */ -struct sock *pn_find_sock_by_sa(const struct sockaddr_pn *spn) +struct sock *pn_find_sock_by_sa(struct net *net, const struct sockaddr_pn *spn) { struct hlist_node *node; struct sock *sknode; @@ -71,6 +71,8 @@ struct sock *pn_find_sock_by_sa(const struct sockaddr_pn *spn) struct pn_sock *pn = pn_sk(sknode); BUG_ON(!pn->sobject); /* unbound socket */ + if (!net_eq(sock_net(sknode), net)) + continue; if (pn_port(obj)) { /* Look up socket by port */ if (pn_port(pn->sobject) != pn_port(obj)) @@ -130,7 +132,7 @@ static int pn_socket_bind(struct socket *sock, struct sockaddr *addr, int len) handle = pn_sockaddr_get_object((struct sockaddr_pn *)addr); saddr = pn_addr(handle); - if (saddr && phonet_address_lookup(saddr)) + if (saddr && phonet_address_lookup(sock_net(sk), saddr)) return -EADDRNOTAVAIL; lock_sock(sk); @@ -225,7 +227,7 @@ static unsigned int pn_socket_poll(struct file *file, struct socket *sock, if (!mask && sk->sk_state == TCP_CLOSE_WAIT) return POLLHUP; - if (sk->sk_state == TCP_ESTABLISHED && pn->tx_credits) + if (sk->sk_state == TCP_ESTABLISHED && atomic_read(&pn->tx_credits)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; return mask; @@ -361,6 +363,7 @@ static DEFINE_MUTEX(port_mutex); int pn_sock_get_port(struct sock *sk, unsigned short sport) { static int port_cur; + struct net *net = sock_net(sk); struct pn_sock *pn = pn_sk(sk); struct sockaddr_pn try_sa; struct sock *tmpsk; @@ -381,7 +384,7 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport) port_cur = pmin; pn_sockaddr_set_port(&try_sa, port_cur); - tmpsk = pn_find_sock_by_sa(&try_sa); + tmpsk = pn_find_sock_by_sa(net, &try_sa); if (tmpsk == NULL) { sport = port_cur; goto found; @@ -391,7 +394,7 @@ int pn_sock_get_port(struct sock *sk, unsigned short sport) } else { /* try to find specific port */ pn_sockaddr_set_port(&try_sa, sport); - tmpsk = pn_find_sock_by_sa(&try_sa); + tmpsk = pn_find_sock_by_sa(net, &try_sa); if (tmpsk == NULL) /* No sock there! We can use that port... */ goto found; diff --git a/net/phonet/sysctl.c b/net/phonet/sysctl.c index 600a4309b8c8f447c4f8560cf0a8095adf4a5b1d..7b5749ee2765c221532e9c3624f66d27e0843db5 100644 --- a/net/phonet/sysctl.c +++ b/net/phonet/sysctl.c @@ -89,13 +89,13 @@ static struct ctl_table phonet_table[] = { .data = &local_port_range, .maxlen = sizeof(local_port_range), .mode = 0644, - .proc_handler = &proc_local_port_range, + .proc_handler = proc_local_port_range, .strategy = NULL, }, { .ctl_name = 0 } }; -struct ctl_path phonet_ctl_path[] = { +static struct ctl_path phonet_ctl_path[] = { { .procname = "net", .ctl_name = CTL_NET, }, { .procname = "phonet", .ctl_name = CTL_UNNUMBERED, }, { }, diff --git a/net/rfkill/rfkill-input.c b/net/rfkill/rfkill-input.c index bfdade72e066f65c52a3bd82a70807b51de6a3f0..84efde97c5a773fe027d051cb3522e55534b8eb1 100644 --- a/net/rfkill/rfkill-input.c +++ b/net/rfkill/rfkill-input.c @@ -24,138 +24,318 @@ MODULE_AUTHOR("Dmitry Torokhov "); MODULE_DESCRIPTION("Input layer to RF switch connector"); MODULE_LICENSE("GPL"); +enum rfkill_input_master_mode { + RFKILL_INPUT_MASTER_DONOTHING = 0, + RFKILL_INPUT_MASTER_RESTORE = 1, + RFKILL_INPUT_MASTER_UNBLOCKALL = 2, + RFKILL_INPUT_MASTER_MAX, /* marker */ +}; + +/* Delay (in ms) between consecutive switch ops */ +#define RFKILL_OPS_DELAY 200 + +static enum rfkill_input_master_mode rfkill_master_switch_mode = + RFKILL_INPUT_MASTER_UNBLOCKALL; +module_param_named(master_switch_mode, rfkill_master_switch_mode, uint, 0); +MODULE_PARM_DESC(master_switch_mode, + "SW_RFKILL_ALL ON should: 0=do nothing; 1=restore; 2=unblock all"); + +enum rfkill_global_sched_op { + RFKILL_GLOBAL_OP_EPO = 0, + RFKILL_GLOBAL_OP_RESTORE, + RFKILL_GLOBAL_OP_UNLOCK, + RFKILL_GLOBAL_OP_UNBLOCK, +}; + +/* + * Currently, the code marked with RFKILL_NEED_SWSET is inactive. + * If handling of EV_SW SW_WLAN/WWAN/BLUETOOTH/etc is needed in the + * future, when such events are added, that code will be necessary. + */ + struct rfkill_task { - struct work_struct work; - enum rfkill_type type; - struct mutex mutex; /* ensures that task is serialized */ - spinlock_t lock; /* for accessing last and desired state */ - unsigned long last; /* last schedule */ - enum rfkill_state desired_state; /* on/off */ + struct delayed_work dwork; + + /* ensures that task is serialized */ + struct mutex mutex; + + /* protects everything below */ + spinlock_t lock; + + /* pending regular switch operations (1=pending) */ + unsigned long sw_pending[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; + +#ifdef RFKILL_NEED_SWSET + /* set operation pending (1=pending) */ + unsigned long sw_setpending[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; + + /* desired state for pending set operation (1=unblock) */ + unsigned long sw_newstate[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; +#endif + + /* should the state be complemented (1=yes) */ + unsigned long sw_togglestate[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; + + bool global_op_pending; + enum rfkill_global_sched_op op; + + /* last time it was scheduled */ + unsigned long last_scheduled; }; +static void __rfkill_handle_global_op(enum rfkill_global_sched_op op) +{ + unsigned int i; + + switch (op) { + case RFKILL_GLOBAL_OP_EPO: + rfkill_epo(); + break; + case RFKILL_GLOBAL_OP_RESTORE: + rfkill_restore_states(); + break; + case RFKILL_GLOBAL_OP_UNLOCK: + rfkill_remove_epo_lock(); + break; + case RFKILL_GLOBAL_OP_UNBLOCK: + rfkill_remove_epo_lock(); + for (i = 0; i < RFKILL_TYPE_MAX; i++) + rfkill_switch_all(i, RFKILL_STATE_UNBLOCKED); + break; + default: + /* memory corruption or bug, fail safely */ + rfkill_epo(); + WARN(1, "Unknown requested operation %d! " + "rfkill Emergency Power Off activated\n", + op); + } +} + +#ifdef RFKILL_NEED_SWSET +static void __rfkill_handle_normal_op(const enum rfkill_type type, + const bool sp, const bool s, const bool c) +{ + enum rfkill_state state; + + if (sp) + state = (s) ? RFKILL_STATE_UNBLOCKED : + RFKILL_STATE_SOFT_BLOCKED; + else + state = rfkill_get_global_state(type); + + if (c) + state = rfkill_state_complement(state); + + rfkill_switch_all(type, state); +} +#else +static void __rfkill_handle_normal_op(const enum rfkill_type type, + const bool c) +{ + enum rfkill_state state; + + state = rfkill_get_global_state(type); + if (c) + state = rfkill_state_complement(state); + + rfkill_switch_all(type, state); +} +#endif + static void rfkill_task_handler(struct work_struct *work) { - struct rfkill_task *task = container_of(work, struct rfkill_task, work); + struct rfkill_task *task = container_of(work, + struct rfkill_task, dwork.work); + bool doit = true; mutex_lock(&task->mutex); - rfkill_switch_all(task->type, task->desired_state); + spin_lock_irq(&task->lock); + while (doit) { + if (task->global_op_pending) { + enum rfkill_global_sched_op op = task->op; + task->global_op_pending = false; + memset(task->sw_pending, 0, sizeof(task->sw_pending)); + spin_unlock_irq(&task->lock); + + __rfkill_handle_global_op(op); + + /* make sure we do at least one pass with + * !task->global_op_pending */ + spin_lock_irq(&task->lock); + continue; + } else if (!rfkill_is_epo_lock_active()) { + unsigned int i = 0; + + while (!task->global_op_pending && + i < RFKILL_TYPE_MAX) { + if (test_and_clear_bit(i, task->sw_pending)) { + bool c; +#ifdef RFKILL_NEED_SWSET + bool sp, s; + sp = test_and_clear_bit(i, + task->sw_setpending); + s = test_bit(i, task->sw_newstate); +#endif + c = test_and_clear_bit(i, + task->sw_togglestate); + spin_unlock_irq(&task->lock); + +#ifdef RFKILL_NEED_SWSET + __rfkill_handle_normal_op(i, sp, s, c); +#else + __rfkill_handle_normal_op(i, c); +#endif + + spin_lock_irq(&task->lock); + } + i++; + } + } + doit = task->global_op_pending; + } + spin_unlock_irq(&task->lock); mutex_unlock(&task->mutex); } -static void rfkill_task_epo_handler(struct work_struct *work) +static struct rfkill_task rfkill_task = { + .dwork = __DELAYED_WORK_INITIALIZER(rfkill_task.dwork, + rfkill_task_handler), + .mutex = __MUTEX_INITIALIZER(rfkill_task.mutex), + .lock = __SPIN_LOCK_UNLOCKED(rfkill_task.lock), +}; + +static unsigned long rfkill_ratelimit(const unsigned long last) { - rfkill_epo(); + const unsigned long delay = msecs_to_jiffies(RFKILL_OPS_DELAY); + return (time_after(jiffies, last + delay)) ? 0 : delay; } -static DECLARE_WORK(epo_work, rfkill_task_epo_handler); +static void rfkill_schedule_ratelimited(void) +{ + if (!delayed_work_pending(&rfkill_task.dwork)) { + schedule_delayed_work(&rfkill_task.dwork, + rfkill_ratelimit(rfkill_task.last_scheduled)); + rfkill_task.last_scheduled = jiffies; + } +} -static void rfkill_schedule_epo(void) +static void rfkill_schedule_global_op(enum rfkill_global_sched_op op) { - schedule_work(&epo_work); + unsigned long flags; + + spin_lock_irqsave(&rfkill_task.lock, flags); + rfkill_task.op = op; + rfkill_task.global_op_pending = true; + if (op == RFKILL_GLOBAL_OP_EPO && !rfkill_is_epo_lock_active()) { + /* bypass the limiter for EPO */ + cancel_delayed_work(&rfkill_task.dwork); + schedule_delayed_work(&rfkill_task.dwork, 0); + rfkill_task.last_scheduled = jiffies; + } else + rfkill_schedule_ratelimited(); + spin_unlock_irqrestore(&rfkill_task.lock, flags); } -static void rfkill_schedule_set(struct rfkill_task *task, +#ifdef RFKILL_NEED_SWSET +/* Use this if you need to add EV_SW SW_WLAN/WWAN/BLUETOOTH/etc handling */ + +static void rfkill_schedule_set(enum rfkill_type type, enum rfkill_state desired_state) { unsigned long flags; - if (unlikely(work_pending(&epo_work))) + if (rfkill_is_epo_lock_active()) return; - spin_lock_irqsave(&task->lock, flags); - - if (time_after(jiffies, task->last + msecs_to_jiffies(200))) { - task->desired_state = desired_state; - task->last = jiffies; - schedule_work(&task->work); + spin_lock_irqsave(&rfkill_task.lock, flags); + if (!rfkill_task.global_op_pending) { + set_bit(type, rfkill_task.sw_pending); + set_bit(type, rfkill_task.sw_setpending); + clear_bit(type, rfkill_task.sw_togglestate); + if (desired_state) + set_bit(type, rfkill_task.sw_newstate); + else + clear_bit(type, rfkill_task.sw_newstate); + rfkill_schedule_ratelimited(); } - - spin_unlock_irqrestore(&task->lock, flags); + spin_unlock_irqrestore(&rfkill_task.lock, flags); } +#endif -static void rfkill_schedule_toggle(struct rfkill_task *task) +static void rfkill_schedule_toggle(enum rfkill_type type) { unsigned long flags; - if (unlikely(work_pending(&epo_work))) + if (rfkill_is_epo_lock_active()) return; - spin_lock_irqsave(&task->lock, flags); - - if (time_after(jiffies, task->last + msecs_to_jiffies(200))) { - task->desired_state = - rfkill_state_complement(task->desired_state); - task->last = jiffies; - schedule_work(&task->work); + spin_lock_irqsave(&rfkill_task.lock, flags); + if (!rfkill_task.global_op_pending) { + set_bit(type, rfkill_task.sw_pending); + change_bit(type, rfkill_task.sw_togglestate); + rfkill_schedule_ratelimited(); } - - spin_unlock_irqrestore(&task->lock, flags); + spin_unlock_irqrestore(&rfkill_task.lock, flags); } -#define DEFINE_RFKILL_TASK(n, t) \ - struct rfkill_task n = { \ - .work = __WORK_INITIALIZER(n.work, \ - rfkill_task_handler), \ - .type = t, \ - .mutex = __MUTEX_INITIALIZER(n.mutex), \ - .lock = __SPIN_LOCK_UNLOCKED(n.lock), \ - .desired_state = RFKILL_STATE_UNBLOCKED, \ - } - -static DEFINE_RFKILL_TASK(rfkill_wlan, RFKILL_TYPE_WLAN); -static DEFINE_RFKILL_TASK(rfkill_bt, RFKILL_TYPE_BLUETOOTH); -static DEFINE_RFKILL_TASK(rfkill_uwb, RFKILL_TYPE_UWB); -static DEFINE_RFKILL_TASK(rfkill_wimax, RFKILL_TYPE_WIMAX); -static DEFINE_RFKILL_TASK(rfkill_wwan, RFKILL_TYPE_WWAN); - static void rfkill_schedule_evsw_rfkillall(int state) { - /* EVERY radio type. state != 0 means radios ON */ - /* handle EPO (emergency power off) through shortcut */ if (state) { - rfkill_schedule_set(&rfkill_wwan, - RFKILL_STATE_UNBLOCKED); - rfkill_schedule_set(&rfkill_wimax, - RFKILL_STATE_UNBLOCKED); - rfkill_schedule_set(&rfkill_uwb, - RFKILL_STATE_UNBLOCKED); - rfkill_schedule_set(&rfkill_bt, - RFKILL_STATE_UNBLOCKED); - rfkill_schedule_set(&rfkill_wlan, - RFKILL_STATE_UNBLOCKED); + switch (rfkill_master_switch_mode) { + case RFKILL_INPUT_MASTER_UNBLOCKALL: + rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNBLOCK); + break; + case RFKILL_INPUT_MASTER_RESTORE: + rfkill_schedule_global_op(RFKILL_GLOBAL_OP_RESTORE); + break; + case RFKILL_INPUT_MASTER_DONOTHING: + rfkill_schedule_global_op(RFKILL_GLOBAL_OP_UNLOCK); + break; + default: + /* memory corruption or driver bug! fail safely */ + rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); + WARN(1, "Unknown rfkill_master_switch_mode (%d), " + "driver bug or memory corruption detected!\n", + rfkill_master_switch_mode); + break; + } } else - rfkill_schedule_epo(); + rfkill_schedule_global_op(RFKILL_GLOBAL_OP_EPO); } static void rfkill_event(struct input_handle *handle, unsigned int type, unsigned int code, int data) { if (type == EV_KEY && data == 1) { + enum rfkill_type t; + switch (code) { case KEY_WLAN: - rfkill_schedule_toggle(&rfkill_wlan); + t = RFKILL_TYPE_WLAN; break; case KEY_BLUETOOTH: - rfkill_schedule_toggle(&rfkill_bt); + t = RFKILL_TYPE_BLUETOOTH; break; case KEY_UWB: - rfkill_schedule_toggle(&rfkill_uwb); + t = RFKILL_TYPE_UWB; break; case KEY_WIMAX: - rfkill_schedule_toggle(&rfkill_wimax); + t = RFKILL_TYPE_WIMAX; break; default: - break; + return; } + rfkill_schedule_toggle(t); + return; } else if (type == EV_SW) { switch (code) { case SW_RFKILL_ALL: rfkill_schedule_evsw_rfkillall(data); - break; + return; default: - break; + return; } } } @@ -256,18 +436,23 @@ static struct input_handler rfkill_handler = { static int __init rfkill_handler_init(void) { - unsigned long last_run = jiffies - msecs_to_jiffies(500); - rfkill_wlan.last = last_run; - rfkill_bt.last = last_run; - rfkill_uwb.last = last_run; - rfkill_wimax.last = last_run; + if (rfkill_master_switch_mode >= RFKILL_INPUT_MASTER_MAX) + return -EINVAL; + + /* + * The penalty to not doing this is a possible RFKILL_OPS_DELAY delay + * at the first use. Acceptable, but if we can avoid it, why not? + */ + rfkill_task.last_scheduled = + jiffies - msecs_to_jiffies(RFKILL_OPS_DELAY) - 1; return input_register_handler(&rfkill_handler); } static void __exit rfkill_handler_exit(void) { input_unregister_handler(&rfkill_handler); - flush_scheduled_work(); + cancel_delayed_work_sync(&rfkill_task.dwork); + rfkill_remove_epo_lock(); } module_init(rfkill_handler_init); diff --git a/net/rfkill/rfkill-input.h b/net/rfkill/rfkill-input.h index bbfa646157c63a1668968bf90658f81ac3f976ad..fe8df6b5b935f4b9a3848f646c3d074e906c22f6 100644 --- a/net/rfkill/rfkill-input.h +++ b/net/rfkill/rfkill-input.h @@ -14,5 +14,8 @@ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state); void rfkill_epo(void); void rfkill_restore_states(void); +void rfkill_remove_epo_lock(void); +bool rfkill_is_epo_lock_active(void); +enum rfkill_state rfkill_get_global_state(const enum rfkill_type type); #endif /* __RFKILL_INPUT_H */ diff --git a/net/rfkill/rfkill.c b/net/rfkill/rfkill.c index 25ba3bd57e66405e64adef4455b66614fd273ea6..3c94f76d5525565f7cbb95372099ca9768d72a75 100644 --- a/net/rfkill/rfkill.c +++ b/net/rfkill/rfkill.c @@ -51,51 +51,7 @@ struct rfkill_gsw_state { static struct rfkill_gsw_state rfkill_global_states[RFKILL_TYPE_MAX]; static unsigned long rfkill_states_lockdflt[BITS_TO_LONGS(RFKILL_TYPE_MAX)]; - -static BLOCKING_NOTIFIER_HEAD(rfkill_notifier_list); - - -/** - * register_rfkill_notifier - Add notifier to rfkill notifier chain - * @nb: pointer to the new entry to add to the chain - * - * See blocking_notifier_chain_register() for return value and further - * observations. - * - * Adds a notifier to the rfkill notifier chain. The chain will be - * called with a pointer to the relevant rfkill structure as a parameter, - * refer to include/linux/rfkill.h for the possible events. - * - * Notifiers added to this chain are to always return NOTIFY_DONE. This - * chain is a blocking notifier chain: notifiers can sleep. - * - * Calls to this chain may have been done through a workqueue. One must - * assume unordered asynchronous behaviour, there is no way to know if - * actions related to the event that generated the notification have been - * carried out already. - */ -int register_rfkill_notifier(struct notifier_block *nb) -{ - BUG_ON(!nb); - return blocking_notifier_chain_register(&rfkill_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(register_rfkill_notifier); - -/** - * unregister_rfkill_notifier - remove notifier from rfkill notifier chain - * @nb: pointer to the entry to remove from the chain - * - * See blocking_notifier_chain_unregister() for return value and further - * observations. - * - * Removes a notifier from the rfkill notifier chain. - */ -int unregister_rfkill_notifier(struct notifier_block *nb) -{ - BUG_ON(!nb); - return blocking_notifier_chain_unregister(&rfkill_notifier_list, nb); -} -EXPORT_SYMBOL_GPL(unregister_rfkill_notifier); +static bool rfkill_epo_lock_active; static void rfkill_led_trigger(struct rfkill *rfkill, @@ -123,12 +79,9 @@ static void rfkill_led_trigger_activate(struct led_classdev *led) } #endif /* CONFIG_RFKILL_LEDS */ -static void notify_rfkill_state_change(struct rfkill *rfkill) +static void rfkill_uevent(struct rfkill *rfkill) { - rfkill_led_trigger(rfkill, rfkill->state); - blocking_notifier_call_chain(&rfkill_notifier_list, - RFKILL_STATE_CHANGED, - rfkill); + kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); } static void update_rfkill_state(struct rfkill *rfkill) @@ -141,7 +94,7 @@ static void update_rfkill_state(struct rfkill *rfkill) oldstate = rfkill->state; rfkill->state = newstate; if (oldstate != newstate) - notify_rfkill_state_change(rfkill); + rfkill_uevent(rfkill); } mutex_unlock(&rfkill->mutex); } @@ -219,7 +172,7 @@ static int rfkill_toggle_radio(struct rfkill *rfkill, } if (force || rfkill->state != oldstate) - notify_rfkill_state_change(rfkill); + rfkill_uevent(rfkill); return retval; } @@ -264,11 +217,14 @@ static void __rfkill_switch_all(const enum rfkill_type type, * * Acquires rfkill_global_mutex and calls __rfkill_switch_all(@type, @state). * Please refer to __rfkill_switch_all() for details. + * + * Does nothing if the EPO lock is active. */ void rfkill_switch_all(enum rfkill_type type, enum rfkill_state state) { mutex_lock(&rfkill_global_mutex); - __rfkill_switch_all(type, state); + if (!rfkill_epo_lock_active) + __rfkill_switch_all(type, state); mutex_unlock(&rfkill_global_mutex); } EXPORT_SYMBOL(rfkill_switch_all); @@ -289,6 +245,7 @@ void rfkill_epo(void) mutex_lock(&rfkill_global_mutex); + rfkill_epo_lock_active = true; list_for_each_entry(rfkill, &rfkill_list, node) { mutex_lock(&rfkill->mutex); rfkill_toggle_radio(rfkill, RFKILL_STATE_SOFT_BLOCKED, 1); @@ -317,12 +274,55 @@ void rfkill_restore_states(void) mutex_lock(&rfkill_global_mutex); + rfkill_epo_lock_active = false; for (i = 0; i < RFKILL_TYPE_MAX; i++) __rfkill_switch_all(i, rfkill_global_states[i].default_state); mutex_unlock(&rfkill_global_mutex); } EXPORT_SYMBOL_GPL(rfkill_restore_states); +/** + * rfkill_remove_epo_lock - unlock state changes + * + * Used by rfkill-input manually unlock state changes, when + * the EPO switch is deactivated. + */ +void rfkill_remove_epo_lock(void) +{ + mutex_lock(&rfkill_global_mutex); + rfkill_epo_lock_active = false; + mutex_unlock(&rfkill_global_mutex); +} +EXPORT_SYMBOL_GPL(rfkill_remove_epo_lock); + +/** + * rfkill_is_epo_lock_active - returns true EPO is active + * + * Returns 0 (false) if there is NOT an active EPO contidion, + * and 1 (true) if there is an active EPO contition, which + * locks all radios in one of the BLOCKED states. + * + * Can be called in atomic context. + */ +bool rfkill_is_epo_lock_active(void) +{ + return rfkill_epo_lock_active; +} +EXPORT_SYMBOL_GPL(rfkill_is_epo_lock_active); + +/** + * rfkill_get_global_state - returns global state for a type + * @type: the type to get the global state of + * + * Returns the current global state for a given wireless + * device type. + */ +enum rfkill_state rfkill_get_global_state(const enum rfkill_type type) +{ + return rfkill_global_states[type].current_state; +} +EXPORT_SYMBOL_GPL(rfkill_get_global_state); + /** * rfkill_force_state - Force the internal rfkill radio state * @rfkill: pointer to the rfkill class to modify. @@ -357,7 +357,7 @@ int rfkill_force_state(struct rfkill *rfkill, enum rfkill_state state) rfkill->state = state; if (state != oldstate) - notify_rfkill_state_change(rfkill); + rfkill_uevent(rfkill); mutex_unlock(&rfkill->mutex); @@ -431,9 +431,15 @@ static ssize_t rfkill_state_store(struct device *dev, state != RFKILL_STATE_SOFT_BLOCKED) return -EINVAL; - if (mutex_lock_interruptible(&rfkill->mutex)) - return -ERESTARTSYS; - error = rfkill_toggle_radio(rfkill, state, 0); + error = mutex_lock_killable(&rfkill->mutex); + if (error) + return error; + + if (!rfkill_epo_lock_active) + error = rfkill_toggle_radio(rfkill, state, 0); + else + error = -EPERM; + mutex_unlock(&rfkill->mutex); return error ? error : count; @@ -472,12 +478,12 @@ static ssize_t rfkill_claim_store(struct device *dev, * Take the global lock to make sure the kernel is not in * the middle of rfkill_switch_all */ - error = mutex_lock_interruptible(&rfkill_global_mutex); + error = mutex_lock_killable(&rfkill_global_mutex); if (error) return error; if (rfkill->user_claim != claim) { - if (!claim) { + if (!claim && !rfkill_epo_lock_active) { mutex_lock(&rfkill->mutex); rfkill_toggle_radio(rfkill, rfkill_global_states[rfkill->type].current_state, @@ -511,24 +517,48 @@ static void rfkill_release(struct device *dev) #ifdef CONFIG_PM static int rfkill_suspend(struct device *dev, pm_message_t state) { + struct rfkill *rfkill = to_rfkill(dev); + /* mark class device as suspended */ if (dev->power.power_state.event != state.event) dev->power.power_state = state; + /* store state for the resume handler */ + rfkill->state_for_resume = rfkill->state; + return 0; } static int rfkill_resume(struct device *dev) { struct rfkill *rfkill = to_rfkill(dev); + enum rfkill_state newstate; if (dev->power.power_state.event != PM_EVENT_ON) { mutex_lock(&rfkill->mutex); dev->power.power_state.event = PM_EVENT_ON; - /* restore radio state AND notify everybody */ - rfkill_toggle_radio(rfkill, rfkill->state, 1); + /* + * rfkill->state could have been modified before we got + * called, and won't be updated by rfkill_toggle_radio() + * in force mode. Sync it FIRST. + */ + if (rfkill->get_state && + !rfkill->get_state(rfkill->data, &newstate)) + rfkill->state = newstate; + + /* + * If we are under EPO, kick transmitter offline, + * otherwise restore to pre-suspend state. + * + * Issue a notification in any case + */ + rfkill_toggle_radio(rfkill, + rfkill_epo_lock_active ? + RFKILL_STATE_SOFT_BLOCKED : + rfkill->state_for_resume, + 1); mutex_unlock(&rfkill->mutex); } @@ -540,28 +570,6 @@ static int rfkill_resume(struct device *dev) #define rfkill_resume NULL #endif -static int rfkill_blocking_uevent_notifier(struct notifier_block *nb, - unsigned long eventid, - void *data) -{ - struct rfkill *rfkill = (struct rfkill *)data; - - switch (eventid) { - case RFKILL_STATE_CHANGED: - kobject_uevent(&rfkill->dev.kobj, KOBJ_CHANGE); - break; - default: - break; - } - - return NOTIFY_DONE; -} - -static struct notifier_block rfkill_blocking_uevent_nb = { - .notifier_call = rfkill_blocking_uevent_notifier, - .priority = 0, -}; - static int rfkill_dev_uevent(struct device *dev, struct kobj_uevent_env *env) { struct rfkill *rfkill = to_rfkill(dev); @@ -711,7 +719,7 @@ static void rfkill_led_trigger_register(struct rfkill *rfkill) int error; if (!rfkill->led_trigger.name) - rfkill->led_trigger.name = rfkill->dev.bus_id; + rfkill->led_trigger.name = dev_name(&rfkill->dev); if (!rfkill->led_trigger.activate) rfkill->led_trigger.activate = rfkill_led_trigger_activate; error = led_trigger_register(&rfkill->led_trigger); @@ -752,8 +760,7 @@ int __must_check rfkill_register(struct rfkill *rfkill) "badly initialized rfkill struct\n")) return -EINVAL; - snprintf(dev->bus_id, sizeof(dev->bus_id), - "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1); + dev_set_name(dev, "rfkill%ld", (long)atomic_inc_return(&rfkill_no) - 1); rfkill_led_trigger_register(rfkill); @@ -833,6 +840,7 @@ int rfkill_set_default(enum rfkill_type type, enum rfkill_state state) if (!test_and_set_bit(type, rfkill_states_lockdflt)) { rfkill_global_states[type].default_state = state; + rfkill_global_states[type].current_state = state; error = 0; } else error = -EPERM; @@ -864,14 +872,11 @@ static int __init rfkill_init(void) return error; } - register_rfkill_notifier(&rfkill_blocking_uevent_nb); - return 0; } static void __exit rfkill_exit(void) { - unregister_rfkill_notifier(&rfkill_blocking_uevent_nb); class_unregister(&rfkill_class); } diff --git a/net/rose/sysctl_net_rose.c b/net/rose/sysctl_net_rose.c index 20be3485a97f9981971481b0915a01157e0e24e1..3bfe504faf86c5ba156023443b8b4d9206301a83 100644 --- a/net/rose/sysctl_net_rose.c +++ b/net/rose/sysctl_net_rose.c @@ -31,8 +31,8 @@ static ctl_table rose_table[] = { .data = &sysctl_rose_restart_request_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_timer, .extra2 = &max_timer }, @@ -42,8 +42,8 @@ static ctl_table rose_table[] = { .data = &sysctl_rose_call_request_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_timer, .extra2 = &max_timer }, @@ -53,8 +53,8 @@ static ctl_table rose_table[] = { .data = &sysctl_rose_reset_request_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_timer, .extra2 = &max_timer }, @@ -64,8 +64,8 @@ static ctl_table rose_table[] = { .data = &sysctl_rose_clear_request_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_timer, .extra2 = &max_timer }, @@ -75,8 +75,8 @@ static ctl_table rose_table[] = { .data = &sysctl_rose_no_activity_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_idle, .extra2 = &max_idle }, @@ -86,8 +86,8 @@ static ctl_table rose_table[] = { .data = &sysctl_rose_ack_hold_back_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_timer, .extra2 = &max_timer }, @@ -97,8 +97,8 @@ static ctl_table rose_table[] = { .data = &sysctl_rose_routing_control, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_route, .extra2 = &max_route }, @@ -108,8 +108,8 @@ static ctl_table rose_table[] = { .data = &sysctl_rose_link_fail_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_ftimer, .extra2 = &max_ftimer }, @@ -119,8 +119,8 @@ static ctl_table rose_table[] = { .data = &sysctl_rose_maximum_vcs, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_maxvcs, .extra2 = &max_maxvcs }, @@ -130,8 +130,8 @@ static ctl_table rose_table[] = { .data = &sysctl_rose_window_size, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_window, .extra2 = &max_window }, diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c index 32e489118bebcc7462316456cf9a4e8dffeaae31..d7d2bed7a6995691eaedb13055f732d1efaa3ac6 100644 --- a/net/rxrpc/af_rxrpc.c +++ b/net/rxrpc/af_rxrpc.c @@ -96,9 +96,9 @@ static int rxrpc_validate_address(struct rxrpc_sock *rx, switch (srx->transport.family) { case AF_INET: - _debug("INET: %x @ %u.%u.%u.%u", + _debug("INET: %x @ %pI4", ntohs(srx->transport.sin.sin_port), - NIPQUAD(srx->transport.sin.sin_addr)); + &srx->transport.sin.sin_addr); if (srx->transport_len > 8) memset((void *)&srx->transport + 8, 0, srx->transport_len - 8); diff --git a/net/rxrpc/ar-connection.c b/net/rxrpc/ar-connection.c index 3869a58667521264be908a61c35adee9a1ec9a67..0f1218b8d289859cb89062ed1f799a32e051c1f6 100644 --- a/net/rxrpc/ar-connection.c +++ b/net/rxrpc/ar-connection.c @@ -826,7 +826,7 @@ static void rxrpc_destroy_connection(struct rxrpc_connection *conn) /* * reap dead connections */ -void rxrpc_connection_reaper(struct work_struct *work) +static void rxrpc_connection_reaper(struct work_struct *work) { struct rxrpc_connection *conn, *_p; unsigned long now, earliest, reap_time; diff --git a/net/rxrpc/ar-connevent.c b/net/rxrpc/ar-connevent.c index 1ada43d5116541e70c01e035044d16d8ee75388b..dc5cb1e19509e4d8d71bb8ad726dc493ddda3ad4 100644 --- a/net/rxrpc/ar-connevent.c +++ b/net/rxrpc/ar-connevent.c @@ -126,7 +126,7 @@ static int rxrpc_abort_connection(struct rxrpc_connection *conn, * mark a call as being on a now-secured channel * - must be called with softirqs disabled */ -void rxrpc_call_is_secure(struct rxrpc_call *call) +static void rxrpc_call_is_secure(struct rxrpc_call *call) { _enter("%p", call); if (call) { diff --git a/net/rxrpc/ar-error.c b/net/rxrpc/ar-error.c index 6cb3e8890e7e8305fb702ab933aff4cc18b58bf4..d4d1ae26d29313fffb1230a1fdcbe09d740a7cd0 100644 --- a/net/rxrpc/ar-error.c +++ b/net/rxrpc/ar-error.c @@ -49,8 +49,7 @@ void rxrpc_UDP_error_report(struct sock *sk) addr = *(__be32 *)(skb_network_header(skb) + serr->addr_offset); port = serr->port; - _net("Rx UDP Error from "NIPQUAD_FMT":%hu", - NIPQUAD(addr), ntohs(port)); + _net("Rx UDP Error from %pI4:%hu", &addr, ntohs(port)); _debug("Msg l:%d d:%d", skb->len, skb->data_len); peer = rxrpc_find_peer(local, addr, port); diff --git a/net/rxrpc/ar-local.c b/net/rxrpc/ar-local.c index f3a2bd747a8f6f09aa4e3006d3ddd66e24a5d370..807535ff29b52d0ebdb85ac6ba4fa5e4c5d18805 100644 --- a/net/rxrpc/ar-local.c +++ b/net/rxrpc/ar-local.c @@ -131,10 +131,10 @@ struct rxrpc_local *rxrpc_lookup_local(struct sockaddr_rxrpc *srx) struct rxrpc_local *local; int ret; - _enter("{%d,%u,%u.%u.%u.%u+%hu}", + _enter("{%d,%u,%pI4+%hu}", srx->transport_type, srx->transport.family, - NIPQUAD(srx->transport.sin.sin_addr), + &srx->transport.sin.sin_addr, ntohs(srx->transport.sin.sin_port)); down_write(&rxrpc_local_sem); @@ -143,10 +143,10 @@ struct rxrpc_local *rxrpc_lookup_local(struct sockaddr_rxrpc *srx) read_lock_bh(&rxrpc_local_lock); list_for_each_entry(local, &rxrpc_locals, link) { - _debug("CMP {%d,%u,%u.%u.%u.%u+%hu}", + _debug("CMP {%d,%u,%pI4+%hu}", local->srx.transport_type, local->srx.transport.family, - NIPQUAD(local->srx.transport.sin.sin_addr), + &local->srx.transport.sin.sin_addr, ntohs(local->srx.transport.sin.sin_port)); if (local->srx.transport_type != srx->transport_type || @@ -188,11 +188,11 @@ struct rxrpc_local *rxrpc_lookup_local(struct sockaddr_rxrpc *srx) up_write(&rxrpc_local_sem); - _net("LOCAL new %d {%d,%u,%u.%u.%u.%u+%hu}", + _net("LOCAL new %d {%d,%u,%pI4+%hu}", local->debug_id, local->srx.transport_type, local->srx.transport.family, - NIPQUAD(local->srx.transport.sin.sin_addr), + &local->srx.transport.sin.sin_addr, ntohs(local->srx.transport.sin.sin_port)); _leave(" = %p [new]", local); @@ -203,11 +203,11 @@ found_local: read_unlock_bh(&rxrpc_local_lock); up_write(&rxrpc_local_sem); - _net("LOCAL old %d {%d,%u,%u.%u.%u.%u+%hu}", + _net("LOCAL old %d {%d,%u,%pI4+%hu}", local->debug_id, local->srx.transport_type, local->srx.transport.family, - NIPQUAD(local->srx.transport.sin.sin_addr), + &local->srx.transport.sin.sin_addr, ntohs(local->srx.transport.sin.sin_port)); _leave(" = %p [reuse]", local); diff --git a/net/rxrpc/ar-peer.c b/net/rxrpc/ar-peer.c index 2abe2081a5e83b9a9ea848872f266ab4f1a711a1..edc026c1eb763aeaf837d27ab9692374a4a7653b 100644 --- a/net/rxrpc/ar-peer.c +++ b/net/rxrpc/ar-peer.c @@ -123,10 +123,10 @@ struct rxrpc_peer *rxrpc_get_peer(struct sockaddr_rxrpc *srx, gfp_t gfp) const char *new = "old"; int usage; - _enter("{%d,%d,%u.%u.%u.%u+%hu}", + _enter("{%d,%d,%pI4+%hu}", srx->transport_type, srx->transport_len, - NIPQUAD(srx->transport.sin.sin_addr), + &srx->transport.sin.sin_addr, ntohs(srx->transport.sin.sin_port)); /* search the peer list first */ @@ -177,12 +177,12 @@ struct rxrpc_peer *rxrpc_get_peer(struct sockaddr_rxrpc *srx, gfp_t gfp) new = "new"; success: - _net("PEER %s %d {%d,%u,%u.%u.%u.%u+%hu}", + _net("PEER %s %d {%d,%u,%pI4+%hu}", new, peer->debug_id, peer->srx.transport_type, peer->srx.transport.family, - NIPQUAD(peer->srx.transport.sin.sin_addr), + &peer->srx.transport.sin.sin_addr, ntohs(peer->srx.transport.sin.sin_port)); _leave(" = %p {u=%d}", peer, atomic_read(&peer->usage)); diff --git a/net/rxrpc/ar-proc.c b/net/rxrpc/ar-proc.c index 017322e2786dedb70f2da284e1a687b57c203cc6..38047f713f2cf0fb2b60261039c475bd7fe19f7e 100644 --- a/net/rxrpc/ar-proc.c +++ b/net/rxrpc/ar-proc.c @@ -61,12 +61,12 @@ static int rxrpc_call_seq_show(struct seq_file *seq, void *v) call = list_entry(v, struct rxrpc_call, link); trans = call->conn->trans; - sprintf(lbuff, NIPQUAD_FMT":%u", - NIPQUAD(trans->local->srx.transport.sin.sin_addr), + sprintf(lbuff, "%pI4:%u", + &trans->local->srx.transport.sin.sin_addr, ntohs(trans->local->srx.transport.sin.sin_port)); - sprintf(rbuff, NIPQUAD_FMT":%u", - NIPQUAD(trans->peer->srx.transport.sin.sin_addr), + sprintf(rbuff, "%pI4:%u", + &trans->peer->srx.transport.sin.sin_addr, ntohs(trans->peer->srx.transport.sin.sin_port)); seq_printf(seq, @@ -144,12 +144,12 @@ static int rxrpc_connection_seq_show(struct seq_file *seq, void *v) conn = list_entry(v, struct rxrpc_connection, link); trans = conn->trans; - sprintf(lbuff, NIPQUAD_FMT":%u", - NIPQUAD(trans->local->srx.transport.sin.sin_addr), + sprintf(lbuff, "%pI4:%u", + &trans->local->srx.transport.sin.sin_addr, ntohs(trans->local->srx.transport.sin.sin_port)); - sprintf(rbuff, NIPQUAD_FMT":%u", - NIPQUAD(trans->peer->srx.transport.sin.sin_addr), + sprintf(rbuff, "%pI4:%u", + &trans->peer->srx.transport.sin.sin_addr, ntohs(trans->peer->srx.transport.sin.sin_port)); seq_printf(seq, diff --git a/net/rxrpc/ar-security.c b/net/rxrpc/ar-security.c index 60d1d364430af6497c681c25647ffb09bdcaa009..dc62920ee19ad5a430f5c6361bc01119f1746def 100644 --- a/net/rxrpc/ar-security.c +++ b/net/rxrpc/ar-security.c @@ -40,7 +40,7 @@ static void rxrpc_security_put(struct rxrpc_security *sec) /* * look up an rxrpc security module */ -struct rxrpc_security *rxrpc_security_lookup(u8 security_index) +static struct rxrpc_security *rxrpc_security_lookup(u8 security_index) { struct rxrpc_security *sec = NULL; diff --git a/net/rxrpc/ar-transport.c b/net/rxrpc/ar-transport.c index 64069c8769a51e0ad629d377d79f847dd26a92d7..0936e1acc30ece6110313c01fb0ee78c0e5dd91e 100644 --- a/net/rxrpc/ar-transport.c +++ b/net/rxrpc/ar-transport.c @@ -78,10 +78,10 @@ struct rxrpc_transport *rxrpc_get_transport(struct rxrpc_local *local, const char *new = "old"; int usage; - _enter("{%u.%u.%u.%u+%hu},{%u.%u.%u.%u+%hu},", - NIPQUAD(local->srx.transport.sin.sin_addr), + _enter("{%pI4+%hu},{%pI4+%hu},", + &local->srx.transport.sin.sin_addr, ntohs(local->srx.transport.sin.sin_port), - NIPQUAD(peer->srx.transport.sin.sin_addr), + &peer->srx.transport.sin.sin_addr, ntohs(peer->srx.transport.sin.sin_port)); /* search the transport list first */ @@ -149,10 +149,10 @@ struct rxrpc_transport *rxrpc_find_transport(struct rxrpc_local *local, { struct rxrpc_transport *trans; - _enter("{%u.%u.%u.%u+%hu},{%u.%u.%u.%u+%hu},", - NIPQUAD(local->srx.transport.sin.sin_addr), + _enter("{%pI4+%hu},{%pI4+%hu},", + &local->srx.transport.sin.sin_addr, ntohs(local->srx.transport.sin.sin_port), - NIPQUAD(peer->srx.transport.sin.sin_addr), + &peer->srx.transport.sin.sin_addr, ntohs(peer->srx.transport.sin.sin_port)); /* search the transport list */ diff --git a/net/rxrpc/rxkad.c b/net/rxrpc/rxkad.c index ba3f6e49fddc59164fed12773b483ee699aa1a3d..ef8f91030a150ff6cb4605c8229dd1955b3528e0 100644 --- a/net/rxrpc/rxkad.c +++ b/net/rxrpc/rxkad.c @@ -897,7 +897,7 @@ static int rxkad_decrypt_ticket(struct rxrpc_connection *conn, /* get the IPv4 address of the entity that requested the ticket */ memcpy(&addr, p, sizeof(addr)); p += 4; - _debug("KIV ADDR : "NIPQUAD_FMT, NIPQUAD(addr)); + _debug("KIV ADDR : %pI4", &addr); /* get the session key from the ticket */ memcpy(&key, p, sizeof(key)); diff --git a/net/sched/Kconfig b/net/sched/Kconfig index 6767e54155dbac238f8ea1707272bd95253a4927..4f7ef0db302b56eaf1e32c2d7ce90c84d686be51 100644 --- a/net/sched/Kconfig +++ b/net/sched/Kconfig @@ -194,6 +194,17 @@ config NET_SCH_NETEM If unsure, say N. +config NET_SCH_DRR + tristate "Deficit Round Robin scheduler (DRR)" + help + Say Y here if you want to use the Deficit Round Robin (DRR) packet + scheduling algorithm. + + To compile this driver as a module, choose M here: the module + will be called sch_drr. + + If unsure, say N. + config NET_SCH_INGRESS tristate "Ingress Qdisc" depends on NET_CLS_ACT @@ -316,6 +327,17 @@ config NET_CLS_FLOW To compile this code as a module, choose M here: the module will be called cls_flow. +config NET_CLS_CGROUP + bool "Control Group Classifier" + select NET_CLS + depends on CGROUPS + ---help--- + Say Y here if you want to classify packets based on the control + cgroup of their process. + + To compile this code as a module, choose M here: the + module will be called cls_cgroup. + config NET_EMATCH bool "Extended Matches" select NET_CLS diff --git a/net/sched/Makefile b/net/sched/Makefile index e60c9925b269ade40c544da32e54d8572b9fa54c..54d950cd4b8db9775b6b69998be0cccd0a48a3ab 100644 --- a/net/sched/Makefile +++ b/net/sched/Makefile @@ -30,6 +30,7 @@ obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o obj-$(CONFIG_NET_SCH_MULTIQ) += sch_multiq.o obj-$(CONFIG_NET_SCH_ATM) += sch_atm.o obj-$(CONFIG_NET_SCH_NETEM) += sch_netem.o +obj-$(CONFIG_NET_SCH_DRR) += sch_drr.o obj-$(CONFIG_NET_CLS_U32) += cls_u32.o obj-$(CONFIG_NET_CLS_ROUTE4) += cls_route.o obj-$(CONFIG_NET_CLS_FW) += cls_fw.o @@ -38,6 +39,7 @@ obj-$(CONFIG_NET_CLS_TCINDEX) += cls_tcindex.o obj-$(CONFIG_NET_CLS_RSVP6) += cls_rsvp6.o obj-$(CONFIG_NET_CLS_BASIC) += cls_basic.o obj-$(CONFIG_NET_CLS_FLOW) += cls_flow.o +obj-$(CONFIG_NET_CLS_CGROUP) += cls_cgroup.o obj-$(CONFIG_NET_EMATCH) += ematch.o obj-$(CONFIG_NET_EMATCH_CMP) += em_cmp.o obj-$(CONFIG_NET_EMATCH_NBYTE) += em_nbyte.o diff --git a/net/sched/act_api.c b/net/sched/act_api.c index 8f457f1e0acf86b16911688b938b262f566669fb..9d03cc33b6ccbfab51e3fe65eadd10b3b84eb101 100644 --- a/net/sched/act_api.c +++ b/net/sched/act_api.c @@ -214,12 +214,14 @@ struct tcf_common *tcf_hash_check(u32 index, struct tc_action *a, int bind, } EXPORT_SYMBOL(tcf_hash_check); -struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est, struct tc_action *a, int size, int bind, u32 *idx_gen, struct tcf_hashinfo *hinfo) +struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est, + struct tc_action *a, int size, int bind, + u32 *idx_gen, struct tcf_hashinfo *hinfo) { struct tcf_common *p = kzalloc(size, GFP_KERNEL); if (unlikely(!p)) - return p; + return ERR_PTR(-ENOMEM); p->tcfc_refcnt = 1; if (bind) p->tcfc_bindcnt = 1; @@ -228,9 +230,15 @@ struct tcf_common *tcf_hash_create(u32 index, struct nlattr *est, struct tc_acti p->tcfc_index = index ? index : tcf_hash_new_index(idx_gen, hinfo); p->tcfc_tm.install = jiffies; p->tcfc_tm.lastuse = jiffies; - if (est) - gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est, - &p->tcfc_lock, est); + if (est) { + int err = gen_new_estimator(&p->tcfc_bstats, &p->tcfc_rate_est, + &p->tcfc_lock, est); + if (err) { + kfree(p); + return ERR_PTR(err); + } + } + a->priv = (void *) p; return p; } diff --git a/net/sched/act_gact.c b/net/sched/act_gact.c index ac04289da5d74519234f0371072bd79064910375..e7f796aec657f90089a4872ab79c831b62bde467 100644 --- a/net/sched/act_gact.c +++ b/net/sched/act_gact.c @@ -88,8 +88,8 @@ static int tcf_gact_init(struct nlattr *nla, struct nlattr *est, if (!pc) { pc = tcf_hash_create(parm->index, est, a, sizeof(*gact), bind, &gact_idx_gen, &gact_hash_info); - if (unlikely(!pc)) - return -ENOMEM; + if (IS_ERR(pc)) + return PTR_ERR(pc); ret = ACT_P_CREATED; } else { if (!ovr) { diff --git a/net/sched/act_ipt.c b/net/sched/act_ipt.c index 0453d79ebf570d985a702ca73194eda80dceae64..082c520b0def5d85f8ca8dc830d3ec20250cd758 100644 --- a/net/sched/act_ipt.c +++ b/net/sched/act_ipt.c @@ -136,8 +136,8 @@ static int tcf_ipt_init(struct nlattr *nla, struct nlattr *est, if (!pc) { pc = tcf_hash_create(index, est, a, sizeof(*ipt), bind, &ipt_idx_gen, &ipt_hash_info); - if (unlikely(!pc)) - return -ENOMEM; + if (IS_ERR(pc)) + return PTR_ERR(pc); ret = ACT_P_CREATED; } else { if (!ovr) { diff --git a/net/sched/act_mirred.c b/net/sched/act_mirred.c index 70341c020b6de33586e7fb02f41857c3770122cb..b9aaab4e03548a848c4f9bba9b527803fa602157 100644 --- a/net/sched/act_mirred.c +++ b/net/sched/act_mirred.c @@ -105,8 +105,8 @@ static int tcf_mirred_init(struct nlattr *nla, struct nlattr *est, return -EINVAL; pc = tcf_hash_create(parm->index, est, a, sizeof(*m), bind, &mirred_idx_gen, &mirred_hash_info); - if (unlikely(!pc)) - return -ENOMEM; + if (IS_ERR(pc)) + return PTR_ERR(pc); ret = ACT_P_CREATED; } else { if (!ovr) { diff --git a/net/sched/act_nat.c b/net/sched/act_nat.c index 7b39ed485bca0beeb44da1572ff053ed61395d5f..d885ba311564d9a766fce6eac37edbaf0ed82b71 100644 --- a/net/sched/act_nat.c +++ b/net/sched/act_nat.c @@ -68,8 +68,8 @@ static int tcf_nat_init(struct nlattr *nla, struct nlattr *est, if (!pc) { pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, &nat_idx_gen, &nat_hash_info); - if (unlikely(!pc)) - return -ENOMEM; + if (IS_ERR(pc)) + return PTR_ERR(pc); p = to_tcf_nat(pc); ret = ACT_P_CREATED; } else { diff --git a/net/sched/act_pedit.c b/net/sched/act_pedit.c index d5f4e3404864eb7ffc70c3b7a79d425658e4ec53..96c0ed115e2a07d6b8ff7afe86632e03fb4174b9 100644 --- a/net/sched/act_pedit.c +++ b/net/sched/act_pedit.c @@ -68,8 +68,8 @@ static int tcf_pedit_init(struct nlattr *nla, struct nlattr *est, return -EINVAL; pc = tcf_hash_create(parm->index, est, a, sizeof(*p), bind, &pedit_idx_gen, &pedit_hash_info); - if (unlikely(!pc)) - return -ENOMEM; + if (IS_ERR(pc)) + return PTR_ERR(pc); p = to_pedit(pc); keys = kmalloc(ksize, GFP_KERNEL); if (keys == NULL) { diff --git a/net/sched/act_police.c b/net/sched/act_police.c index 38015b49394755d06cd1cfa56306ea358c968a49..5c72a116b1a4513405735349391a01ff1c9b376a 100644 --- a/net/sched/act_police.c +++ b/net/sched/act_police.c @@ -182,17 +182,32 @@ override: R_tab = qdisc_get_rtab(&parm->rate, tb[TCA_POLICE_RATE]); if (R_tab == NULL) goto failure; + + if (!est && (ret == ACT_P_CREATED || + !gen_estimator_active(&police->tcf_bstats, + &police->tcf_rate_est))) { + err = -EINVAL; + goto failure; + } + if (parm->peakrate.rate) { P_tab = qdisc_get_rtab(&parm->peakrate, tb[TCA_POLICE_PEAKRATE]); - if (P_tab == NULL) { - qdisc_put_rtab(R_tab); + if (P_tab == NULL) goto failure; - } } } - /* No failure allowed after this point */ + spin_lock_bh(&police->tcf_lock); + if (est) { + err = gen_replace_estimator(&police->tcf_bstats, + &police->tcf_rate_est, + &police->tcf_lock, est); + if (err) + goto failure_unlock; + } + + /* No failure allowed after this point */ if (R_tab != NULL) { qdisc_put_rtab(police->tcfp_R_tab); police->tcfp_R_tab = R_tab; @@ -217,10 +232,6 @@ override: if (tb[TCA_POLICE_AVRATE]) police->tcfp_ewma_rate = nla_get_u32(tb[TCA_POLICE_AVRATE]); - if (est) - gen_replace_estimator(&police->tcf_bstats, - &police->tcf_rate_est, - &police->tcf_lock, est); spin_unlock_bh(&police->tcf_lock); if (ret != ACT_P_CREATED) @@ -238,7 +249,13 @@ override: a->priv = police; return ret; +failure_unlock: + spin_unlock_bh(&police->tcf_lock); failure: + if (P_tab) + qdisc_put_rtab(P_tab); + if (R_tab) + qdisc_put_rtab(R_tab); if (ret == ACT_P_CREATED) kfree(police); return err; diff --git a/net/sched/act_simple.c b/net/sched/act_simple.c index e7851ce92cfea56cef8ba52943cbbba5a1942b68..8daa1ebc7413b971dafde75606af039d52a7e83e 100644 --- a/net/sched/act_simple.c +++ b/net/sched/act_simple.c @@ -124,8 +124,8 @@ static int tcf_simp_init(struct nlattr *nla, struct nlattr *est, if (!pc) { pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind, &simp_idx_gen, &simp_hash_info); - if (unlikely(!pc)) - return -ENOMEM; + if (IS_ERR(pc)) + return PTR_ERR(pc); d = to_defact(pc); ret = alloc_defdata(d, defdata); diff --git a/net/sched/act_skbedit.c b/net/sched/act_skbedit.c index fe9777e77f3582a3d50bcba78caac038d00f94f6..4ab916b8074be28daea9fe9f329b4b3b460132c7 100644 --- a/net/sched/act_skbedit.c +++ b/net/sched/act_skbedit.c @@ -104,8 +104,8 @@ static int tcf_skbedit_init(struct nlattr *nla, struct nlattr *est, if (!pc) { pc = tcf_hash_create(parm->index, est, a, sizeof(*d), bind, &skbedit_idx_gen, &skbedit_hash_info); - if (unlikely(!pc)) - return -ENOMEM; + if (IS_ERR(pc)) + return PTR_ERR(pc); d = to_skbedit(pc); ret = ACT_P_CREATED; diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 16e7ac9774e5aeab547d6aee1fabcab56efc7480..173fcc4b050ddac8b4470c9616216974312bc121 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c @@ -531,7 +531,8 @@ void tcf_exts_change(struct tcf_proto *tp, struct tcf_exts *dst, if (src->action) { struct tc_action *act; tcf_tree_lock(tp); - act = xchg(&dst->action, src->action); + act = dst->action; + dst->action = src->action; tcf_tree_unlock(tp); if (act) tcf_action_destroy(act, TCA_ACT_UNBIND); diff --git a/net/sched/cls_basic.c b/net/sched/cls_basic.c index 956915c217d6dbc8599b3fa8248eedb8914160a3..4e2bda854119bf87391dc89a3cda8ce44810c5a0 100644 --- a/net/sched/cls_basic.c +++ b/net/sched/cls_basic.c @@ -102,7 +102,7 @@ static inline void basic_delete_filter(struct tcf_proto *tp, static void basic_destroy(struct tcf_proto *tp) { - struct basic_head *head = (struct basic_head *) xchg(&tp->root, NULL); + struct basic_head *head = tp->root; struct basic_filter *f, *n; list_for_each_entry_safe(f, n, &head->flist, link) { diff --git a/net/sched/cls_cgroup.c b/net/sched/cls_cgroup.c new file mode 100644 index 0000000000000000000000000000000000000000..0d68b1975983a323775b5c4deef4f2ae1ae8ae5d --- /dev/null +++ b/net/sched/cls_cgroup.c @@ -0,0 +1,288 @@ +/* + * net/sched/cls_cgroup.c Control Group Classifier + * + * 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. + * + * Authors: Thomas Graf + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct cgroup_cls_state +{ + struct cgroup_subsys_state css; + u32 classid; +}; + +static inline struct cgroup_cls_state *net_cls_state(struct cgroup *cgrp) +{ + return (struct cgroup_cls_state *) + cgroup_subsys_state(cgrp, net_cls_subsys_id); +} + +static struct cgroup_subsys_state *cgrp_create(struct cgroup_subsys *ss, + struct cgroup *cgrp) +{ + struct cgroup_cls_state *cs; + + if (!(cs = kzalloc(sizeof(*cs), GFP_KERNEL))) + return ERR_PTR(-ENOMEM); + + if (cgrp->parent) + cs->classid = net_cls_state(cgrp->parent)->classid; + + return &cs->css; +} + +static void cgrp_destroy(struct cgroup_subsys *ss, struct cgroup *cgrp) +{ + kfree(ss); +} + +static u64 read_classid(struct cgroup *cgrp, struct cftype *cft) +{ + return net_cls_state(cgrp)->classid; +} + +static int write_classid(struct cgroup *cgrp, struct cftype *cft, u64 value) +{ + if (!cgroup_lock_live_group(cgrp)) + return -ENODEV; + + net_cls_state(cgrp)->classid = (u32) value; + + cgroup_unlock(); + + return 0; +} + +static struct cftype ss_files[] = { + { + .name = "classid", + .read_u64 = read_classid, + .write_u64 = write_classid, + }, +}; + +static int cgrp_populate(struct cgroup_subsys *ss, struct cgroup *cgrp) +{ + return cgroup_add_files(cgrp, ss, ss_files, ARRAY_SIZE(ss_files)); +} + +struct cgroup_subsys net_cls_subsys = { + .name = "net_cls", + .create = cgrp_create, + .destroy = cgrp_destroy, + .populate = cgrp_populate, + .subsys_id = net_cls_subsys_id, +}; + +struct cls_cgroup_head +{ + u32 handle; + struct tcf_exts exts; + struct tcf_ematch_tree ematches; +}; + +static int cls_cgroup_classify(struct sk_buff *skb, struct tcf_proto *tp, + struct tcf_result *res) +{ + struct cls_cgroup_head *head = tp->root; + struct cgroup_cls_state *cs; + int ret = 0; + + /* + * Due to the nature of the classifier it is required to ignore all + * packets originating from softirq context as accessing `current' + * would lead to false results. + * + * This test assumes that all callers of dev_queue_xmit() explicitely + * disable bh. Knowing this, it is possible to detect softirq based + * calls by looking at the number of nested bh disable calls because + * softirqs always disables bh. + */ + if (softirq_count() != SOFTIRQ_OFFSET) + return -1; + + rcu_read_lock(); + cs = (struct cgroup_cls_state *) task_subsys_state(current, + net_cls_subsys_id); + if (cs->classid && tcf_em_tree_match(skb, &head->ematches, NULL)) { + res->classid = cs->classid; + res->class = 0; + ret = tcf_exts_exec(skb, &head->exts, res); + } else + ret = -1; + + rcu_read_unlock(); + + return ret; +} + +static unsigned long cls_cgroup_get(struct tcf_proto *tp, u32 handle) +{ + return 0UL; +} + +static void cls_cgroup_put(struct tcf_proto *tp, unsigned long f) +{ +} + +static int cls_cgroup_init(struct tcf_proto *tp) +{ + return 0; +} + +static const struct tcf_ext_map cgroup_ext_map = { + .action = TCA_CGROUP_ACT, + .police = TCA_CGROUP_POLICE, +}; + +static const struct nla_policy cgroup_policy[TCA_CGROUP_MAX + 1] = { + [TCA_CGROUP_EMATCHES] = { .type = NLA_NESTED }, +}; + +static int cls_cgroup_change(struct tcf_proto *tp, unsigned long base, + u32 handle, struct nlattr **tca, + unsigned long *arg) +{ + struct nlattr *tb[TCA_CGROUP_MAX+1]; + struct cls_cgroup_head *head = tp->root; + struct tcf_ematch_tree t; + struct tcf_exts e; + int err; + + if (head == NULL) { + if (!handle) + return -EINVAL; + + head = kzalloc(sizeof(*head), GFP_KERNEL); + if (head == NULL) + return -ENOBUFS; + + head->handle = handle; + + tcf_tree_lock(tp); + tp->root = head; + tcf_tree_unlock(tp); + } + + if (handle != head->handle) + return -ENOENT; + + err = nla_parse_nested(tb, TCA_CGROUP_MAX, tca[TCA_OPTIONS], + cgroup_policy); + if (err < 0) + return err; + + err = tcf_exts_validate(tp, tb, tca[TCA_RATE], &e, &cgroup_ext_map); + if (err < 0) + return err; + + err = tcf_em_tree_validate(tp, tb[TCA_CGROUP_EMATCHES], &t); + if (err < 0) + return err; + + tcf_exts_change(tp, &head->exts, &e); + tcf_em_tree_change(tp, &head->ematches, &t); + + return 0; +} + +static void cls_cgroup_destroy(struct tcf_proto *tp) +{ + struct cls_cgroup_head *head = tp->root; + + if (head) { + tcf_exts_destroy(tp, &head->exts); + tcf_em_tree_destroy(tp, &head->ematches); + kfree(head); + } +} + +static int cls_cgroup_delete(struct tcf_proto *tp, unsigned long arg) +{ + return -EOPNOTSUPP; +} + +static void cls_cgroup_walk(struct tcf_proto *tp, struct tcf_walker *arg) +{ + struct cls_cgroup_head *head = tp->root; + + if (arg->count < arg->skip) + goto skip; + + if (arg->fn(tp, (unsigned long) head, arg) < 0) { + arg->stop = 1; + return; + } +skip: + arg->count++; +} + +static int cls_cgroup_dump(struct tcf_proto *tp, unsigned long fh, + struct sk_buff *skb, struct tcmsg *t) +{ + struct cls_cgroup_head *head = tp->root; + unsigned char *b = skb_tail_pointer(skb); + struct nlattr *nest; + + t->tcm_handle = head->handle; + + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; + + if (tcf_exts_dump(skb, &head->exts, &cgroup_ext_map) < 0 || + tcf_em_tree_dump(skb, &head->ematches, TCA_CGROUP_EMATCHES) < 0) + goto nla_put_failure; + + nla_nest_end(skb, nest); + + if (tcf_exts_dump_stats(skb, &head->exts, &cgroup_ext_map) < 0) + goto nla_put_failure; + + return skb->len; + +nla_put_failure: + nlmsg_trim(skb, b); + return -1; +} + +static struct tcf_proto_ops cls_cgroup_ops __read_mostly = { + .kind = "cgroup", + .init = cls_cgroup_init, + .change = cls_cgroup_change, + .classify = cls_cgroup_classify, + .destroy = cls_cgroup_destroy, + .get = cls_cgroup_get, + .put = cls_cgroup_put, + .delete = cls_cgroup_delete, + .walk = cls_cgroup_walk, + .dump = cls_cgroup_dump, + .owner = THIS_MODULE, +}; + +static int __init init_cgroup_cls(void) +{ + return register_tcf_proto_ops(&cls_cgroup_ops); +} + +static void __exit exit_cgroup_cls(void) +{ + unregister_tcf_proto_ops(&cls_cgroup_ops); +} + +module_init(init_cgroup_cls); +module_exit(exit_cgroup_cls); +MODULE_LICENSE("GPL"); diff --git a/net/sched/cls_fw.c b/net/sched/cls_fw.c index b0f90e593af0d510b6e61db352a8db9602830311..6d6e87585fb1a5028285210cd404ebc67547daa3 100644 --- a/net/sched/cls_fw.c +++ b/net/sched/cls_fw.c @@ -148,7 +148,7 @@ fw_delete_filter(struct tcf_proto *tp, struct fw_filter *f) static void fw_destroy(struct tcf_proto *tp) { - struct fw_head *head = (struct fw_head*)xchg(&tp->root, NULL); + struct fw_head *head = tp->root; struct fw_filter *f; int h; diff --git a/net/sched/cls_route.c b/net/sched/cls_route.c index e3d8455eebc29c32d37a5b2c943c07de1573b0e1..bdf1f4172eef5a7d13783e4192babb10ff526726 100644 --- a/net/sched/cls_route.c +++ b/net/sched/cls_route.c @@ -260,7 +260,7 @@ route4_delete_filter(struct tcf_proto *tp, struct route4_filter *f) static void route4_destroy(struct tcf_proto *tp) { - struct route4_head *head = xchg(&tp->root, NULL); + struct route4_head *head = tp->root; int h1, h2; if (head == NULL) diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c index 7a7bff5ded2487801e3c34941c1e12b8d77926fc..e806f2314b5e24281dd4bfbe3f442d1c1ee51d41 100644 --- a/net/sched/cls_tcindex.c +++ b/net/sched/cls_tcindex.c @@ -13,12 +13,6 @@ #include #include - -/* - * Not quite sure if we need all the xchgs Alexey uses when accessing things. - * Can always add them later ... :) - */ - /* * Passing parameters to the root seems to be done more awkwardly than really * necessary. At least, u32 doesn't seem to use such dirty hacks. To be diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 246f9065ce34b0ad8f7b176807dea7d50221b087..05d178008cbc9046d682f2bc2dbc01ce1e85737b 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c @@ -387,7 +387,7 @@ static int u32_destroy_hnode(struct tcf_proto *tp, struct tc_u_hnode *ht) static void u32_destroy(struct tcf_proto *tp) { struct tc_u_common *tp_c = tp->data; - struct tc_u_hnode *root_ht = xchg(&tp->root, NULL); + struct tc_u_hnode *root_ht = tp->root; WARN_ON(root_ht == NULL); @@ -479,7 +479,7 @@ static int u32_set_parms(struct tcf_proto *tp, unsigned long base, err = -EINVAL; if (tb[TCA_U32_LINK]) { u32 handle = nla_get_u32(tb[TCA_U32_LINK]); - struct tc_u_hnode *ht_down = NULL; + struct tc_u_hnode *ht_down = NULL, *ht_old; if (TC_U32_KEY(handle)) goto errout; @@ -493,11 +493,12 @@ static int u32_set_parms(struct tcf_proto *tp, unsigned long base, } tcf_tree_lock(tp); - ht_down = xchg(&n->ht_down, ht_down); + ht_old = n->ht_down; + n->ht_down = ht_down; tcf_tree_unlock(tp); - if (ht_down) - ht_down->refcnt--; + if (ht_old) + ht_old->refcnt--; } if (tb[TCA_U32_CLASSID]) { n->res.classid = nla_get_u32(tb[TCA_U32_CLASSID]); diff --git a/net/sched/ematch.c b/net/sched/ematch.c index e82519e548d70c747f602bc179ca487f120ef5af..aab59409728b4c50c4c45bc233570c10b8844980 100644 --- a/net/sched/ematch.c +++ b/net/sched/ematch.c @@ -71,7 +71,7 @@ * * static void __exit exit_my_ematch(void) * { - * return tcf_em_unregister(&my_ops); + * tcf_em_unregister(&my_ops); * } * * module_init(init_my_ematch); @@ -154,23 +154,11 @@ EXPORT_SYMBOL(tcf_em_register); * * Returns -ENOENT if no matching ematch was found. */ -int tcf_em_unregister(struct tcf_ematch_ops *ops) +void tcf_em_unregister(struct tcf_ematch_ops *ops) { - int err = 0; - struct tcf_ematch_ops *e; - write_lock(&ematch_mod_lock); - list_for_each_entry(e, &ematch_ops, link) { - if (e == ops) { - list_del(&e->link); - goto out; - } - } - - err = -ENOENT; -out: + list_del(&ops->link); write_unlock(&ematch_mod_lock); - return err; } EXPORT_SYMBOL(tcf_em_unregister); diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 6ab4a2f92ca0b390849547e8e93f99b07e6d4a6b..0fc4a18fd96f7d83ec21e95bc6d0740025f6a219 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c @@ -97,10 +97,9 @@ static int tclass_notify(struct sk_buff *oskb, struct nlmsghdr *n, Auxiliary routines: - ---requeue + ---peek - requeues once dequeued packet. It is used for non-standard or - just buggy devices, which can defer output even if netif_queue_stopped()=0. + like dequeue but without removing a packet from the queue ---reset @@ -147,8 +146,14 @@ int register_qdisc(struct Qdisc_ops *qops) if (qops->enqueue == NULL) qops->enqueue = noop_qdisc_ops.enqueue; - if (qops->requeue == NULL) - qops->requeue = noop_qdisc_ops.requeue; + if (qops->peek == NULL) { + if (qops->dequeue == NULL) { + qops->peek = noop_qdisc_ops.peek; + } else { + rc = -EINVAL; + goto out; + } + } if (qops->dequeue == NULL) qops->dequeue = noop_qdisc_ops.dequeue; @@ -184,7 +189,7 @@ EXPORT_SYMBOL(unregister_qdisc); (root qdisc, all its children, children of children etc.) */ -struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) +static struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) { struct Qdisc *q; @@ -199,28 +204,16 @@ struct Qdisc *qdisc_match_from_root(struct Qdisc *root, u32 handle) return NULL; } -/* - * This lock is needed until some qdiscs stop calling qdisc_tree_decrease_qlen() - * without rtnl_lock(); currently hfsc_dequeue(), netem_dequeue(), tbf_dequeue() - */ -static DEFINE_SPINLOCK(qdisc_list_lock); - static void qdisc_list_add(struct Qdisc *q) { - if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) { - spin_lock_bh(&qdisc_list_lock); + if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) list_add_tail(&q->list, &qdisc_root_sleeping(q)->list); - spin_unlock_bh(&qdisc_list_lock); - } } void qdisc_list_del(struct Qdisc *q) { - if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) { - spin_lock_bh(&qdisc_list_lock); + if ((q->parent != TC_H_ROOT) && !(q->flags & TCQ_F_INGRESS)) list_del(&q->list); - spin_unlock_bh(&qdisc_list_lock); - } } EXPORT_SYMBOL(qdisc_list_del); @@ -229,22 +222,17 @@ struct Qdisc *qdisc_lookup(struct net_device *dev, u32 handle) unsigned int i; struct Qdisc *q; - spin_lock_bh(&qdisc_list_lock); - for (i = 0; i < dev->num_tx_queues; i++) { struct netdev_queue *txq = netdev_get_tx_queue(dev, i); struct Qdisc *txq_root = txq->qdisc_sleeping; q = qdisc_match_from_root(txq_root, handle); if (q) - goto unlock; + goto out; } q = qdisc_match_from_root(dev->rx_queue.qdisc_sleeping, handle); - -unlock: - spin_unlock_bh(&qdisc_list_lock); - +out: return q; } @@ -462,7 +450,6 @@ static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) timer); wd->qdisc->flags &= ~TCQ_F_THROTTLED; - smp_wmb(); __netif_schedule(qdisc_root(wd->qdisc)); return HRTIMER_NORESTART; @@ -892,9 +879,12 @@ static int qdisc_change(struct Qdisc *sch, struct nlattr **tca) sch->stab = stab; if (tca[TCA_RATE]) + /* NB: ignores errors from replace_estimator + because change can't be undone. */ gen_replace_estimator(&sch->bstats, &sch->rate_est, - qdisc_root_sleeping_lock(sch), - tca[TCA_RATE]); + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE]); + return 0; } diff --git a/net/sched/sch_atm.c b/net/sched/sch_atm.c index 43d37256c15e3864655364ee96822a834266b89e..2a8b83af7c47a4bbee4471cc62894d46ca1d233a 100644 --- a/net/sched/sch_atm.c +++ b/net/sched/sch_atm.c @@ -62,7 +62,7 @@ struct atm_qdisc_data { struct atm_flow_data link; /* unclassified skbs go here */ struct atm_flow_data *flows; /* NB: "link" is also on this list */ - struct tasklet_struct task; /* requeue tasklet */ + struct tasklet_struct task; /* dequeue tasklet */ }; /* ------------------------- Class/flow operations ------------------------- */ @@ -102,7 +102,8 @@ static int atm_tc_graft(struct Qdisc *sch, unsigned long arg, return -EINVAL; if (!new) new = &noop_qdisc; - *old = xchg(&flow->q, new); + *old = flow->q; + flow->q = new; if (*old) qdisc_reset(*old); return 0; @@ -480,11 +481,14 @@ static void sch_atm_dequeue(unsigned long data) * If traffic is properly shaped, this won't generate nasty * little bursts. Otherwise, it may ... (but that's okay) */ - while ((skb = flow->q->dequeue(flow->q))) { - if (!atm_may_send(flow->vcc, skb->truesize)) { - (void)flow->q->ops->requeue(skb, flow->q); + while ((skb = flow->q->ops->peek(flow->q))) { + if (!atm_may_send(flow->vcc, skb->truesize)) break; - } + + skb = qdisc_dequeue_peeked(flow->q); + if (unlikely(!skb)) + break; + pr_debug("atm_tc_dequeue: sending on class %p\n", flow); /* remove any LL header somebody else has attached */ skb_pull(skb, skb_network_offset(skb)); @@ -516,27 +520,19 @@ static struct sk_buff *atm_tc_dequeue(struct Qdisc *sch) pr_debug("atm_tc_dequeue(sch %p,[qdisc %p])\n", sch, p); tasklet_schedule(&p->task); - skb = p->link.q->dequeue(p->link.q); + skb = qdisc_dequeue_peeked(p->link.q); if (skb) sch->q.qlen--; return skb; } -static int atm_tc_requeue(struct sk_buff *skb, struct Qdisc *sch) +static struct sk_buff *atm_tc_peek(struct Qdisc *sch) { struct atm_qdisc_data *p = qdisc_priv(sch); - int ret; - pr_debug("atm_tc_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); - ret = p->link.q->ops->requeue(skb, p->link.q); - if (!ret) { - sch->q.qlen++; - sch->qstats.requeues++; - } else if (net_xmit_drop_count(ret)) { - sch->qstats.drops++; - p->link.qstats.drops++; - } - return ret; + pr_debug("atm_tc_peek(sch %p,[qdisc %p])\n", sch, p); + + return p->link.q->ops->peek(p->link.q); } static unsigned int atm_tc_drop(struct Qdisc *sch) @@ -694,7 +690,7 @@ static struct Qdisc_ops atm_qdisc_ops __read_mostly = { .priv_size = sizeof(struct atm_qdisc_data), .enqueue = atm_tc_enqueue, .dequeue = atm_tc_dequeue, - .requeue = atm_tc_requeue, + .peek = atm_tc_peek, .drop = atm_tc_drop, .init = atm_tc_init, .reset = atm_tc_reset, diff --git a/net/sched/sch_blackhole.c b/net/sched/sch_blackhole.c index 507fb488bc985a18d13e0d79d95720b704118153..094a874b48bc43ca9337887bdd7cf462ee0ea63f 100644 --- a/net/sched/sch_blackhole.c +++ b/net/sched/sch_blackhole.c @@ -33,6 +33,7 @@ static struct Qdisc_ops blackhole_qdisc_ops __read_mostly = { .priv_size = 0, .enqueue = blackhole_enqueue, .dequeue = blackhole_dequeue, + .peek = blackhole_dequeue, .owner = THIS_MODULE, }; diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c index 03e389e8d945d2b93b2d31b408a2ee78c6f0c8b9..9e43ed949167affccd96c7e9a11e88e493206f6c 100644 --- a/net/sched/sch_cbq.c +++ b/net/sched/sch_cbq.c @@ -405,40 +405,6 @@ cbq_enqueue(struct sk_buff *skb, struct Qdisc *sch) return ret; } -static int -cbq_requeue(struct sk_buff *skb, struct Qdisc *sch) -{ - struct cbq_sched_data *q = qdisc_priv(sch); - struct cbq_class *cl; - int ret; - - if ((cl = q->tx_class) == NULL) { - kfree_skb(skb); - sch->qstats.drops++; - return NET_XMIT_CN; - } - q->tx_class = NULL; - - cbq_mark_toplevel(q, cl); - -#ifdef CONFIG_NET_CLS_ACT - q->rx_class = cl; - cl->q->__parent = sch; -#endif - if ((ret = cl->q->ops->requeue(skb, cl->q)) == 0) { - sch->q.qlen++; - sch->qstats.requeues++; - if (!cl->next_alive) - cbq_activate_class(cl); - return 0; - } - if (net_xmit_drop_count(ret)) { - sch->qstats.drops++; - cl->qstats.drops++; - } - return ret; -} - /* Overlimit actions */ /* TC_CBQ_OVL_CLASSIC: (default) penalize leaf class by adding offtime */ @@ -1669,7 +1635,8 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, #endif } sch_tree_lock(sch); - *old = xchg(&cl->q, new); + *old = cl->q; + cl->q = new; qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); qdisc_reset(*old); sch_tree_unlock(sch); @@ -1798,11 +1765,23 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t } if (tb[TCA_CBQ_RATE]) { - rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), tb[TCA_CBQ_RTAB]); + rtab = qdisc_get_rtab(nla_data(tb[TCA_CBQ_RATE]), + tb[TCA_CBQ_RTAB]); if (rtab == NULL) return -EINVAL; } + if (tca[TCA_RATE]) { + err = gen_replace_estimator(&cl->bstats, &cl->rate_est, + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE]); + if (err) { + if (rtab) + qdisc_put_rtab(rtab); + return err; + } + } + /* Change class parameters */ sch_tree_lock(sch); @@ -1810,8 +1789,8 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t cbq_deactivate_class(cl); if (rtab) { - rtab = xchg(&cl->R_tab, rtab); - qdisc_put_rtab(rtab); + qdisc_put_rtab(cl->R_tab); + cl->R_tab = rtab; } if (tb[TCA_CBQ_LSSOPT]) @@ -1838,10 +1817,6 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t sch_tree_unlock(sch); - if (tca[TCA_RATE]) - gen_replace_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_sleeping_lock(sch), - tca[TCA_RATE]); return 0; } @@ -1888,6 +1863,17 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t cl = kzalloc(sizeof(*cl), GFP_KERNEL); if (cl == NULL) goto failure; + + if (tca[TCA_RATE]) { + err = gen_new_estimator(&cl->bstats, &cl->rate_est, + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE]); + if (err) { + kfree(cl); + goto failure; + } + } + cl->R_tab = rtab; rtab = NULL; cl->refcnt = 1; @@ -1929,10 +1915,6 @@ cbq_change_class(struct Qdisc *sch, u32 classid, u32 parentid, struct nlattr **t qdisc_class_hash_grow(sch, &q->clhash); - if (tca[TCA_RATE]) - gen_new_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_sleeping_lock(sch), tca[TCA_RATE]); - *arg = (unsigned long)cl; return 0; @@ -2066,7 +2048,7 @@ static struct Qdisc_ops cbq_qdisc_ops __read_mostly = { .priv_size = sizeof(struct cbq_sched_data), .enqueue = cbq_enqueue, .dequeue = cbq_dequeue, - .requeue = cbq_requeue, + .peek = qdisc_peek_dequeued, .drop = cbq_drop, .init = cbq_init, .reset = cbq_reset, diff --git a/net/sched/sch_drr.c b/net/sched/sch_drr.c new file mode 100644 index 0000000000000000000000000000000000000000..f6b4fa97df70e353b58ed04ba4a74f50f4c8fbcf --- /dev/null +++ b/net/sched/sch_drr.c @@ -0,0 +1,519 @@ +/* + * net/sched/sch_drr.c Deficit Round Robin scheduler + * + * Copyright (c) 2008 Patrick McHardy + * + * 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 +#include +#include +#include +#include +#include +#include +#include + +struct drr_class { + struct Qdisc_class_common common; + unsigned int refcnt; + unsigned int filter_cnt; + + struct gnet_stats_basic bstats; + struct gnet_stats_queue qstats; + struct gnet_stats_rate_est rate_est; + struct list_head alist; + struct Qdisc *qdisc; + + u32 quantum; + u32 deficit; +}; + +struct drr_sched { + struct list_head active; + struct tcf_proto *filter_list; + struct Qdisc_class_hash clhash; +}; + +static struct drr_class *drr_find_class(struct Qdisc *sch, u32 classid) +{ + struct drr_sched *q = qdisc_priv(sch); + struct Qdisc_class_common *clc; + + clc = qdisc_class_find(&q->clhash, classid); + if (clc == NULL) + return NULL; + return container_of(clc, struct drr_class, common); +} + +static void drr_purge_queue(struct drr_class *cl) +{ + unsigned int len = cl->qdisc->q.qlen; + + qdisc_reset(cl->qdisc); + qdisc_tree_decrease_qlen(cl->qdisc, len); +} + +static const struct nla_policy drr_policy[TCA_DRR_MAX + 1] = { + [TCA_DRR_QUANTUM] = { .type = NLA_U32 }, +}; + +static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid, + struct nlattr **tca, unsigned long *arg) +{ + struct drr_sched *q = qdisc_priv(sch); + struct drr_class *cl = (struct drr_class *)*arg; + struct nlattr *tb[TCA_DRR_MAX + 1]; + u32 quantum; + int err; + + err = nla_parse_nested(tb, TCA_DRR_MAX, tca[TCA_OPTIONS], drr_policy); + if (err < 0) + return err; + + if (tb[TCA_DRR_QUANTUM]) { + quantum = nla_get_u32(tb[TCA_DRR_QUANTUM]); + if (quantum == 0) + return -EINVAL; + } else + quantum = psched_mtu(qdisc_dev(sch)); + + if (cl != NULL) { + if (tca[TCA_RATE]) { + err = gen_replace_estimator(&cl->bstats, &cl->rate_est, + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE]); + if (err) + return err; + } + + sch_tree_lock(sch); + if (tb[TCA_DRR_QUANTUM]) + cl->quantum = quantum; + sch_tree_unlock(sch); + + return 0; + } + + cl = kzalloc(sizeof(struct drr_class), GFP_KERNEL); + if (cl == NULL) + return -ENOBUFS; + + cl->refcnt = 1; + cl->common.classid = classid; + cl->quantum = quantum; + cl->qdisc = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, classid); + if (cl->qdisc == NULL) + cl->qdisc = &noop_qdisc; + + if (tca[TCA_RATE]) { + err = gen_replace_estimator(&cl->bstats, &cl->rate_est, + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE]); + if (err) { + qdisc_destroy(cl->qdisc); + kfree(cl); + return err; + } + } + + sch_tree_lock(sch); + qdisc_class_hash_insert(&q->clhash, &cl->common); + sch_tree_unlock(sch); + + qdisc_class_hash_grow(sch, &q->clhash); + + *arg = (unsigned long)cl; + return 0; +} + +static void drr_destroy_class(struct Qdisc *sch, struct drr_class *cl) +{ + gen_kill_estimator(&cl->bstats, &cl->rate_est); + qdisc_destroy(cl->qdisc); + kfree(cl); +} + +static int drr_delete_class(struct Qdisc *sch, unsigned long arg) +{ + struct drr_sched *q = qdisc_priv(sch); + struct drr_class *cl = (struct drr_class *)arg; + + if (cl->filter_cnt > 0) + return -EBUSY; + + sch_tree_lock(sch); + + drr_purge_queue(cl); + qdisc_class_hash_remove(&q->clhash, &cl->common); + + if (--cl->refcnt == 0) + drr_destroy_class(sch, cl); + + sch_tree_unlock(sch); + return 0; +} + +static unsigned long drr_get_class(struct Qdisc *sch, u32 classid) +{ + struct drr_class *cl = drr_find_class(sch, classid); + + if (cl != NULL) + cl->refcnt++; + + return (unsigned long)cl; +} + +static void drr_put_class(struct Qdisc *sch, unsigned long arg) +{ + struct drr_class *cl = (struct drr_class *)arg; + + if (--cl->refcnt == 0) + drr_destroy_class(sch, cl); +} + +static struct tcf_proto **drr_tcf_chain(struct Qdisc *sch, unsigned long cl) +{ + struct drr_sched *q = qdisc_priv(sch); + + if (cl) + return NULL; + + return &q->filter_list; +} + +static unsigned long drr_bind_tcf(struct Qdisc *sch, unsigned long parent, + u32 classid) +{ + struct drr_class *cl = drr_find_class(sch, classid); + + if (cl != NULL) + cl->filter_cnt++; + + return (unsigned long)cl; +} + +static void drr_unbind_tcf(struct Qdisc *sch, unsigned long arg) +{ + struct drr_class *cl = (struct drr_class *)arg; + + cl->filter_cnt--; +} + +static int drr_graft_class(struct Qdisc *sch, unsigned long arg, + struct Qdisc *new, struct Qdisc **old) +{ + struct drr_class *cl = (struct drr_class *)arg; + + if (new == NULL) { + new = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, + &pfifo_qdisc_ops, cl->common.classid); + if (new == NULL) + new = &noop_qdisc; + } + + sch_tree_lock(sch); + drr_purge_queue(cl); + *old = cl->qdisc; + cl->qdisc = new; + sch_tree_unlock(sch); + return 0; +} + +static struct Qdisc *drr_class_leaf(struct Qdisc *sch, unsigned long arg) +{ + struct drr_class *cl = (struct drr_class *)arg; + + return cl->qdisc; +} + +static void drr_qlen_notify(struct Qdisc *csh, unsigned long arg) +{ + struct drr_class *cl = (struct drr_class *)arg; + + if (cl->qdisc->q.qlen == 0) + list_del(&cl->alist); +} + +static int drr_dump_class(struct Qdisc *sch, unsigned long arg, + struct sk_buff *skb, struct tcmsg *tcm) +{ + struct drr_class *cl = (struct drr_class *)arg; + struct nlattr *nest; + + tcm->tcm_parent = TC_H_ROOT; + tcm->tcm_handle = cl->common.classid; + tcm->tcm_info = cl->qdisc->handle; + + nest = nla_nest_start(skb, TCA_OPTIONS); + if (nest == NULL) + goto nla_put_failure; + NLA_PUT_U32(skb, TCA_DRR_QUANTUM, cl->quantum); + return nla_nest_end(skb, nest); + +nla_put_failure: + nla_nest_cancel(skb, nest); + return -EMSGSIZE; +} + +static int drr_dump_class_stats(struct Qdisc *sch, unsigned long arg, + struct gnet_dump *d) +{ + struct drr_class *cl = (struct drr_class *)arg; + struct tc_drr_stats xstats; + + memset(&xstats, 0, sizeof(xstats)); + if (cl->qdisc->q.qlen) + xstats.deficit = cl->deficit; + + if (gnet_stats_copy_basic(d, &cl->bstats) < 0 || + gnet_stats_copy_rate_est(d, &cl->rate_est) < 0 || + gnet_stats_copy_queue(d, &cl->qdisc->qstats) < 0) + return -1; + + return gnet_stats_copy_app(d, &xstats, sizeof(xstats)); +} + +static void drr_walk(struct Qdisc *sch, struct qdisc_walker *arg) +{ + struct drr_sched *q = qdisc_priv(sch); + struct drr_class *cl; + struct hlist_node *n; + unsigned int i; + + if (arg->stop) + return; + + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) { + if (arg->count < arg->skip) { + arg->count++; + continue; + } + if (arg->fn(sch, (unsigned long)cl, arg) < 0) { + arg->stop = 1; + return; + } + arg->count++; + } + } +} + +static struct drr_class *drr_classify(struct sk_buff *skb, struct Qdisc *sch, + int *qerr) +{ + struct drr_sched *q = qdisc_priv(sch); + struct drr_class *cl; + struct tcf_result res; + int result; + + if (TC_H_MAJ(skb->priority ^ sch->handle) == 0) { + cl = drr_find_class(sch, skb->priority); + if (cl != NULL) + return cl; + } + + *qerr = NET_XMIT_SUCCESS | __NET_XMIT_BYPASS; + result = tc_classify(skb, q->filter_list, &res); + if (result >= 0) { +#ifdef CONFIG_NET_CLS_ACT + switch (result) { + case TC_ACT_QUEUED: + case TC_ACT_STOLEN: + *qerr = NET_XMIT_SUCCESS | __NET_XMIT_STOLEN; + case TC_ACT_SHOT: + return NULL; + } +#endif + cl = (struct drr_class *)res.class; + if (cl == NULL) + cl = drr_find_class(sch, res.classid); + return cl; + } + return NULL; +} + +static int drr_enqueue(struct sk_buff *skb, struct Qdisc *sch) +{ + struct drr_sched *q = qdisc_priv(sch); + struct drr_class *cl; + unsigned int len; + int err; + + cl = drr_classify(skb, sch, &err); + if (cl == NULL) { + if (err & __NET_XMIT_BYPASS) + sch->qstats.drops++; + kfree_skb(skb); + return err; + } + + len = qdisc_pkt_len(skb); + err = qdisc_enqueue(skb, cl->qdisc); + if (unlikely(err != NET_XMIT_SUCCESS)) { + if (net_xmit_drop_count(err)) { + cl->qstats.drops++; + sch->qstats.drops++; + } + return err; + } + + if (cl->qdisc->q.qlen == 1) { + list_add_tail(&cl->alist, &q->active); + cl->deficit = cl->quantum; + } + + cl->bstats.packets++; + cl->bstats.bytes += len; + sch->bstats.packets++; + sch->bstats.bytes += len; + + sch->q.qlen++; + return err; +} + +static struct sk_buff *drr_dequeue(struct Qdisc *sch) +{ + struct drr_sched *q = qdisc_priv(sch); + struct drr_class *cl; + struct sk_buff *skb; + unsigned int len; + + if (list_empty(&q->active)) + goto out; + while (1) { + cl = list_first_entry(&q->active, struct drr_class, alist); + skb = cl->qdisc->ops->peek(cl->qdisc); + if (skb == NULL) + goto out; + + len = qdisc_pkt_len(skb); + if (len <= cl->deficit) { + cl->deficit -= len; + skb = qdisc_dequeue_peeked(cl->qdisc); + if (cl->qdisc->q.qlen == 0) + list_del(&cl->alist); + sch->q.qlen--; + return skb; + } + + cl->deficit += cl->quantum; + list_move_tail(&cl->alist, &q->active); + } +out: + return NULL; +} + +static unsigned int drr_drop(struct Qdisc *sch) +{ + struct drr_sched *q = qdisc_priv(sch); + struct drr_class *cl; + unsigned int len; + + list_for_each_entry(cl, &q->active, alist) { + if (cl->qdisc->ops->drop) { + len = cl->qdisc->ops->drop(cl->qdisc); + if (len > 0) { + sch->q.qlen--; + if (cl->qdisc->q.qlen == 0) + list_del(&cl->alist); + return len; + } + } + } + return 0; +} + +static int drr_init_qdisc(struct Qdisc *sch, struct nlattr *opt) +{ + struct drr_sched *q = qdisc_priv(sch); + int err; + + err = qdisc_class_hash_init(&q->clhash); + if (err < 0) + return err; + INIT_LIST_HEAD(&q->active); + return 0; +} + +static void drr_reset_qdisc(struct Qdisc *sch) +{ + struct drr_sched *q = qdisc_priv(sch); + struct drr_class *cl; + struct hlist_node *n; + unsigned int i; + + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry(cl, n, &q->clhash.hash[i], common.hnode) { + if (cl->qdisc->q.qlen) + list_del(&cl->alist); + qdisc_reset(cl->qdisc); + } + } + sch->q.qlen = 0; +} + +static void drr_destroy_qdisc(struct Qdisc *sch) +{ + struct drr_sched *q = qdisc_priv(sch); + struct drr_class *cl; + struct hlist_node *n, *next; + unsigned int i; + + tcf_destroy_chain(&q->filter_list); + + for (i = 0; i < q->clhash.hashsize; i++) { + hlist_for_each_entry_safe(cl, n, next, &q->clhash.hash[i], + common.hnode) + drr_destroy_class(sch, cl); + } + qdisc_class_hash_destroy(&q->clhash); +} + +static const struct Qdisc_class_ops drr_class_ops = { + .change = drr_change_class, + .delete = drr_delete_class, + .get = drr_get_class, + .put = drr_put_class, + .tcf_chain = drr_tcf_chain, + .bind_tcf = drr_bind_tcf, + .unbind_tcf = drr_unbind_tcf, + .graft = drr_graft_class, + .leaf = drr_class_leaf, + .qlen_notify = drr_qlen_notify, + .dump = drr_dump_class, + .dump_stats = drr_dump_class_stats, + .walk = drr_walk, +}; + +static struct Qdisc_ops drr_qdisc_ops __read_mostly = { + .cl_ops = &drr_class_ops, + .id = "drr", + .priv_size = sizeof(struct drr_sched), + .enqueue = drr_enqueue, + .dequeue = drr_dequeue, + .peek = qdisc_peek_dequeued, + .drop = drr_drop, + .init = drr_init_qdisc, + .reset = drr_reset_qdisc, + .destroy = drr_destroy_qdisc, + .owner = THIS_MODULE, +}; + +static int __init drr_init(void) +{ + return register_qdisc(&drr_qdisc_ops); +} + +static void __exit drr_exit(void) +{ + unregister_qdisc(&drr_qdisc_ops); +} + +module_init(drr_init); +module_exit(drr_exit); +MODULE_LICENSE("GPL"); diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c index ba43aab3a8515ed3a71925254a4a531849665baa..d303daa45d49e54f34bc11d698d309253c5e77b2 100644 --- a/net/sched/sch_dsmark.c +++ b/net/sched/sch_dsmark.c @@ -68,7 +68,8 @@ static int dsmark_graft(struct Qdisc *sch, unsigned long arg, } sch_tree_lock(sch); - *old = xchg(&p->q, new); + *old = p->q; + p->q = new; qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); qdisc_reset(*old); sch_tree_unlock(sch); @@ -313,24 +314,13 @@ static struct sk_buff *dsmark_dequeue(struct Qdisc *sch) return skb; } -static int dsmark_requeue(struct sk_buff *skb, struct Qdisc *sch) +static struct sk_buff *dsmark_peek(struct Qdisc *sch) { struct dsmark_qdisc_data *p = qdisc_priv(sch); - int err; - - pr_debug("dsmark_requeue(skb %p,sch %p,[qdisc %p])\n", skb, sch, p); - - err = p->q->ops->requeue(skb, p->q); - if (err != NET_XMIT_SUCCESS) { - if (net_xmit_drop_count(err)) - sch->qstats.drops++; - return err; - } - sch->q.qlen++; - sch->qstats.requeues++; + pr_debug("dsmark_peek(sch %p,[qdisc %p])\n", sch, p); - return NET_XMIT_SUCCESS; + return p->q->ops->peek(p->q); } static unsigned int dsmark_drop(struct Qdisc *sch) @@ -496,7 +486,7 @@ static struct Qdisc_ops dsmark_qdisc_ops __read_mostly = { .priv_size = sizeof(struct dsmark_qdisc_data), .enqueue = dsmark_enqueue, .dequeue = dsmark_dequeue, - .requeue = dsmark_requeue, + .peek = dsmark_peek, .drop = dsmark_drop, .init = dsmark_init, .reset = dsmark_reset, diff --git a/net/sched/sch_fifo.c b/net/sched/sch_fifo.c index 23d258bfe8ace223e07d0c23dc62fbe7e0ae9faa..92cfc9d7e3b93486a718bea3712a983814d605f0 100644 --- a/net/sched/sch_fifo.c +++ b/net/sched/sch_fifo.c @@ -83,7 +83,7 @@ struct Qdisc_ops pfifo_qdisc_ops __read_mostly = { .priv_size = sizeof(struct fifo_sched_data), .enqueue = pfifo_enqueue, .dequeue = qdisc_dequeue_head, - .requeue = qdisc_requeue, + .peek = qdisc_peek_head, .drop = qdisc_queue_drop, .init = fifo_init, .reset = qdisc_reset_queue, @@ -98,7 +98,7 @@ struct Qdisc_ops bfifo_qdisc_ops __read_mostly = { .priv_size = sizeof(struct fifo_sched_data), .enqueue = bfifo_enqueue, .dequeue = qdisc_dequeue_head, - .requeue = qdisc_requeue, + .peek = qdisc_peek_head, .drop = qdisc_queue_drop, .init = fifo_init, .reset = qdisc_reset_queue, diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c index cdcd16fcfeda463c0e9057d288f1b0910070648b..5f5efe4e6072e2959d6f6802a268cc7c5afca66b 100644 --- a/net/sched/sch_generic.c +++ b/net/sched/sch_generic.c @@ -224,7 +224,7 @@ static void dev_watchdog(unsigned long arg) char drivername[64]; WARN_ONCE(1, KERN_INFO "NETDEV WATCHDOG: %s (%s): transmit timed out\n", dev->name, netdev_drivername(dev, drivername, 64)); - dev->tx_timeout(dev); + dev->netdev_ops->ndo_tx_timeout(dev); } if (!mod_timer(&dev->watchdog_timer, round_jiffies(jiffies + @@ -239,7 +239,7 @@ static void dev_watchdog(unsigned long arg) void __netdev_watchdog_up(struct net_device *dev) { - if (dev->tx_timeout) { + if (dev->netdev_ops->ndo_tx_timeout) { if (dev->watchdog_timeo <= 0) dev->watchdog_timeo = 5*HZ; if (!mod_timer(&dev->watchdog_timer, @@ -311,21 +311,12 @@ static struct sk_buff *noop_dequeue(struct Qdisc * qdisc) return NULL; } -static int noop_requeue(struct sk_buff *skb, struct Qdisc* qdisc) -{ - if (net_ratelimit()) - printk(KERN_DEBUG "%s deferred output. It is buggy.\n", - skb->dev->name); - kfree_skb(skb); - return NET_XMIT_CN; -} - struct Qdisc_ops noop_qdisc_ops __read_mostly = { .id = "noop", .priv_size = 0, .enqueue = noop_enqueue, .dequeue = noop_dequeue, - .requeue = noop_requeue, + .peek = noop_dequeue, .owner = THIS_MODULE, }; @@ -340,7 +331,6 @@ struct Qdisc noop_qdisc = { .flags = TCQ_F_BUILTIN, .ops = &noop_qdisc_ops, .list = LIST_HEAD_INIT(noop_qdisc.list), - .requeue.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), .q.lock = __SPIN_LOCK_UNLOCKED(noop_qdisc.q.lock), .dev_queue = &noop_netdev_queue, }; @@ -351,7 +341,7 @@ static struct Qdisc_ops noqueue_qdisc_ops __read_mostly = { .priv_size = 0, .enqueue = noop_enqueue, .dequeue = noop_dequeue, - .requeue = noop_requeue, + .peek = noop_dequeue, .owner = THIS_MODULE, }; @@ -367,7 +357,6 @@ static struct Qdisc noqueue_qdisc = { .flags = TCQ_F_BUILTIN, .ops = &noqueue_qdisc_ops, .list = LIST_HEAD_INIT(noqueue_qdisc.list), - .requeue.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock), .q.lock = __SPIN_LOCK_UNLOCKED(noqueue_qdisc.q.lock), .dev_queue = &noqueue_netdev_queue, }; @@ -416,10 +405,17 @@ static struct sk_buff *pfifo_fast_dequeue(struct Qdisc* qdisc) return NULL; } -static int pfifo_fast_requeue(struct sk_buff *skb, struct Qdisc* qdisc) +static struct sk_buff *pfifo_fast_peek(struct Qdisc* qdisc) { - qdisc->q.qlen++; - return __qdisc_requeue(skb, qdisc, prio2list(skb, qdisc)); + int prio; + struct sk_buff_head *list = qdisc_priv(qdisc); + + for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) { + if (!skb_queue_empty(list + prio)) + return skb_peek(list + prio); + } + + return NULL; } static void pfifo_fast_reset(struct Qdisc* qdisc) @@ -462,7 +458,7 @@ static struct Qdisc_ops pfifo_fast_ops __read_mostly = { .priv_size = PFIFO_FAST_BANDS * sizeof(struct sk_buff_head), .enqueue = pfifo_fast_enqueue, .dequeue = pfifo_fast_dequeue, - .requeue = pfifo_fast_requeue, + .peek = pfifo_fast_peek, .init = pfifo_fast_init, .reset = pfifo_fast_reset, .dump = pfifo_fast_dump, @@ -488,7 +484,6 @@ struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue, sch->padded = (char *) sch - (char *) p; INIT_LIST_HEAD(&sch->list); - skb_queue_head_init(&sch->requeue); skb_queue_head_init(&sch->q); sch->ops = ops; sch->enqueue = ops->enqueue; @@ -531,6 +526,9 @@ void qdisc_reset(struct Qdisc *qdisc) if (ops->reset) ops->reset(qdisc); + + kfree_skb(qdisc->gso_skb); + qdisc->gso_skb = NULL; } EXPORT_SYMBOL(qdisc_reset); @@ -557,8 +555,6 @@ void qdisc_destroy(struct Qdisc *qdisc) dev_put(qdisc_dev(qdisc)); kfree_skb(qdisc->gso_skb); - __skb_queue_purge(&qdisc->requeue); - kfree((char *) qdisc - qdisc->padded); } EXPORT_SYMBOL(qdisc_destroy); diff --git a/net/sched/sch_gred.c b/net/sched/sch_gred.c index c1ad6b8de105a60bbb4427d8f49e47b7e5adc46e..40408d595c08da0163e9a2c4c358e0293d4cebce 100644 --- a/net/sched/sch_gred.c +++ b/net/sched/sch_gred.c @@ -240,26 +240,6 @@ congestion_drop: return NET_XMIT_CN; } -static int gred_requeue(struct sk_buff *skb, struct Qdisc* sch) -{ - struct gred_sched *t = qdisc_priv(sch); - struct gred_sched_data *q; - u16 dp = tc_index_to_dp(skb); - - if (dp >= t->DPs || (q = t->tab[dp]) == NULL) { - if (net_ratelimit()) - printk(KERN_WARNING "GRED: Unable to relocate VQ 0x%x " - "for requeue, screwing up backlog.\n", - tc_index_to_dp(skb)); - } else { - if (red_is_idling(&q->parms)) - red_end_of_idle_period(&q->parms); - q->backlog += qdisc_pkt_len(skb); - } - - return qdisc_requeue(skb, sch); -} - static struct sk_buff *gred_dequeue(struct Qdisc* sch) { struct sk_buff *skb; @@ -602,7 +582,7 @@ static struct Qdisc_ops gred_qdisc_ops __read_mostly = { .priv_size = sizeof(struct gred_sched), .enqueue = gred_enqueue, .dequeue = gred_dequeue, - .requeue = gred_requeue, + .peek = qdisc_peek_head, .drop = gred_drop, .init = gred_init, .reset = gred_reset, diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index c1e77da8cd09bc7dfc0bbe5aee25da12f7f69918..45c31b1a4e1dd0b488e6f6e20cc966e7aad70467 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -184,7 +184,6 @@ struct hfsc_sched struct rb_root eligible; /* eligible tree */ struct list_head droplist; /* active leaf class list (for dropping) */ - struct sk_buff_head requeue; /* requeued packet */ struct qdisc_watchdog watchdog; /* watchdog timer */ }; @@ -880,28 +879,20 @@ set_passive(struct hfsc_class *cl) */ } -/* - * hack to get length of first packet in queue. - */ static unsigned int qdisc_peek_len(struct Qdisc *sch) { struct sk_buff *skb; unsigned int len; - skb = sch->dequeue(sch); + skb = sch->ops->peek(sch); if (skb == NULL) { if (net_ratelimit()) printk("qdisc_peek_len: non work-conserving qdisc ?\n"); return 0; } len = qdisc_pkt_len(skb); - if (unlikely(sch->ops->requeue(skb, sch) != NET_XMIT_SUCCESS)) { - if (net_ratelimit()) - printk("qdisc_peek_len: failed to requeue\n"); - qdisc_tree_decrease_qlen(sch, 1); - return 0; - } + return len; } @@ -1027,6 +1018,14 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, } cur_time = psched_get_time(); + if (tca[TCA_RATE]) { + err = gen_replace_estimator(&cl->bstats, &cl->rate_est, + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE]); + if (err) + return err; + } + sch_tree_lock(sch); if (rsc != NULL) hfsc_change_rsc(cl, rsc, cur_time); @@ -1043,10 +1042,6 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, } sch_tree_unlock(sch); - if (tca[TCA_RATE]) - gen_replace_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_sleeping_lock(sch), - tca[TCA_RATE]); return 0; } @@ -1072,6 +1067,16 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, if (cl == NULL) return -ENOBUFS; + if (tca[TCA_RATE]) { + err = gen_new_estimator(&cl->bstats, &cl->rate_est, + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE]); + if (err) { + kfree(cl); + return err; + } + } + if (rsc != NULL) hfsc_change_rsc(cl, rsc, 0); if (fsc != NULL) @@ -1102,9 +1107,6 @@ hfsc_change_class(struct Qdisc *sch, u32 classid, u32 parentid, qdisc_class_hash_grow(sch, &q->clhash); - if (tca[TCA_RATE]) - gen_new_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_sleeping_lock(sch), tca[TCA_RATE]); *arg = (unsigned long)cl; return 0; } @@ -1211,7 +1213,8 @@ hfsc_graft_class(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, sch_tree_lock(sch); hfsc_purge_queue(sch, cl); - *old = xchg(&cl->qdisc, new); + *old = cl->qdisc; + cl->qdisc = new; sch_tree_unlock(sch); return 0; } @@ -1440,7 +1443,6 @@ hfsc_init_qdisc(struct Qdisc *sch, struct nlattr *opt) return err; q->eligible = RB_ROOT; INIT_LIST_HEAD(&q->droplist); - skb_queue_head_init(&q->requeue); q->root.cl_common.classid = sch->handle; q->root.refcnt = 1; @@ -1525,7 +1527,6 @@ hfsc_reset_qdisc(struct Qdisc *sch) hlist_for_each_entry(cl, n, &q->clhash.hash[i], cl_common.hnode) hfsc_reset_class(cl); } - __skb_queue_purge(&q->requeue); q->eligible = RB_ROOT; INIT_LIST_HEAD(&q->droplist); qdisc_watchdog_cancel(&q->watchdog); @@ -1550,7 +1551,6 @@ hfsc_destroy_qdisc(struct Qdisc *sch) hfsc_destroy_class(sch, cl); } qdisc_class_hash_destroy(&q->clhash); - __skb_queue_purge(&q->requeue); qdisc_watchdog_cancel(&q->watchdog); } @@ -1574,7 +1574,7 @@ static int hfsc_enqueue(struct sk_buff *skb, struct Qdisc *sch) { struct hfsc_class *cl; - int err; + int uninitialized_var(err); cl = hfsc_classify(skb, sch, &err); if (cl == NULL) { @@ -1617,8 +1617,6 @@ hfsc_dequeue(struct Qdisc *sch) if (sch->q.qlen == 0) return NULL; - if ((skb = __skb_dequeue(&q->requeue))) - goto out; cur_time = psched_get_time(); @@ -1642,7 +1640,7 @@ hfsc_dequeue(struct Qdisc *sch) } } - skb = cl->qdisc->dequeue(cl->qdisc); + skb = qdisc_dequeue_peeked(cl->qdisc); if (skb == NULL) { if (net_ratelimit()) printk("HFSC: Non-work-conserving qdisc ?\n"); @@ -1667,24 +1665,12 @@ hfsc_dequeue(struct Qdisc *sch) set_passive(cl); } - out: sch->flags &= ~TCQ_F_THROTTLED; sch->q.qlen--; return skb; } -static int -hfsc_requeue(struct sk_buff *skb, struct Qdisc *sch) -{ - struct hfsc_sched *q = qdisc_priv(sch); - - __skb_queue_head(&q->requeue, skb); - sch->q.qlen++; - sch->qstats.requeues++; - return NET_XMIT_SUCCESS; -} - static unsigned int hfsc_drop(struct Qdisc *sch) { @@ -1735,7 +1721,7 @@ static struct Qdisc_ops hfsc_qdisc_ops __read_mostly = { .dump = hfsc_dump_qdisc, .enqueue = hfsc_enqueue, .dequeue = hfsc_dequeue, - .requeue = hfsc_requeue, + .peek = qdisc_peek_dequeued, .drop = hfsc_drop, .cl_ops = &hfsc_class_ops, .priv_size = sizeof(struct hfsc_sched), diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c index d14f02056ae6dcc31dbfad8c90ba57424e4a6d45..5070643ce534b468a85b3df2f1666d0ae35b08ad 100644 --- a/net/sched/sch_htb.c +++ b/net/sched/sch_htb.c @@ -84,12 +84,12 @@ struct htb_class { unsigned int children; struct htb_class *parent; /* parent class */ + int prio; /* these two are used only by leaves... */ + int quantum; /* but stored for parent-to-leaf return */ + union { struct htb_class_leaf { struct Qdisc *q; - int prio; - int aprio; - int quantum; int deficit[TC_HTB_MAXDEPTH]; struct list_head drop_list; } leaf; @@ -123,19 +123,8 @@ struct htb_class { psched_tdiff_t mbuffer; /* max wait time */ long tokens, ctokens; /* current number of tokens */ psched_time_t t_c; /* checkpoint time */ - - int prio; /* For parent to leaf return possible here */ - int quantum; /* we do backup. Finally full replacement */ - /* of un.leaf originals should be done. */ }; -static inline long L2T(struct htb_class *cl, struct qdisc_rate_table *rate, - int size) -{ - long result = qdisc_l2t(rate, size); - return result; -} - struct htb_sched { struct Qdisc_class_hash clhash; struct list_head drops[TC_HTB_NUMPRIO];/* active leaves (for drops) */ @@ -152,9 +141,6 @@ struct htb_sched { /* time of nearest event per level (row) */ psched_time_t near_ev_cache[TC_HTB_MAXDEPTH]; - /* whether we hit non-work conserving class during this dequeue; we use */ - int nwc_hit; /* this to disable mindelay complaint in dequeue */ - int defcls; /* class where unclassified flows go to */ /* filters for qdisc itself */ @@ -527,10 +513,10 @@ static inline void htb_activate(struct htb_sched *q, struct htb_class *cl) WARN_ON(cl->level || !cl->un.leaf.q || !cl->un.leaf.q->q.qlen); if (!cl->prio_activity) { - cl->prio_activity = 1 << (cl->un.leaf.aprio = cl->un.leaf.prio); + cl->prio_activity = 1 << cl->prio; htb_activate_prios(q, cl); list_add_tail(&cl->un.leaf.drop_list, - q->drops + cl->un.leaf.aprio); + q->drops + cl->prio); } } @@ -551,7 +537,7 @@ static inline void htb_deactivate(struct htb_sched *q, struct htb_class *cl) static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch) { - int ret; + int uninitialized_var(ret); struct htb_sched *q = qdisc_priv(sch); struct htb_class *cl = htb_classify(skb, sch, &ret); @@ -591,45 +577,30 @@ static int htb_enqueue(struct sk_buff *skb, struct Qdisc *sch) return NET_XMIT_SUCCESS; } -/* TODO: requeuing packet charges it to policers again !! */ -static int htb_requeue(struct sk_buff *skb, struct Qdisc *sch) +static inline void htb_accnt_tokens(struct htb_class *cl, int bytes, long diff) { - int ret; - struct htb_sched *q = qdisc_priv(sch); - struct htb_class *cl = htb_classify(skb, sch, &ret); - struct sk_buff *tskb; + long toks = diff + cl->tokens; - if (cl == HTB_DIRECT) { - /* enqueue to helper queue */ - if (q->direct_queue.qlen < q->direct_qlen) { - __skb_queue_head(&q->direct_queue, skb); - } else { - __skb_queue_head(&q->direct_queue, skb); - tskb = __skb_dequeue_tail(&q->direct_queue); - kfree_skb(tskb); - sch->qstats.drops++; - return NET_XMIT_CN; - } -#ifdef CONFIG_NET_CLS_ACT - } else if (!cl) { - if (ret & __NET_XMIT_BYPASS) - sch->qstats.drops++; - kfree_skb(skb); - return ret; -#endif - } else if ((ret = cl->un.leaf.q->ops->requeue(skb, cl->un.leaf.q)) != - NET_XMIT_SUCCESS) { - if (net_xmit_drop_count(ret)) { - sch->qstats.drops++; - cl->qstats.drops++; - } - return ret; - } else - htb_activate(q, cl); + if (toks > cl->buffer) + toks = cl->buffer; + toks -= (long) qdisc_l2t(cl->rate, bytes); + if (toks <= -cl->mbuffer) + toks = 1 - cl->mbuffer; - sch->q.qlen++; - sch->qstats.requeues++; - return NET_XMIT_SUCCESS; + cl->tokens = toks; +} + +static inline void htb_accnt_ctokens(struct htb_class *cl, int bytes, long diff) +{ + long toks = diff + cl->ctokens; + + if (toks > cl->cbuffer) + toks = cl->cbuffer; + toks -= (long) qdisc_l2t(cl->ceil, bytes); + if (toks <= -cl->mbuffer) + toks = 1 - cl->mbuffer; + + cl->ctokens = toks; } /** @@ -647,26 +618,20 @@ static void htb_charge_class(struct htb_sched *q, struct htb_class *cl, int level, struct sk_buff *skb) { int bytes = qdisc_pkt_len(skb); - long toks, diff; enum htb_cmode old_mode; - -#define HTB_ACCNT(T,B,R) toks = diff + cl->T; \ - if (toks > cl->B) toks = cl->B; \ - toks -= L2T(cl, cl->R, bytes); \ - if (toks <= -cl->mbuffer) toks = 1-cl->mbuffer; \ - cl->T = toks + long diff; while (cl) { diff = psched_tdiff_bounded(q->now, cl->t_c, cl->mbuffer); if (cl->level >= level) { if (cl->level == level) cl->xstats.lends++; - HTB_ACCNT(tokens, buffer, rate); + htb_accnt_tokens(cl, bytes, diff); } else { cl->xstats.borrows++; cl->tokens += diff; /* we moved t_c; update tokens */ } - HTB_ACCNT(ctokens, cbuffer, ceil); + htb_accnt_ctokens(cl, bytes, diff); cl->t_c = q->now; old_mode = cl->cmode; @@ -733,14 +698,14 @@ static struct rb_node *htb_id_find_next_upper(int prio, struct rb_node *n, while (n) { struct htb_class *cl = rb_entry(n, struct htb_class, node[prio]); - if (id == cl->common.classid) - return n; if (id > cl->common.classid) { n = n->rb_right; - } else { + } else if (id < cl->common.classid) { r = n; n = n->rb_left; + } else { + return n; } } return r; @@ -761,7 +726,7 @@ static struct htb_class *htb_lookup_leaf(struct rb_root *tree, int prio, u32 *pid; } stk[TC_HTB_MAXDEPTH], *sp = stk; - WARN_ON(!tree->rb_node); + BUG_ON(!tree->rb_node); sp->root = tree->rb_node; sp->pptr = pptr; sp->pid = pid; @@ -781,9 +746,10 @@ static struct htb_class *htb_lookup_leaf(struct rb_root *tree, int prio, *sp->pptr = (*sp->pptr)->rb_left; if (sp > stk) { sp--; - WARN_ON(!*sp->pptr); - if (!*sp->pptr) + if (!*sp->pptr) { + WARN_ON(1); return NULL; + } htb_next_rb_node(sp->pptr); } } else { @@ -814,8 +780,7 @@ static struct sk_buff *htb_dequeue_tree(struct htb_sched *q, int prio, do { next: - WARN_ON(!cl); - if (!cl) + if (unlikely(!cl)) return NULL; /* class can be empty - it is unlikely but can be true if leaf @@ -849,7 +814,7 @@ next: cl->common.classid); cl->warned = 1; } - q->nwc_hit++; + htb_next_rb_node((level ? cl->parent->un.inner.ptr : q-> ptr[0]) + prio); cl = htb_lookup_leaf(q->row[level] + prio, prio, @@ -861,7 +826,7 @@ next: if (likely(skb != NULL)) { cl->un.leaf.deficit[level] -= qdisc_pkt_len(skb); if (cl->un.leaf.deficit[level] < 0) { - cl->un.leaf.deficit[level] += cl->un.leaf.quantum; + cl->un.leaf.deficit[level] += cl->quantum; htb_next_rb_node((level ? cl->parent->un.inner.ptr : q-> ptr[0]) + prio); } @@ -894,7 +859,7 @@ static struct sk_buff *htb_dequeue(struct Qdisc *sch) q->now = psched_get_time(); next_event = q->now + 5 * PSCHED_TICKS_PER_SEC; - q->nwc_hit = 0; + for (level = 0; level < TC_HTB_MAXDEPTH; level++) { /* common case optimization - skip event handler quickly */ int m; @@ -1095,8 +1060,8 @@ static int htb_dump_class(struct Qdisc *sch, unsigned long arg, opt.buffer = cl->buffer; opt.ceil = cl->ceil->rate; opt.cbuffer = cl->cbuffer; - opt.quantum = cl->un.leaf.quantum; - opt.prio = cl->un.leaf.prio; + opt.quantum = cl->quantum; + opt.prio = cl->prio; opt.level = cl->level; NLA_PUT(skb, TCA_HTB_PARMS, sizeof(opt), &opt); @@ -1141,7 +1106,9 @@ static int htb_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, == NULL) return -ENOBUFS; sch_tree_lock(sch); - if ((*old = xchg(&cl->un.leaf.q, new)) != NULL) { + *old = cl->un.leaf.q; + cl->un.leaf.q = new; + if (*old != NULL) { qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); qdisc_reset(*old); } @@ -1198,8 +1165,6 @@ static void htb_parent_to_leaf(struct htb_sched *q, struct htb_class *cl, memset(&parent->un.inner, 0, sizeof(parent->un.inner)); INIT_LIST_HEAD(&parent->un.leaf.drop_list); parent->un.leaf.q = new_q ? new_q : &noop_qdisc; - parent->un.leaf.quantum = parent->quantum; - parent->un.leaf.prio = parent->prio; parent->tokens = parent->buffer; parent->ctokens = parent->cbuffer; parent->t_c = psched_get_time(); @@ -1371,9 +1336,14 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, if ((cl = kzalloc(sizeof(*cl), GFP_KERNEL)) == NULL) goto failure; - gen_new_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_sleeping_lock(sch), - tca[TCA_RATE] ? : &est.nla); + err = gen_new_estimator(&cl->bstats, &cl->rate_est, + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE] ? : &est.nla); + if (err) { + kfree(cl); + goto failure; + } + cl->refcnt = 1; cl->children = 0; INIT_LIST_HEAD(&cl->un.leaf.drop_list); @@ -1425,37 +1395,36 @@ static int htb_change_class(struct Qdisc *sch, u32 classid, if (parent) parent->children++; } else { - if (tca[TCA_RATE]) - gen_replace_estimator(&cl->bstats, &cl->rate_est, - qdisc_root_sleeping_lock(sch), - tca[TCA_RATE]); + if (tca[TCA_RATE]) { + err = gen_replace_estimator(&cl->bstats, &cl->rate_est, + qdisc_root_sleeping_lock(sch), + tca[TCA_RATE]); + if (err) + return err; + } sch_tree_lock(sch); } /* it used to be a nasty bug here, we have to check that node is really leaf before changing cl->un.leaf ! */ if (!cl->level) { - cl->un.leaf.quantum = rtab->rate.rate / q->rate2quantum; - if (!hopt->quantum && cl->un.leaf.quantum < 1000) { + cl->quantum = rtab->rate.rate / q->rate2quantum; + if (!hopt->quantum && cl->quantum < 1000) { printk(KERN_WARNING "HTB: quantum of class %X is small. Consider r2q change.\n", cl->common.classid); - cl->un.leaf.quantum = 1000; + cl->quantum = 1000; } - if (!hopt->quantum && cl->un.leaf.quantum > 200000) { + if (!hopt->quantum && cl->quantum > 200000) { printk(KERN_WARNING "HTB: quantum of class %X is big. Consider r2q change.\n", cl->common.classid); - cl->un.leaf.quantum = 200000; + cl->quantum = 200000; } if (hopt->quantum) - cl->un.leaf.quantum = hopt->quantum; - if ((cl->un.leaf.prio = hopt->prio) >= TC_HTB_NUMPRIO) - cl->un.leaf.prio = TC_HTB_NUMPRIO - 1; - - /* backup for htb_parent_to_leaf */ - cl->quantum = cl->un.leaf.quantum; - cl->prio = cl->un.leaf.prio; + cl->quantum = hopt->quantum; + if ((cl->prio = hopt->prio) >= TC_HTB_NUMPRIO) + cl->prio = TC_HTB_NUMPRIO - 1; } cl->buffer = hopt->buffer; @@ -1565,7 +1534,7 @@ static struct Qdisc_ops htb_qdisc_ops __read_mostly = { .priv_size = sizeof(struct htb_sched), .enqueue = htb_enqueue, .dequeue = htb_dequeue, - .requeue = htb_requeue, + .peek = qdisc_peek_dequeued, .drop = htb_drop, .init = htb_init, .reset = htb_reset, diff --git a/net/sched/sch_multiq.c b/net/sched/sch_multiq.c index 915f3149dde23c6d5391d505ae957714961cd2d1..7e151861794b5eb09eb7eb448834fc7be9fec3bc 100644 --- a/net/sched/sch_multiq.c +++ b/net/sched/sch_multiq.c @@ -92,40 +92,6 @@ multiq_enqueue(struct sk_buff *skb, struct Qdisc *sch) return ret; } - -static int -multiq_requeue(struct sk_buff *skb, struct Qdisc *sch) -{ - struct Qdisc *qdisc; - struct multiq_sched_data *q = qdisc_priv(sch); - int ret; - - qdisc = multiq_classify(skb, sch, &ret); -#ifdef CONFIG_NET_CLS_ACT - if (qdisc == NULL) { - if (ret & __NET_XMIT_BYPASS) - sch->qstats.drops++; - kfree_skb(skb); - return ret; - } -#endif - - ret = qdisc->ops->requeue(skb, qdisc); - if (ret == NET_XMIT_SUCCESS) { - sch->q.qlen++; - sch->qstats.requeues++; - if (q->curband) - q->curband--; - else - q->curband = q->bands - 1; - return NET_XMIT_SUCCESS; - } - if (net_xmit_drop_count(ret)) - sch->qstats.drops++; - return ret; -} - - static struct sk_buff *multiq_dequeue(struct Qdisc *sch) { struct multiq_sched_data *q = qdisc_priv(sch); @@ -140,7 +106,7 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch) q->curband = 0; /* Check that target subqueue is available before - * pulling an skb to avoid excessive requeues + * pulling an skb to avoid head-of-line blocking. */ if (!__netif_subqueue_stopped(qdisc_dev(sch), q->curband)) { qdisc = q->queues[q->curband]; @@ -155,6 +121,34 @@ static struct sk_buff *multiq_dequeue(struct Qdisc *sch) } +static struct sk_buff *multiq_peek(struct Qdisc *sch) +{ + struct multiq_sched_data *q = qdisc_priv(sch); + unsigned int curband = q->curband; + struct Qdisc *qdisc; + struct sk_buff *skb; + int band; + + for (band = 0; band < q->bands; band++) { + /* cycle through bands to ensure fairness */ + curband++; + if (curband >= q->bands) + curband = 0; + + /* Check that target subqueue is available before + * pulling an skb to avoid head-of-line blocking. + */ + if (!__netif_subqueue_stopped(qdisc_dev(sch), curband)) { + qdisc = q->queues[curband]; + skb = qdisc->ops->peek(qdisc); + if (skb) + return skb; + } + } + return NULL; + +} + static unsigned int multiq_drop(struct Qdisc *sch) { struct multiq_sched_data *q = qdisc_priv(sch); @@ -220,7 +214,8 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) q->bands = qopt->bands; for (i = q->bands; i < q->max_bands; i++) { if (q->queues[i] != &noop_qdisc) { - struct Qdisc *child = xchg(&q->queues[i], &noop_qdisc); + struct Qdisc *child = q->queues[i]; + q->queues[i] = &noop_qdisc; qdisc_tree_decrease_qlen(child, child->q.qlen); qdisc_destroy(child); } @@ -230,7 +225,7 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) for (i = 0; i < q->bands; i++) { if (q->queues[i] == &noop_qdisc) { - struct Qdisc *child; + struct Qdisc *child, *old; child = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, &pfifo_qdisc_ops, @@ -238,12 +233,13 @@ static int multiq_tune(struct Qdisc *sch, struct nlattr *opt) i + 1)); if (child) { sch_tree_lock(sch); - child = xchg(&q->queues[i], child); + old = q->queues[i]; + q->queues[i] = child; - if (child != &noop_qdisc) { - qdisc_tree_decrease_qlen(child, - child->q.qlen); - qdisc_destroy(child); + if (old != &noop_qdisc) { + qdisc_tree_decrease_qlen(old, + old->q.qlen); + qdisc_destroy(old); } sch_tree_unlock(sch); } @@ -451,7 +447,7 @@ static struct Qdisc_ops multiq_qdisc_ops __read_mostly = { .priv_size = sizeof(struct multiq_sched_data), .enqueue = multiq_enqueue, .dequeue = multiq_dequeue, - .requeue = multiq_requeue, + .peek = multiq_peek, .drop = multiq_drop, .init = multiq_init, .reset = multiq_reset, diff --git a/net/sched/sch_netem.c b/net/sched/sch_netem.c index 98402f0efa47727677b8d57acfe2ecd7cb9441b2..d876b873484852d0a1da004e51fc4198d65627de 100644 --- a/net/sched/sch_netem.c +++ b/net/sched/sch_netem.c @@ -230,7 +230,11 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) */ cb->time_to_send = psched_get_time(); q->counter = 0; - ret = q->qdisc->ops->requeue(skb, q->qdisc); + + __skb_queue_head(&q->qdisc->q, skb); + q->qdisc->qstats.backlog += qdisc_pkt_len(skb); + q->qdisc->qstats.requeues++; + ret = NET_XMIT_SUCCESS; } if (likely(ret == NET_XMIT_SUCCESS)) { @@ -245,20 +249,6 @@ static int netem_enqueue(struct sk_buff *skb, struct Qdisc *sch) return ret; } -/* Requeue packets but don't change time stamp */ -static int netem_requeue(struct sk_buff *skb, struct Qdisc *sch) -{ - struct netem_sched_data *q = qdisc_priv(sch); - int ret; - - if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) { - sch->q.qlen++; - sch->qstats.requeues++; - } - - return ret; -} - static unsigned int netem_drop(struct Qdisc* sch) { struct netem_sched_data *q = qdisc_priv(sch); @@ -276,29 +266,25 @@ static struct sk_buff *netem_dequeue(struct Qdisc *sch) struct netem_sched_data *q = qdisc_priv(sch); struct sk_buff *skb; - smp_mb(); if (sch->flags & TCQ_F_THROTTLED) return NULL; - skb = q->qdisc->dequeue(q->qdisc); + skb = q->qdisc->ops->peek(q->qdisc); if (skb) { const struct netem_skb_cb *cb = netem_skb_cb(skb); psched_time_t now = psched_get_time(); /* if more time remaining? */ if (cb->time_to_send <= now) { + skb = qdisc_dequeue_peeked(q->qdisc); + if (unlikely(!skb)) + return NULL; + pr_debug("netem_dequeue: return skb=%p\n", skb); sch->q.qlen--; return skb; } - if (unlikely(q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS)) { - qdisc_tree_decrease_qlen(q->qdisc, 1); - sch->qstats.drops++; - printk(KERN_ERR "netem: %s could not requeue\n", - q->qdisc->ops->id); - } - qdisc_watchdog_schedule(&q->watchdog, cb->time_to_send); } @@ -341,14 +327,13 @@ static int get_dist_table(struct Qdisc *sch, const struct nlattr *attr) root_lock = qdisc_root_sleeping_lock(sch); spin_lock_bh(root_lock); - d = xchg(&q->delay_dist, d); + kfree(q->delay_dist); + q->delay_dist = d; spin_unlock_bh(root_lock); - - kfree(d); return 0; } -static int get_correlation(struct Qdisc *sch, const struct nlattr *attr) +static void get_correlation(struct Qdisc *sch, const struct nlattr *attr) { struct netem_sched_data *q = qdisc_priv(sch); const struct tc_netem_corr *c = nla_data(attr); @@ -356,27 +341,24 @@ static int get_correlation(struct Qdisc *sch, const struct nlattr *attr) init_crandom(&q->delay_cor, c->delay_corr); init_crandom(&q->loss_cor, c->loss_corr); init_crandom(&q->dup_cor, c->dup_corr); - return 0; } -static int get_reorder(struct Qdisc *sch, const struct nlattr *attr) +static void get_reorder(struct Qdisc *sch, const struct nlattr *attr) { struct netem_sched_data *q = qdisc_priv(sch); const struct tc_netem_reorder *r = nla_data(attr); q->reorder = r->probability; init_crandom(&q->reorder_cor, r->correlation); - return 0; } -static int get_corrupt(struct Qdisc *sch, const struct nlattr *attr) +static void get_corrupt(struct Qdisc *sch, const struct nlattr *attr) { struct netem_sched_data *q = qdisc_priv(sch); const struct tc_netem_corrupt *r = nla_data(attr); q->corrupt = r->probability; init_crandom(&q->corrupt_cor, r->correlation); - return 0; } static const struct nla_policy netem_policy[TCA_NETEM_MAX + 1] = { @@ -435,11 +417,8 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt) if (q->gap) q->reorder = ~0; - if (tb[TCA_NETEM_CORR]) { - ret = get_correlation(sch, tb[TCA_NETEM_CORR]); - if (ret) - return ret; - } + if (tb[TCA_NETEM_CORR]) + get_correlation(sch, tb[TCA_NETEM_CORR]); if (tb[TCA_NETEM_DELAY_DIST]) { ret = get_dist_table(sch, tb[TCA_NETEM_DELAY_DIST]); @@ -447,17 +426,11 @@ static int netem_change(struct Qdisc *sch, struct nlattr *opt) return ret; } - if (tb[TCA_NETEM_REORDER]) { - ret = get_reorder(sch, tb[TCA_NETEM_REORDER]); - if (ret) - return ret; - } + if (tb[TCA_NETEM_REORDER]) + get_reorder(sch, tb[TCA_NETEM_REORDER]); - if (tb[TCA_NETEM_CORRUPT]) { - ret = get_corrupt(sch, tb[TCA_NETEM_CORRUPT]); - if (ret) - return ret; - } + if (tb[TCA_NETEM_CORRUPT]) + get_corrupt(sch, tb[TCA_NETEM_CORRUPT]); return 0; } @@ -538,7 +511,7 @@ static struct Qdisc_ops tfifo_qdisc_ops __read_mostly = { .priv_size = sizeof(struct fifo_sched_data), .enqueue = tfifo_enqueue, .dequeue = qdisc_dequeue_head, - .requeue = qdisc_requeue, + .peek = qdisc_peek_head, .drop = qdisc_queue_drop, .init = tfifo_init, .reset = qdisc_reset_queue, @@ -621,99 +594,12 @@ nla_put_failure: return -1; } -static int netem_dump_class(struct Qdisc *sch, unsigned long cl, - struct sk_buff *skb, struct tcmsg *tcm) -{ - struct netem_sched_data *q = qdisc_priv(sch); - - if (cl != 1) /* only one class */ - return -ENOENT; - - tcm->tcm_handle |= TC_H_MIN(1); - tcm->tcm_info = q->qdisc->handle; - - return 0; -} - -static int netem_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, - struct Qdisc **old) -{ - struct netem_sched_data *q = qdisc_priv(sch); - - if (new == NULL) - new = &noop_qdisc; - - sch_tree_lock(sch); - *old = xchg(&q->qdisc, new); - qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); - qdisc_reset(*old); - sch_tree_unlock(sch); - - return 0; -} - -static struct Qdisc *netem_leaf(struct Qdisc *sch, unsigned long arg) -{ - struct netem_sched_data *q = qdisc_priv(sch); - return q->qdisc; -} - -static unsigned long netem_get(struct Qdisc *sch, u32 classid) -{ - return 1; -} - -static void netem_put(struct Qdisc *sch, unsigned long arg) -{ -} - -static int netem_change_class(struct Qdisc *sch, u32 classid, u32 parentid, - struct nlattr **tca, unsigned long *arg) -{ - return -ENOSYS; -} - -static int netem_delete(struct Qdisc *sch, unsigned long arg) -{ - return -ENOSYS; -} - -static void netem_walk(struct Qdisc *sch, struct qdisc_walker *walker) -{ - if (!walker->stop) { - if (walker->count >= walker->skip) - if (walker->fn(sch, 1, walker) < 0) { - walker->stop = 1; - return; - } - walker->count++; - } -} - -static struct tcf_proto **netem_find_tcf(struct Qdisc *sch, unsigned long cl) -{ - return NULL; -} - -static const struct Qdisc_class_ops netem_class_ops = { - .graft = netem_graft, - .leaf = netem_leaf, - .get = netem_get, - .put = netem_put, - .change = netem_change_class, - .delete = netem_delete, - .walk = netem_walk, - .tcf_chain = netem_find_tcf, - .dump = netem_dump_class, -}; - static struct Qdisc_ops netem_qdisc_ops __read_mostly = { .id = "netem", - .cl_ops = &netem_class_ops, .priv_size = sizeof(struct netem_sched_data), .enqueue = netem_enqueue, .dequeue = netem_dequeue, - .requeue = netem_requeue, + .peek = qdisc_peek_dequeued, .drop = netem_drop, .init = netem_init, .reset = netem_reset, diff --git a/net/sched/sch_prio.c b/net/sched/sch_prio.c index 504a78cdb718bb7dd7ba05e60feb1f5fd2e89ea3..94cecef7014517b5784bdc297c36a8fad644ca28 100644 --- a/net/sched/sch_prio.c +++ b/net/sched/sch_prio.c @@ -93,34 +93,20 @@ prio_enqueue(struct sk_buff *skb, struct Qdisc *sch) return ret; } - -static int -prio_requeue(struct sk_buff *skb, struct Qdisc* sch) +static struct sk_buff *prio_peek(struct Qdisc *sch) { - struct Qdisc *qdisc; - int ret; - - qdisc = prio_classify(skb, sch, &ret); -#ifdef CONFIG_NET_CLS_ACT - if (qdisc == NULL) { - if (ret & __NET_XMIT_BYPASS) - sch->qstats.drops++; - kfree_skb(skb); - return ret; - } -#endif + struct prio_sched_data *q = qdisc_priv(sch); + int prio; - if ((ret = qdisc->ops->requeue(skb, qdisc)) == NET_XMIT_SUCCESS) { - sch->q.qlen++; - sch->qstats.requeues++; - return NET_XMIT_SUCCESS; + for (prio = 0; prio < q->bands; prio++) { + struct Qdisc *qdisc = q->queues[prio]; + struct sk_buff *skb = qdisc->ops->peek(qdisc); + if (skb) + return skb; } - if (net_xmit_drop_count(ret)) - sch->qstats.drops++; - return ret; + return NULL; } - static struct sk_buff *prio_dequeue(struct Qdisc* sch) { struct prio_sched_data *q = qdisc_priv(sch); @@ -201,7 +187,8 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) memcpy(q->prio2band, qopt->priomap, TC_PRIO_MAX+1); for (i=q->bands; iqueues[i], &noop_qdisc); + struct Qdisc *child = q->queues[i]; + q->queues[i] = &noop_qdisc; if (child != &noop_qdisc) { qdisc_tree_decrease_qlen(child, child->q.qlen); qdisc_destroy(child); @@ -211,18 +198,19 @@ static int prio_tune(struct Qdisc *sch, struct nlattr *opt) for (i=0; ibands; i++) { if (q->queues[i] == &noop_qdisc) { - struct Qdisc *child; + struct Qdisc *child, *old; child = qdisc_create_dflt(qdisc_dev(sch), sch->dev_queue, &pfifo_qdisc_ops, TC_H_MAKE(sch->handle, i + 1)); if (child) { sch_tree_lock(sch); - child = xchg(&q->queues[i], child); + old = q->queues[i]; + q->queues[i] = child; - if (child != &noop_qdisc) { - qdisc_tree_decrease_qlen(child, - child->q.qlen); - qdisc_destroy(child); + if (old != &noop_qdisc) { + qdisc_tree_decrease_qlen(old, + old->q.qlen); + qdisc_destroy(old); } sch_tree_unlock(sch); } @@ -421,7 +409,7 @@ static struct Qdisc_ops prio_qdisc_ops __read_mostly = { .priv_size = sizeof(struct prio_sched_data), .enqueue = prio_enqueue, .dequeue = prio_dequeue, - .requeue = prio_requeue, + .peek = prio_peek, .drop = prio_drop, .init = prio_init, .reset = prio_reset, diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c index 5da05839e225001bd9afeae5e6ba975a96fc3da1..2bdf241f63154df3996bf0c5ec3460cf1fae25c7 100644 --- a/net/sched/sch_red.c +++ b/net/sched/sch_red.c @@ -108,23 +108,6 @@ congestion_drop: return NET_XMIT_CN; } -static int red_requeue(struct sk_buff *skb, struct Qdisc* sch) -{ - struct red_sched_data *q = qdisc_priv(sch); - struct Qdisc *child = q->qdisc; - int ret; - - if (red_is_idling(&q->parms)) - red_end_of_idle_period(&q->parms); - - ret = child->ops->requeue(skb, child); - if (likely(ret == NET_XMIT_SUCCESS)) { - sch->qstats.requeues++; - sch->q.qlen++; - } - return ret; -} - static struct sk_buff * red_dequeue(struct Qdisc* sch) { struct sk_buff *skb; @@ -140,6 +123,14 @@ static struct sk_buff * red_dequeue(struct Qdisc* sch) return skb; } +static struct sk_buff * red_peek(struct Qdisc* sch) +{ + struct red_sched_data *q = qdisc_priv(sch); + struct Qdisc *child = q->qdisc; + + return child->ops->peek(child); +} + static unsigned int red_drop(struct Qdisc* sch) { struct red_sched_data *q = qdisc_priv(sch); @@ -211,7 +202,8 @@ static int red_change(struct Qdisc *sch, struct nlattr *opt) q->limit = ctl->limit; if (child) { qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); - qdisc_destroy(xchg(&q->qdisc, child)); + qdisc_destroy(q->qdisc); + q->qdisc = child; } red_set_parms(&q->parms, ctl->qth_min, ctl->qth_max, ctl->Wlog, @@ -292,7 +284,8 @@ static int red_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, new = &noop_qdisc; sch_tree_lock(sch); - *old = xchg(&q->qdisc, new); + *old = q->qdisc; + q->qdisc = new; qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); qdisc_reset(*old); sch_tree_unlock(sch); @@ -361,7 +354,7 @@ static struct Qdisc_ops red_qdisc_ops __read_mostly = { .cl_ops = &red_class_ops, .enqueue = red_enqueue, .dequeue = red_dequeue, - .requeue = red_requeue, + .peek = red_peek, .drop = red_drop, .init = red_init, .reset = red_reset, diff --git a/net/sched/sch_sfq.c b/net/sched/sch_sfq.c index fe1508ef0d3d51e7d552a88e253a1d4b0b82fec6..f3965df00559d970e4b46d871014ac9e08c8c5de 100644 --- a/net/sched/sch_sfq.c +++ b/net/sched/sch_sfq.c @@ -281,7 +281,7 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) struct sfq_sched_data *q = qdisc_priv(sch); unsigned int hash; sfq_index x; - int ret; + int uninitialized_var(ret); hash = sfq_classify(skb, sch, &ret); if (hash == 0) { @@ -329,71 +329,20 @@ sfq_enqueue(struct sk_buff *skb, struct Qdisc *sch) return NET_XMIT_CN; } -static int -sfq_requeue(struct sk_buff *skb, struct Qdisc *sch) +static struct sk_buff * +sfq_peek(struct Qdisc *sch) { struct sfq_sched_data *q = qdisc_priv(sch); - unsigned int hash; - sfq_index x; - int ret; - - hash = sfq_classify(skb, sch, &ret); - if (hash == 0) { - if (ret & __NET_XMIT_BYPASS) - sch->qstats.drops++; - kfree_skb(skb); - return ret; - } - hash--; + sfq_index a; - x = q->ht[hash]; - if (x == SFQ_DEPTH) { - q->ht[hash] = x = q->dep[SFQ_DEPTH].next; - q->hash[x] = hash; - } - - sch->qstats.backlog += qdisc_pkt_len(skb); - __skb_queue_head(&q->qs[x], skb); - /* If selected queue has length q->limit+1, this means that - * all another queues are empty and we do simple tail drop. - * This packet is still requeued at head of queue, tail packet - * is dropped. - */ - if (q->qs[x].qlen > q->limit) { - skb = q->qs[x].prev; - __skb_unlink(skb, &q->qs[x]); - sch->qstats.drops++; - sch->qstats.backlog -= qdisc_pkt_len(skb); - kfree_skb(skb); - return NET_XMIT_CN; - } - - sfq_inc(q, x); - if (q->qs[x].qlen == 1) { /* The flow is new */ - if (q->tail == SFQ_DEPTH) { /* It is the first flow */ - q->tail = x; - q->next[x] = x; - q->allot[x] = q->quantum; - } else { - q->next[x] = q->next[q->tail]; - q->next[q->tail] = x; - q->tail = x; - } - } - - if (++sch->q.qlen <= q->limit) { - sch->qstats.requeues++; - return 0; - } + /* No active slots */ + if (q->tail == SFQ_DEPTH) + return NULL; - sch->qstats.drops++; - sfq_drop(sch); - return NET_XMIT_CN; + a = q->next[q->tail]; + return skb_peek(&q->qs[a]); } - - - static struct sk_buff * sfq_dequeue(struct Qdisc *sch) { @@ -624,7 +573,7 @@ static struct Qdisc_ops sfq_qdisc_ops __read_mostly = { .priv_size = sizeof(struct sfq_sched_data), .enqueue = sfq_enqueue, .dequeue = sfq_dequeue, - .requeue = sfq_requeue, + .peek = sfq_peek, .drop = sfq_drop, .init = sfq_init, .reset = sfq_reset, diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c index 94c61598b86ae1c0f52a23817f797a216b77492f..a2f93c09f3cc2490b5131df91659112b3fc10693 100644 --- a/net/sched/sch_tbf.c +++ b/net/sched/sch_tbf.c @@ -139,19 +139,6 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc* sch) return 0; } -static int tbf_requeue(struct sk_buff *skb, struct Qdisc* sch) -{ - struct tbf_sched_data *q = qdisc_priv(sch); - int ret; - - if ((ret = q->qdisc->ops->requeue(skb, q->qdisc)) == 0) { - sch->q.qlen++; - sch->qstats.requeues++; - } - - return ret; -} - static unsigned int tbf_drop(struct Qdisc* sch) { struct tbf_sched_data *q = qdisc_priv(sch); @@ -169,7 +156,7 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch) struct tbf_sched_data *q = qdisc_priv(sch); struct sk_buff *skb; - skb = q->qdisc->dequeue(q->qdisc); + skb = q->qdisc->ops->peek(q->qdisc); if (skb) { psched_time_t now; @@ -192,6 +179,10 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch) toks -= L2T(q, len); if ((toks|ptoks) >= 0) { + skb = qdisc_dequeue_peeked(q->qdisc); + if (unlikely(!skb)) + return NULL; + q->t_c = now; q->tokens = toks; q->ptokens = ptoks; @@ -214,12 +205,6 @@ static struct sk_buff *tbf_dequeue(struct Qdisc* sch) (cf. CSZ, HPFQ, HFSC) */ - if (q->qdisc->ops->requeue(skb, q->qdisc) != NET_XMIT_SUCCESS) { - /* When requeue fails skb is dropped */ - qdisc_tree_decrease_qlen(q->qdisc, 1); - sch->qstats.drops++; - } - sch->qstats.overlimits++; } return NULL; @@ -251,6 +236,7 @@ static int tbf_change(struct Qdisc* sch, struct nlattr *opt) struct tc_tbf_qopt *qopt; struct qdisc_rate_table *rtab = NULL; struct qdisc_rate_table *ptab = NULL; + struct qdisc_rate_table *tmp; struct Qdisc *child = NULL; int max_size,n; @@ -299,7 +285,8 @@ static int tbf_change(struct Qdisc* sch, struct nlattr *opt) sch_tree_lock(sch); if (child) { qdisc_tree_decrease_qlen(q->qdisc, q->qdisc->q.qlen); - qdisc_destroy(xchg(&q->qdisc, child)); + qdisc_destroy(q->qdisc); + q->qdisc = child; } q->limit = qopt->limit; q->mtu = qopt->mtu; @@ -307,8 +294,14 @@ static int tbf_change(struct Qdisc* sch, struct nlattr *opt) q->buffer = qopt->buffer; q->tokens = q->buffer; q->ptokens = q->mtu; - rtab = xchg(&q->R_tab, rtab); - ptab = xchg(&q->P_tab, ptab); + + tmp = q->R_tab; + q->R_tab = rtab; + rtab = tmp; + + tmp = q->P_tab; + q->P_tab = ptab; + ptab = tmp; sch_tree_unlock(sch); err = 0; done: @@ -398,7 +391,8 @@ static int tbf_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new, new = &noop_qdisc; sch_tree_lock(sch); - *old = xchg(&q->qdisc, new); + *old = q->qdisc; + q->qdisc = new; qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); qdisc_reset(*old); sch_tree_unlock(sch); @@ -469,7 +463,7 @@ static struct Qdisc_ops tbf_qdisc_ops __read_mostly = { .priv_size = sizeof(struct tbf_sched_data), .enqueue = tbf_enqueue, .dequeue = tbf_dequeue, - .requeue = tbf_requeue, + .peek = qdisc_peek_dequeued, .drop = tbf_drop, .init = tbf_init, .reset = tbf_reset, diff --git a/net/sched/sch_teql.c b/net/sched/sch_teql.c index d35ef059abb1781e41becb98e6b1a15e3596001b..cfc8e7caba6223f62cbe998c24491aed533a306d 100644 --- a/net/sched/sch_teql.c +++ b/net/sched/sch_teql.c @@ -93,16 +93,6 @@ teql_enqueue(struct sk_buff *skb, struct Qdisc* sch) return NET_XMIT_DROP; } -static int -teql_requeue(struct sk_buff *skb, struct Qdisc* sch) -{ - struct teql_sched_data *q = qdisc_priv(sch); - - __skb_queue_head(&q->q, skb); - sch->qstats.requeues++; - return 0; -} - static struct sk_buff * teql_dequeue(struct Qdisc* sch) { @@ -123,6 +113,13 @@ teql_dequeue(struct Qdisc* sch) return skb; } +static struct sk_buff * +teql_peek(struct Qdisc* sch) +{ + /* teql is meant to be used as root qdisc */ + return NULL; +} + static __inline__ void teql_neigh_release(struct neighbour *n) { @@ -433,7 +430,7 @@ static __init void teql_master_setup(struct net_device *dev) ops->enqueue = teql_enqueue; ops->dequeue = teql_dequeue; - ops->requeue = teql_requeue; + ops->peek = teql_peek; ops->init = teql_qdisc_init; ops->reset = teql_reset; ops->destroy = teql_destroy; diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 4124bbb9994774cc6536cd1dd8f092202ca68d6e..ceaa4aa066eaea3e00162d200f6d9bcb0c1d31f3 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -223,10 +223,9 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport) ipv6_addr_copy(&fl.fl6_dst, rt0->addr); } - SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, " - "src:" NIP6_FMT " dst:" NIP6_FMT "\n", + SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb, skb->len, - NIP6(fl.fl6_src), NIP6(fl.fl6_dst)); + &fl.fl6_src, &fl.fl6_dst); SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS); @@ -252,23 +251,19 @@ static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, fl.oif = daddr->v6.sin6_scope_id; - SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ", - __func__, NIP6(fl.fl6_dst)); + SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl.fl6_dst); if (saddr) { ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr); - SCTP_DEBUG_PRINTK( - "SRC=" NIP6_FMT " - ", - NIP6(fl.fl6_src)); + SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl.fl6_src); } dst = ip6_route_output(&init_net, NULL, &fl); if (!dst->error) { struct rt6_info *rt; rt = (struct rt6_info *)dst; - SCTP_DEBUG_PRINTK( - "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n", - NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr)); + SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", + &rt->rt6i_dst.addr, &rt->rt6i_src.addr); return dst; } SCTP_DEBUG_PRINTK("NO ROUTE\n"); @@ -314,9 +309,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk, __u8 matchlen = 0; __u8 bmatchlen; - SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p " - "daddr:" NIP6_FMT " ", - __func__, asoc, dst, NIP6(daddr->v6.sin6_addr)); + SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ", + __func__, asoc, dst, &daddr->v6.sin6_addr); if (!asoc) { ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)), @@ -324,8 +318,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk, &daddr->v6.sin6_addr, inet6_sk(&sk->inet.sk)->srcprefs, &saddr->v6.sin6_addr); - SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n", - NIP6(saddr->v6.sin6_addr)); + SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n", + &saddr->v6.sin6_addr); return; } @@ -353,12 +347,11 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk, if (baddr) { memcpy(saddr, baddr, sizeof(union sctp_addr)); - SCTP_DEBUG_PRINTK("saddr: " NIP6_FMT "\n", - NIP6(saddr->v6.sin6_addr)); + SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr); } else { printk(KERN_ERR "%s: asoc:%p Could not find a valid source " - "address for the dest:" NIP6_FMT "\n", - __func__, asoc, NIP6(daddr->v6.sin6_addr)); + "address for the dest:%pI6\n", + __func__, asoc, &daddr->v6.sin6_addr); } rcu_read_unlock(); @@ -727,7 +720,7 @@ static int sctp_v6_is_ce(const struct sk_buff *skb) /* Dump the v6 addr to the seq file. */ static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr) { - seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr)); + seq_printf(seq, "%pI6 ", &addr->v6.sin6_addr); } static void sctp_v6_ecn_capable(struct sock *sk) diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 0b65354aaf64978a68836f1cb9754e4101cbc35b..b78e3be6901398f7a62b76a291fb8954341aacc0 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -102,6 +102,8 @@ struct sock *sctp_get_ctl_sock(void) /* Set up the proc fs entry for the SCTP protocol. */ static __init int sctp_proc_init(void) { + if (percpu_counter_init(&sctp_sockets_allocated, 0)) + goto out_nomem; #ifdef CONFIG_PROC_FS if (!proc_net_sctp) { struct proc_dir_entry *ent; @@ -110,7 +112,7 @@ static __init int sctp_proc_init(void) ent->owner = THIS_MODULE; proc_net_sctp = ent; } else - goto out_nomem; + goto out_free_percpu; } if (sctp_snmp_proc_init()) @@ -135,11 +137,14 @@ out_snmp_proc_init: proc_net_sctp = NULL; remove_proc_entry("sctp", init_net.proc_net); } -out_nomem: - return -ENOMEM; +out_free_percpu: + percpu_counter_destroy(&sctp_sockets_allocated); #else return 0; #endif /* CONFIG_PROC_FS */ + +out_nomem: + return -ENOMEM; } /* Clean up the proc fs entry for the SCTP protocol. @@ -482,9 +487,8 @@ static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc, if (saddr) fl.fl4_src = saddr->v4.sin_addr.s_addr; - SCTP_DEBUG_PRINTK("%s: DST:%u.%u.%u.%u, SRC:%u.%u.%u.%u - ", - __func__, NIPQUAD(fl.fl4_dst), - NIPQUAD(fl.fl4_src)); + SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ", + __func__, &fl.fl4_dst, &fl.fl4_src); if (!ip_route_output_key(&init_net, &rt, &fl)) { dst = &rt->u.dst; @@ -540,8 +544,8 @@ out_unlock: rcu_read_unlock(); out: if (dst) - SCTP_DEBUG_PRINTK("rt_dst:%u.%u.%u.%u, rt_src:%u.%u.%u.%u\n", - NIPQUAD(rt->rt_dst), NIPQUAD(rt->rt_src)); + SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n", + &rt->rt_dst, &rt->rt_src); else SCTP_DEBUG_PRINTK("NO ROUTE\n"); @@ -646,7 +650,7 @@ static void sctp_v4_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr) /* Dump the v4 addr to the seq file. */ static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr) { - seq_printf(seq, "%d.%d.%d.%d ", NIPQUAD(addr->v4.sin_addr)); + seq_printf(seq, "%pI4 ", &addr->v4.sin_addr); } static void sctp_v4_ecn_capable(struct sock *sk) @@ -866,11 +870,10 @@ static inline int sctp_v4_xmit(struct sk_buff *skb, { struct inet_sock *inet = inet_sk(skb->sk); - SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, " - "src:%u.%u.%u.%u, dst:%u.%u.%u.%u\n", + SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, skb->len, - NIPQUAD(skb->rtable->rt_src), - NIPQUAD(skb->rtable->rt_dst)); + &skb->rtable->rt_src, + &skb->rtable->rt_dst); inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index a6a0ea71ae93147813abdec8bdd2d3f040950ce3..1c4e5d6c29c07e9c1905235d4adcd1774bee3117 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -1123,19 +1123,17 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep, if (from_addr.sa.sa_family == AF_INET6) { if (net_ratelimit()) printk(KERN_WARNING - "%s association %p could not find address " - NIP6_FMT "\n", + "%s association %p could not find address %pI6\n", __func__, asoc, - NIP6(from_addr.v6.sin6_addr)); + &from_addr.v6.sin6_addr); } else { if (net_ratelimit()) printk(KERN_WARNING - "%s association %p could not find address " - NIPQUAD_FMT "\n", + "%s association %p could not find address %pI4\n", __func__, asoc, - NIPQUAD(from_addr.v4.sin_addr.s_addr)); + &from_addr.v4.sin_addr.s_addr); } return SCTP_DISPOSITION_DISCARD; } @@ -3691,6 +3689,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep, { struct sctp_chunk *chunk = arg; struct sctp_fwdtsn_hdr *fwdtsn_hdr; + struct sctp_fwdtsn_skip *skip; __u16 len; __u32 tsn; @@ -3720,6 +3719,12 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep, if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) goto discard_noforce; + /* Silently discard the chunk if stream-id is not valid */ + sctp_walk_fwdtsn(skip, chunk) { + if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) + goto discard_noforce; + } + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); if (len > sizeof(struct sctp_fwdtsn_hdr)) sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, @@ -3751,6 +3756,7 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast( { struct sctp_chunk *chunk = arg; struct sctp_fwdtsn_hdr *fwdtsn_hdr; + struct sctp_fwdtsn_skip *skip; __u16 len; __u32 tsn; @@ -3780,6 +3786,12 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast( if (sctp_tsnmap_check(&asoc->peer.tsn_map, tsn) < 0) goto gen_shutdown; + /* Silently discard the chunk if stream-id is not valid */ + sctp_walk_fwdtsn(skip, chunk) { + if (ntohs(skip->stream) >= asoc->c.sinit_max_instreams) + goto gen_shutdown; + } + sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_FWDTSN, SCTP_U32(tsn)); if (len > sizeof(struct sctp_fwdtsn_hdr)) sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_FWDTSN, diff --git a/net/sctp/socket.c b/net/sctp/socket.c index a1b904529d5e1c3e12ba0a6c1ff7bfbc2b5dbddb..b14a8f33e42d6ad26a2e6fc3005943cc266d8434 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -114,7 +114,7 @@ extern int sysctl_sctp_wmem[3]; static int sctp_memory_pressure; static atomic_t sctp_memory_allocated; -static atomic_t sctp_sockets_allocated; +struct percpu_counter sctp_sockets_allocated; static void sctp_enter_memory_pressure(struct sock *sk) { @@ -2404,9 +2404,9 @@ static int sctp_setsockopt_delayed_ack(struct sock *sk, if (params.sack_delay == 0 && params.sack_freq == 0) return 0; } else if (optlen == sizeof(struct sctp_assoc_value)) { - printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info " + printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value " "in delayed_ack socket option deprecated\n"); - printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n"); + printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n"); if (copy_from_user(¶ms, optval, optlen)) return -EFAULT; @@ -2778,32 +2778,77 @@ static int sctp_setsockopt_mappedv4(struct sock *sk, char __user *optval, int op } /* - * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) - * - * This socket option specifies the maximum size to put in any outgoing - * SCTP chunk. If a message is larger than this size it will be + * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) + * This option will get or set the maximum size to put in any outgoing + * SCTP DATA chunk. If a message is larger than this size it will be * fragmented by SCTP into the specified size. Note that the underlying * SCTP implementation may fragment into smaller sized chunks when the * PMTU of the underlying association is smaller than the value set by - * the user. + * the user. The default value for this option is '0' which indicates + * the user is NOT limiting fragmentation and only the PMTU will effect + * SCTP's choice of DATA chunk size. Note also that values set larger + * than the maximum size of an IP datagram will effectively let SCTP + * control fragmentation (i.e. the same as setting this option to 0). + * + * The following structure is used to access and modify this parameter: + * + * struct sctp_assoc_value { + * sctp_assoc_t assoc_id; + * uint32_t assoc_value; + * }; + * + * assoc_id: This parameter is ignored for one-to-one style sockets. + * For one-to-many style sockets this parameter indicates which + * association the user is performing an action upon. Note that if + * this field's value is zero then the endpoints default value is + * changed (effecting future associations only). + * assoc_value: This parameter specifies the maximum size in bytes. */ static int sctp_setsockopt_maxseg(struct sock *sk, char __user *optval, int optlen) { + struct sctp_assoc_value params; struct sctp_association *asoc; struct sctp_sock *sp = sctp_sk(sk); int val; - if (optlen < sizeof(int)) + if (optlen == sizeof(int)) { + printk(KERN_WARNING + "SCTP: Use of int in maxseg socket option deprecated\n"); + printk(KERN_WARNING + "SCTP: Use struct sctp_assoc_value instead\n"); + if (copy_from_user(&val, optval, optlen)) + return -EFAULT; + params.assoc_id = 0; + } else if (optlen == sizeof(struct sctp_assoc_value)) { + if (copy_from_user(¶ms, optval, optlen)) + return -EFAULT; + val = params.assoc_value; + } else return -EINVAL; - if (get_user(val, (int __user *)optval)) - return -EFAULT; + if ((val != 0) && ((val < 8) || (val > SCTP_MAX_CHUNK_LEN))) return -EINVAL; - sp->user_frag = val; - /* Update the frag_point of the existing associations. */ - list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { - asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); + asoc = sctp_id2assoc(sk, params.assoc_id); + if (!asoc && params.assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + if (asoc) { + if (val == 0) { + val = asoc->pathmtu; + val -= sp->pf->af->net_header_len; + val -= sizeof(struct sctphdr) + + sizeof(struct sctp_data_chunk); + } + + asoc->frag_point = val; + } else { + sp->user_frag = val; + + /* Update the frag_point of the existing associations. */ + list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { + asoc->frag_point = sctp_frag_point(sp, asoc->pathmtu); + } } return 0; @@ -2965,14 +3010,21 @@ static int sctp_setsockopt_fragment_interleave(struct sock *sk, } /* - * 7.1.25. Set or Get the sctp partial delivery point + * 8.1.21. Set or Get the SCTP Partial Delivery Point * (SCTP_PARTIAL_DELIVERY_POINT) + * * This option will set or get the SCTP partial delivery point. This * point is the size of a message where the partial delivery API will be * invoked to help free up rwnd space for the peer. Setting this to a - * lower value will cause partial delivery's to happen more often. The + * lower value will cause partial deliveries to happen more often. The * calls argument is an integer that sets or gets the partial delivery - * point. + * point. Note also that the call will fail if the user attempts to set + * this value larger than the socket receive buffer size. + * + * Note that any single message having a length smaller than or equal to + * the SCTP partial delivery point will be delivered in one single read + * call as long as the user provided buffer is large enough to hold the + * message. */ static int sctp_setsockopt_partial_delivery_point(struct sock *sk, char __user *optval, @@ -2985,6 +3037,12 @@ static int sctp_setsockopt_partial_delivery_point(struct sock *sk, if (get_user(val, (int __user *)optval)) return -EFAULT; + /* Note: We double the receive buffer from what the user sets + * it to be, also initial rwnd is based on rcvbuf/2. + */ + if (val > (sk->sk_rcvbuf >> 1)) + return -EINVAL; + sctp_sk(sk)->pd_point = val; return 0; /* is this the right error code? */ @@ -3613,7 +3671,12 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) sp->hmac = NULL; SCTP_DBG_OBJCNT_INC(sock); - atomic_inc(&sctp_sockets_allocated); + percpu_counter_inc(&sctp_sockets_allocated); + + local_bh_disable(); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + local_bh_enable(); + return 0; } @@ -3627,7 +3690,10 @@ SCTP_STATIC void sctp_destroy_sock(struct sock *sk) /* Release our hold on the endpoint. */ ep = sctp_sk(sk)->ep; sctp_endpoint_free(ep); - atomic_dec(&sctp_sockets_allocated); + percpu_counter_dec(&sctp_sockets_allocated); + local_bh_disable(); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + local_bh_enable(); } /* API 4.1.7 shutdown() - TCP Style Syntax @@ -4168,9 +4234,9 @@ static int sctp_getsockopt_delayed_ack(struct sock *sk, int len, if (copy_from_user(¶ms, optval, len)) return -EFAULT; } else if (len == sizeof(struct sctp_assoc_value)) { - printk(KERN_WARNING "SCTP: Use of struct sctp_sack_info " + printk(KERN_WARNING "SCTP: Use of struct sctp_assoc_value " "in delayed_ack socket option deprecated\n"); - printk(KERN_WARNING "SCTP: struct sctp_sack_info instead\n"); + printk(KERN_WARNING "SCTP: Use struct sctp_sack_info instead\n"); if (copy_from_user(¶ms, optval, len)) return -EFAULT; } else @@ -5092,30 +5158,69 @@ static int sctp_getsockopt_context(struct sock *sk, int len, } /* - * 7.1.17 Set the maximum fragrmentation size (SCTP_MAXSEG) - * - * This socket option specifies the maximum size to put in any outgoing - * SCTP chunk. If a message is larger than this size it will be + * 8.1.16. Get or Set the Maximum Fragmentation Size (SCTP_MAXSEG) + * This option will get or set the maximum size to put in any outgoing + * SCTP DATA chunk. If a message is larger than this size it will be * fragmented by SCTP into the specified size. Note that the underlying * SCTP implementation may fragment into smaller sized chunks when the * PMTU of the underlying association is smaller than the value set by - * the user. + * the user. The default value for this option is '0' which indicates + * the user is NOT limiting fragmentation and only the PMTU will effect + * SCTP's choice of DATA chunk size. Note also that values set larger + * than the maximum size of an IP datagram will effectively let SCTP + * control fragmentation (i.e. the same as setting this option to 0). + * + * The following structure is used to access and modify this parameter: + * + * struct sctp_assoc_value { + * sctp_assoc_t assoc_id; + * uint32_t assoc_value; + * }; + * + * assoc_id: This parameter is ignored for one-to-one style sockets. + * For one-to-many style sockets this parameter indicates which + * association the user is performing an action upon. Note that if + * this field's value is zero then the endpoints default value is + * changed (effecting future associations only). + * assoc_value: This parameter specifies the maximum size in bytes. */ static int sctp_getsockopt_maxseg(struct sock *sk, int len, char __user *optval, int __user *optlen) { - int val; + struct sctp_assoc_value params; + struct sctp_association *asoc; - if (len < sizeof(int)) + if (len == sizeof(int)) { + printk(KERN_WARNING + "SCTP: Use of int in maxseg socket option deprecated\n"); + printk(KERN_WARNING + "SCTP: Use struct sctp_assoc_value instead\n"); + params.assoc_id = 0; + } else if (len >= sizeof(struct sctp_assoc_value)) { + len = sizeof(struct sctp_assoc_value); + if (copy_from_user(¶ms, optval, sizeof(params))) + return -EFAULT; + } else return -EINVAL; - len = sizeof(int); + asoc = sctp_id2assoc(sk, params.assoc_id); + if (!asoc && params.assoc_id && sctp_style(sk, UDP)) + return -EINVAL; + + if (asoc) + params.assoc_value = asoc->frag_point; + else + params.assoc_value = sctp_sk(sk)->user_frag; - val = sctp_sk(sk)->user_frag; if (put_user(len, optlen)) return -EFAULT; - if (copy_to_user(optval, &val, len)) - return -EFAULT; + if (len == sizeof(int)) { + if (copy_to_user(optval, ¶ms.assoc_value, len)) + return -EFAULT; + } else { + if (copy_to_user(optval, ¶ms, len)) + return -EFAULT; + } return 0; } @@ -5368,6 +5473,38 @@ num: return 0; } +/* + * 8.2.5. Get the Current Number of Associations (SCTP_GET_ASSOC_NUMBER) + * This option gets the current number of associations that are attached + * to a one-to-many style socket. The option value is an uint32_t. + */ +static int sctp_getsockopt_assoc_number(struct sock *sk, int len, + char __user *optval, int __user *optlen) +{ + struct sctp_sock *sp = sctp_sk(sk); + struct sctp_association *asoc; + u32 val = 0; + + if (sctp_style(sk, TCP)) + return -EOPNOTSUPP; + + if (len < sizeof(u32)) + return -EINVAL; + + len = sizeof(u32); + + list_for_each_entry(asoc, &(sp->ep->asocs), asocs) { + val++; + } + + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + + return 0; +} + SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char __user *optval, int __user *optlen) { @@ -5510,6 +5647,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, retval = sctp_getsockopt_local_auth_chunks(sk, len, optval, optlen); break; + case SCTP_GET_ASSOC_NUMBER: + retval = sctp_getsockopt_assoc_number(sk, len, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; diff --git a/net/sctp/sysctl.c b/net/sctp/sysctl.c index 52910697e104ceaadae120adcd1e5c8375b2c658..f58e994e6852f72a956c24afbc17258f49955aa0 100644 --- a/net/sctp/sysctl.c +++ b/net/sctp/sysctl.c @@ -63,8 +63,8 @@ static ctl_table sctp_table[] = { .data = &sctp_rto_initial, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &one, .extra2 = &timer_max }, @@ -74,8 +74,8 @@ static ctl_table sctp_table[] = { .data = &sctp_rto_min, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &one, .extra2 = &timer_max }, @@ -85,8 +85,8 @@ static ctl_table sctp_table[] = { .data = &sctp_rto_max, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &one, .extra2 = &timer_max }, @@ -96,8 +96,8 @@ static ctl_table sctp_table[] = { .data = &sctp_valid_cookie_life, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &one, .extra2 = &timer_max }, @@ -107,8 +107,8 @@ static ctl_table sctp_table[] = { .data = &sctp_max_burst, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &zero, .extra2 = &int_max }, @@ -118,8 +118,8 @@ static ctl_table sctp_table[] = { .data = &sctp_max_retrans_association, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &one, .extra2 = &int_max }, @@ -129,8 +129,8 @@ static ctl_table sctp_table[] = { .data = &sctp_sndbuf_policy, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec }, { .ctl_name = NET_SCTP_RCVBUF_POLICY, @@ -138,8 +138,8 @@ static ctl_table sctp_table[] = { .data = &sctp_rcvbuf_policy, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec }, { .ctl_name = NET_SCTP_PATH_MAX_RETRANS, @@ -147,8 +147,8 @@ static ctl_table sctp_table[] = { .data = &sctp_max_retrans_path, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &one, .extra2 = &int_max }, @@ -158,8 +158,8 @@ static ctl_table sctp_table[] = { .data = &sctp_max_retrans_init, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &one, .extra2 = &int_max }, @@ -169,8 +169,8 @@ static ctl_table sctp_table[] = { .data = &sctp_hb_interval, .maxlen = sizeof(unsigned int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &one, .extra2 = &timer_max }, @@ -180,8 +180,8 @@ static ctl_table sctp_table[] = { .data = &sctp_cookie_preserve_enable, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec }, { .ctl_name = NET_SCTP_RTO_ALPHA, @@ -189,8 +189,8 @@ static ctl_table sctp_table[] = { .data = &sctp_rto_alpha, .maxlen = sizeof(int), .mode = 0444, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec }, { .ctl_name = NET_SCTP_RTO_BETA, @@ -198,8 +198,8 @@ static ctl_table sctp_table[] = { .data = &sctp_rto_beta, .maxlen = sizeof(int), .mode = 0444, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec }, { .ctl_name = NET_SCTP_ADDIP_ENABLE, @@ -207,8 +207,8 @@ static ctl_table sctp_table[] = { .data = &sctp_addip_enable, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec }, { .ctl_name = NET_SCTP_PRSCTP_ENABLE, @@ -216,8 +216,8 @@ static ctl_table sctp_table[] = { .data = &sctp_prsctp_enable, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec }, { .ctl_name = NET_SCTP_SACK_TIMEOUT, @@ -225,8 +225,8 @@ static ctl_table sctp_table[] = { .data = &sctp_sack_timeout, .maxlen = sizeof(long), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &sack_timer_min, .extra2 = &sack_timer_max, }, @@ -236,7 +236,7 @@ static ctl_table sctp_table[] = { .data = &sysctl_sctp_mem, .maxlen = sizeof(sysctl_sctp_mem), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = CTL_UNNUMBERED, @@ -244,7 +244,7 @@ static ctl_table sctp_table[] = { .data = &sysctl_sctp_rmem, .maxlen = sizeof(sysctl_sctp_rmem), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = CTL_UNNUMBERED, @@ -252,7 +252,7 @@ static ctl_table sctp_table[] = { .data = &sysctl_sctp_wmem, .maxlen = sizeof(sysctl_sctp_wmem), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { .ctl_name = CTL_UNNUMBERED, @@ -260,8 +260,8 @@ static ctl_table sctp_table[] = { .data = &sctp_auth_enable, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec }, { .ctl_name = CTL_UNNUMBERED, @@ -269,8 +269,8 @@ static ctl_table sctp_table[] = { .data = &sctp_addip_noauth, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, - .strategy = &sysctl_intvec + .proc_handler = proc_dointvec, + .strategy = sysctl_intvec }, { .ctl_name = 0 } }; diff --git a/net/socket.c b/net/socket.c index 072e2e525ae6a783c79a02654436e04758e6b294..2c730fc718ab4f28f2135893ccd9683def86be78 100644 --- a/net/socket.c +++ b/net/socket.c @@ -69,7 +69,6 @@ #include #include #include -#include #include #include #include diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 4895c341e46d03b2ad31b23c229e58876dce1c68..3ca518386d15d33959ea12a0fc1315d1e8499b98 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -271,15 +271,15 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *)args->address; - snprintf(servername, sizeof(servername), NIPQUAD_FMT, - NIPQUAD(sin->sin_addr.s_addr)); + snprintf(servername, sizeof(servername), "%pI4", + &sin->sin_addr.s_addr); break; } case AF_INET6: { struct sockaddr_in6 *sin = (struct sockaddr_in6 *)args->address; - snprintf(servername, sizeof(servername), NIP6_FMT, - NIP6(sin->sin6_addr)); + snprintf(servername, sizeof(servername), "%pI6", + &sin->sin6_addr); break; } default: diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 41013dd66ac3f3e61e4823ef853911e179efc46b..03ae007641e48523ee22cbd4aa4d5cef825b84c5 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -270,10 +270,9 @@ static int rpcb_register_netid4(struct sockaddr_in *address_to_register, char buf[32]; /* Construct AF_INET universal address */ - snprintf(buf, sizeof(buf), - NIPQUAD_FMT".%u.%u", - NIPQUAD(address_to_register->sin_addr.s_addr), - port >> 8, port & 0xff); + snprintf(buf, sizeof(buf), "%pI4.%u.%u", + &address_to_register->sin_addr.s_addr, + port >> 8, port & 0xff); map->r_addr = buf; dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " @@ -305,9 +304,9 @@ static int rpcb_register_netid6(struct sockaddr_in6 *address_to_register, snprintf(buf, sizeof(buf), "::.%u.%u", port >> 8, port & 0xff); else - snprintf(buf, sizeof(buf), NIP6_FMT".%u.%u", - NIP6(address_to_register->sin6_addr), - port >> 8, port & 0xff); + snprintf(buf, sizeof(buf), "%pI6.%u.%u", + &address_to_register->sin6_addr, + port >> 8, port & 0xff); map->r_addr = buf; dprintk("RPC: %sregistering [%u, %u, %s, '%s'] with " @@ -422,8 +421,8 @@ int rpcb_getport_sync(struct sockaddr_in *sin, u32 prog, u32 vers, int prot) struct rpc_clnt *rpcb_clnt; int status; - dprintk("RPC: %s(" NIPQUAD_FMT ", %u, %u, %d)\n", - __func__, NIPQUAD(sin->sin_addr.s_addr), prog, vers, prot); + dprintk("RPC: %s(%pI4, %u, %u, %d)\n", + __func__, &sin->sin_addr.s_addr, prog, vers, prot); rpcb_clnt = rpcb_create(NULL, (struct sockaddr *)sin, sizeof(*sin), prot, RPCBVERS_2); diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c index f24800f2c098c3b83d812881af05947b062a1ed3..82240e6127b2ce08b597f8ad2885b5eb86d5ab1d 100644 --- a/net/sunrpc/svcauth_unix.c +++ b/net/sunrpc/svcauth_unix.c @@ -162,13 +162,9 @@ static void ip_map_request(struct cache_detail *cd, struct ip_map *im = container_of(h, struct ip_map, h); if (ipv6_addr_v4mapped(&(im->m_addr))) { - snprintf(text_addr, 20, NIPQUAD_FMT, - ntohl(im->m_addr.s6_addr32[3]) >> 24 & 0xff, - ntohl(im->m_addr.s6_addr32[3]) >> 16 & 0xff, - ntohl(im->m_addr.s6_addr32[3]) >> 8 & 0xff, - ntohl(im->m_addr.s6_addr32[3]) >> 0 & 0xff); + snprintf(text_addr, 20, "%pI4", &im->m_addr.s6_addr32[3]); } else { - snprintf(text_addr, 40, NIP6_FMT, NIP6(im->m_addr)); + snprintf(text_addr, 40, "%pI6", &im->m_addr); } qword_add(bpp, blen, im->m_class); qword_add(bpp, blen, text_addr); @@ -208,13 +204,13 @@ static int ip_map_parse(struct cache_detail *cd, len = qword_get(&mesg, buf, mlen); if (len <= 0) return -EINVAL; - if (sscanf(buf, NIPQUAD_FMT "%c", &b1, &b2, &b3, &b4, &c) == 4) { + if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) == 4) { addr.s6_addr32[0] = 0; addr.s6_addr32[1] = 0; addr.s6_addr32[2] = htonl(0xffff); addr.s6_addr32[3] = htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); - } else if (sscanf(buf, NIP6_FMT "%c", + } else if (sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x%c", &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) { addr.s6_addr16[0] = htons(b1); addr.s6_addr16[1] = htons(b2); @@ -278,16 +274,10 @@ static int ip_map_show(struct seq_file *m, dom = im->m_client->h.name; if (ipv6_addr_v4mapped(&addr)) { - seq_printf(m, "%s " NIPQUAD_FMT " %s\n", - im->m_class, - ntohl(addr.s6_addr32[3]) >> 24 & 0xff, - ntohl(addr.s6_addr32[3]) >> 16 & 0xff, - ntohl(addr.s6_addr32[3]) >> 8 & 0xff, - ntohl(addr.s6_addr32[3]) >> 0 & 0xff, - dom); + seq_printf(m, "%s %pI4 %s\n", + im->m_class, &addr.s6_addr32[3], dom); } else { - seq_printf(m, "%s " NIP6_FMT " %s\n", - im->m_class, NIP6(addr), dom); + seq_printf(m, "%s %pI6 %s\n", im->m_class, &addr, dom); } return 0; } diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index a1951dcc577614df63fc0a3ab1e5ce92dce9d7ab..ef3238d665ee6ff37c22f7bbfd116756db18e8b5 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -250,10 +250,10 @@ static int one_sock_name(char *buf, struct svc_sock *svsk) switch(svsk->sk_sk->sk_family) { case AF_INET: - len = sprintf(buf, "ipv4 %s %u.%u.%u.%u %d\n", - svsk->sk_sk->sk_protocol==IPPROTO_UDP? + len = sprintf(buf, "ipv4 %s %pI4 %d\n", + svsk->sk_sk->sk_protocol == IPPROTO_UDP ? "udp" : "tcp", - NIPQUAD(inet_sk(svsk->sk_sk)->rcv_saddr), + &inet_sk(svsk->sk_sk)->rcv_saddr, inet_sk(svsk->sk_sk)->num); break; default: diff --git a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c index a4756576d68794a1106c4404b39ad9adf510a906..629a28764da9362c773050a5bcde27ecb19d0ed2 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c +++ b/net/sunrpc/xprtrdma/svc_rdma_recvfrom.c @@ -646,8 +646,7 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp) ret = rdma_read_xdr(rdma_xprt, rmsgp, rqstp, ctxt); if (ret > 0) { /* read-list posted, defer until data received from client. */ - svc_xprt_received(xprt); - return 0; + goto defer; } if (ret < 0) { /* Post of read-list failed, free context. */ @@ -679,6 +678,7 @@ int svc_rdma_recvfrom(struct svc_rqst *rqstp) * close bit and call svc_xprt_delete */ set_bit(XPT_CLOSE, &xprt->xpt_flags); +defer: svc_xprt_received(xprt); return 0; } diff --git a/net/sunrpc/xprtrdma/svc_rdma_sendto.c b/net/sunrpc/xprtrdma/svc_rdma_sendto.c index 9a7a8e7ae038fbb255dd34880e7882feb8eff322..a3334e3b73cc19f82c47453ad4da6603153ca0b2 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_sendto.c +++ b/net/sunrpc/xprtrdma/svc_rdma_sendto.c @@ -69,7 +69,7 @@ * array is only concerned with the reply we are assured that we have * on extra page for the RPCRMDA header. */ -int fast_reg_xdr(struct svcxprt_rdma *xprt, +static int fast_reg_xdr(struct svcxprt_rdma *xprt, struct xdr_buf *xdr, struct svc_rdma_req_map *vec) { diff --git a/net/sunrpc/xprtrdma/svc_rdma_transport.c b/net/sunrpc/xprtrdma/svc_rdma_transport.c index 6fb493cbd29fcd2786479965bb526ba343e1b70f..3d810e7df3fb70e491ef5888bcbc329a098db077 100644 --- a/net/sunrpc/xprtrdma/svc_rdma_transport.c +++ b/net/sunrpc/xprtrdma/svc_rdma_transport.c @@ -61,7 +61,7 @@ static int svc_rdma_has_wspace(struct svc_xprt *xprt); static void rq_cq_reap(struct svcxprt_rdma *xprt); static void sq_cq_reap(struct svcxprt_rdma *xprt); -DECLARE_TASKLET(dto_tasklet, dto_tasklet_func, 0UL); +static DECLARE_TASKLET(dto_tasklet, dto_tasklet_func, 0UL); static DEFINE_SPINLOCK(dto_lock); static LIST_HEAD(dto_xprt_q); @@ -827,7 +827,7 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) struct rdma_conn_param conn_param; struct ib_qp_init_attr qp_attr; struct ib_device_attr devattr; - int dma_mr_acc; + int uninitialized_var(dma_mr_acc); int need_dma_mr; int ret; int i; @@ -1048,21 +1048,21 @@ static struct svc_xprt *svc_rdma_accept(struct svc_xprt *xprt) dprintk("svcrdma: new connection %p accepted with the following " "attributes:\n" - " local_ip : %d.%d.%d.%d\n" + " local_ip : %pI4\n" " local_port : %d\n" - " remote_ip : %d.%d.%d.%d\n" + " remote_ip : %pI4\n" " remote_port : %d\n" " max_sge : %d\n" " sq_depth : %d\n" " max_requests : %d\n" " ord : %d\n", newxprt, - NIPQUAD(((struct sockaddr_in *)&newxprt->sc_cm_id-> - route.addr.src_addr)->sin_addr.s_addr), + &((struct sockaddr_in *)&newxprt->sc_cm_id-> + route.addr.src_addr)->sin_addr.s_addr, ntohs(((struct sockaddr_in *)&newxprt->sc_cm_id-> route.addr.src_addr)->sin_port), - NIPQUAD(((struct sockaddr_in *)&newxprt->sc_cm_id-> - route.addr.dst_addr)->sin_addr.s_addr), + &((struct sockaddr_in *)&newxprt->sc_cm_id-> + route.addr.dst_addr)->sin_addr.s_addr, ntohs(((struct sockaddr_in *)&newxprt->sc_cm_id-> route.addr.dst_addr)->sin_port), newxprt->sc_max_sge, diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 9839c3d94145d4b154c71ac754f65f9a52239f63..1dd6123070e94b52023a2f6596462edb3928e860 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c @@ -174,7 +174,7 @@ xprt_rdma_format_addresses(struct rpc_xprt *xprt) buf = kzalloc(20, GFP_KERNEL); if (buf) - snprintf(buf, 20, NIPQUAD_FMT, NIPQUAD(addr->sin_addr.s_addr)); + snprintf(buf, 20, "%pI4", &addr->sin_addr.s_addr); xprt->address_strings[RPC_DISPLAY_ADDR] = buf; buf = kzalloc(8, GFP_KERNEL); @@ -186,8 +186,8 @@ xprt_rdma_format_addresses(struct rpc_xprt *xprt) buf = kzalloc(48, GFP_KERNEL); if (buf) - snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s", - NIPQUAD(addr->sin_addr.s_addr), + snprintf(buf, 48, "addr=%pI4 port=%u proto=%s", + &addr->sin_addr.s_addr, ntohs(addr->sin_port), "rdma"); xprt->address_strings[RPC_DISPLAY_ALL] = buf; @@ -204,8 +204,8 @@ xprt_rdma_format_addresses(struct rpc_xprt *xprt) buf = kzalloc(30, GFP_KERNEL); if (buf) - snprintf(buf, 30, NIPQUAD_FMT".%u.%u", - NIPQUAD(addr->sin_addr.s_addr), + snprintf(buf, 30, "%pI4.%u.%u", + &addr->sin_addr.s_addr, ntohs(addr->sin_port) >> 8, ntohs(addr->sin_port) & 0xff); xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; @@ -369,8 +369,8 @@ xprt_setup_rdma(struct xprt_create *args) if (ntohs(sin->sin_port) != 0) xprt_set_bound(xprt); - dprintk("RPC: %s: %u.%u.%u.%u:%u\n", __func__, - NIPQUAD(sin->sin_addr.s_addr), ntohs(sin->sin_port)); + dprintk("RPC: %s: %pI4:%u\n", + __func__, &sin->sin_addr.s_addr, ntohs(sin->sin_port)); /* Set max requests */ cdata.max_requests = xprt->max_reqs; diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index a5fef5e6c32314b7098fe59756ddb5280681e5df..3b21e0cc5e6925413c65bb2cdf75aaa45f10dbe6 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c @@ -276,7 +276,9 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) struct rpcrdma_xprt *xprt = id->context; struct rpcrdma_ia *ia = &xprt->rx_ia; struct rpcrdma_ep *ep = &xprt->rx_ep; +#ifdef RPC_DEBUG struct sockaddr_in *addr = (struct sockaddr_in *) &ep->rep_remote_addr; +#endif struct ib_qp_attr attr; struct ib_qp_init_attr iattr; int connstate = 0; @@ -323,12 +325,11 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) case RDMA_CM_EVENT_DEVICE_REMOVAL: connstate = -ENODEV; connected: - dprintk("RPC: %s: %s: %u.%u.%u.%u:%u" - " (ep 0x%p event 0x%x)\n", + dprintk("RPC: %s: %s: %pI4:%u (ep 0x%p event 0x%x)\n", __func__, (event->event <= 11) ? conn[event->event] : "unknown connection error", - NIPQUAD(addr->sin_addr.s_addr), + &addr->sin_addr.s_addr, ntohs(addr->sin_port), ep, event->event); atomic_set(&rpcx_to_rdmax(ep->rep_xprt)->rx_buf.rb_credits, 1); @@ -348,18 +349,17 @@ connected: if (connstate == 1) { int ird = attr.max_dest_rd_atomic; int tird = ep->rep_remote_cma.responder_resources; - printk(KERN_INFO "rpcrdma: connection to %u.%u.%u.%u:%u " + printk(KERN_INFO "rpcrdma: connection to %pI4:%u " "on %s, memreg %d slots %d ird %d%s\n", - NIPQUAD(addr->sin_addr.s_addr), + &addr->sin_addr.s_addr, ntohs(addr->sin_port), ia->ri_id->device->name, ia->ri_memreg_strategy, xprt->rx_buf.rb_max_requests, ird, ird < 4 && ird < tird / 2 ? " (low!)" : ""); } else if (connstate < 0) { - printk(KERN_INFO "rpcrdma: connection to %u.%u.%u.%u:%u " - "closed (%d)\n", - NIPQUAD(addr->sin_addr.s_addr), + printk(KERN_INFO "rpcrdma: connection to %pI4:%u closed (%d)\n", + &addr->sin_addr.s_addr, ntohs(addr->sin_port), connstate); } diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 0a50361e3d83535492160f7f08a36a5a5c34d4be..5cbb404c4cdf89da7a6dd328ec5d7137d2d54dbc 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -284,8 +284,7 @@ static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt, buf = kzalloc(20, GFP_KERNEL); if (buf) { - snprintf(buf, 20, NIPQUAD_FMT, - NIPQUAD(addr->sin_addr.s_addr)); + snprintf(buf, 20, "%pI4", &addr->sin_addr.s_addr); } xprt->address_strings[RPC_DISPLAY_ADDR] = buf; @@ -300,8 +299,8 @@ static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt, buf = kzalloc(48, GFP_KERNEL); if (buf) { - snprintf(buf, 48, "addr="NIPQUAD_FMT" port=%u proto=%s", - NIPQUAD(addr->sin_addr.s_addr), + snprintf(buf, 48, "addr=%pI4 port=%u proto=%s", + &addr->sin_addr.s_addr, ntohs(addr->sin_port), protocol); } @@ -323,8 +322,8 @@ static void xs_format_ipv4_peer_addresses(struct rpc_xprt *xprt, buf = kzalloc(30, GFP_KERNEL); if (buf) { - snprintf(buf, 30, NIPQUAD_FMT".%u.%u", - NIPQUAD(addr->sin_addr.s_addr), + snprintf(buf, 30, "%pI4.%u.%u", + &addr->sin_addr.s_addr, ntohs(addr->sin_port) >> 8, ntohs(addr->sin_port) & 0xff); } @@ -342,8 +341,7 @@ static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt, buf = kzalloc(40, GFP_KERNEL); if (buf) { - snprintf(buf, 40, NIP6_FMT, - NIP6(addr->sin6_addr)); + snprintf(buf, 40, "%pI6",&addr->sin6_addr); } xprt->address_strings[RPC_DISPLAY_ADDR] = buf; @@ -358,18 +356,17 @@ static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt, buf = kzalloc(64, GFP_KERNEL); if (buf) { - snprintf(buf, 64, "addr="NIP6_FMT" port=%u proto=%s", - NIP6(addr->sin6_addr), + snprintf(buf, 64, "addr=%pI6 port=%u proto=%s", + &addr->sin6_addr, ntohs(addr->sin6_port), protocol); } xprt->address_strings[RPC_DISPLAY_ALL] = buf; buf = kzalloc(36, GFP_KERNEL); - if (buf) { - snprintf(buf, 36, NIP6_SEQFMT, - NIP6(addr->sin6_addr)); - } + if (buf) + snprintf(buf, 36, "%pi6", &addr->sin6_addr); + xprt->address_strings[RPC_DISPLAY_HEX_ADDR] = buf; buf = kzalloc(8, GFP_KERNEL); @@ -381,10 +378,10 @@ static void xs_format_ipv6_peer_addresses(struct rpc_xprt *xprt, buf = kzalloc(50, GFP_KERNEL); if (buf) { - snprintf(buf, 50, NIP6_FMT".%u.%u", - NIP6(addr->sin6_addr), - ntohs(addr->sin6_port) >> 8, - ntohs(addr->sin6_port) & 0xff); + snprintf(buf, 50, "%pI6.%u.%u", + &addr->sin6_addr, + ntohs(addr->sin6_port) >> 8, + ntohs(addr->sin6_port) & 0xff); } xprt->address_strings[RPC_DISPLAY_UNIVERSAL_ADDR] = buf; @@ -1415,8 +1412,8 @@ static int xs_bind4(struct sock_xprt *transport, struct socket *sock) if (port > last) nloop++; } while (err == -EADDRINUSE && nloop != 2); - dprintk("RPC: %s "NIPQUAD_FMT":%u: %s (%d)\n", - __func__, NIPQUAD(myaddr.sin_addr), + dprintk("RPC: %s %pI4:%u: %s (%d)\n", + __func__, &myaddr.sin_addr, port, err ? "failed" : "ok", err); return err; } @@ -1448,8 +1445,8 @@ static int xs_bind6(struct sock_xprt *transport, struct socket *sock) if (port > last) nloop++; } while (err == -EADDRINUSE && nloop != 2); - dprintk("RPC: xs_bind6 "NIP6_FMT":%u: %s (%d)\n", - NIP6(myaddr.sin6_addr), port, err ? "failed" : "ok", err); + dprintk("RPC: xs_bind6 %pI6:%u: %s (%d)\n", + &myaddr.sin6_addr, port, err ? "failed" : "ok", err); return err; } diff --git a/net/tipc/eth_media.c b/net/tipc/eth_media.c index fe43ef7dd7e3ce81652d9d2572b25d2a11df3175..f72ba774c246835228405e712a64c1387c6123e3 100644 --- a/net/tipc/eth_media.c +++ b/net/tipc/eth_media.c @@ -243,12 +243,11 @@ static int recv_notification(struct notifier_block *nb, unsigned long evt, static char *eth_addr2str(struct tipc_media_addr *a, char *str_buf, int str_size) { unchar *addr = (unchar *)&a->dev_addr; - DECLARE_MAC_BUF(mac); if (str_size < 18) *str_buf = '\0'; else - sprintf(str_buf, "%s", print_mac(mac, addr)); + sprintf(str_buf, "%pM", addr); return str_buf; } diff --git a/net/tipc/name_table.c b/net/tipc/name_table.c index cd72e22b132b381bad5ebc6e3dbc4fcf231a91f3..acab41a48d675a3f1c3709fb1489c1b433bd5460 100644 --- a/net/tipc/name_table.c +++ b/net/tipc/name_table.c @@ -555,7 +555,7 @@ static struct name_seq *nametbl_find_seq(u32 type) struct name_seq *ns; dbg("find_seq %u,(%u,0x%x) table = %p, hash[type] = %u\n", - type, ntohl(type), type, table.types, hash(type)); + type, htonl(type), type, table.types, hash(type)); seq_head = &table.types[hash(type)]; hlist_for_each_entry(ns, seq_node, seq_head, ns_list) { diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c index b152e2b9b9888792700a0a1daf784f232a75aa6c..c6250d0055d2f1badce36d7d27e2f4edeed3bf00 100644 --- a/net/unix/af_unix.c +++ b/net/unix/af_unix.c @@ -164,7 +164,7 @@ static inline int unix_our_peer(struct sock *sk, struct sock *osk) static inline int unix_may_send(struct sock *sk, struct sock *osk) { - return (unix_peer(osk) == NULL || unix_our_peer(sk, osk)); + return unix_peer(osk) == NULL || unix_our_peer(sk, osk); } static inline int unix_recvq_full(struct sock const *sk) @@ -197,7 +197,7 @@ static inline void unix_release_addr(struct unix_address *addr) * - if started by zero, it is abstract name. */ -static int unix_mkname(struct sockaddr_un * sunaddr, int len, unsigned *hashp) +static int unix_mkname(struct sockaddr_un *sunaddr, int len, unsigned *hashp) { if (len <= sizeof(short) || len > sizeof(*sunaddr)) return -EINVAL; @@ -211,12 +211,12 @@ static int unix_mkname(struct sockaddr_un * sunaddr, int len, unsigned *hashp) * we are guaranteed that it is a valid memory location in our * kernel address buffer. */ - ((char *)sunaddr)[len]=0; + ((char *)sunaddr)[len] = 0; len = strlen(sunaddr->sun_path)+1+sizeof(short); return len; } - *hashp = unix_hash_fold(csum_partial((char*)sunaddr, len, 0)); + *hashp = unix_hash_fold(csum_partial(sunaddr, len, 0)); return len; } @@ -295,8 +295,7 @@ static struct sock *unix_find_socket_byinode(struct net *net, struct inode *i) if (!net_eq(sock_net(s), net)) continue; - if(dentry && dentry->d_inode == i) - { + if (dentry && dentry->d_inode == i) { sock_hold(s); goto found; } @@ -354,7 +353,7 @@ static void unix_sock_destructor(struct sock *sk) WARN_ON(!sk_unhashed(sk)); WARN_ON(sk->sk_socket); if (!sock_flag(sk, SOCK_DEAD)) { - printk("Attempt to release alive unix socket: %p\n", sk); + printk(KERN_INFO "Attempt to release alive unix socket: %p\n", sk); return; } @@ -362,12 +361,16 @@ static void unix_sock_destructor(struct sock *sk) unix_release_addr(u->addr); atomic_dec(&unix_nr_socks); + local_bh_disable(); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); + local_bh_enable(); #ifdef UNIX_REFCNT_DEBUG - printk(KERN_DEBUG "UNIX %p is destroyed, %d are still alive.\n", sk, atomic_read(&unix_nr_socks)); + printk(KERN_DEBUG "UNIX %p is destroyed, %d are still alive.\n", sk, + atomic_read(&unix_nr_socks)); #endif } -static int unix_release_sock (struct sock *sk, int embrion) +static int unix_release_sock(struct sock *sk, int embrion) { struct unix_sock *u = unix_sk(sk); struct dentry *dentry; @@ -392,9 +395,9 @@ static int unix_release_sock (struct sock *sk, int embrion) wake_up_interruptible_all(&u->peer_wait); - skpair=unix_peer(sk); + skpair = unix_peer(sk); - if (skpair!=NULL) { + if (skpair != NULL) { if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) { unix_state_lock(skpair); /* No more writes */ @@ -414,7 +417,7 @@ static int unix_release_sock (struct sock *sk, int embrion) /* Try to flush out this socket. Throw out buffers at least */ while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) { - if (state==TCP_LISTEN) + if (state == TCP_LISTEN) unix_release_sock(skb->sk, 1); /* passed fds are erased in the kfree_skb hook */ kfree_skb(skb); @@ -453,11 +456,11 @@ static int unix_listen(struct socket *sock, int backlog) struct unix_sock *u = unix_sk(sk); err = -EOPNOTSUPP; - if (sock->type!=SOCK_STREAM && sock->type!=SOCK_SEQPACKET) - goto out; /* Only stream/seqpacket sockets accept */ + if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) + goto out; /* Only stream/seqpacket sockets accept */ err = -EINVAL; if (!u->addr) - goto out; /* No listens on an unbound socket */ + goto out; /* No listens on an unbound socket */ unix_state_lock(sk); if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN) goto out_unlock; @@ -565,9 +568,9 @@ static const struct proto_ops unix_seqpacket_ops = { }; static struct proto unix_proto = { - .name = "UNIX", - .owner = THIS_MODULE, - .obj_size = sizeof(struct unix_sock), + .name = "UNIX", + .owner = THIS_MODULE, + .obj_size = sizeof(struct unix_sock), }; /* @@ -578,7 +581,7 @@ static struct proto unix_proto = { */ static struct lock_class_key af_unix_sk_receive_queue_lock_key; -static struct sock * unix_create1(struct net *net, struct socket *sock) +static struct sock *unix_create1(struct net *net, struct socket *sock) { struct sock *sk = NULL; struct unix_sock *u; @@ -591,7 +594,7 @@ static struct sock * unix_create1(struct net *net, struct socket *sock) if (!sk) goto out; - sock_init_data(sock,sk); + sock_init_data(sock, sk); lockdep_set_class(&sk->sk_receive_queue.lock, &af_unix_sk_receive_queue_lock_key); @@ -610,6 +613,11 @@ static struct sock * unix_create1(struct net *net, struct socket *sock) out: if (sk == NULL) atomic_dec(&unix_nr_socks); + else { + local_bh_disable(); + sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); + local_bh_enable(); + } return sk; } @@ -629,7 +637,7 @@ static int unix_create(struct net *net, struct socket *sock, int protocol) * nothing uses it. */ case SOCK_RAW: - sock->type=SOCK_DGRAM; + sock->type = SOCK_DGRAM; case SOCK_DGRAM: sock->ops = &unix_dgram_ops; break; @@ -652,7 +660,7 @@ static int unix_release(struct socket *sock) sock->sk = NULL; - return unix_release_sock (sk, 0); + return unix_release_sock(sk, 0); } static int unix_autobind(struct socket *sock) @@ -661,7 +669,7 @@ static int unix_autobind(struct socket *sock) struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); static u32 ordernum = 1; - struct unix_address * addr; + struct unix_address *addr; int err; mutex_lock(&u->readlock); @@ -680,7 +688,7 @@ static int unix_autobind(struct socket *sock) retry: addr->len = sprintf(addr->name->sun_path+1, "%05x", ordernum) + 1 + sizeof(short); - addr->hash = unix_hash_fold(csum_partial((void*)addr->name, addr->len, 0)); + addr->hash = unix_hash_fold(csum_partial(addr->name, addr->len, 0)); spin_lock(&unix_table_lock); ordernum = (ordernum+1)&0xFFFFF; @@ -735,14 +743,14 @@ static struct sock *unix_find_other(struct net *net, path_put(&path); - err=-EPROTOTYPE; + err = -EPROTOTYPE; if (u->sk_type != type) { sock_put(u); goto fail; } } else { err = -ECONNREFUSED; - u=unix_find_socket_byname(net, sunname, len, type, hash); + u = unix_find_socket_byname(net, sunname, len, type, hash); if (u) { struct dentry *dentry; dentry = unix_sk(u)->dentry; @@ -756,7 +764,7 @@ static struct sock *unix_find_other(struct net *net, put_fail: path_put(&path); fail: - *error=err; + *error = err; return NULL; } @@ -766,8 +774,8 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) struct sock *sk = sock->sk; struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); - struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; - struct dentry * dentry = NULL; + struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; + struct dentry *dentry = NULL; struct nameidata nd; int err; unsigned hash; @@ -778,7 +786,7 @@ static int unix_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) if (sunaddr->sun_family != AF_UNIX) goto out; - if (addr_len==sizeof(short)) { + if (addr_len == sizeof(short)) { err = unix_autobind(sock); goto out; } @@ -874,8 +882,8 @@ out_mknod_unlock: mutex_unlock(&nd.path.dentry->d_inode->i_mutex); path_put(&nd.path); out_mknod_parent: - if (err==-EEXIST) - err=-EADDRINUSE; + if (err == -EEXIST) + err = -EADDRINUSE; unix_release_addr(addr); goto out_up; } @@ -910,7 +918,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, { struct sock *sk = sock->sk; struct net *net = sock_net(sk); - struct sockaddr_un *sunaddr=(struct sockaddr_un*)addr; + struct sockaddr_un *sunaddr = (struct sockaddr_un *)addr; struct sock *other; unsigned hash; int err; @@ -926,7 +934,7 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, goto out; restart: - other=unix_find_other(net, sunaddr, alen, sock->type, hash, &err); + other = unix_find_other(net, sunaddr, alen, sock->type, hash, &err); if (!other) goto out; @@ -960,14 +968,14 @@ restart: */ if (unix_peer(sk)) { struct sock *old_peer = unix_peer(sk); - unix_peer(sk)=other; + unix_peer(sk) = other; unix_state_double_unlock(sk, other); if (other != old_peer) unix_dgram_disconnected(sk, old_peer); sock_put(old_peer); } else { - unix_peer(sk)=other; + unix_peer(sk) = other; unix_state_double_unlock(sk, other); } return 0; @@ -1003,7 +1011,7 @@ static long unix_wait_for_peer(struct sock *other, long timeo) static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) { - struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; + struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; struct sock *sk = sock->sk; struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk), *newu, *otheru; @@ -1177,13 +1185,13 @@ out: static int unix_socketpair(struct socket *socka, struct socket *sockb) { - struct sock *ska=socka->sk, *skb = sockb->sk; + struct sock *ska = socka->sk, *skb = sockb->sk; /* Join our sockets back to back */ sock_hold(ska); sock_hold(skb); - unix_peer(ska)=skb; - unix_peer(skb)=ska; + unix_peer(ska) = skb; + unix_peer(skb) = ska; ska->sk_peercred.pid = skb->sk_peercred.pid = task_tgid_vnr(current); current_euid_egid(&skb->sk_peercred.uid, &skb->sk_peercred.gid); ska->sk_peercred.uid = skb->sk_peercred.uid; @@ -1206,7 +1214,7 @@ static int unix_accept(struct socket *sock, struct socket *newsock, int flags) int err; err = -EOPNOTSUPP; - if (sock->type!=SOCK_STREAM && sock->type!=SOCK_SEQPACKET) + if (sock->type != SOCK_STREAM && sock->type != SOCK_SEQPACKET) goto out; err = -EINVAL; @@ -1245,7 +1253,7 @@ static int unix_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_ { struct sock *sk = sock->sk; struct unix_sock *u; - struct sockaddr_un *sunaddr=(struct sockaddr_un *)uaddr; + struct sockaddr_un *sunaddr = (struct sockaddr_un *)uaddr; int err = 0; if (peer) { @@ -1285,7 +1293,7 @@ static void unix_detach_fds(struct scm_cookie *scm, struct sk_buff *skb) skb->destructor = sock_wfree; UNIXCB(skb).fp = NULL; - for (i=scm->fp->count-1; i>=0; i--) + for (i = scm->fp->count-1; i >= 0; i--) unix_notinflight(scm->fp->fp[i]); } @@ -1314,7 +1322,7 @@ static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb) if (!UNIXCB(skb).fp) return -ENOMEM; - for (i=scm->fp->count-1; i>=0; i--) + for (i = scm->fp->count-1; i >= 0; i--) unix_inflight(scm->fp->fp[i]); skb->destructor = unix_destruct_fds; return 0; @@ -1331,7 +1339,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, struct sock *sk = sock->sk; struct net *net = sock_net(sk); struct unix_sock *u = unix_sk(sk); - struct sockaddr_un *sunaddr=msg->msg_name; + struct sockaddr_un *sunaddr = msg->msg_name; struct sock *other = NULL; int namelen = 0; /* fake GCC */ int err; @@ -1373,7 +1381,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, goto out; skb = sock_alloc_send_skb(sk, len, msg->msg_flags&MSG_DONTWAIT, &err); - if (skb==NULL) + if (skb == NULL) goto out; memcpy(UNIXCREDS(skb), &siocb->scm->creds, sizeof(struct ucred)); @@ -1385,7 +1393,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock, unix_get_secdata(siocb->scm, skb); skb_reset_transport_header(skb); - err = memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len); + err = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); if (err) goto out_free; @@ -1399,7 +1407,7 @@ restart: other = unix_find_other(net, sunaddr, namelen, sk->sk_type, hash, &err); - if (other==NULL) + if (other == NULL) goto out_free; } @@ -1419,7 +1427,7 @@ restart: err = 0; unix_state_lock(sk); if (unix_peer(sk) == other) { - unix_peer(sk)=NULL; + unix_peer(sk) = NULL; unix_state_unlock(sk); unix_dgram_disconnected(sk, other); @@ -1485,10 +1493,10 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, struct sock_iocb *siocb = kiocb_to_siocb(kiocb); struct sock *sk = sock->sk; struct sock *other = NULL; - struct sockaddr_un *sunaddr=msg->msg_name; - int err,size; + struct sockaddr_un *sunaddr = msg->msg_name; + int err, size; struct sk_buff *skb; - int sent=0; + int sent = 0; struct scm_cookie tmp_scm; if (NULL == siocb->scm) @@ -1516,8 +1524,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, if (sk->sk_shutdown & SEND_SHUTDOWN) goto pipe_err; - while(sent < len) - { + while (sent < len) { /* * Optimisation for the fact that under 0.01% of X * messages typically need breaking up. @@ -1536,9 +1543,10 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, * Grab a buffer */ - skb=sock_alloc_send_skb(sk,size,msg->msg_flags&MSG_DONTWAIT, &err); + skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, + &err); - if (skb==NULL) + if (skb == NULL) goto out_err; /* @@ -1559,7 +1567,8 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, } } - if ((err = memcpy_fromiovec(skb_put(skb,size), msg->msg_iov, size)) != 0) { + err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); + if (err) { kfree_skb(skb); goto out_err; } @@ -1573,7 +1582,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock, skb_queue_tail(&other->sk_receive_queue, skb); unix_state_unlock(other); other->sk_data_ready(other, size); - sent+=size; + sent += size; } scm_destroy(siocb->scm); @@ -1585,8 +1594,8 @@ pipe_err_free: unix_state_unlock(other); kfree_skb(skb); pipe_err: - if (sent==0 && !(msg->msg_flags&MSG_NOSIGNAL)) - send_sig(SIGPIPE,current,0); + if (sent == 0 && !(msg->msg_flags&MSG_NOSIGNAL)) + send_sig(SIGPIPE, current, 0); err = -EPIPE; out_err: scm_destroy(siocb->scm); @@ -1676,13 +1685,10 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, siocb->scm->creds = *UNIXCREDS(skb); unix_set_secdata(siocb->scm, skb); - if (!(flags & MSG_PEEK)) - { + if (!(flags & MSG_PEEK)) { if (UNIXCB(skb).fp) unix_detach_fds(siocb->scm, skb); - } - else - { + } else { /* It is questionable: on PEEK we could: - do not return fds - good, but too simple 8) - return fds, and do not return them on read (old strategy, @@ -1703,7 +1709,7 @@ static int unix_dgram_recvmsg(struct kiocb *iocb, struct socket *sock, scm_recv(sock, msg, siocb->scm, flags); out_free: - skb_free_datagram(sk,skb); + skb_free_datagram(sk, skb); out_unlock: mutex_unlock(&u->readlock); out: @@ -1714,7 +1720,7 @@ out: * Sleep until data has arrive. But check for races.. */ -static long unix_stream_data_wait(struct sock * sk, long timeo) +static long unix_stream_data_wait(struct sock *sk, long timeo) { DEFINE_WAIT(wait); @@ -1752,7 +1758,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, struct scm_cookie tmp_scm; struct sock *sk = sock->sk; struct unix_sock *u = unix_sk(sk); - struct sockaddr_un *sunaddr=msg->msg_name; + struct sockaddr_un *sunaddr = msg->msg_name; int copied = 0; int check_creds = 0; int target; @@ -1783,15 +1789,13 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, mutex_lock(&u->readlock); - do - { + do { int chunk; struct sk_buff *skb; unix_state_lock(sk); skb = skb_dequeue(&sk->sk_receive_queue); - if (skb==NULL) - { + if (skb == NULL) { if (copied >= target) goto unlock; @@ -1799,7 +1803,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, * POSIX 1003.1g mandates this order. */ - if ((err = sock_error(sk)) != 0) + err = sock_error(sk); + if (err) goto unlock; if (sk->sk_shutdown & RCV_SHUTDOWN) goto unlock; @@ -1826,7 +1831,8 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (check_creds) { /* Never glue messages from different writers */ - if (memcmp(UNIXCREDS(skb), &siocb->scm->creds, sizeof(siocb->scm->creds)) != 0) { + if (memcmp(UNIXCREDS(skb), &siocb->scm->creds, + sizeof(siocb->scm->creds)) != 0) { skb_queue_head(&sk->sk_receive_queue, skb); break; } @@ -1837,8 +1843,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, } /* Copy address just once */ - if (sunaddr) - { + if (sunaddr) { unix_copy_addr(msg, skb->sk); sunaddr = NULL; } @@ -1854,16 +1859,14 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, size -= chunk; /* Mark read part of skb as used */ - if (!(flags & MSG_PEEK)) - { + if (!(flags & MSG_PEEK)) { skb_pull(skb, chunk); if (UNIXCB(skb).fp) unix_detach_fds(siocb->scm, skb); /* put the skb back if we didn't use it up.. */ - if (skb->len) - { + if (skb->len) { skb_queue_head(&sk->sk_receive_queue, skb); break; } @@ -1872,9 +1875,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock, if (siocb->scm->fp) break; - } - else - { + } else { /* It is questionable, see note in unix_dgram_recvmsg. */ if (UNIXCB(skb).fp) @@ -1902,7 +1903,7 @@ static int unix_shutdown(struct socket *sock, int mode) if (mode) { unix_state_lock(sk); sk->sk_shutdown |= mode; - other=unix_peer(sk); + other = unix_peer(sk); if (other) sock_hold(other); unix_state_unlock(sk); @@ -1937,16 +1938,15 @@ static int unix_shutdown(struct socket *sock, int mode) static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { struct sock *sk = sock->sk; - long amount=0; + long amount = 0; int err; - switch(cmd) - { - case SIOCOUTQ: - amount = atomic_read(&sk->sk_wmem_alloc); - err = put_user(amount, (int __user *)arg); - break; - case SIOCINQ: + switch (cmd) { + case SIOCOUTQ: + amount = atomic_read(&sk->sk_wmem_alloc); + err = put_user(amount, (int __user *)arg); + break; + case SIOCINQ: { struct sk_buff *skb; @@ -1963,21 +1963,21 @@ static int unix_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } else { skb = skb_peek(&sk->sk_receive_queue); if (skb) - amount=skb->len; + amount = skb->len; } spin_unlock(&sk->sk_receive_queue.lock); err = put_user(amount, (int __user *)arg); break; } - default: - err = -ENOIOCTLCMD; - break; + default: + err = -ENOIOCTLCMD; + break; } return err; } -static unsigned int unix_poll(struct file * file, struct socket *sock, poll_table *wait) +static unsigned int unix_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; unsigned int mask; @@ -1999,7 +1999,8 @@ static unsigned int unix_poll(struct file * file, struct socket *sock, poll_tabl mask |= POLLIN | POLLRDNORM; /* Connection-based need to check for termination and startup */ - if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) && sk->sk_state == TCP_CLOSE) + if ((sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) && + sk->sk_state == TCP_CLOSE) mask |= POLLHUP; /* @@ -2095,6 +2096,7 @@ struct unix_iter_state { struct seq_net_private p; int i; }; + static struct sock *unix_seq_idx(struct seq_file *seq, loff_t pos) { struct unix_iter_state *iter = seq->private; @@ -2111,7 +2113,6 @@ static struct sock *unix_seq_idx(struct seq_file *seq, loff_t pos) return NULL; } - static void *unix_seq_start(struct seq_file *seq, loff_t *pos) __acquires(unix_table_lock) { @@ -2191,7 +2192,6 @@ static const struct seq_operations unix_seq_ops = { .show = unix_seq_show, }; - static int unix_seq_open(struct inode *inode, struct file *file) { return seq_open_net(inode, file, &unix_seq_ops, diff --git a/net/unix/garbage.c b/net/unix/garbage.c index abb3ab34cb1ece8f357819c8124430996e15d443..19c17e4a0c8b96d0468a7652661f8b5ff34b9b86 100644 --- a/net/unix/garbage.c +++ b/net/unix/garbage.c @@ -106,8 +106,8 @@ static struct sock *unix_get_socket(struct file *filp) * Socket ? */ if (S_ISSOCK(inode->i_mode)) { - struct socket * sock = SOCKET_I(inode); - struct sock * s = sock->sk; + struct socket *sock = SOCKET_I(inode); + struct sock *s = sock->sk; /* * PF_UNIX ? @@ -126,7 +126,7 @@ static struct sock *unix_get_socket(struct file *filp) void unix_inflight(struct file *fp) { struct sock *s = unix_get_socket(fp); - if(s) { + if (s) { struct unix_sock *u = unix_sk(s); spin_lock(&unix_gc_lock); if (atomic_long_inc_return(&u->inflight) == 1) { @@ -143,7 +143,7 @@ void unix_inflight(struct file *fp) void unix_notinflight(struct file *fp) { struct sock *s = unix_get_socket(fp); - if(s) { + if (s) { struct unix_sock *u = unix_sk(s); spin_lock(&unix_gc_lock); BUG_ON(list_empty(&u->link)); @@ -156,7 +156,7 @@ void unix_notinflight(struct file *fp) static inline struct sk_buff *sock_queue_head(struct sock *sk) { - return (struct sk_buff *) &sk->sk_receive_queue; + return (struct sk_buff *)&sk->sk_receive_queue; } #define receive_queue_for_each_skb(sk, next, skb) \ @@ -370,7 +370,7 @@ void unix_gc(void) */ skb_queue_head_init(&hitlist); list_for_each_entry(u, &gc_candidates, link) - scan_children(&u->sk, inc_inflight, &hitlist); + scan_children(&u->sk, inc_inflight, &hitlist); spin_unlock(&unix_gc_lock); diff --git a/net/unix/sysctl_net_unix.c b/net/unix/sysctl_net_unix.c index 77513d7e35f2522251452754deaa4c1b949a2ed3..83c093077ebc845ae89979ff8e0724b99a03f095 100644 --- a/net/unix/sysctl_net_unix.c +++ b/net/unix/sysctl_net_unix.c @@ -21,7 +21,7 @@ static ctl_table unix_table[] = { .data = &init_net.unx.sysctl_max_dgram_qlen, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec + .proc_handler = proc_dointvec }, { .ctl_name = 0 } }; @@ -61,4 +61,3 @@ void unix_sysctl_unregister(struct net *net) unregister_sysctl_table(net->unx.ctl); kfree(table); } - diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c index 7f07152bc109e579118870d03f150e7620fd8725..39701dec1dbae7c400cfcfcf72ad471d489eb776 100644 --- a/net/wanrouter/wanmain.c +++ b/net/wanrouter/wanmain.c @@ -60,6 +60,8 @@ #define KMEM_SAFETYZONE 8 +#define DEV_TO_SLAVE(dev) (*((struct net_device **)netdev_priv(dev))) + /* * Function Prototypes */ @@ -511,7 +513,7 @@ static int wanrouter_device_shutdown(struct wan_device *wandev) if (err) return err; /* The above function deallocates the current dev - * structure. Therefore, we cannot use dev->priv + * structure. Therefore, we cannot use netdev_priv(dev) * as the next element: wandev->dev points to the * next element */ dev = wandev->dev; @@ -589,10 +591,6 @@ static int wanrouter_device_new_if(struct wan_device *wandev, err = -EPROTONOSUPPORT; goto out; } else { - dev = kzalloc(sizeof(struct net_device), GFP_KERNEL); - err = -ENOBUFS; - if (dev == NULL) - goto out; err = wandev->new_if(wandev, dev, cnf); } @@ -622,10 +620,9 @@ static int wanrouter_device_new_if(struct wan_device *wandev, wandev->dev = dev; } else { for (slave=wandev->dev; - *((struct net_device **)slave->priv); - slave = *((struct net_device **)slave->priv)); - - *((struct net_device **)slave->priv) = dev; + DEV_TO_SLAVE(slave); + slave = DEV_TO_SLAVE(slave)) + DEV_TO_SLAVE(slave) = dev; } ++wandev->ndev; @@ -636,15 +633,9 @@ static int wanrouter_device_new_if(struct wan_device *wandev, } if (wandev->del_if) wandev->del_if(wandev, dev); + free_netdev(dev); } - /* This code has moved from del_if() function */ - kfree(dev->priv); - dev->priv = NULL; - - /* Sync PPP is disabled */ - if (cnf->config_id != WANCONFIG_MPPP) - kfree(dev); out: kfree(cnf); return err; @@ -734,7 +725,7 @@ static int wanrouter_delete_interface(struct wan_device *wandev, char *name) dev = wandev->dev; prev = NULL; while (dev && strcmp(name, dev->name)) { - struct net_device **slave = dev->priv; + struct net_device **slave = netdev_priv(dev); prev = dev; dev = *slave; } @@ -751,12 +742,12 @@ static int wanrouter_delete_interface(struct wan_device *wandev, char *name) lock_adapter_irq(&wandev->lock, &smp_flags); if (prev) { - struct net_device **prev_slave = prev->priv; - struct net_device **slave = dev->priv; + struct net_device **prev_slave = netdev_priv(prev); + struct net_device **slave = netdev_priv(dev); *prev_slave = *slave; } else { - struct net_device **slave = dev->priv; + struct net_device **slave = netdev_priv(dev); wandev->dev = *slave; } --wandev->ndev; @@ -764,11 +755,6 @@ static int wanrouter_delete_interface(struct wan_device *wandev, char *name) printk(KERN_INFO "%s: unregistering '%s'\n", wandev->name, dev->name); - /* Due to new interface linking method using dev->priv, - * this code has moved from del_if() function.*/ - kfree(dev->priv); - dev->priv=NULL; - unregister_netdev(dev); free_netdev(dev); diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig index 646c7121dbc0a78ca0c3018f6e6025ff9bca5249..e28e2b8fa436edc1290e8704bab478781a308111 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig @@ -1,6 +1,15 @@ config CFG80211 tristate "Improved wireless configuration API" +config CFG80211_REG_DEBUG + bool "cfg80211 regulatory debugging" + depends on CFG80211 + default n + ---help--- + You can enable this if you want to debug regulatory changes. + + If unsure, say N. + config NL80211 bool "nl80211 new netlink interface support" depends on CFG80211 @@ -40,6 +49,8 @@ config WIRELESS_OLD_REGULATORY ieee80211_regdom module parameter. This is being phased out and you should stop using them ASAP. + Note: You will need CRDA if you want 802.11d support + Say Y unless you have installed a new userspace application. Also say Y if have one currently depending on the ieee80211_regdom module parameter and cannot port it to use the new userspace @@ -72,3 +83,22 @@ config WIRELESS_EXT_SYSFS Say Y if you have programs using it, like old versions of hal. + +config LIB80211 + tristate "Common routines for IEEE802.11 drivers" + default n + help + This options enables a library of common routines used + by IEEE802.11 wireless LAN drivers. + + Drivers should select this themselves if needed. Say Y if + you want this built into your kernel. + +config LIB80211_CRYPT_WEP + tristate + +config LIB80211_CRYPT_CCMP + tristate + +config LIB80211_CRYPT_TKIP + tristate diff --git a/net/wireless/Makefile b/net/wireless/Makefile index b9f943c45f3b2584e3462d61af9cd1d799cc6579..938a334c8dbc3ba6fe72afbd1b320f41bdd7c73f 100644 --- a/net/wireless/Makefile +++ b/net/wireless/Makefile @@ -1,5 +1,12 @@ obj-$(CONFIG_WIRELESS_EXT) += wext.o obj-$(CONFIG_CFG80211) += cfg80211.o +obj-$(CONFIG_LIB80211) += lib80211.o +obj-$(CONFIG_LIB80211_CRYPT_WEP) += lib80211_crypt_wep.o +obj-$(CONFIG_LIB80211_CRYPT_CCMP) += lib80211_crypt_ccmp.o +obj-$(CONFIG_LIB80211_CRYPT_TKIP) += lib80211_crypt_tkip.o cfg80211-y += core.o sysfs.o radiotap.o util.o reg.o +cfg80211-$(CONFIG_WIRELESS_EXT) += wext-compat.o cfg80211-$(CONFIG_NL80211) += nl80211.o + +ccflags-y += -D__CHECK_ENDIAN__ diff --git a/net/wireless/core.c b/net/wireless/core.c index 5031db7b275b734b46870089765420c75c136d10..b96fc0c3f1c446132cf71e3e0464a6a2ff4edd84 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -19,7 +19,6 @@ #include "nl80211.h" #include "core.h" #include "sysfs.h" -#include "reg.h" /* name for sysfs, %d is appended */ #define PHY_NAME "phy" @@ -236,8 +235,7 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv) mutex_unlock(&cfg80211_drv_mutex); /* give it a proper name */ - snprintf(drv->wiphy.dev.bus_id, BUS_ID_SIZE, - PHY_NAME "%d", drv->idx); + dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->idx); mutex_init(&drv->mtx); mutex_init(&drv->devlist_mtx); @@ -301,12 +299,10 @@ int wiphy_register(struct wiphy *wiphy) /* check and set up bitrates */ ieee80211_set_bitrate_flags(wiphy); + mutex_lock(&cfg80211_drv_mutex); + /* set up regulatory info */ - mutex_lock(&cfg80211_reg_mutex); wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE); - mutex_unlock(&cfg80211_reg_mutex); - - mutex_lock(&cfg80211_drv_mutex); res = device_add(&drv->wiphy.dev); if (res) @@ -351,6 +347,10 @@ void wiphy_unregister(struct wiphy *wiphy) /* unlock again before freeing */ mutex_unlock(&drv->mtx); + /* If this device got a regulatory hint tell core its + * free to listen now to a new shiny device regulatory hint */ + reg_device_remove(wiphy); + list_del(&drv->list); device_del(&drv->wiphy.dev); debugfs_remove(drv->wiphy.debugfsdir); diff --git a/net/wireless/core.h b/net/wireless/core.h index 771cc5cc7658cbb43c07a10386d76307d3c8f159..f7fb9f413028a7f4783e2d7ae1616ebc1dcfe311 100644 --- a/net/wireless/core.h +++ b/net/wireless/core.h @@ -11,6 +11,7 @@ #include #include #include +#include "reg.h" struct cfg80211_registered_device { struct cfg80211_ops *ops; @@ -21,6 +22,18 @@ struct cfg80211_registered_device { * any call is in progress */ struct mutex mtx; + /* ISO / IEC 3166 alpha2 for which this device is receiving + * country IEs on, this can help disregard country IEs from APs + * on the same alpha2 quickly. The alpha2 may differ from + * cfg80211_regdomain's alpha2 when an intersection has occurred. + * If the AP is reconfigured this can also be used to tell us if + * the country on the country IE changed. */ + char country_ie_alpha2[2]; + + /* If a Country IE has been received this tells us the environment + * which its telling us its in. This defaults to ENVIRON_ANY */ + enum environment_cap env; + /* wiphy index, internal only */ int idx; diff --git a/net/wireless/lib80211.c b/net/wireless/lib80211.c new file mode 100644 index 0000000000000000000000000000000000000000..97d411f7450707294038ad0272d7cc1d1a544e2a --- /dev/null +++ b/net/wireless/lib80211.c @@ -0,0 +1,284 @@ +/* + * lib80211 -- common bits for IEEE802.11 drivers + * + * Copyright(c) 2008 John W. Linville + * + * Portions copied from old ieee80211 component, w/ original copyright + * notices below: + * + * Host AP crypto routines + * + * Copyright (c) 2002-2003, Jouni Malinen + * Portions Copyright (C) 2004, Intel Corporation + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define DRV_NAME "lib80211" + +#define DRV_DESCRIPTION "common routines for IEEE802.11 drivers" + +MODULE_DESCRIPTION(DRV_DESCRIPTION); +MODULE_AUTHOR("John W. Linville "); +MODULE_LICENSE("GPL"); + +struct lib80211_crypto_alg { + struct list_head list; + struct lib80211_crypto_ops *ops; +}; + +static LIST_HEAD(lib80211_crypto_algs); +static DEFINE_SPINLOCK(lib80211_crypto_lock); + +const char *print_ssid(char *buf, const char *ssid, u8 ssid_len) +{ + const char *s = ssid; + char *d = buf; + + ssid_len = min_t(u8, ssid_len, IEEE80211_MAX_SSID_LEN); + while (ssid_len--) { + if (isprint(*s)) { + *d++ = *s++; + continue; + } + + *d++ = '\\'; + if (*s == '\0') + *d++ = '0'; + else if (*s == '\n') + *d++ = 'n'; + else if (*s == '\r') + *d++ = 'r'; + else if (*s == '\t') + *d++ = 't'; + else if (*s == '\\') + *d++ = '\\'; + else + d += snprintf(d, 3, "%03o", *s); + s++; + } + *d = '\0'; + return buf; +} +EXPORT_SYMBOL(print_ssid); + +int lib80211_crypt_info_init(struct lib80211_crypt_info *info, char *name, + spinlock_t *lock) +{ + memset(info, 0, sizeof(*info)); + + info->name = name; + info->lock = lock; + + INIT_LIST_HEAD(&info->crypt_deinit_list); + setup_timer(&info->crypt_deinit_timer, lib80211_crypt_deinit_handler, + (unsigned long)info); + + return 0; +} +EXPORT_SYMBOL(lib80211_crypt_info_init); + +void lib80211_crypt_info_free(struct lib80211_crypt_info *info) +{ + int i; + + lib80211_crypt_quiescing(info); + del_timer_sync(&info->crypt_deinit_timer); + lib80211_crypt_deinit_entries(info, 1); + + for (i = 0; i < NUM_WEP_KEYS; i++) { + struct lib80211_crypt_data *crypt = info->crypt[i]; + if (crypt) { + if (crypt->ops) { + crypt->ops->deinit(crypt->priv); + module_put(crypt->ops->owner); + } + kfree(crypt); + info->crypt[i] = NULL; + } + } +} +EXPORT_SYMBOL(lib80211_crypt_info_free); + +void lib80211_crypt_deinit_entries(struct lib80211_crypt_info *info, int force) +{ + struct lib80211_crypt_data *entry, *next; + unsigned long flags; + + spin_lock_irqsave(info->lock, flags); + list_for_each_entry_safe(entry, next, &info->crypt_deinit_list, list) { + if (atomic_read(&entry->refcnt) != 0 && !force) + continue; + + list_del(&entry->list); + + if (entry->ops) { + entry->ops->deinit(entry->priv); + module_put(entry->ops->owner); + } + kfree(entry); + } + spin_unlock_irqrestore(info->lock, flags); +} +EXPORT_SYMBOL(lib80211_crypt_deinit_entries); + +/* After this, crypt_deinit_list won't accept new members */ +void lib80211_crypt_quiescing(struct lib80211_crypt_info *info) +{ + unsigned long flags; + + spin_lock_irqsave(info->lock, flags); + info->crypt_quiesced = 1; + spin_unlock_irqrestore(info->lock, flags); +} +EXPORT_SYMBOL(lib80211_crypt_quiescing); + +void lib80211_crypt_deinit_handler(unsigned long data) +{ + struct lib80211_crypt_info *info = (struct lib80211_crypt_info *)data; + unsigned long flags; + + lib80211_crypt_deinit_entries(info, 0); + + spin_lock_irqsave(info->lock, flags); + if (!list_empty(&info->crypt_deinit_list) && !info->crypt_quiesced) { + printk(KERN_DEBUG "%s: entries remaining in delayed crypt " + "deletion list\n", info->name); + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); + } + spin_unlock_irqrestore(info->lock, flags); +} +EXPORT_SYMBOL(lib80211_crypt_deinit_handler); + +void lib80211_crypt_delayed_deinit(struct lib80211_crypt_info *info, + struct lib80211_crypt_data **crypt) +{ + struct lib80211_crypt_data *tmp; + unsigned long flags; + + if (*crypt == NULL) + return; + + tmp = *crypt; + *crypt = NULL; + + /* must not run ops->deinit() while there may be pending encrypt or + * decrypt operations. Use a list of delayed deinits to avoid needing + * locking. */ + + spin_lock_irqsave(info->lock, flags); + if (!info->crypt_quiesced) { + list_add(&tmp->list, &info->crypt_deinit_list); + if (!timer_pending(&info->crypt_deinit_timer)) { + info->crypt_deinit_timer.expires = jiffies + HZ; + add_timer(&info->crypt_deinit_timer); + } + } + spin_unlock_irqrestore(info->lock, flags); +} +EXPORT_SYMBOL(lib80211_crypt_delayed_deinit); + +int lib80211_register_crypto_ops(struct lib80211_crypto_ops *ops) +{ + unsigned long flags; + struct lib80211_crypto_alg *alg; + + alg = kzalloc(sizeof(*alg), GFP_KERNEL); + if (alg == NULL) + return -ENOMEM; + + alg->ops = ops; + + spin_lock_irqsave(&lib80211_crypto_lock, flags); + list_add(&alg->list, &lib80211_crypto_algs); + spin_unlock_irqrestore(&lib80211_crypto_lock, flags); + + printk(KERN_DEBUG "lib80211_crypt: registered algorithm '%s'\n", + ops->name); + + return 0; +} +EXPORT_SYMBOL(lib80211_register_crypto_ops); + +int lib80211_unregister_crypto_ops(struct lib80211_crypto_ops *ops) +{ + struct lib80211_crypto_alg *alg; + unsigned long flags; + + spin_lock_irqsave(&lib80211_crypto_lock, flags); + list_for_each_entry(alg, &lib80211_crypto_algs, list) { + if (alg->ops == ops) + goto found; + } + spin_unlock_irqrestore(&lib80211_crypto_lock, flags); + return -EINVAL; + + found: + printk(KERN_DEBUG "lib80211_crypt: unregistered algorithm " + "'%s'\n", ops->name); + list_del(&alg->list); + spin_unlock_irqrestore(&lib80211_crypto_lock, flags); + kfree(alg); + return 0; +} +EXPORT_SYMBOL(lib80211_unregister_crypto_ops); + +struct lib80211_crypto_ops *lib80211_get_crypto_ops(const char *name) +{ + struct lib80211_crypto_alg *alg; + unsigned long flags; + + spin_lock_irqsave(&lib80211_crypto_lock, flags); + list_for_each_entry(alg, &lib80211_crypto_algs, list) { + if (strcmp(alg->ops->name, name) == 0) + goto found; + } + spin_unlock_irqrestore(&lib80211_crypto_lock, flags); + return NULL; + + found: + spin_unlock_irqrestore(&lib80211_crypto_lock, flags); + return alg->ops; +} +EXPORT_SYMBOL(lib80211_get_crypto_ops); + +static void *lib80211_crypt_null_init(int keyidx) +{ + return (void *)1; +} + +static void lib80211_crypt_null_deinit(void *priv) +{ +} + +static struct lib80211_crypto_ops lib80211_crypt_null = { + .name = "NULL", + .init = lib80211_crypt_null_init, + .deinit = lib80211_crypt_null_deinit, + .owner = THIS_MODULE, +}; + +static int __init lib80211_init(void) +{ + printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION "\n"); + return lib80211_register_crypto_ops(&lib80211_crypt_null); +} + +static void __exit lib80211_exit(void) +{ + lib80211_unregister_crypto_ops(&lib80211_crypt_null); + BUG_ON(!list_empty(&lib80211_crypto_algs)); +} + +module_init(lib80211_init); +module_exit(lib80211_exit); diff --git a/net/ieee80211/ieee80211_crypt_ccmp.c b/net/wireless/lib80211_crypt_ccmp.c similarity index 74% rename from net/ieee80211/ieee80211_crypt_ccmp.c rename to net/wireless/lib80211_crypt_ccmp.c index 208bf35b55463d10d95222f36e38c11bedf8c18a..db428194c16ae184cd9e1829c09de2a1b8afd138 100644 --- a/net/ieee80211/ieee80211_crypt_ccmp.c +++ b/net/wireless/lib80211_crypt_ccmp.c @@ -1,7 +1,8 @@ /* - * Host AP crypt: host-based CCMP encryption implementation for Host AP driver + * lib80211 crypt: host-based CCMP encryption implementation for lib80211 * * Copyright (c) 2003-2004, Jouni Malinen + * Copyright (c) 2008, John W. Linville * * 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 @@ -22,10 +23,12 @@ #include #include -#include +#include #include +#include + MODULE_AUTHOR("Jouni Malinen"); MODULE_DESCRIPTION("Host AP crypt: CCMP"); MODULE_LICENSE("GPL"); @@ -36,7 +39,7 @@ MODULE_LICENSE("GPL"); #define CCMP_TK_LEN 16 #define CCMP_PN_LEN 6 -struct ieee80211_ccmp_data { +struct lib80211_ccmp_data { u8 key[CCMP_TK_LEN]; int key_set; @@ -57,15 +60,15 @@ struct ieee80211_ccmp_data { u8 rx_b0[AES_BLOCK_LEN], rx_b[AES_BLOCK_LEN], rx_a[AES_BLOCK_LEN]; }; -static inline void ieee80211_ccmp_aes_encrypt(struct crypto_cipher *tfm, +static inline void lib80211_ccmp_aes_encrypt(struct crypto_cipher *tfm, const u8 pt[16], u8 ct[16]) { crypto_cipher_encrypt_one(tfm, ct, pt); } -static void *ieee80211_ccmp_init(int key_idx) +static void *lib80211_ccmp_init(int key_idx) { - struct ieee80211_ccmp_data *priv; + struct lib80211_ccmp_data *priv; priv = kzalloc(sizeof(*priv), GFP_ATOMIC); if (priv == NULL) @@ -74,7 +77,7 @@ static void *ieee80211_ccmp_init(int key_idx) priv->tfm = crypto_alloc_cipher("aes", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tfm)) { - printk(KERN_DEBUG "ieee80211_crypt_ccmp: could not allocate " + printk(KERN_DEBUG "lib80211_crypt_ccmp: could not allocate " "crypto API aes\n"); priv->tfm = NULL; goto fail; @@ -92,9 +95,9 @@ static void *ieee80211_ccmp_init(int key_idx) return NULL; } -static void ieee80211_ccmp_deinit(void *priv) +static void lib80211_ccmp_deinit(void *priv) { - struct ieee80211_ccmp_data *_priv = priv; + struct lib80211_ccmp_data *_priv = priv; if (_priv && _priv->tfm) crypto_free_cipher(_priv->tfm); kfree(priv); @@ -108,20 +111,17 @@ static inline void xor_block(u8 * b, u8 * a, size_t len) } static void ccmp_init_blocks(struct crypto_cipher *tfm, - struct ieee80211_hdr_4addr *hdr, + struct ieee80211_hdr *hdr, u8 * pn, size_t dlen, u8 * b0, u8 * auth, u8 * s0) { u8 *pos, qc = 0; size_t aad_len; - u16 fc; int a4_included, qc_included; u8 aad[2 * AES_BLOCK_LEN]; - fc = le16_to_cpu(hdr->frame_ctl); - a4_included = ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) == - (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)); - qc_included = ((WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) && - (WLAN_FC_GET_STYPE(fc) & IEEE80211_STYPE_QOS_DATA)); + a4_included = ieee80211_has_a4(hdr->frame_control); + qc_included = ieee80211_is_data_qos(hdr->frame_control); + aad_len = 22; if (a4_included) aad_len += 6; @@ -158,7 +158,7 @@ static void ccmp_init_blocks(struct crypto_cipher *tfm, aad[2] = pos[0] & 0x8f; aad[3] = pos[1] & 0xc7; memcpy(aad + 4, hdr->addr1, 3 * ETH_ALEN); - pos = (u8 *) & hdr->seq_ctl; + pos = (u8 *) & hdr->seq_ctrl; aad[22] = pos[0] & 0x0f; aad[23] = 0; /* all bits masked */ memset(aad + 24, 0, 8); @@ -170,20 +170,20 @@ static void ccmp_init_blocks(struct crypto_cipher *tfm, } /* Start with the first block and AAD */ - ieee80211_ccmp_aes_encrypt(tfm, b0, auth); + lib80211_ccmp_aes_encrypt(tfm, b0, auth); xor_block(auth, aad, AES_BLOCK_LEN); - ieee80211_ccmp_aes_encrypt(tfm, auth, auth); + lib80211_ccmp_aes_encrypt(tfm, auth, auth); xor_block(auth, &aad[AES_BLOCK_LEN], AES_BLOCK_LEN); - ieee80211_ccmp_aes_encrypt(tfm, auth, auth); + lib80211_ccmp_aes_encrypt(tfm, auth, auth); b0[0] &= 0x07; b0[14] = b0[15] = 0; - ieee80211_ccmp_aes_encrypt(tfm, b0, s0); + lib80211_ccmp_aes_encrypt(tfm, b0, s0); } -static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, +static int lib80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, u8 *aeskey, int keylen, void *priv) { - struct ieee80211_ccmp_data *key = priv; + struct lib80211_ccmp_data *key = priv; int i; u8 *pos; @@ -217,12 +217,12 @@ static int ieee80211_ccmp_hdr(struct sk_buff *skb, int hdr_len, return CCMP_HDR_LEN; } -static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +static int lib80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { - struct ieee80211_ccmp_data *key = priv; + struct lib80211_ccmp_data *key = priv; int data_len, i, blocks, last, len; u8 *pos, *mic; - struct ieee80211_hdr_4addr *hdr; + struct ieee80211_hdr *hdr; u8 *b0 = key->tx_b0; u8 *b = key->tx_b; u8 *e = key->tx_e; @@ -232,13 +232,13 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) return -1; data_len = skb->len - hdr_len; - len = ieee80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv); + len = lib80211_ccmp_hdr(skb, hdr_len, NULL, 0, priv); if (len < 0) return -1; pos = skb->data + hdr_len + CCMP_HDR_LEN; mic = skb_put(skb, CCMP_MIC_LEN); - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct ieee80211_hdr *)skb->data; ccmp_init_blocks(key->tfm, hdr, key->tx_pn, data_len, b0, b, s0); blocks = DIV_ROUND_UP(data_len, AES_BLOCK_LEN); @@ -248,11 +248,11 @@ static int ieee80211_ccmp_encrypt(struct sk_buff *skb, int hdr_len, void *priv) len = (i == blocks && last) ? last : AES_BLOCK_LEN; /* Authentication */ xor_block(b, pos, len); - ieee80211_ccmp_aes_encrypt(key->tfm, b, b); + lib80211_ccmp_aes_encrypt(key->tfm, b, b); /* Encryption, with counter */ b0[14] = (i >> 8) & 0xff; b0[15] = i & 0xff; - ieee80211_ccmp_aes_encrypt(key->tfm, b0, e); + lib80211_ccmp_aes_encrypt(key->tfm, b0, e); xor_block(pos, e, len); pos += len; } @@ -284,11 +284,11 @@ static inline int ccmp_replay_check(u8 *pn_n, u8 *pn_o) return 0; } -static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +static int lib80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { - struct ieee80211_ccmp_data *key = priv; + struct lib80211_ccmp_data *key = priv; u8 keyidx, *pos; - struct ieee80211_hdr_4addr *hdr; + struct ieee80211_hdr *hdr; u8 *b0 = key->rx_b0; u8 *b = key->rx_b; u8 *a = key->rx_a; @@ -296,20 +296,19 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) int i, blocks, last, len; size_t data_len = skb->len - hdr_len - CCMP_HDR_LEN - CCMP_MIC_LEN; u8 *mic = skb->data + skb->len - CCMP_MIC_LEN; - DECLARE_MAC_BUF(mac); if (skb->len < hdr_len + CCMP_HDR_LEN + CCMP_MIC_LEN) { key->dot11RSNAStatsCCMPFormatErrors++; return -1; } - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct ieee80211_hdr *)skb->data; pos = skb->data + hdr_len; keyidx = pos[3]; if (!(keyidx & (1 << 5))) { if (net_ratelimit()) { printk(KERN_DEBUG "CCMP: received packet without ExtIV" - " flag from %s\n", print_mac(mac, hdr->addr2)); + " flag from %pM\n", hdr->addr2); } key->dot11RSNAStatsCCMPFormatErrors++; return -2; @@ -322,9 +321,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) } if (!key->key_set) { if (net_ratelimit()) { - printk(KERN_DEBUG "CCMP: received packet from %s" + printk(KERN_DEBUG "CCMP: received packet from %pM" " with keyid=%d that does not have a configured" - " key\n", print_mac(mac, hdr->addr2), keyidx); + " key\n", hdr->addr2, keyidx); } return -3; } @@ -338,11 +337,11 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) pos += 8; if (ccmp_replay_check(pn, key->rx_pn)) { - if (ieee80211_ratelimit_debug(IEEE80211_DL_DROP)) { - IEEE80211_DEBUG_DROP("CCMP: replay detected: STA=%s " + if (net_ratelimit()) { + printk(KERN_DEBUG "CCMP: replay detected: STA=%pM " "previous PN %02x%02x%02x%02x%02x%02x " "received PN %02x%02x%02x%02x%02x%02x\n", - print_mac(mac, hdr->addr2), + hdr->addr2, key->rx_pn[0], key->rx_pn[1], key->rx_pn[2], key->rx_pn[3], key->rx_pn[4], key->rx_pn[5], pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]); @@ -362,18 +361,18 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) /* Decrypt, with counter */ b0[14] = (i >> 8) & 0xff; b0[15] = i & 0xff; - ieee80211_ccmp_aes_encrypt(key->tfm, b0, b); + lib80211_ccmp_aes_encrypt(key->tfm, b0, b); xor_block(pos, b, len); /* Authentication */ xor_block(a, pos, len); - ieee80211_ccmp_aes_encrypt(key->tfm, a, a); + lib80211_ccmp_aes_encrypt(key->tfm, a, a); pos += len; } if (memcmp(mic, a, CCMP_MIC_LEN) != 0) { if (net_ratelimit()) { printk(KERN_DEBUG "CCMP: decrypt failed: STA=" - "%s\n", print_mac(mac, hdr->addr2)); + "%pM\n", hdr->addr2); } key->dot11RSNAStatsCCMPDecryptErrors++; return -5; @@ -389,9 +388,9 @@ static int ieee80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv) return keyidx; } -static int ieee80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv) +static int lib80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv) { - struct ieee80211_ccmp_data *data = priv; + struct lib80211_ccmp_data *data = priv; int keyidx; struct crypto_cipher *tfm = data->tfm; @@ -419,9 +418,9 @@ static int ieee80211_ccmp_set_key(void *key, int len, u8 * seq, void *priv) return 0; } -static int ieee80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv) +static int lib80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv) { - struct ieee80211_ccmp_data *data = priv; + struct lib80211_ccmp_data *data = priv; if (len < CCMP_TK_LEN) return -1; @@ -442,9 +441,9 @@ static int ieee80211_ccmp_get_key(void *key, int len, u8 * seq, void *priv) return CCMP_TK_LEN; } -static char *ieee80211_ccmp_print_stats(char *p, void *priv) +static char *lib80211_ccmp_print_stats(char *p, void *priv) { - struct ieee80211_ccmp_data *ccmp = priv; + struct lib80211_ccmp_data *ccmp = priv; p += sprintf(p, "key[%d] alg=CCMP key_set=%d " "tx_pn=%02x%02x%02x%02x%02x%02x " @@ -462,32 +461,32 @@ static char *ieee80211_ccmp_print_stats(char *p, void *priv) return p; } -static struct ieee80211_crypto_ops ieee80211_crypt_ccmp = { +static struct lib80211_crypto_ops lib80211_crypt_ccmp = { .name = "CCMP", - .init = ieee80211_ccmp_init, - .deinit = ieee80211_ccmp_deinit, - .build_iv = ieee80211_ccmp_hdr, - .encrypt_mpdu = ieee80211_ccmp_encrypt, - .decrypt_mpdu = ieee80211_ccmp_decrypt, + .init = lib80211_ccmp_init, + .deinit = lib80211_ccmp_deinit, + .build_iv = lib80211_ccmp_hdr, + .encrypt_mpdu = lib80211_ccmp_encrypt, + .decrypt_mpdu = lib80211_ccmp_decrypt, .encrypt_msdu = NULL, .decrypt_msdu = NULL, - .set_key = ieee80211_ccmp_set_key, - .get_key = ieee80211_ccmp_get_key, - .print_stats = ieee80211_ccmp_print_stats, + .set_key = lib80211_ccmp_set_key, + .get_key = lib80211_ccmp_get_key, + .print_stats = lib80211_ccmp_print_stats, .extra_mpdu_prefix_len = CCMP_HDR_LEN, .extra_mpdu_postfix_len = CCMP_MIC_LEN, .owner = THIS_MODULE, }; -static int __init ieee80211_crypto_ccmp_init(void) +static int __init lib80211_crypto_ccmp_init(void) { - return ieee80211_register_crypto_ops(&ieee80211_crypt_ccmp); + return lib80211_register_crypto_ops(&lib80211_crypt_ccmp); } -static void __exit ieee80211_crypto_ccmp_exit(void) +static void __exit lib80211_crypto_ccmp_exit(void) { - ieee80211_unregister_crypto_ops(&ieee80211_crypt_ccmp); + lib80211_unregister_crypto_ops(&lib80211_crypt_ccmp); } -module_init(ieee80211_crypto_ccmp_init); -module_exit(ieee80211_crypto_ccmp_exit); +module_init(lib80211_crypto_ccmp_init); +module_exit(lib80211_crypto_ccmp_exit); diff --git a/net/ieee80211/ieee80211_crypt_tkip.c b/net/wireless/lib80211_crypt_tkip.c similarity index 79% rename from net/ieee80211/ieee80211_crypt_tkip.c rename to net/wireless/lib80211_crypt_tkip.c index bba0152e2d713b5798e6501711312e59a4267cef..7e8e22bfed90a09bf6f1d66543a1ebbe8867808d 100644 --- a/net/ieee80211/ieee80211_crypt_tkip.c +++ b/net/wireless/lib80211_crypt_tkip.c @@ -1,7 +1,8 @@ /* - * Host AP crypt: host-based TKIP encryption implementation for Host AP driver + * lib80211 crypt: host-based TKIP encryption implementation for lib80211 * * Copyright (c) 2003-2004, Jouni Malinen + * Copyright (c) 2008, John W. Linville * * 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 @@ -22,16 +23,20 @@ #include #include -#include +#include +#include +#include #include #include +#include + MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Host AP crypt: TKIP"); +MODULE_DESCRIPTION("lib80211 crypt: TKIP"); MODULE_LICENSE("GPL"); -struct ieee80211_tkip_data { +struct lib80211_tkip_data { #define TKIP_KEY_LEN 32 u8 key[TKIP_KEY_LEN]; int key_set; @@ -65,23 +70,23 @@ struct ieee80211_tkip_data { unsigned long flags; }; -static unsigned long ieee80211_tkip_set_flags(unsigned long flags, void *priv) +static unsigned long lib80211_tkip_set_flags(unsigned long flags, void *priv) { - struct ieee80211_tkip_data *_priv = priv; + struct lib80211_tkip_data *_priv = priv; unsigned long old_flags = _priv->flags; _priv->flags = flags; return old_flags; } -static unsigned long ieee80211_tkip_get_flags(void *priv) +static unsigned long lib80211_tkip_get_flags(void *priv) { - struct ieee80211_tkip_data *_priv = priv; + struct lib80211_tkip_data *_priv = priv; return _priv->flags; } -static void *ieee80211_tkip_init(int key_idx) +static void *lib80211_tkip_init(int key_idx) { - struct ieee80211_tkip_data *priv; + struct lib80211_tkip_data *priv; priv = kzalloc(sizeof(*priv), GFP_ATOMIC); if (priv == NULL) @@ -92,7 +97,7 @@ static void *ieee80211_tkip_init(int key_idx) priv->tx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tx_tfm_arc4)) { - printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " "crypto API arc4\n"); priv->tx_tfm_arc4 = NULL; goto fail; @@ -101,7 +106,7 @@ static void *ieee80211_tkip_init(int key_idx) priv->tx_tfm_michael = crypto_alloc_hash("michael_mic", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tx_tfm_michael)) { - printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " "crypto API michael_mic\n"); priv->tx_tfm_michael = NULL; goto fail; @@ -110,7 +115,7 @@ static void *ieee80211_tkip_init(int key_idx) priv->rx_tfm_arc4 = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->rx_tfm_arc4)) { - printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " "crypto API arc4\n"); priv->rx_tfm_arc4 = NULL; goto fail; @@ -119,7 +124,7 @@ static void *ieee80211_tkip_init(int key_idx) priv->rx_tfm_michael = crypto_alloc_hash("michael_mic", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->rx_tfm_michael)) { - printk(KERN_DEBUG "ieee80211_crypt_tkip: could not allocate " + printk(KERN_DEBUG "lib80211_crypt_tkip: could not allocate " "crypto API michael_mic\n"); priv->rx_tfm_michael = NULL; goto fail; @@ -143,9 +148,9 @@ static void *ieee80211_tkip_init(int key_idx) return NULL; } -static void ieee80211_tkip_deinit(void *priv) +static void lib80211_tkip_deinit(void *priv) { - struct ieee80211_tkip_data *_priv = priv; + struct lib80211_tkip_data *_priv = priv; if (_priv) { if (_priv->tx_tfm_michael) crypto_free_hash(_priv->tx_tfm_michael); @@ -305,15 +310,15 @@ static void tkip_mixing_phase2(u8 * WEPSeed, const u8 * TK, const u16 * TTAK, #endif } -static int ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, +static int lib80211_tkip_hdr(struct sk_buff *skb, int hdr_len, u8 * rc4key, int keylen, void *priv) { - struct ieee80211_tkip_data *tkey = priv; + struct lib80211_tkip_data *tkey = priv; int len; u8 *pos; - struct ieee80211_hdr_4addr *hdr; + struct ieee80211_hdr *hdr; - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct ieee80211_hdr *)skb->data; if (skb_headroom(skb) < 8 || skb->len < hdr_len) return -1; @@ -351,23 +356,21 @@ static int ieee80211_tkip_hdr(struct sk_buff *skb, int hdr_len, return 8; } -static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +static int lib80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { - struct ieee80211_tkip_data *tkey = priv; + struct lib80211_tkip_data *tkey = priv; struct blkcipher_desc desc = { .tfm = tkey->tx_tfm_arc4 }; int len; u8 rc4key[16], *pos, *icv; u32 crc; struct scatterlist sg; - DECLARE_MAC_BUF(mac); if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { - struct ieee80211_hdr_4addr *hdr = - (struct ieee80211_hdr_4addr *)skb->data; + struct ieee80211_hdr *hdr = + (struct ieee80211_hdr *)skb->data; printk(KERN_DEBUG ": TKIP countermeasures: dropped " - "TX packet to %s\n", - print_mac(mac, hdr->addr1)); + "TX packet to %pM\n", hdr->addr1); } return -1; } @@ -378,7 +381,7 @@ static int ieee80211_tkip_encrypt(struct sk_buff *skb, int hdr_len, void *priv) len = skb->len - hdr_len; pos = skb->data + hdr_len; - if ((ieee80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0) + if ((lib80211_tkip_hdr(skb, hdr_len, rc4key, 16, priv)) < 0) return -1; icv = skb_put(skb, 4); @@ -407,28 +410,26 @@ static inline int tkip_replay_check(u32 iv32_n, u16 iv16_n, return 0; } -static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { - struct ieee80211_tkip_data *tkey = priv; + struct lib80211_tkip_data *tkey = priv; struct blkcipher_desc desc = { .tfm = tkey->rx_tfm_arc4 }; u8 rc4key[16]; u8 keyidx, *pos; u32 iv32; u16 iv16; - struct ieee80211_hdr_4addr *hdr; + struct ieee80211_hdr *hdr; u8 icv[4]; u32 crc; struct scatterlist sg; int plen; - DECLARE_MAC_BUF(mac); - hdr = (struct ieee80211_hdr_4addr *)skb->data; + hdr = (struct ieee80211_hdr *)skb->data; if (tkey->flags & IEEE80211_CRYPTO_TKIP_COUNTERMEASURES) { if (net_ratelimit()) { printk(KERN_DEBUG ": TKIP countermeasures: dropped " - "received packet from %s\n", - print_mac(mac, hdr->addr2)); + "received packet from %pM\n", hdr->addr2); } return -1; } @@ -441,7 +442,7 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (!(keyidx & (1 << 5))) { if (net_ratelimit()) { printk(KERN_DEBUG "TKIP: received packet without ExtIV" - " flag from %s\n", print_mac(mac, hdr->addr2)); + " flag from %pM\n", hdr->addr2); } return -2; } @@ -453,9 +454,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) } if (!tkey->key_set) { if (net_ratelimit()) { - printk(KERN_DEBUG "TKIP: received packet from %s" + printk(KERN_DEBUG "TKIP: received packet from %pM" " with keyid=%d that does not have a configured" - " key\n", print_mac(mac, hdr->addr2), keyidx); + " key\n", hdr->addr2, keyidx); } return -3; } @@ -464,10 +465,10 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) pos += 8; if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) { - if (ieee80211_ratelimit_debug(IEEE80211_DL_DROP)) { - IEEE80211_DEBUG_DROP("TKIP: replay detected: STA=%s" + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: replay detected: STA=%pM" " previous TSC %08x%04x received TSC " - "%08x%04x\n", print_mac(mac, hdr->addr2), + "%08x%04x\n", hdr->addr2, tkey->rx_iv32, tkey->rx_iv16, iv32, iv16); } tkey->dot11RSNAStatsTKIPReplays++; @@ -487,8 +488,8 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) if (crypto_blkcipher_decrypt(&desc, &sg, &sg, plen + 4)) { if (net_ratelimit()) { printk(KERN_DEBUG ": TKIP: failed to decrypt " - "received packet from %s\n", - print_mac(mac, hdr->addr2)); + "received packet from %pM\n", + hdr->addr2); } return -7; } @@ -504,9 +505,9 @@ static int ieee80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv) * it needs to be recalculated for the next packet. */ tkey->rx_phase1_done = 0; } - if (ieee80211_ratelimit_debug(IEEE80211_DL_DROP)) { - IEEE80211_DEBUG_DROP("TKIP: ICV error detected: STA=" - "%s\n", print_mac(mac, hdr->addr2)); + if (net_ratelimit()) { + printk(KERN_DEBUG "TKIP: ICV error detected: STA=" + "%pM\n", hdr->addr2); } tkey->dot11RSNAStatsTKIPICVErrors++; return -5; @@ -549,13 +550,11 @@ static int michael_mic(struct crypto_hash *tfm_michael, u8 * key, u8 * hdr, static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) { - struct ieee80211_hdr_4addr *hdr11; - u16 stype; + struct ieee80211_hdr *hdr11; - hdr11 = (struct ieee80211_hdr_4addr *)skb->data; - stype = WLAN_FC_GET_STYPE(le16_to_cpu(hdr11->frame_ctl)); + hdr11 = (struct ieee80211_hdr *)skb->data; - switch (le16_to_cpu(hdr11->frame_ctl) & + switch (le16_to_cpu(hdr11->frame_control) & (IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS)) { case IEEE80211_FCTL_TODS: memcpy(hdr, hdr11->addr3, ETH_ALEN); /* DA */ @@ -575,20 +574,19 @@ static void michael_mic_hdr(struct sk_buff *skb, u8 * hdr) break; } - if (stype & IEEE80211_STYPE_QOS_DATA) { - const struct ieee80211_hdr_3addrqos *qoshdr = - (struct ieee80211_hdr_3addrqos *)skb->data; - hdr[12] = le16_to_cpu(qoshdr->qos_ctl) & IEEE80211_QCTL_TID; + if (ieee80211_is_data_qos(hdr11->frame_control)) { + hdr[12] = le16_to_cpu(*ieee80211_get_qos_ctl(hdr11)) + & IEEE80211_QOS_CTL_TID_MASK; } else hdr[12] = 0; /* priority */ hdr[13] = hdr[14] = hdr[15] = 0; /* reserved */ } -static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, +static int lib80211_michael_mic_add(struct sk_buff *skb, int hdr_len, void *priv) { - struct ieee80211_tkip_data *tkey = priv; + struct lib80211_tkip_data *tkey = priv; u8 *pos; if (skb_tailroom(skb) < 8 || skb->len < hdr_len) { @@ -607,8 +605,8 @@ static int ieee80211_michael_mic_add(struct sk_buff *skb, int hdr_len, return 0; } -static void ieee80211_michael_mic_failure(struct net_device *dev, - struct ieee80211_hdr_4addr *hdr, +static void lib80211_michael_mic_failure(struct net_device *dev, + struct ieee80211_hdr *hdr, int keyidx) { union iwreq_data wrqu; @@ -628,12 +626,11 @@ static void ieee80211_michael_mic_failure(struct net_device *dev, wireless_send_event(dev, IWEVMICHAELMICFAILURE, &wrqu, (char *)&ev); } -static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, +static int lib80211_michael_mic_verify(struct sk_buff *skb, int keyidx, int hdr_len, void *priv) { - struct ieee80211_tkip_data *tkey = priv; + struct lib80211_tkip_data *tkey = priv; u8 mic[8]; - DECLARE_MAC_BUF(mac); if (!tkey->key_set) return -1; @@ -643,14 +640,14 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, skb->data + hdr_len, skb->len - 8 - hdr_len, mic)) return -1; if (memcmp(mic, skb->data + skb->len - 8, 8) != 0) { - struct ieee80211_hdr_4addr *hdr; - hdr = (struct ieee80211_hdr_4addr *)skb->data; + struct ieee80211_hdr *hdr; + hdr = (struct ieee80211_hdr *)skb->data; printk(KERN_DEBUG "%s: Michael MIC verification failed for " - "MSDU from %s keyidx=%d\n", - skb->dev ? skb->dev->name : "N/A", print_mac(mac, hdr->addr2), + "MSDU from %pM keyidx=%d\n", + skb->dev ? skb->dev->name : "N/A", hdr->addr2, keyidx); if (skb->dev) - ieee80211_michael_mic_failure(skb->dev, hdr, keyidx); + lib80211_michael_mic_failure(skb->dev, hdr, keyidx); tkey->dot11RSNAStatsTKIPLocalMICFailures++; return -1; } @@ -665,9 +662,9 @@ static int ieee80211_michael_mic_verify(struct sk_buff *skb, int keyidx, return 0; } -static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv) +static int lib80211_tkip_set_key(void *key, int len, u8 * seq, void *priv) { - struct ieee80211_tkip_data *tkey = priv; + struct lib80211_tkip_data *tkey = priv; int keyidx; struct crypto_hash *tfm = tkey->tx_tfm_michael; struct crypto_blkcipher *tfm2 = tkey->tx_tfm_arc4; @@ -698,9 +695,9 @@ static int ieee80211_tkip_set_key(void *key, int len, u8 * seq, void *priv) return 0; } -static int ieee80211_tkip_get_key(void *key, int len, u8 * seq, void *priv) +static int lib80211_tkip_get_key(void *key, int len, u8 * seq, void *priv) { - struct ieee80211_tkip_data *tkey = priv; + struct lib80211_tkip_data *tkey = priv; if (len < TKIP_KEY_LEN) return -1; @@ -727,9 +724,9 @@ static int ieee80211_tkip_get_key(void *key, int len, u8 * seq, void *priv) return TKIP_KEY_LEN; } -static char *ieee80211_tkip_print_stats(char *p, void *priv) +static char *lib80211_tkip_print_stats(char *p, void *priv) { - struct ieee80211_tkip_data *tkip = priv; + struct lib80211_tkip_data *tkip = priv; p += sprintf(p, "key[%d] alg=TKIP key_set=%d " "tx_pn=%02x%02x%02x%02x%02x%02x " "rx_pn=%02x%02x%02x%02x%02x%02x " @@ -753,35 +750,35 @@ static char *ieee80211_tkip_print_stats(char *p, void *priv) return p; } -static struct ieee80211_crypto_ops ieee80211_crypt_tkip = { +static struct lib80211_crypto_ops lib80211_crypt_tkip = { .name = "TKIP", - .init = ieee80211_tkip_init, - .deinit = ieee80211_tkip_deinit, - .build_iv = ieee80211_tkip_hdr, - .encrypt_mpdu = ieee80211_tkip_encrypt, - .decrypt_mpdu = ieee80211_tkip_decrypt, - .encrypt_msdu = ieee80211_michael_mic_add, - .decrypt_msdu = ieee80211_michael_mic_verify, - .set_key = ieee80211_tkip_set_key, - .get_key = ieee80211_tkip_get_key, - .print_stats = ieee80211_tkip_print_stats, + .init = lib80211_tkip_init, + .deinit = lib80211_tkip_deinit, + .build_iv = lib80211_tkip_hdr, + .encrypt_mpdu = lib80211_tkip_encrypt, + .decrypt_mpdu = lib80211_tkip_decrypt, + .encrypt_msdu = lib80211_michael_mic_add, + .decrypt_msdu = lib80211_michael_mic_verify, + .set_key = lib80211_tkip_set_key, + .get_key = lib80211_tkip_get_key, + .print_stats = lib80211_tkip_print_stats, .extra_mpdu_prefix_len = 4 + 4, /* IV + ExtIV */ .extra_mpdu_postfix_len = 4, /* ICV */ .extra_msdu_postfix_len = 8, /* MIC */ - .get_flags = ieee80211_tkip_get_flags, - .set_flags = ieee80211_tkip_set_flags, + .get_flags = lib80211_tkip_get_flags, + .set_flags = lib80211_tkip_set_flags, .owner = THIS_MODULE, }; -static int __init ieee80211_crypto_tkip_init(void) +static int __init lib80211_crypto_tkip_init(void) { - return ieee80211_register_crypto_ops(&ieee80211_crypt_tkip); + return lib80211_register_crypto_ops(&lib80211_crypt_tkip); } -static void __exit ieee80211_crypto_tkip_exit(void) +static void __exit lib80211_crypto_tkip_exit(void) { - ieee80211_unregister_crypto_ops(&ieee80211_crypt_tkip); + lib80211_unregister_crypto_ops(&lib80211_crypt_tkip); } -module_init(ieee80211_crypto_tkip_init); -module_exit(ieee80211_crypto_tkip_exit); +module_init(lib80211_crypto_tkip_init); +module_exit(lib80211_crypto_tkip_exit); diff --git a/net/ieee80211/ieee80211_crypt_wep.c b/net/wireless/lib80211_crypt_wep.c similarity index 74% rename from net/ieee80211/ieee80211_crypt_wep.c rename to net/wireless/lib80211_crypt_wep.c index 3fa30c40779f6b7c8242541a6a484440409a40d3..6d41e05ca33bd83d865c19117e77f9822bb05275 100644 --- a/net/ieee80211/ieee80211_crypt_wep.c +++ b/net/wireless/lib80211_crypt_wep.c @@ -1,7 +1,8 @@ /* - * Host AP crypt: host-based WEP encryption implementation for Host AP driver + * lib80211 crypt: host-based WEP encryption implementation for lib80211 * * Copyright (c) 2002-2004, Jouni Malinen + * Copyright (c) 2008, John W. Linville * * 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 @@ -19,16 +20,16 @@ #include #include -#include +#include #include #include MODULE_AUTHOR("Jouni Malinen"); -MODULE_DESCRIPTION("Host AP crypt: WEP"); +MODULE_DESCRIPTION("lib80211 crypt: WEP"); MODULE_LICENSE("GPL"); -struct prism2_wep_data { +struct lib80211_wep_data { u32 iv; #define WEP_KEY_LEN 13 u8 key[WEP_KEY_LEN + 1]; @@ -38,9 +39,9 @@ struct prism2_wep_data { struct crypto_blkcipher *rx_tfm; }; -static void *prism2_wep_init(int keyidx) +static void *lib80211_wep_init(int keyidx) { - struct prism2_wep_data *priv; + struct lib80211_wep_data *priv; priv = kzalloc(sizeof(*priv), GFP_ATOMIC); if (priv == NULL) @@ -49,7 +50,7 @@ static void *prism2_wep_init(int keyidx) priv->tx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->tx_tfm)) { - printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " + printk(KERN_DEBUG "lib80211_crypt_wep: could not allocate " "crypto API arc4\n"); priv->tx_tfm = NULL; goto fail; @@ -57,7 +58,7 @@ static void *prism2_wep_init(int keyidx) priv->rx_tfm = crypto_alloc_blkcipher("ecb(arc4)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(priv->rx_tfm)) { - printk(KERN_DEBUG "ieee80211_crypt_wep: could not allocate " + printk(KERN_DEBUG "lib80211_crypt_wep: could not allocate " "crypto API arc4\n"); priv->rx_tfm = NULL; goto fail; @@ -78,9 +79,9 @@ static void *prism2_wep_init(int keyidx) return NULL; } -static void prism2_wep_deinit(void *priv) +static void lib80211_wep_deinit(void *priv) { - struct prism2_wep_data *_priv = priv; + struct lib80211_wep_data *_priv = priv; if (_priv) { if (_priv->tx_tfm) crypto_free_blkcipher(_priv->tx_tfm); @@ -91,10 +92,10 @@ static void prism2_wep_deinit(void *priv) } /* Add WEP IV/key info to a frame that has at least 4 bytes of headroom */ -static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, +static int lib80211_wep_build_iv(struct sk_buff *skb, int hdr_len, u8 *key, int keylen, void *priv) { - struct prism2_wep_data *wep = priv; + struct lib80211_wep_data *wep = priv; u32 klen, len; u8 *pos; @@ -134,21 +135,21 @@ static int prism2_wep_build_iv(struct sk_buff *skb, int hdr_len, * * WEP frame payload: IV + TX key idx, RC4(data), ICV = RC4(CRC32(data)) */ -static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) +static int lib80211_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) { - struct prism2_wep_data *wep = priv; + struct lib80211_wep_data *wep = priv; struct blkcipher_desc desc = { .tfm = wep->tx_tfm }; u32 crc, klen, len; u8 *pos, *icv; struct scatterlist sg; u8 key[WEP_KEY_LEN + 3]; - /* other checks are in prism2_wep_build_iv */ + /* other checks are in lib80211_wep_build_iv */ if (skb_tailroom(skb) < 4) return -1; /* add the IV to the frame */ - if (prism2_wep_build_iv(skb, hdr_len, NULL, 0, priv)) + if (lib80211_wep_build_iv(skb, hdr_len, NULL, 0, priv)) return -1; /* Copy the IV into the first 3 bytes of the key */ @@ -181,9 +182,9 @@ static int prism2_wep_encrypt(struct sk_buff *skb, int hdr_len, void *priv) * Returns 0 if frame was decrypted successfully and ICV was correct and -1 on * failure. If frame is OK, IV and ICV will be removed. */ -static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) +static int lib80211_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) { - struct prism2_wep_data *wep = priv; + struct lib80211_wep_data *wep = priv; struct blkcipher_desc desc = { .tfm = wep->rx_tfm }; u32 crc, klen, plen; u8 key[WEP_KEY_LEN + 3]; @@ -232,9 +233,9 @@ static int prism2_wep_decrypt(struct sk_buff *skb, int hdr_len, void *priv) return 0; } -static int prism2_wep_set_key(void *key, int len, u8 * seq, void *priv) +static int lib80211_wep_set_key(void *key, int len, u8 * seq, void *priv) { - struct prism2_wep_data *wep = priv; + struct lib80211_wep_data *wep = priv; if (len < 0 || len > WEP_KEY_LEN) return -1; @@ -245,9 +246,9 @@ static int prism2_wep_set_key(void *key, int len, u8 * seq, void *priv) return 0; } -static int prism2_wep_get_key(void *key, int len, u8 * seq, void *priv) +static int lib80211_wep_get_key(void *key, int len, u8 * seq, void *priv) { - struct prism2_wep_data *wep = priv; + struct lib80211_wep_data *wep = priv; if (len < wep->key_len) return -1; @@ -257,39 +258,39 @@ static int prism2_wep_get_key(void *key, int len, u8 * seq, void *priv) return wep->key_len; } -static char *prism2_wep_print_stats(char *p, void *priv) +static char *lib80211_wep_print_stats(char *p, void *priv) { - struct prism2_wep_data *wep = priv; + struct lib80211_wep_data *wep = priv; p += sprintf(p, "key[%d] alg=WEP len=%d\n", wep->key_idx, wep->key_len); return p; } -static struct ieee80211_crypto_ops ieee80211_crypt_wep = { +static struct lib80211_crypto_ops lib80211_crypt_wep = { .name = "WEP", - .init = prism2_wep_init, - .deinit = prism2_wep_deinit, - .build_iv = prism2_wep_build_iv, - .encrypt_mpdu = prism2_wep_encrypt, - .decrypt_mpdu = prism2_wep_decrypt, + .init = lib80211_wep_init, + .deinit = lib80211_wep_deinit, + .build_iv = lib80211_wep_build_iv, + .encrypt_mpdu = lib80211_wep_encrypt, + .decrypt_mpdu = lib80211_wep_decrypt, .encrypt_msdu = NULL, .decrypt_msdu = NULL, - .set_key = prism2_wep_set_key, - .get_key = prism2_wep_get_key, - .print_stats = prism2_wep_print_stats, + .set_key = lib80211_wep_set_key, + .get_key = lib80211_wep_get_key, + .print_stats = lib80211_wep_print_stats, .extra_mpdu_prefix_len = 4, /* IV */ .extra_mpdu_postfix_len = 4, /* ICV */ .owner = THIS_MODULE, }; -static int __init ieee80211_crypto_wep_init(void) +static int __init lib80211_crypto_wep_init(void) { - return ieee80211_register_crypto_ops(&ieee80211_crypt_wep); + return lib80211_register_crypto_ops(&lib80211_crypt_wep); } -static void __exit ieee80211_crypto_wep_exit(void) +static void __exit lib80211_crypto_wep_exit(void) { - ieee80211_unregister_crypto_ops(&ieee80211_crypt_wep); + lib80211_unregister_crypto_ops(&lib80211_crypt_wep); } -module_init(ieee80211_crypto_wep_init); -module_exit(ieee80211_crypto_wep_exit); +module_init(lib80211_crypto_wep_init); +module_exit(lib80211_crypto_wep_exit); diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c index 572793c8c7ab6b576dae03753b69503ee05f04cf..1e728fff474eb97bce9c983fac4afbc005f66fd1 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c @@ -58,6 +58,9 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_WIPHY] = { .type = NLA_U32 }, [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING, .len = BUS_ID_SIZE-1 }, + [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED }, + [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 }, + [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 }, [NL80211_ATTR_IFTYPE] = { .type = NLA_U32 }, [NL80211_ATTR_IFINDEX] = { .type = NLA_U32 }, @@ -84,7 +87,7 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { .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_MNTR_FLAGS] = { /* NLA_NESTED can't be empty */ }, [NL80211_ATTR_MESH_ID] = { .type = NLA_BINARY, .len = IEEE80211_MAX_MESH_ID_LEN }, [NL80211_ATTR_MPATH_NEXT_HOP] = { .type = NLA_U32 }, @@ -95,6 +98,10 @@ static struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] __read_mostly = { [NL80211_ATTR_BSS_CTS_PROT] = { .type = NLA_U8 }, [NL80211_ATTR_BSS_SHORT_PREAMBLE] = { .type = NLA_U8 }, [NL80211_ATTR_BSS_SHORT_SLOT_TIME] = { .type = NLA_U8 }, + [NL80211_ATTR_BSS_BASIC_RATES] = { .type = NLA_BINARY, + .len = NL80211_MAX_SUPP_RATES }, + + [NL80211_ATTR_MESH_PARAMS] = { .type = NLA_NESTED }, [NL80211_ATTR_HT_CAPABILITY] = { .type = NLA_BINARY, .len = NL80211_HT_CAPABILITY_LEN }, @@ -157,6 +164,19 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, if (!nl_band) goto nla_put_failure; + /* add HT info */ + if (dev->wiphy.bands[band]->ht_cap.ht_supported) { + NLA_PUT(msg, NL80211_BAND_ATTR_HT_MCS_SET, + sizeof(dev->wiphy.bands[band]->ht_cap.mcs), + &dev->wiphy.bands[band]->ht_cap.mcs); + NLA_PUT_U16(msg, NL80211_BAND_ATTR_HT_CAPA, + dev->wiphy.bands[band]->ht_cap.cap); + NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_FACTOR, + dev->wiphy.bands[band]->ht_cap.ampdu_factor); + NLA_PUT_U8(msg, NL80211_BAND_ATTR_HT_AMPDU_DENSITY, + dev->wiphy.bands[band]->ht_cap.ampdu_density); + } + /* add frequencies */ nl_freqs = nla_nest_start(msg, NL80211_BAND_ATTR_FREQS); if (!nl_freqs) @@ -180,6 +200,9 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags, if (chan->flags & IEEE80211_CHAN_RADAR) NLA_PUT_FLAG(msg, NL80211_FREQUENCY_ATTR_RADAR); + NLA_PUT_U32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, + DBM_TO_MBM(chan->max_power)); + nla_nest_end(msg, nl_freq); } @@ -269,20 +292,142 @@ static int nl80211_get_wiphy(struct sk_buff *skb, struct genl_info *info) return -ENOBUFS; } +static const struct nla_policy txq_params_policy[NL80211_TXQ_ATTR_MAX + 1] = { + [NL80211_TXQ_ATTR_QUEUE] = { .type = NLA_U8 }, + [NL80211_TXQ_ATTR_TXOP] = { .type = NLA_U16 }, + [NL80211_TXQ_ATTR_CWMIN] = { .type = NLA_U16 }, + [NL80211_TXQ_ATTR_CWMAX] = { .type = NLA_U16 }, + [NL80211_TXQ_ATTR_AIFS] = { .type = NLA_U8 }, +}; + +static int parse_txq_params(struct nlattr *tb[], + struct ieee80211_txq_params *txq_params) +{ + if (!tb[NL80211_TXQ_ATTR_QUEUE] || !tb[NL80211_TXQ_ATTR_TXOP] || + !tb[NL80211_TXQ_ATTR_CWMIN] || !tb[NL80211_TXQ_ATTR_CWMAX] || + !tb[NL80211_TXQ_ATTR_AIFS]) + return -EINVAL; + + txq_params->queue = nla_get_u8(tb[NL80211_TXQ_ATTR_QUEUE]); + txq_params->txop = nla_get_u16(tb[NL80211_TXQ_ATTR_TXOP]); + txq_params->cwmin = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMIN]); + txq_params->cwmax = nla_get_u16(tb[NL80211_TXQ_ATTR_CWMAX]); + txq_params->aifs = nla_get_u8(tb[NL80211_TXQ_ATTR_AIFS]); + + return 0; +} + static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) { struct cfg80211_registered_device *rdev; - int result; - - if (!info->attrs[NL80211_ATTR_WIPHY_NAME]) - return -EINVAL; + int result = 0, rem_txq_params = 0; + struct nlattr *nl_txq_params; rdev = cfg80211_get_dev_from_info(info); if (IS_ERR(rdev)) return PTR_ERR(rdev); - result = cfg80211_dev_rename(rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); + if (info->attrs[NL80211_ATTR_WIPHY_NAME]) { + result = cfg80211_dev_rename( + rdev, nla_data(info->attrs[NL80211_ATTR_WIPHY_NAME])); + if (result) + goto bad_res; + } + + if (info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS]) { + struct ieee80211_txq_params txq_params; + struct nlattr *tb[NL80211_TXQ_ATTR_MAX + 1]; + + if (!rdev->ops->set_txq_params) { + result = -EOPNOTSUPP; + goto bad_res; + } + + nla_for_each_nested(nl_txq_params, + info->attrs[NL80211_ATTR_WIPHY_TXQ_PARAMS], + rem_txq_params) { + nla_parse(tb, NL80211_TXQ_ATTR_MAX, + nla_data(nl_txq_params), + nla_len(nl_txq_params), + txq_params_policy); + result = parse_txq_params(tb, &txq_params); + if (result) + goto bad_res; + + result = rdev->ops->set_txq_params(&rdev->wiphy, + &txq_params); + if (result) + goto bad_res; + } + } + + if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) { + enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT; + struct ieee80211_channel *chan; + struct ieee80211_sta_ht_cap *ht_cap; + u32 freq, sec_freq; + + if (!rdev->ops->set_channel) { + result = -EOPNOTSUPP; + goto bad_res; + } + + result = -EINVAL; + + if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) { + channel_type = nla_get_u32(info->attrs[ + NL80211_ATTR_WIPHY_CHANNEL_TYPE]); + if (channel_type != NL80211_CHAN_NO_HT && + channel_type != NL80211_CHAN_HT20 && + channel_type != NL80211_CHAN_HT40PLUS && + channel_type != NL80211_CHAN_HT40MINUS) + goto bad_res; + } + + freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]); + chan = ieee80211_get_channel(&rdev->wiphy, freq); + + /* Primary channel not allowed */ + if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) + goto bad_res; + + if (channel_type == NL80211_CHAN_HT40MINUS) + sec_freq = freq - 20; + else if (channel_type == NL80211_CHAN_HT40PLUS) + sec_freq = freq + 20; + else + sec_freq = 0; + + ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap; + /* no HT capabilities */ + if (channel_type != NL80211_CHAN_NO_HT && + !ht_cap->ht_supported) + goto bad_res; + + if (sec_freq) { + struct ieee80211_channel *schan; + + /* no 40 MHz capabilities */ + if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) || + (ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)) + goto bad_res; + + schan = ieee80211_get_channel(&rdev->wiphy, sec_freq); + + /* Secondary channel not allowed */ + if (!schan || schan->flags & IEEE80211_CHAN_DISABLED) + goto bad_res; + } + + result = rdev->ops->set_channel(&rdev->wiphy, chan, + channel_type); + if (result) + goto bad_res; + } + + + bad_res: cfg80211_put_dev(rdev); return result; } @@ -945,12 +1090,46 @@ static int parse_station_flags(struct nlattr *nla, u32 *staflags) return 0; } +static u16 nl80211_calculate_bitrate(struct rate_info *rate) +{ + int modulation, streams, bitrate; + + if (!(rate->flags & RATE_INFO_FLAGS_MCS)) + return rate->legacy; + + /* the formula below does only work for MCS values smaller than 32 */ + if (rate->mcs >= 32) + return 0; + + modulation = rate->mcs & 7; + streams = (rate->mcs >> 3) + 1; + + bitrate = (rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) ? + 13500000 : 6500000; + + if (modulation < 4) + bitrate *= (modulation + 1); + else if (modulation == 4) + bitrate *= (modulation + 2); + else + bitrate *= (modulation + 3); + + bitrate *= streams; + + if (rate->flags & RATE_INFO_FLAGS_SHORT_GI) + bitrate = (bitrate / 9) * 10; + + /* do NOT round down here */ + return (bitrate + 50000) / 100000; +} + static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, int flags, struct net_device *dev, u8 *mac_addr, struct station_info *sinfo) { void *hdr; - struct nlattr *sinfoattr; + struct nlattr *sinfoattr, *txrate; + u16 bitrate; hdr = nl80211hdr_put(msg, pid, seq, flags, NL80211_CMD_NEW_STATION); if (!hdr) @@ -980,7 +1159,29 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq, if (sinfo->filled & STATION_INFO_PLINK_STATE) NLA_PUT_U8(msg, NL80211_STA_INFO_PLINK_STATE, sinfo->plink_state); + if (sinfo->filled & STATION_INFO_SIGNAL) + NLA_PUT_U8(msg, NL80211_STA_INFO_SIGNAL, + sinfo->signal); + if (sinfo->filled & STATION_INFO_TX_BITRATE) { + txrate = nla_nest_start(msg, NL80211_STA_INFO_TX_BITRATE); + if (!txrate) + goto nla_put_failure; + + /* nl80211_calculate_bitrate will return 0 for mcs >= 32 */ + bitrate = nl80211_calculate_bitrate(&sinfo->txrate); + if (bitrate > 0) + NLA_PUT_U16(msg, NL80211_RATE_INFO_BITRATE, bitrate); + + if (sinfo->txrate.flags & RATE_INFO_FLAGS_MCS) + NLA_PUT_U8(msg, NL80211_RATE_INFO_MCS, + sinfo->txrate.mcs); + if (sinfo->txrate.flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) + NLA_PUT_FLAG(msg, NL80211_RATE_INFO_40_MHZ_WIDTH); + if (sinfo->txrate.flags & RATE_INFO_FLAGS_SHORT_GI) + NLA_PUT_FLAG(msg, NL80211_RATE_INFO_SHORT_GI); + nla_nest_end(msg, txrate); + } nla_nest_end(msg, sinfoattr); return genlmsg_end(msg, hdr); @@ -1598,6 +1799,12 @@ static int nl80211_set_bss(struct sk_buff *skb, struct genl_info *info) if (info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]) params.use_short_slot_time = nla_get_u8(info->attrs[NL80211_ATTR_BSS_SHORT_SLOT_TIME]); + if (info->attrs[NL80211_ATTR_BSS_BASIC_RATES]) { + params.basic_rates = + nla_data(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); + params.basic_rates_len = + nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]); + } err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); if (err) @@ -1680,11 +1887,188 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info) return -EINVAL; #endif mutex_lock(&cfg80211_drv_mutex); - r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, NULL); + r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY); mutex_unlock(&cfg80211_drv_mutex); return r; } +static int nl80211_get_mesh_params(struct sk_buff *skb, + struct genl_info *info) +{ + struct cfg80211_registered_device *drv; + struct mesh_config cur_params; + int err; + struct net_device *dev; + void *hdr; + struct nlattr *pinfoattr; + struct sk_buff *msg; + + /* Look up our device */ + err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + if (err) + return err; + + /* Get the mesh params */ + rtnl_lock(); + err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params); + rtnl_unlock(); + if (err) + goto out; + + /* Draw up a netlink message to send back */ + msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); + if (!msg) { + err = -ENOBUFS; + goto out; + } + hdr = nl80211hdr_put(msg, info->snd_pid, info->snd_seq, 0, + NL80211_CMD_GET_MESH_PARAMS); + if (!hdr) + goto nla_put_failure; + pinfoattr = nla_nest_start(msg, NL80211_ATTR_MESH_PARAMS); + if (!pinfoattr) + goto nla_put_failure; + NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, dev->ifindex); + NLA_PUT_U16(msg, NL80211_MESHCONF_RETRY_TIMEOUT, + cur_params.dot11MeshRetryTimeout); + NLA_PUT_U16(msg, NL80211_MESHCONF_CONFIRM_TIMEOUT, + cur_params.dot11MeshConfirmTimeout); + NLA_PUT_U16(msg, NL80211_MESHCONF_HOLDING_TIMEOUT, + cur_params.dot11MeshHoldingTimeout); + NLA_PUT_U16(msg, NL80211_MESHCONF_MAX_PEER_LINKS, + cur_params.dot11MeshMaxPeerLinks); + NLA_PUT_U8(msg, NL80211_MESHCONF_MAX_RETRIES, + cur_params.dot11MeshMaxRetries); + NLA_PUT_U8(msg, NL80211_MESHCONF_TTL, + cur_params.dot11MeshTTL); + NLA_PUT_U8(msg, NL80211_MESHCONF_AUTO_OPEN_PLINKS, + cur_params.auto_open_plinks); + NLA_PUT_U8(msg, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, + cur_params.dot11MeshHWMPmaxPREQretries); + NLA_PUT_U32(msg, NL80211_MESHCONF_PATH_REFRESH_TIME, + cur_params.path_refresh_time); + NLA_PUT_U16(msg, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, + cur_params.min_discovery_timeout); + NLA_PUT_U32(msg, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, + cur_params.dot11MeshHWMPactivePathTimeout); + NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, + cur_params.dot11MeshHWMPpreqMinInterval); + NLA_PUT_U16(msg, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, + cur_params.dot11MeshHWMPnetDiameterTraversalTime); + nla_nest_end(msg, pinfoattr); + genlmsg_end(msg, hdr); + err = genlmsg_unicast(msg, info->snd_pid); + goto out; + +nla_put_failure: + genlmsg_cancel(msg, hdr); + err = -EMSGSIZE; +out: + /* Cleanup */ + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + +#define FILL_IN_MESH_PARAM_IF_SET(table, cfg, param, mask, attr_num, nla_fn) \ +do {\ + if (table[attr_num]) {\ + cfg.param = nla_fn(table[attr_num]); \ + mask |= (1 << (attr_num - 1)); \ + } \ +} while (0);\ + +static struct nla_policy +nl80211_meshconf_params_policy[NL80211_MESHCONF_ATTR_MAX+1] __read_mostly = { + [NL80211_MESHCONF_RETRY_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_MESHCONF_CONFIRM_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_MESHCONF_HOLDING_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_MESHCONF_MAX_PEER_LINKS] = { .type = NLA_U16 }, + [NL80211_MESHCONF_MAX_RETRIES] = { .type = NLA_U8 }, + [NL80211_MESHCONF_TTL] = { .type = NLA_U8 }, + [NL80211_MESHCONF_AUTO_OPEN_PLINKS] = { .type = NLA_U8 }, + + [NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES] = { .type = NLA_U8 }, + [NL80211_MESHCONF_PATH_REFRESH_TIME] = { .type = NLA_U32 }, + [NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT] = { .type = NLA_U16 }, + [NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT] = { .type = NLA_U32 }, + [NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL] = { .type = NLA_U16 }, + [NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME] = { .type = NLA_U16 }, +}; + +static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info) +{ + int err; + u32 mask; + struct cfg80211_registered_device *drv; + struct net_device *dev; + struct mesh_config cfg; + struct nlattr *tb[NL80211_MESHCONF_ATTR_MAX + 1]; + struct nlattr *parent_attr; + + parent_attr = info->attrs[NL80211_ATTR_MESH_PARAMS]; + if (!parent_attr) + return -EINVAL; + if (nla_parse_nested(tb, NL80211_MESHCONF_ATTR_MAX, + parent_attr, nl80211_meshconf_params_policy)) + return -EINVAL; + + err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev); + if (err) + return err; + + /* This makes sure that there aren't more than 32 mesh config + * parameters (otherwise our bitfield scheme would not work.) */ + BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32); + + /* Fill in the params struct */ + mask = 0; + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshRetryTimeout, + mask, NL80211_MESHCONF_RETRY_TIMEOUT, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshConfirmTimeout, + mask, NL80211_MESHCONF_CONFIRM_TIMEOUT, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHoldingTimeout, + mask, NL80211_MESHCONF_HOLDING_TIMEOUT, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxPeerLinks, + mask, NL80211_MESHCONF_MAX_PEER_LINKS, nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshMaxRetries, + mask, NL80211_MESHCONF_MAX_RETRIES, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshTTL, + mask, NL80211_MESHCONF_TTL, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, auto_open_plinks, + mask, NL80211_MESHCONF_AUTO_OPEN_PLINKS, nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPmaxPREQretries, + mask, NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES, + nla_get_u8); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, path_refresh_time, + mask, NL80211_MESHCONF_PATH_REFRESH_TIME, nla_get_u32); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, min_discovery_timeout, + mask, NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPactivePathTimeout, + mask, NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT, + nla_get_u32); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, dot11MeshHWMPpreqMinInterval, + mask, NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL, + nla_get_u16); + FILL_IN_MESH_PARAM_IF_SET(tb, cfg, + dot11MeshHWMPnetDiameterTraversalTime, + mask, NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME, + nla_get_u16); + + /* Apply changes */ + rtnl_lock(); + err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask); + rtnl_unlock(); + + /* cleanup */ + cfg80211_put_dev(drv); + dev_put(dev); + return err; +} + +#undef FILL_IN_MESH_PARAM_IF_SET + static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) { struct nlattr *tb[NL80211_REG_RULE_ATTR_MAX + 1]; @@ -1743,12 +2127,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info) mutex_lock(&cfg80211_drv_mutex); r = set_regdom(rd); mutex_unlock(&cfg80211_drv_mutex); - if (r) - goto bad_reg; - return r; -bad_reg: + bad_reg: kfree(rd); return -EINVAL; } @@ -1902,6 +2283,18 @@ static struct genl_ops nl80211_ops[] = { .policy = nl80211_policy, .flags = GENL_ADMIN_PERM, }, + { + .cmd = NL80211_CMD_GET_MESH_PARAMS, + .doit = nl80211_get_mesh_params, + .policy = nl80211_policy, + /* can be retrieved by unprivileged users */ + }, + { + .cmd = NL80211_CMD_SET_MESH_PARAMS, + .doit = nl80211_set_mesh_params, + .policy = nl80211_policy, + .flags = GENL_ADMIN_PERM, + }, }; /* multicast groups */ diff --git a/net/wireless/reg.c b/net/wireless/reg.c index eb3b1a9f9b12477d5a2562916491e9d73c6a7792..4f877535e666ba8f22f9af132628e510d1627b94 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -42,17 +42,40 @@ #include "core.h" #include "reg.h" -/* wiphy is set if this request's initiator is REGDOM_SET_BY_DRIVER */ +/** + * struct regulatory_request - receipt of last regulatory request + * + * @wiphy: this is set if this request's initiator is + * %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This + * can be used by the wireless core to deal with conflicts + * and potentially inform users of which devices specifically + * cased the conflicts. + * @initiator: indicates who sent this request, could be any of + * of those set in reg_set_by, %REGDOM_SET_BY_* + * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested + * regulatory domain. We have a few special codes: + * 00 - World regulatory domain + * 99 - built by driver but a specific alpha2 cannot be determined + * 98 - result of an intersection between two regulatory domains + * @intersect: indicates whether the wireless core should intersect + * the requested regulatory domain with the presently set regulatory + * domain. + * @country_ie_checksum: checksum of the last processed and accepted + * country IE + * @country_ie_env: lets us know if the AP is telling us we are outdoor, + * indoor, or if it doesn't matter + */ struct regulatory_request { - struct list_head list; struct wiphy *wiphy; - int granted; enum reg_set_by initiator; char alpha2[2]; + bool intersect; + u32 country_ie_checksum; + enum environment_cap country_ie_env; }; -static LIST_HEAD(regulatory_requests); -DEFINE_MUTEX(cfg80211_reg_mutex); +/* Receipt of information from last regulatory request */ +static struct regulatory_request *last_request; /* To trigger userspace events */ static struct platform_device *reg_pdev; @@ -63,13 +86,16 @@ static u32 supported_bandwidths[] = { MHZ_TO_KHZ(20), }; -static struct list_head regulatory_requests; - /* Central wireless core regulatory domains, we only need two, * the current one and a world regulatory domain in case we have no * information to give us an alpha2 */ static const struct ieee80211_regdomain *cfg80211_regdomain; +/* We use this as a place for the rd structure built from the + * last parsed country IE to rest until CRDA gets back to us with + * what it thinks should apply for the same country */ +static const struct ieee80211_regdomain *country_ie_regdomain; + /* We keep a static world regulatory domain in case of the absence of CRDA */ static const struct ieee80211_regdomain world_regdom = { .n_reg_rules = 1, @@ -204,7 +230,7 @@ static void reset_regdomains(void) * core upon initialization */ static void update_world_regdomain(const struct ieee80211_regdomain *rd) { - BUG_ON(list_empty(®ulatory_requests)); + BUG_ON(!last_request); reset_regdomains(); @@ -249,6 +275,18 @@ static bool is_unknown_alpha2(const char *alpha2) return false; } +static bool is_intersected_alpha2(const char *alpha2) +{ + if (!alpha2) + return false; + /* Special case where regulatory domain is the + * result of an intersection between two regulatory domain + * structures */ + if (alpha2[0] == '9' && alpha2[1] == '8') + return true; + return false; +} + static bool is_an_alpha2(const char *alpha2) { if (!alpha2) @@ -277,6 +315,25 @@ static bool regdom_changed(const char *alpha2) return true; } +/** + * country_ie_integrity_changes - tells us if the country IE has changed + * @checksum: checksum of country IE of fields we are interested in + * + * If the country IE has not changed you can ignore it safely. This is + * useful to determine if two devices are seeing two different country IEs + * even on the same alpha2. Note that this will return false if no IE has + * been set on the wireless core yet. + */ +static bool country_ie_integrity_changes(u32 checksum) +{ + /* If no IE has been set then the checksum doesn't change */ + if (unlikely(!last_request->country_ie_checksum)) + return false; + if (unlikely(last_request->country_ie_checksum != checksum)) + return true; + return false; +} + /* This lets us keep regulatory code which is updated on a regulatory * basis in userspace. */ static int call_crda(const char *alpha2) @@ -300,121 +357,13 @@ static int call_crda(const char *alpha2) return kobject_uevent_env(®_pdev->dev.kobj, KOBJ_CHANGE, envp); } -/* This has the logic which determines when a new request - * should be ignored. */ -static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, - char *alpha2, struct ieee80211_regdomain *rd) -{ - struct regulatory_request *last_request = NULL; - - /* All initial requests are respected */ - if (list_empty(®ulatory_requests)) - return 0; - - last_request = list_first_entry(®ulatory_requests, - struct regulatory_request, list); - - switch (set_by) { - case REGDOM_SET_BY_INIT: - return -EINVAL; - case REGDOM_SET_BY_CORE: - /* Always respect new wireless core hints, should only - * come in for updating the world regulatory domain at init - * anyway */ - return 0; - case REGDOM_SET_BY_COUNTRY_IE: - if (last_request->initiator == set_by) { - if (last_request->wiphy != wiphy) { - /* Two cards with two APs claiming different - * different Country IE alpha2s! - * You're special!! */ - if (!alpha2_equal(last_request->alpha2, - cfg80211_regdomain->alpha2)) { - /* XXX: Deal with conflict, consider - * building a new one out of the - * intersection */ - WARN_ON(1); - return -EOPNOTSUPP; - } - return -EALREADY; - } - /* Two consecutive Country IE hints on the same wiphy */ - if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2)) - return 0; - return -EALREADY; - } - if (WARN(!is_alpha2_set(alpha2) || !is_an_alpha2(alpha2), - "Invalid Country IE regulatory hint passed " - "to the wireless core\n")) - return -EINVAL; - /* We ignore Country IE hints for now, as we haven't yet - * added the dot11MultiDomainCapabilityEnabled flag - * for wiphys */ - return 1; - case REGDOM_SET_BY_DRIVER: - BUG_ON(!wiphy); - if (last_request->initiator == set_by) { - /* Two separate drivers hinting different things, - * this is possible if you have two devices present - * on a system with different EEPROM regulatory - * readings. XXX: Do intersection, we support only - * the first regulatory hint for now */ - if (last_request->wiphy != wiphy) - return -EALREADY; - if (rd) - return -EALREADY; - /* Driver should not be trying to hint different - * regulatory domains! */ - BUG_ON(!alpha2_equal(alpha2, - cfg80211_regdomain->alpha2)); - return -EALREADY; - } - if (last_request->initiator == REGDOM_SET_BY_CORE) - return 0; - /* XXX: Handle intersection, and add the - * dot11MultiDomainCapabilityEnabled flag to wiphy. For now - * we assume the driver has this set to false, following the - * 802.11d dot11MultiDomainCapabilityEnabled documentation */ - if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) - return 0; - return 0; - case REGDOM_SET_BY_USER: - if (last_request->initiator == set_by || - last_request->initiator == REGDOM_SET_BY_CORE) - return 0; - /* Drivers can use their wiphy's reg_notifier() - * to override any information */ - if (last_request->initiator == REGDOM_SET_BY_DRIVER) - return 0; - /* XXX: Handle intersection */ - if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) - return -EOPNOTSUPP; - return 0; - default: - return -EINVAL; - } -} - -static bool __reg_is_valid_request(const char *alpha2, - struct regulatory_request **request) -{ - struct regulatory_request *req; - if (list_empty(®ulatory_requests)) - return false; - list_for_each_entry(req, ®ulatory_requests, list) { - if (alpha2_equal(req->alpha2, alpha2)) { - *request = req; - return true; - } - } - return false; -} - /* Used by nl80211 before kmalloc'ing our regulatory domain */ bool reg_is_valid_request(const char *alpha2) { - struct regulatory_request *request = NULL; - return __reg_is_valid_request(alpha2, &request); + if (!last_request) + return false; + + return alpha2_equal(last_request->alpha2, alpha2); } /* Sanity check on a regulatory rule */ @@ -423,7 +372,7 @@ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) const struct ieee80211_freq_range *freq_range = &rule->freq_range; u32 freq_diff; - if (freq_range->start_freq_khz == 0 || freq_range->end_freq_khz == 0) + if (freq_range->start_freq_khz <= 0 || freq_range->end_freq_khz <= 0) return false; if (freq_range->start_freq_khz > freq_range->end_freq_khz) @@ -431,7 +380,7 @@ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule) freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; - if (freq_range->max_bandwidth_khz > freq_diff) + if (freq_diff <= 0 || freq_range->max_bandwidth_khz > freq_diff) return false; return true; @@ -445,6 +394,9 @@ static bool is_valid_rd(const struct ieee80211_regdomain *rd) if (!rd->n_reg_rules) return false; + if (WARN_ON(rd->n_reg_rules > NL80211_MAX_SUPP_REG_RULES)) + return false; + for (i = 0; i < rd->n_reg_rules; i++) { reg_rule = &rd->reg_rules[i]; if (!is_valid_reg_rule(reg_rule)) @@ -469,6 +421,311 @@ static u32 freq_max_bandwidth(const struct ieee80211_freq_range *freq_range, return 0; } +/* Converts a country IE to a regulatory domain. A regulatory domain + * structure has a lot of information which the IE doesn't yet have, + * so for the other values we use upper max values as we will intersect + * with our userspace regulatory agent to get lower bounds. */ +static struct ieee80211_regdomain *country_ie_2_rd( + u8 *country_ie, + u8 country_ie_len, + u32 *checksum) +{ + struct ieee80211_regdomain *rd = NULL; + unsigned int i = 0; + char alpha2[2]; + u32 flags = 0; + u32 num_rules = 0, size_of_regd = 0; + u8 *triplets_start = NULL; + u8 len_at_triplet = 0; + /* the last channel we have registered in a subband (triplet) */ + int last_sub_max_channel = 0; + + *checksum = 0xDEADBEEF; + + /* Country IE requirements */ + BUG_ON(country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN || + country_ie_len & 0x01); + + alpha2[0] = country_ie[0]; + alpha2[1] = country_ie[1]; + + /* + * Third octet can be: + * 'I' - Indoor + * 'O' - Outdoor + * + * anything else we assume is no restrictions + */ + if (country_ie[2] == 'I') + flags = NL80211_RRF_NO_OUTDOOR; + else if (country_ie[2] == 'O') + flags = NL80211_RRF_NO_INDOOR; + + country_ie += 3; + country_ie_len -= 3; + + triplets_start = country_ie; + len_at_triplet = country_ie_len; + + *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8); + + /* We need to build a reg rule for each triplet, but first we must + * calculate the number of reg rules we will need. We will need one + * for each channel subband */ + while (country_ie_len >= 3) { + struct ieee80211_country_ie_triplet *triplet = + (struct ieee80211_country_ie_triplet *) country_ie; + int cur_sub_max_channel = 0, cur_channel = 0; + + if (triplet->ext.reg_extension_id >= + IEEE80211_COUNTRY_EXTENSION_ID) { + country_ie += 3; + country_ie_len -= 3; + continue; + } + + cur_channel = triplet->chans.first_channel; + cur_sub_max_channel = ieee80211_channel_to_frequency( + cur_channel + triplet->chans.num_channels); + + /* Basic sanity check */ + if (cur_sub_max_channel < cur_channel) + return NULL; + + /* Do not allow overlapping channels. Also channels + * passed in each subband must be monotonically + * increasing */ + if (last_sub_max_channel) { + if (cur_channel <= last_sub_max_channel) + return NULL; + if (cur_sub_max_channel <= last_sub_max_channel) + return NULL; + } + + /* When dot11RegulatoryClassesRequired is supported + * we can throw ext triplets as part of this soup, + * for now we don't care when those change as we + * don't support them */ + *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) | + ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) | + ((triplet->chans.max_power ^ cur_sub_max_channel) << 24); + + last_sub_max_channel = cur_sub_max_channel; + + country_ie += 3; + country_ie_len -= 3; + num_rules++; + + /* Note: this is not a IEEE requirement but + * simply a memory requirement */ + if (num_rules > NL80211_MAX_SUPP_REG_RULES) + return NULL; + } + + country_ie = triplets_start; + country_ie_len = len_at_triplet; + + size_of_regd = sizeof(struct ieee80211_regdomain) + + (num_rules * sizeof(struct ieee80211_reg_rule)); + + rd = kzalloc(size_of_regd, GFP_KERNEL); + if (!rd) + return NULL; + + rd->n_reg_rules = num_rules; + rd->alpha2[0] = alpha2[0]; + rd->alpha2[1] = alpha2[1]; + + /* This time around we fill in the rd */ + while (country_ie_len >= 3) { + struct ieee80211_country_ie_triplet *triplet = + (struct ieee80211_country_ie_triplet *) country_ie; + struct ieee80211_reg_rule *reg_rule = NULL; + struct ieee80211_freq_range *freq_range = NULL; + struct ieee80211_power_rule *power_rule = NULL; + + /* Must parse if dot11RegulatoryClassesRequired is true, + * we don't support this yet */ + if (triplet->ext.reg_extension_id >= + IEEE80211_COUNTRY_EXTENSION_ID) { + country_ie += 3; + country_ie_len -= 3; + continue; + } + + reg_rule = &rd->reg_rules[i]; + freq_range = ®_rule->freq_range; + power_rule = ®_rule->power_rule; + + reg_rule->flags = flags; + + /* The +10 is since the regulatory domain expects + * the actual band edge, not the center of freq for + * its start and end freqs, assuming 20 MHz bandwidth on + * the channels passed */ + freq_range->start_freq_khz = + MHZ_TO_KHZ(ieee80211_channel_to_frequency( + triplet->chans.first_channel) - 10); + freq_range->end_freq_khz = + MHZ_TO_KHZ(ieee80211_channel_to_frequency( + triplet->chans.first_channel + + triplet->chans.num_channels) + 10); + + /* Large arbitrary values, we intersect later */ + /* Increment this if we ever support >= 40 MHz channels + * in IEEE 802.11 */ + freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40); + power_rule->max_antenna_gain = DBI_TO_MBI(100); + power_rule->max_eirp = DBM_TO_MBM(100); + + country_ie += 3; + country_ie_len -= 3; + i++; + + BUG_ON(i > NL80211_MAX_SUPP_REG_RULES); + } + + return rd; +} + + +/* Helper for regdom_intersect(), this does the real + * mathematical intersection fun */ +static int reg_rules_intersect( + const struct ieee80211_reg_rule *rule1, + const struct ieee80211_reg_rule *rule2, + struct ieee80211_reg_rule *intersected_rule) +{ + const struct ieee80211_freq_range *freq_range1, *freq_range2; + struct ieee80211_freq_range *freq_range; + const struct ieee80211_power_rule *power_rule1, *power_rule2; + struct ieee80211_power_rule *power_rule; + u32 freq_diff; + + freq_range1 = &rule1->freq_range; + freq_range2 = &rule2->freq_range; + freq_range = &intersected_rule->freq_range; + + power_rule1 = &rule1->power_rule; + power_rule2 = &rule2->power_rule; + power_rule = &intersected_rule->power_rule; + + freq_range->start_freq_khz = max(freq_range1->start_freq_khz, + freq_range2->start_freq_khz); + freq_range->end_freq_khz = min(freq_range1->end_freq_khz, + freq_range2->end_freq_khz); + freq_range->max_bandwidth_khz = min(freq_range1->max_bandwidth_khz, + freq_range2->max_bandwidth_khz); + + freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz; + if (freq_range->max_bandwidth_khz > freq_diff) + freq_range->max_bandwidth_khz = freq_diff; + + power_rule->max_eirp = min(power_rule1->max_eirp, + power_rule2->max_eirp); + power_rule->max_antenna_gain = min(power_rule1->max_antenna_gain, + power_rule2->max_antenna_gain); + + intersected_rule->flags = (rule1->flags | rule2->flags); + + if (!is_valid_reg_rule(intersected_rule)) + return -EINVAL; + + return 0; +} + +/** + * regdom_intersect - do the intersection between two regulatory domains + * @rd1: first regulatory domain + * @rd2: second regulatory domain + * + * Use this function to get the intersection between two regulatory domains. + * Once completed we will mark the alpha2 for the rd as intersected, "98", + * as no one single alpha2 can represent this regulatory domain. + * + * Returns a pointer to the regulatory domain structure which will hold the + * resulting intersection of rules between rd1 and rd2. We will + * kzalloc() this structure for you. + */ +static struct ieee80211_regdomain *regdom_intersect( + const struct ieee80211_regdomain *rd1, + const struct ieee80211_regdomain *rd2) +{ + int r, size_of_regd; + unsigned int x, y; + unsigned int num_rules = 0, rule_idx = 0; + const struct ieee80211_reg_rule *rule1, *rule2; + struct ieee80211_reg_rule *intersected_rule; + struct ieee80211_regdomain *rd; + /* This is just a dummy holder to help us count */ + struct ieee80211_reg_rule irule; + + /* Uses the stack temporarily for counter arithmetic */ + intersected_rule = &irule; + + memset(intersected_rule, 0, sizeof(struct ieee80211_reg_rule)); + + if (!rd1 || !rd2) + return NULL; + + /* First we get a count of the rules we'll need, then we actually + * build them. This is to so we can malloc() and free() a + * regdomain once. The reason we use reg_rules_intersect() here + * is it will return -EINVAL if the rule computed makes no sense. + * All rules that do check out OK are valid. */ + + for (x = 0; x < rd1->n_reg_rules; x++) { + rule1 = &rd1->reg_rules[x]; + for (y = 0; y < rd2->n_reg_rules; y++) { + rule2 = &rd2->reg_rules[y]; + if (!reg_rules_intersect(rule1, rule2, + intersected_rule)) + num_rules++; + memset(intersected_rule, 0, + sizeof(struct ieee80211_reg_rule)); + } + } + + if (!num_rules) + return NULL; + + size_of_regd = sizeof(struct ieee80211_regdomain) + + ((num_rules + 1) * sizeof(struct ieee80211_reg_rule)); + + rd = kzalloc(size_of_regd, GFP_KERNEL); + if (!rd) + return NULL; + + for (x = 0; x < rd1->n_reg_rules; x++) { + rule1 = &rd1->reg_rules[x]; + for (y = 0; y < rd2->n_reg_rules; y++) { + rule2 = &rd2->reg_rules[y]; + /* This time around instead of using the stack lets + * write to the target rule directly saving ourselves + * a memcpy() */ + intersected_rule = &rd->reg_rules[rule_idx]; + r = reg_rules_intersect(rule1, rule2, + intersected_rule); + /* No need to memset here the intersected rule here as + * we're not using the stack anymore */ + if (r) + continue; + rule_idx++; + } + } + + if (rule_idx != num_rules) { + kfree(rd); + return NULL; + } + + rd->n_reg_rules = num_rules; + rd->alpha2[0] = '9'; + rd->alpha2[1] = '8'; + + return rd; +} + /* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may * want to just have the channel structure use these */ static u32 map_regdom_flags(u32 rd_flags) @@ -559,12 +816,23 @@ static void handle_band(struct ieee80211_supported_band *sband) handle_channel(&sband->channels[i]); } +static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby) +{ + if (!last_request) + return true; + if (setby == REGDOM_SET_BY_CORE && + wiphy->fw_handles_regulatory) + return true; + return false; +} + static void update_all_wiphy_regulatory(enum reg_set_by setby) { struct cfg80211_registered_device *drv; list_for_each_entry(drv, &cfg80211_drv_list, list) - wiphy_update_regulatory(&drv->wiphy, setby); + if (!ignore_reg_update(&drv->wiphy, setby)) + wiphy_update_regulatory(&drv->wiphy, setby); } void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) @@ -578,78 +846,237 @@ void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby) } } -/* Caller must hold &cfg80211_drv_mutex */ -int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, - const char *alpha2, struct ieee80211_regdomain *rd) -{ - struct regulatory_request *request; - char *rd_alpha2; - int r = 0; - - r = ignore_request(wiphy, set_by, (char *) alpha2, rd); - if (r) - return r; +/* Return value which can be used by ignore_request() to indicate + * it has been determined we should intersect two regulatory domains */ +#define REG_INTERSECT 1 - if (rd) - rd_alpha2 = rd->alpha2; - else - rd_alpha2 = (char *) alpha2; +/* This has the logic which determines when a new request + * should be ignored. */ +static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by, + const char *alpha2) +{ + /* All initial requests are respected */ + if (!last_request) + return 0; switch (set_by) { + case REGDOM_SET_BY_INIT: + return -EINVAL; case REGDOM_SET_BY_CORE: + /* + * Always respect new wireless core hints, should only happen + * when updating the world regulatory domain at init. + */ + return 0; case REGDOM_SET_BY_COUNTRY_IE: + if (unlikely(!is_an_alpha2(alpha2))) + return -EINVAL; + if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { + if (last_request->wiphy != wiphy) { + /* + * Two cards with two APs claiming different + * different Country IE alpha2s. We could + * intersect them, but that seems unlikely + * to be correct. Reject second one for now. + */ + if (!alpha2_equal(alpha2, + cfg80211_regdomain->alpha2)) + return -EOPNOTSUPP; + return -EALREADY; + } + /* Two consecutive Country IE hints on the same wiphy. + * This should be picked up early by the driver/stack */ + if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2, + alpha2))) + return 0; + return -EALREADY; + } + return REG_INTERSECT; case REGDOM_SET_BY_DRIVER: + if (last_request->initiator == REGDOM_SET_BY_DRIVER) + return -EALREADY; + return 0; case REGDOM_SET_BY_USER: - request = kzalloc(sizeof(struct regulatory_request), - GFP_KERNEL); - if (!request) - return -ENOMEM; - - request->alpha2[0] = rd_alpha2[0]; - request->alpha2[1] = rd_alpha2[1]; - request->initiator = set_by; - request->wiphy = wiphy; - - list_add_tail(&request->list, ®ulatory_requests); - if (rd) - break; - r = call_crda(alpha2); -#ifndef CONFIG_WIRELESS_OLD_REGULATORY - if (r) - printk(KERN_ERR "cfg80211: Failed calling CRDA\n"); -#endif - break; - default: - r = -ENOTSUPP; - break; + if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) + return REG_INTERSECT; + /* If the user knows better the user should set the regdom + * to their country before the IE is picked up */ + if (last_request->initiator == REGDOM_SET_BY_USER && + last_request->intersect) + return -EOPNOTSUPP; + return 0; } - return r; + return -EINVAL; } -/* If rd is not NULL and if this call fails the caller must free it */ -int regulatory_hint(struct wiphy *wiphy, const char *alpha2, - struct ieee80211_regdomain *rd) +/* Caller must hold &cfg80211_drv_mutex */ +int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, + const char *alpha2, + u32 country_ie_checksum, + enum environment_cap env) { - int r; - BUG_ON(!rd && !alpha2); + struct regulatory_request *request; + bool intersect = false; + int r = 0; - mutex_lock(&cfg80211_drv_mutex); + r = ignore_request(wiphy, set_by, alpha2); - r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, rd); - if (r || !rd) - goto unlock_and_exit; + if (r == REG_INTERSECT) + intersect = true; + else if (r) + return r; - /* If the driver passed a regulatory domain we skipped asking - * userspace for one so we can now go ahead and set it */ - r = set_regdom(rd); + request = kzalloc(sizeof(struct regulatory_request), + GFP_KERNEL); + if (!request) + return -ENOMEM; + + request->alpha2[0] = alpha2[0]; + request->alpha2[1] = alpha2[1]; + request->initiator = set_by; + request->wiphy = wiphy; + request->intersect = intersect; + request->country_ie_checksum = country_ie_checksum; + request->country_ie_env = env; + + kfree(last_request); + last_request = request; + /* + * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled + * AND if CRDA is NOT present nothing will happen, if someone + * wants to bother with 11d with OLD_REG you can add a timer. + * If after x amount of time nothing happens you can call: + * + * return set_regdom(country_ie_regdomain); + * + * to intersect with the static rd + */ + return call_crda(alpha2); +} + +void regulatory_hint(struct wiphy *wiphy, const char *alpha2) +{ + BUG_ON(!alpha2); -unlock_and_exit: + mutex_lock(&cfg80211_drv_mutex); + __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER, alpha2, 0, ENVIRON_ANY); mutex_unlock(&cfg80211_drv_mutex); - return r; } EXPORT_SYMBOL(regulatory_hint); +static bool reg_same_country_ie_hint(struct wiphy *wiphy, + u32 country_ie_checksum) +{ + if (!last_request->wiphy) + return false; + if (likely(last_request->wiphy != wiphy)) + return !country_ie_integrity_changes(country_ie_checksum); + /* We should not have let these through at this point, they + * should have been picked up earlier by the first alpha2 check + * on the device */ + if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum))) + return true; + return false; +} + +void regulatory_hint_11d(struct wiphy *wiphy, + u8 *country_ie, + u8 country_ie_len) +{ + struct ieee80211_regdomain *rd = NULL; + char alpha2[2]; + u32 checksum = 0; + enum environment_cap env = ENVIRON_ANY; + + if (!last_request) + return; + + mutex_lock(&cfg80211_drv_mutex); + + /* IE len must be evenly divisible by 2 */ + if (country_ie_len & 0x01) + goto out; + + if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN) + goto out; + + /* Pending country IE processing, this can happen after we + * call CRDA and wait for a response if a beacon was received before + * we were able to process the last regulatory_hint_11d() call */ + if (country_ie_regdomain) + goto out; + + alpha2[0] = country_ie[0]; + alpha2[1] = country_ie[1]; + + if (country_ie[2] == 'I') + env = ENVIRON_INDOOR; + else if (country_ie[2] == 'O') + env = ENVIRON_OUTDOOR; + + /* We will run this for *every* beacon processed for the BSSID, so + * we optimize an early check to exit out early if we don't have to + * do anything */ + if (likely(last_request->wiphy)) { + struct cfg80211_registered_device *drv_last_ie; + + drv_last_ie = wiphy_to_dev(last_request->wiphy); + + /* Lets keep this simple -- we trust the first AP + * after we intersect with CRDA */ + if (likely(last_request->wiphy == wiphy)) { + /* Ignore IEs coming in on this wiphy with + * the same alpha2 and environment cap */ + if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, + alpha2) && + env == drv_last_ie->env)) { + goto out; + } + /* the wiphy moved on to another BSSID or the AP + * was reconfigured. XXX: We need to deal with the + * case where the user suspends and goes to goes + * to another country, and then gets IEs from an + * AP with different settings */ + goto out; + } else { + /* Ignore IEs coming in on two separate wiphys with + * the same alpha2 and environment cap */ + if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2, + alpha2) && + env == drv_last_ie->env)) { + goto out; + } + /* We could potentially intersect though */ + goto out; + } + } + + rd = country_ie_2_rd(country_ie, country_ie_len, &checksum); + if (!rd) + goto out; + + /* This will not happen right now but we leave it here for the + * the future when we want to add suspend/resume support and having + * the user move to another country after doing so, or having the user + * move to another AP. Right now we just trust the first AP. This is why + * this is marked as likley(). If we hit this before we add this support + * we want to be informed of it as it would indicate a mistake in the + * current design */ + if (likely(WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))) + goto out; + + /* We keep this around for when CRDA comes back with a response so + * we can intersect with that */ + country_ie_regdomain = rd; + + __regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE, + country_ie_regdomain->alpha2, checksum, env); + +out: + mutex_unlock(&cfg80211_drv_mutex); +} +EXPORT_SYMBOL(regulatory_hint_11d); static void print_rd_rules(const struct ieee80211_regdomain *rd) { @@ -689,7 +1116,25 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd) static void print_regdomain(const struct ieee80211_regdomain *rd) { - if (is_world_regdom(rd->alpha2)) + if (is_intersected_alpha2(rd->alpha2)) { + struct wiphy *wiphy = NULL; + struct cfg80211_registered_device *drv; + + if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) { + if (last_request->wiphy) { + wiphy = last_request->wiphy; + drv = wiphy_to_dev(wiphy); + printk(KERN_INFO "cfg80211: Current regulatory " + "domain updated by AP to: %c%c\n", + drv->country_ie_alpha2[0], + drv->country_ie_alpha2[1]); + } else + printk(KERN_INFO "cfg80211: Current regulatory " + "domain intersected: \n"); + } else + printk(KERN_INFO "cfg80211: Current regulatory " + "intersected: \n"); + } else if (is_world_regdom(rd->alpha2)) printk(KERN_INFO "cfg80211: World regulatory " "domain updated:\n"); else { @@ -705,21 +1150,50 @@ static void print_regdomain(const struct ieee80211_regdomain *rd) print_rd_rules(rd); } -void print_regdomain_info(const struct ieee80211_regdomain *rd) +static void print_regdomain_info(const struct ieee80211_regdomain *rd) { printk(KERN_INFO "cfg80211: Regulatory domain: %c%c\n", rd->alpha2[0], rd->alpha2[1]); print_rd_rules(rd); } -static int __set_regdom(const struct ieee80211_regdomain *rd) +#ifdef CONFIG_CFG80211_REG_DEBUG +static void reg_country_ie_process_debug( + const struct ieee80211_regdomain *rd, + const struct ieee80211_regdomain *country_ie_regdomain, + const struct ieee80211_regdomain *intersected_rd) { - struct regulatory_request *request = NULL; + printk(KERN_DEBUG "cfg80211: Received country IE:\n"); + print_regdomain_info(country_ie_regdomain); + printk(KERN_DEBUG "cfg80211: CRDA thinks this should applied:\n"); + print_regdomain_info(rd); + if (intersected_rd) { + printk(KERN_DEBUG "cfg80211: We intersect both of these " + "and get:\n"); + print_regdomain_info(rd); + return; + } + printk(KERN_DEBUG "cfg80211: Intersection between both failed\n"); +} +#else +static inline void reg_country_ie_process_debug( + const struct ieee80211_regdomain *rd, + const struct ieee80211_regdomain *country_ie_regdomain, + const struct ieee80211_regdomain *intersected_rd) +{ +} +#endif +/* Takes ownership of rd only if it doesn't fail */ +static int __set_regdom(const struct ieee80211_regdomain *rd) +{ + const struct ieee80211_regdomain *intersected_rd = NULL; + struct cfg80211_registered_device *drv = NULL; + struct wiphy *wiphy = NULL; /* Some basic sanity checks first */ if (is_world_regdom(rd->alpha2)) { - if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request))) + if (WARN_ON(!reg_is_valid_request(rd->alpha2))) return -EINVAL; update_world_regdomain(rd); return 0; @@ -729,45 +1203,102 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) !is_unknown_alpha2(rd->alpha2)) return -EINVAL; - if (list_empty(®ulatory_requests)) + if (!last_request) return -EINVAL; - /* allow overriding the static definitions if CRDA is present */ - if (!is_old_static_regdom(cfg80211_regdomain) && - !regdom_changed(rd->alpha2)) - return -EINVAL; + /* Lets only bother proceeding on the same alpha2 if the current + * rd is non static (it means CRDA was present and was used last) + * and the pending request came in from a country IE */ + if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) { + /* If someone else asked us to change the rd lets only bother + * checking if the alpha2 changes if CRDA was already called */ + if (!is_old_static_regdom(cfg80211_regdomain) && + !regdom_changed(rd->alpha2)) + return -EINVAL; + } + + wiphy = last_request->wiphy; /* Now lets set the regulatory domain, update all driver channels * and finally inform them of what we have done, in case they want * to review or adjust their own settings based on their own * internal EEPROM data */ - if (WARN_ON(!__reg_is_valid_request(rd->alpha2, &request))) + if (WARN_ON(!reg_is_valid_request(rd->alpha2))) return -EINVAL; - reset_regdomains(); + if (!is_valid_rd(rd)) { + printk(KERN_ERR "cfg80211: Invalid " + "regulatory domain detected:\n"); + print_regdomain_info(rd); + return -EINVAL; + } - /* Country IE parsing coming soon */ - switch (request->initiator) { - case REGDOM_SET_BY_CORE: - case REGDOM_SET_BY_DRIVER: - case REGDOM_SET_BY_USER: - if (!is_valid_rd(rd)) { - printk(KERN_ERR "cfg80211: Invalid " - "regulatory domain detected:\n"); - print_regdomain_info(rd); + if (!last_request->intersect) { + reset_regdomains(); + cfg80211_regdomain = rd; + return 0; + } + + /* Intersection requires a bit more work */ + + if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) { + + intersected_rd = regdom_intersect(rd, cfg80211_regdomain); + if (!intersected_rd) return -EINVAL; - } - break; - case REGDOM_SET_BY_COUNTRY_IE: /* Not yet */ - WARN_ON(1); - default: - return -EOPNOTSUPP; + + /* We can trash what CRDA provided now */ + kfree(rd); + rd = NULL; + + reset_regdomains(); + cfg80211_regdomain = intersected_rd; + + return 0; } - /* Tada! */ - cfg80211_regdomain = rd; - request->granted = 1; + /* + * Country IE requests are handled a bit differently, we intersect + * the country IE rd with what CRDA believes that country should have + */ + + BUG_ON(!country_ie_regdomain); + + if (rd != country_ie_regdomain) { + /* Intersect what CRDA returned and our what we + * had built from the Country IE received */ + + intersected_rd = regdom_intersect(rd, country_ie_regdomain); + + reg_country_ie_process_debug(rd, country_ie_regdomain, + intersected_rd); + + kfree(country_ie_regdomain); + country_ie_regdomain = NULL; + } else { + /* This would happen when CRDA was not present and + * OLD_REGULATORY was enabled. We intersect our Country + * IE rd and what was set on cfg80211 originally */ + intersected_rd = regdom_intersect(rd, cfg80211_regdomain); + } + + if (!intersected_rd) + return -EINVAL; + + drv = wiphy_to_dev(wiphy); + + drv->country_ie_alpha2[0] = rd->alpha2[0]; + drv->country_ie_alpha2[1] = rd->alpha2[1]; + drv->env = last_request->country_ie_env; + + BUG_ON(intersected_rd == rd); + + kfree(rd); + rd = NULL; + + reset_regdomains(); + cfg80211_regdomain = intersected_rd; return 0; } @@ -775,52 +1306,41 @@ static int __set_regdom(const struct ieee80211_regdomain *rd) /* Use this call to set the current regulatory domain. Conflicts with * multiple drivers can be ironed out later. Caller must've already - * kmalloc'd the rd structure. If this calls fails you should kfree() - * the passed rd. Caller must hold cfg80211_drv_mutex */ + * kmalloc'd the rd structure. Caller must hold cfg80211_drv_mutex */ int set_regdom(const struct ieee80211_regdomain *rd) { - struct regulatory_request *this_request = NULL, *prev_request = NULL; int r; - if (!list_empty(®ulatory_requests)) - prev_request = list_first_entry(®ulatory_requests, - struct regulatory_request, list); - /* Note that this doesn't update the wiphys, this is done below */ r = __set_regdom(rd); - if (r) + if (r) { + kfree(rd); return r; - - BUG_ON((!__reg_is_valid_request(rd->alpha2, &this_request))); - - /* The initial standard core update of the world regulatory domain, no - * need to keep that request info around if it didn't fail. */ - if (is_world_regdom(rd->alpha2) && - this_request->initiator == REGDOM_SET_BY_CORE && - this_request->granted) { - list_del(&this_request->list); - kfree(this_request); - this_request = NULL; - } - - /* Remove old requests, we only leave behind the last one */ - if (prev_request) { - list_del(&prev_request->list); - kfree(prev_request); - prev_request = NULL; } /* This would make this whole thing pointless */ - BUG_ON(rd != cfg80211_regdomain); + if (!last_request->intersect) + BUG_ON(rd != cfg80211_regdomain); /* update all wiphys now with the new established regulatory domain */ - update_all_wiphy_regulatory(this_request->initiator); + update_all_wiphy_regulatory(last_request->initiator); - print_regdomain(rd); + print_regdomain(cfg80211_regdomain); return r; } +/* Caller must hold cfg80211_drv_mutex */ +void reg_device_remove(struct wiphy *wiphy) +{ + if (!last_request || !last_request->wiphy) + return; + if (last_request->wiphy != wiphy) + return; + last_request->wiphy = NULL; + last_request->country_ie_env = ENVIRON_ANY; +} + int regulatory_init(void) { int err; @@ -838,13 +1358,13 @@ int regulatory_init(void) * you have CRDA you get it updated, otherwise you get * stuck with the static values. We ignore "EU" code as * that is not a valid ISO / IEC 3166 alpha2 */ - if (ieee80211_regdom[0] != 'E' && ieee80211_regdom[1] != 'U') + if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U') err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, - ieee80211_regdom, NULL); + ieee80211_regdom, 0, ENVIRON_ANY); #else cfg80211_regdomain = cfg80211_world_regdom; - err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", NULL); + err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", 0, ENVIRON_ANY); if (err) printk(KERN_ERR "cfg80211: calling CRDA failed - " "unable to update world regulatory domain, " @@ -856,16 +1376,15 @@ int regulatory_init(void) void regulatory_exit(void) { - struct regulatory_request *req, *req_tmp; - mutex_lock(&cfg80211_drv_mutex); reset_regdomains(); - list_for_each_entry_safe(req, req_tmp, ®ulatory_requests, list) { - list_del(&req->list); - kfree(req); - } + kfree(country_ie_regdomain); + country_ie_regdomain = NULL; + + kfree(last_request); + platform_device_unregister(reg_pdev); mutex_unlock(&cfg80211_drv_mutex); diff --git a/net/wireless/reg.h b/net/wireless/reg.h index a33362872f3cc3820ae46c32c010400242912bc0..a76ea3ff7cd6af1a9da0044a7b8eca2afabea85a 100644 --- a/net/wireless/reg.h +++ b/net/wireless/reg.h @@ -1,13 +1,44 @@ #ifndef __NET_WIRELESS_REG_H #define __NET_WIRELESS_REG_H -extern struct mutex cfg80211_reg_mutex; bool is_world_regdom(const char *alpha2); bool reg_is_valid_request(const char *alpha2); +void reg_device_remove(struct wiphy *wiphy); + int regulatory_init(void); void regulatory_exit(void); int set_regdom(const struct ieee80211_regdomain *rd); +enum environment_cap { + ENVIRON_ANY, + ENVIRON_INDOOR, + ENVIRON_OUTDOOR, +}; + + +/** + * __regulatory_hint - hint to the wireless core a regulatory domain + * @wiphy: if the hint comes from country information from an AP, this + * is required to be set to the wiphy that received the information + * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain + * should be in. + * @country_ie_checksum: checksum of processed country IE, set this to 0 + * if the hint did not come from a country IE + * @country_ie_env: the environment the IE told us we are in, %ENVIRON_* + * + * The Wireless subsystem can use this function to hint to the wireless core + * what it believes should be the current regulatory domain by giving it an + * ISO/IEC 3166 alpha2 country code it knows its regulatory domain should be + * in. + * + * Returns zero if all went fine, %-EALREADY if a regulatory domain had + * already been set or other standard error codes. + * + */ +extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by, + const char *alpha2, u32 country_ie_checksum, + enum environment_cap country_ie_env); + #endif /* __NET_WIRELESS_REG_H */ diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 29f820e182511fcf8a70bf672e32887404f9cb10..79a38287764165c41b74533efa0043aaae4a6c3f 100644 --- a/net/wireless/sysfs.c +++ b/net/wireless/sysfs.c @@ -23,25 +23,20 @@ static inline struct cfg80211_registered_device *dev_to_rdev( return container_of(dev, struct cfg80211_registered_device, wiphy.dev); } -static ssize_t _show_index(struct device *dev, struct device_attribute *attr, - char *buf) -{ - return sprintf(buf, "%d\n", dev_to_rdev(dev)->idx); +#define SHOW_FMT(name, fmt, member) \ +static ssize_t name ## _show(struct device *dev, \ + struct device_attribute *attr, \ + char *buf) \ +{ \ + return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member); \ } -static ssize_t _show_permaddr(struct device *dev, - struct device_attribute *attr, - char *buf) -{ - unsigned char *addr = dev_to_rdev(dev)->wiphy.perm_addr; - - return sprintf(buf, "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n", - addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]); -} +SHOW_FMT(index, "%d", idx); +SHOW_FMT(macaddress, "%pM", wiphy.perm_addr); static struct device_attribute ieee80211_dev_attrs[] = { - __ATTR(index, S_IRUGO, _show_index, NULL), - __ATTR(macaddress, S_IRUGO, _show_permaddr, NULL), + __ATTR_RO(index), + __ATTR_RO(macaddress), {} }; diff --git a/net/wireless/util.c b/net/wireless/util.c index f54424693a38a378bd5e7cdc25326907b5fbb983..e76cc28b034557fc1dfcadbae21a09307f6fee5c 100644 --- a/net/wireless/util.c +++ b/net/wireless/util.c @@ -7,6 +7,25 @@ #include #include "core.h" +struct ieee80211_rate * +ieee80211_get_response_rate(struct ieee80211_supported_band *sband, + u64 basic_rates, int bitrate) +{ + struct ieee80211_rate *result = &sband->bitrates[0]; + int i; + + for (i = 0; i < sband->n_bitrates; i++) { + if (!(basic_rates & BIT(i))) + continue; + if (sband->bitrates[i].bitrate > bitrate) + continue; + result = &sband->bitrates[i]; + } + + return result; +} +EXPORT_SYMBOL(ieee80211_get_response_rate); + int ieee80211_channel_to_frequency(int chan) { if (chan < 14) diff --git a/net/wireless/wext-compat.c b/net/wireless/wext-compat.c new file mode 100644 index 0000000000000000000000000000000000000000..58e489fd4aedf0527241c4c39aa5d20482a6dea2 --- /dev/null +++ b/net/wireless/wext-compat.c @@ -0,0 +1,139 @@ +/* + * cfg80211 - wext compat code + * + * This is temporary code until all wireless functionality is migrated + * into cfg80211, when that happens all the exports here go away and + * we directly assign the wireless handlers of wireless interfaces. + * + * Copyright 2008 Johannes Berg + */ + +#include +#include +#include +#include +#include +#include "core.h" + +int cfg80211_wext_giwname(struct net_device *dev, + struct iw_request_info *info, + char *name, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_supported_band *sband; + bool is_ht = false, is_a = false, is_b = false, is_g = false; + + if (!wdev) + return -EOPNOTSUPP; + + sband = wdev->wiphy->bands[IEEE80211_BAND_5GHZ]; + if (sband) { + is_a = true; + is_ht |= sband->ht_cap.ht_supported; + } + + sband = wdev->wiphy->bands[IEEE80211_BAND_2GHZ]; + if (sband) { + int i; + /* Check for mandatory rates */ + for (i = 0; i < sband->n_bitrates; i++) { + if (sband->bitrates[i].bitrate == 10) + is_b = true; + if (sband->bitrates[i].bitrate == 60) + is_g = true; + } + is_ht |= sband->ht_cap.ht_supported; + } + + strcpy(name, "IEEE 802.11"); + if (is_a) + strcat(name, "a"); + if (is_b) + strcat(name, "b"); + if (is_g) + strcat(name, "g"); + if (is_ht) + strcat(name, "n"); + + return 0; +} +EXPORT_SYMBOL(cfg80211_wext_giwname); + +int cfg80211_wext_siwmode(struct net_device *dev, struct iw_request_info *info, + u32 *mode, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct cfg80211_registered_device *rdev; + struct vif_params vifparams; + enum nl80211_iftype type; + + if (!wdev) + return -EOPNOTSUPP; + + rdev = wiphy_to_dev(wdev->wiphy); + + if (!rdev->ops->change_virtual_intf) + return -EOPNOTSUPP; + + /* don't support changing VLANs, you just re-create them */ + if (wdev->iftype == NL80211_IFTYPE_AP_VLAN) + return -EOPNOTSUPP; + + switch (*mode) { + case IW_MODE_INFRA: + type = NL80211_IFTYPE_STATION; + break; + case IW_MODE_ADHOC: + type = NL80211_IFTYPE_ADHOC; + break; + case IW_MODE_REPEAT: + type = NL80211_IFTYPE_WDS; + break; + case IW_MODE_MONITOR: + type = NL80211_IFTYPE_MONITOR; + break; + default: + return -EINVAL; + } + + memset(&vifparams, 0, sizeof(vifparams)); + + return rdev->ops->change_virtual_intf(wdev->wiphy, dev->ifindex, type, + NULL, &vifparams); +} +EXPORT_SYMBOL(cfg80211_wext_siwmode); + +int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info, + u32 *mode, char *extra) +{ + struct wireless_dev *wdev = dev->ieee80211_ptr; + + if (!wdev) + return -EOPNOTSUPP; + + switch (wdev->iftype) { + case NL80211_IFTYPE_AP: + *mode = IW_MODE_MASTER; + break; + case NL80211_IFTYPE_STATION: + *mode = IW_MODE_INFRA; + break; + case NL80211_IFTYPE_ADHOC: + *mode = IW_MODE_ADHOC; + break; + case NL80211_IFTYPE_MONITOR: + *mode = IW_MODE_MONITOR; + break; + case NL80211_IFTYPE_WDS: + *mode = IW_MODE_REPEAT; + break; + case NL80211_IFTYPE_AP_VLAN: + *mode = IW_MODE_SECOND; /* FIXME */ + break; + default: + *mode = IW_MODE_AUTO; + break; + } + return 0; +} +EXPORT_SYMBOL(cfg80211_wext_giwmode); diff --git a/net/wireless/wext.c b/net/wireless/wext.c index d98ffb75119ac02891446056b3e507c23f3453ce..e49a2d1ef1e48a735ddda23b0d6226a66b5c4f39 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c @@ -64,7 +64,7 @@ * o Remove spy_offset from struct iw_handler_def * o Start deprecating dev->get_wireless_stats, output a warning * o If IW_QUAL_DBM is set, show dBm values in /proc/net/wireless - * o Don't loose INVALID/DBM flags when clearing UPDATED flags (iwstats) + * o Don't lose INVALID/DBM flags when clearing UPDATED flags (iwstats) * * v8 - 17.02.06 - Jean II * o RtNetlink requests support (SET/GET) diff --git a/net/x25/sysctl_net_x25.c b/net/x25/sysctl_net_x25.c index 6ebda25c24e96a4471ee7eb8aa3db69b2411075d..a5d3416522de124b7458c21641dcc2e648d03577 100644 --- a/net/x25/sysctl_net_x25.c +++ b/net/x25/sysctl_net_x25.c @@ -24,8 +24,8 @@ static struct ctl_table x25_table[] = { .data = &sysctl_x25_restart_request_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_timer, .extra2 = &max_timer, }, @@ -35,8 +35,8 @@ static struct ctl_table x25_table[] = { .data = &sysctl_x25_call_request_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_timer, .extra2 = &max_timer, }, @@ -46,8 +46,8 @@ static struct ctl_table x25_table[] = { .data = &sysctl_x25_reset_request_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_timer, .extra2 = &max_timer, }, @@ -57,8 +57,8 @@ static struct ctl_table x25_table[] = { .data = &sysctl_x25_clear_request_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_timer, .extra2 = &max_timer, }, @@ -68,8 +68,8 @@ static struct ctl_table x25_table[] = { .data = &sysctl_x25_ack_holdback_timeout, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec_minmax, - .strategy = &sysctl_intvec, + .proc_handler = proc_dointvec_minmax, + .strategy = sysctl_intvec, .extra1 = &min_timer, .extra2 = &max_timer, }, @@ -79,7 +79,7 @@ static struct ctl_table x25_table[] = { .data = &sysctl_x25_forward, .maxlen = sizeof(int), .mode = 0644, - .proc_handler = &proc_dointvec, + .proc_handler = proc_dointvec, }, { 0, }, }; diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile index 0f439a72ccab4fa8129a0e0c9868241fae4ad610..c631047e1b272a11bf439739dc50ebb1af3c4ca6 100644 --- a/net/xfrm/Makefile +++ b/net/xfrm/Makefile @@ -3,8 +3,8 @@ # obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \ - xfrm_input.o xfrm_output.o xfrm_algo.o + xfrm_input.o xfrm_output.o xfrm_algo.o \ + xfrm_sysctl.o obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o obj-$(CONFIG_XFRM_USER) += xfrm_user.o obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o - diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c index 75279402ccf46f085f249cd65eda2a9e69db40a2..b4a13178fb40176e41d90ff171e971ac7d6f8935 100644 --- a/net/xfrm/xfrm_input.c +++ b/net/xfrm/xfrm_input.c @@ -104,6 +104,7 @@ EXPORT_SYMBOL(xfrm_prepare_input); int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) { + struct net *net = dev_net(skb->dev); int err; __be32 seq; struct xfrm_state *x; @@ -127,7 +128,7 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) sp = secpath_dup(skb->sp); if (!sp) { - XFRM_INC_STATS(LINUX_MIB_XFRMINERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR); goto drop; } if (skb->sp) @@ -141,19 +142,19 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) seq = 0; if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) { - XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); goto drop; } do { if (skb->sp->len == XFRM_MAX_DEPTH) { - XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); goto drop; } - x = xfrm_state_lookup(daddr, spi, nexthdr, family); + x = xfrm_state_lookup(net, daddr, spi, nexthdr, family); if (x == NULL) { - XFRM_INC_STATS(LINUX_MIB_XFRMINNOSTATES); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES); xfrm_audit_state_notfound(skb, family, spi, seq); goto drop; } @@ -162,22 +163,22 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) spin_lock(&x->lock); if (unlikely(x->km.state != XFRM_STATE_VALID)) { - XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEINVALID); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEINVALID); goto drop_unlock; } if ((x->encap ? x->encap->encap_type : 0) != encap_type) { - XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMISMATCH); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH); goto drop_unlock; } if (x->props.replay_window && xfrm_replay_check(x, skb, seq)) { - XFRM_INC_STATS(LINUX_MIB_XFRMINSTATESEQERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR); goto drop_unlock; } if (xfrm_state_check_expire(x)) { - XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEEXPIRED); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEEXPIRED); goto drop_unlock; } @@ -198,7 +199,7 @@ resume: x->type->proto); x->stats.integrity_failed++; } - XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEPROTOERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR); goto drop_unlock; } @@ -224,7 +225,7 @@ resume: } if (inner_mode->input(x, skb)) { - XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMODEERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR); goto drop; } @@ -242,7 +243,7 @@ resume: err = xfrm_parse_spi(skb, nexthdr, &spi, &seq); if (err < 0) { - XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); goto drop; } } while (!err); diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c index dc50f1e71f76f86487ebded9991cb20bc4e46ef9..c235597ba8dd9c1f24b7fb6a139a29bee66e5141 100644 --- a/net/xfrm/xfrm_output.c +++ b/net/xfrm/xfrm_output.c @@ -41,6 +41,7 @@ static int xfrm_output_one(struct sk_buff *skb, int err) { struct dst_entry *dst = skb->dst; struct xfrm_state *x = dst->xfrm; + struct net *net = xs_net(x); if (err <= 0) goto resume; @@ -48,33 +49,33 @@ static int xfrm_output_one(struct sk_buff *skb, int err) do { err = xfrm_state_check_space(x, skb); if (err) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); goto error_nolock; } err = x->outer_mode->output(x, skb); if (err) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATEMODEERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEMODEERROR); goto error_nolock; } spin_lock_bh(&x->lock); err = xfrm_state_check_expire(x); if (err) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATEEXPIRED); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEEXPIRED); goto error; } if (x->type->flags & XFRM_TYPE_REPLAY_PROT) { XFRM_SKB_CB(skb)->seq.output = ++x->replay.oseq; if (unlikely(x->replay.oseq == 0)) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATESEQERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATESEQERROR); x->replay.oseq--; xfrm_audit_state_replay_overflow(x, skb); err = -EOVERFLOW; goto error; } - if (xfrm_aevent_is_on()) + if (xfrm_aevent_is_on(net)) xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); } @@ -89,12 +90,12 @@ static int xfrm_output_one(struct sk_buff *skb, int err) resume: if (err) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTSTATEPROTOERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTSTATEPROTOERROR); goto error_nolock; } if (!(skb->dst = dst_pop(dst))) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); err = -EHOSTUNREACH; goto error_nolock; } @@ -178,6 +179,7 @@ static int xfrm_output_gso(struct sk_buff *skb) int xfrm_output(struct sk_buff *skb) { + struct net *net = dev_net(skb->dst->dev); int err; if (skb_is_gso(skb)) @@ -186,7 +188,7 @@ int xfrm_output(struct sk_buff *skb) if (skb->ip_summed == CHECKSUM_PARTIAL) { err = skb_checksum_help(skb); if (err) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTERROR); kfree_skb(skb); return err; } diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index fb216c9adf86722bc81079fd25f4ed4b908e642c..9c068ab3a834fbb0948e130c0713e6e6edda536b 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -34,28 +34,16 @@ #include "xfrm_hash.h" -int sysctl_xfrm_larval_drop __read_mostly = 1; - -#ifdef CONFIG_XFRM_STATISTICS -DEFINE_SNMP_STAT(struct linux_xfrm_mib, xfrm_statistics) __read_mostly; -EXPORT_SYMBOL(xfrm_statistics); -#endif - DEFINE_MUTEX(xfrm_cfg_mutex); EXPORT_SYMBOL(xfrm_cfg_mutex); static DEFINE_RWLOCK(xfrm_policy_lock); -static struct list_head xfrm_policy_all; -unsigned int xfrm_policy_count[XFRM_POLICY_MAX*2]; -EXPORT_SYMBOL(xfrm_policy_count); - static DEFINE_RWLOCK(xfrm_policy_afinfo_lock); static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO]; static struct kmem_cache *xfrm_dst_cache __read_mostly; -static struct work_struct xfrm_policy_gc_work; static HLIST_HEAD(xfrm_policy_gc_list); static DEFINE_SPINLOCK(xfrm_policy_gc_lock); @@ -63,6 +51,9 @@ static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); static void xfrm_init_pmtu(struct dst_entry *dst); +static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, + int dir); + static inline int __xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl) { @@ -97,7 +88,7 @@ int xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl, return 0; } -static inline struct dst_entry *__xfrm_dst_lookup(int tos, +static inline struct dst_entry *__xfrm_dst_lookup(struct net *net, int tos, xfrm_address_t *saddr, xfrm_address_t *daddr, int family) @@ -109,7 +100,7 @@ static inline struct dst_entry *__xfrm_dst_lookup(int tos, if (unlikely(afinfo == NULL)) return ERR_PTR(-EAFNOSUPPORT); - dst = afinfo->dst_lookup(tos, saddr, daddr); + dst = afinfo->dst_lookup(net, tos, saddr, daddr); xfrm_policy_put_afinfo(afinfo); @@ -121,6 +112,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos, xfrm_address_t *prev_daddr, int family) { + struct net *net = xs_net(x); xfrm_address_t *saddr = &x->props.saddr; xfrm_address_t *daddr = &x->id.daddr; struct dst_entry *dst; @@ -134,7 +126,7 @@ static inline struct dst_entry *xfrm_dst_lookup(struct xfrm_state *x, int tos, daddr = x->coaddr; } - dst = __xfrm_dst_lookup(tos, saddr, daddr, family); + dst = __xfrm_dst_lookup(net, tos, saddr, daddr, family); if (!IS_ERR(dst)) { if (prev_saddr != saddr) @@ -229,13 +221,14 @@ expired: * SPD calls. */ -struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp) +struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp) { struct xfrm_policy *policy; policy = kzalloc(sizeof(struct xfrm_policy), gfp); if (policy) { + write_pnet(&policy->xp_net, net); INIT_LIST_HEAD(&policy->walk.all); INIT_HLIST_NODE(&policy->bydst); INIT_HLIST_NODE(&policy->byidx); @@ -296,6 +289,7 @@ static void xfrm_policy_gc_task(struct work_struct *work) hlist_for_each_entry_safe(policy, entry, tmp, &gc_list, bydst) xfrm_policy_gc_kill(policy); } +static DECLARE_WORK(xfrm_policy_gc_work, xfrm_policy_gc_task); /* Rule must be locked. Release descentant resources, announce * entry dead. The rule must be unlinked from lists to the moment. @@ -322,38 +316,29 @@ static void xfrm_policy_kill(struct xfrm_policy *policy) schedule_work(&xfrm_policy_gc_work); } -struct xfrm_policy_hash { - struct hlist_head *table; - unsigned int hmask; -}; - -static struct hlist_head xfrm_policy_inexact[XFRM_POLICY_MAX*2]; -static struct xfrm_policy_hash xfrm_policy_bydst[XFRM_POLICY_MAX*2] __read_mostly; -static struct hlist_head *xfrm_policy_byidx __read_mostly; -static unsigned int xfrm_idx_hmask __read_mostly; static unsigned int xfrm_policy_hashmax __read_mostly = 1 * 1024 * 1024; -static inline unsigned int idx_hash(u32 index) +static inline unsigned int idx_hash(struct net *net, u32 index) { - return __idx_hash(index, xfrm_idx_hmask); + return __idx_hash(index, net->xfrm.policy_idx_hmask); } -static struct hlist_head *policy_hash_bysel(struct xfrm_selector *sel, unsigned short family, int dir) +static struct hlist_head *policy_hash_bysel(struct net *net, struct xfrm_selector *sel, unsigned short family, int dir) { - unsigned int hmask = xfrm_policy_bydst[dir].hmask; + unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; unsigned int hash = __sel_hash(sel, family, hmask); return (hash == hmask + 1 ? - &xfrm_policy_inexact[dir] : - xfrm_policy_bydst[dir].table + hash); + &net->xfrm.policy_inexact[dir] : + net->xfrm.policy_bydst[dir].table + hash); } -static struct hlist_head *policy_hash_direct(xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, int dir) +static struct hlist_head *policy_hash_direct(struct net *net, xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, int dir) { - unsigned int hmask = xfrm_policy_bydst[dir].hmask; + unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; unsigned int hash = __addr_hash(daddr, saddr, family, hmask); - return xfrm_policy_bydst[dir].table + hash; + return net->xfrm.policy_bydst[dir].table + hash; } static void xfrm_dst_hash_transfer(struct hlist_head *list, @@ -408,12 +393,12 @@ static unsigned long xfrm_new_hash_mask(unsigned int old_hmask) return ((old_hmask + 1) << 1) - 1; } -static void xfrm_bydst_resize(int dir) +static void xfrm_bydst_resize(struct net *net, int dir) { - unsigned int hmask = xfrm_policy_bydst[dir].hmask; + unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; unsigned int nhashmask = xfrm_new_hash_mask(hmask); unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); - struct hlist_head *odst = xfrm_policy_bydst[dir].table; + struct hlist_head *odst = net->xfrm.policy_bydst[dir].table; struct hlist_head *ndst = xfrm_hash_alloc(nsize); int i; @@ -425,20 +410,20 @@ static void xfrm_bydst_resize(int dir) for (i = hmask; i >= 0; i--) xfrm_dst_hash_transfer(odst + i, ndst, nhashmask); - xfrm_policy_bydst[dir].table = ndst; - xfrm_policy_bydst[dir].hmask = nhashmask; + net->xfrm.policy_bydst[dir].table = ndst; + net->xfrm.policy_bydst[dir].hmask = nhashmask; write_unlock_bh(&xfrm_policy_lock); xfrm_hash_free(odst, (hmask + 1) * sizeof(struct hlist_head)); } -static void xfrm_byidx_resize(int total) +static void xfrm_byidx_resize(struct net *net, int total) { - unsigned int hmask = xfrm_idx_hmask; + unsigned int hmask = net->xfrm.policy_idx_hmask; unsigned int nhashmask = xfrm_new_hash_mask(hmask); unsigned int nsize = (nhashmask + 1) * sizeof(struct hlist_head); - struct hlist_head *oidx = xfrm_policy_byidx; + struct hlist_head *oidx = net->xfrm.policy_byidx; struct hlist_head *nidx = xfrm_hash_alloc(nsize); int i; @@ -450,18 +435,18 @@ static void xfrm_byidx_resize(int total) for (i = hmask; i >= 0; i--) xfrm_idx_hash_transfer(oidx + i, nidx, nhashmask); - xfrm_policy_byidx = nidx; - xfrm_idx_hmask = nhashmask; + net->xfrm.policy_byidx = nidx; + net->xfrm.policy_idx_hmask = nhashmask; write_unlock_bh(&xfrm_policy_lock); xfrm_hash_free(oidx, (hmask + 1) * sizeof(struct hlist_head)); } -static inline int xfrm_bydst_should_resize(int dir, int *total) +static inline int xfrm_bydst_should_resize(struct net *net, int dir, int *total) { - unsigned int cnt = xfrm_policy_count[dir]; - unsigned int hmask = xfrm_policy_bydst[dir].hmask; + unsigned int cnt = net->xfrm.policy_count[dir]; + unsigned int hmask = net->xfrm.policy_bydst[dir].hmask; if (total) *total += cnt; @@ -473,9 +458,9 @@ static inline int xfrm_bydst_should_resize(int dir, int *total) return 0; } -static inline int xfrm_byidx_should_resize(int total) +static inline int xfrm_byidx_should_resize(struct net *net, int total) { - unsigned int hmask = xfrm_idx_hmask; + unsigned int hmask = net->xfrm.policy_idx_hmask; if ((hmask + 1) < xfrm_policy_hashmax && total > hmask) @@ -487,41 +472,40 @@ static inline int xfrm_byidx_should_resize(int total) void xfrm_spd_getinfo(struct xfrmk_spdinfo *si) { read_lock_bh(&xfrm_policy_lock); - si->incnt = xfrm_policy_count[XFRM_POLICY_IN]; - si->outcnt = xfrm_policy_count[XFRM_POLICY_OUT]; - si->fwdcnt = xfrm_policy_count[XFRM_POLICY_FWD]; - si->inscnt = xfrm_policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX]; - si->outscnt = xfrm_policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX]; - si->fwdscnt = xfrm_policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; - si->spdhcnt = xfrm_idx_hmask; + si->incnt = init_net.xfrm.policy_count[XFRM_POLICY_IN]; + si->outcnt = init_net.xfrm.policy_count[XFRM_POLICY_OUT]; + si->fwdcnt = init_net.xfrm.policy_count[XFRM_POLICY_FWD]; + si->inscnt = init_net.xfrm.policy_count[XFRM_POLICY_IN+XFRM_POLICY_MAX]; + si->outscnt = init_net.xfrm.policy_count[XFRM_POLICY_OUT+XFRM_POLICY_MAX]; + si->fwdscnt = init_net.xfrm.policy_count[XFRM_POLICY_FWD+XFRM_POLICY_MAX]; + si->spdhcnt = init_net.xfrm.policy_idx_hmask; si->spdhmcnt = xfrm_policy_hashmax; read_unlock_bh(&xfrm_policy_lock); } EXPORT_SYMBOL(xfrm_spd_getinfo); static DEFINE_MUTEX(hash_resize_mutex); -static void xfrm_hash_resize(struct work_struct *__unused) +static void xfrm_hash_resize(struct work_struct *work) { + struct net *net = container_of(work, struct net, xfrm.policy_hash_work); int dir, total; mutex_lock(&hash_resize_mutex); total = 0; for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { - if (xfrm_bydst_should_resize(dir, &total)) - xfrm_bydst_resize(dir); + if (xfrm_bydst_should_resize(net, dir, &total)) + xfrm_bydst_resize(net, dir); } - if (xfrm_byidx_should_resize(total)) - xfrm_byidx_resize(total); + if (xfrm_byidx_should_resize(net, total)) + xfrm_byidx_resize(net, total); mutex_unlock(&hash_resize_mutex); } -static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize); - /* Generate new index... KAME seems to generate them ordered by cost * of an absolute inpredictability of ordering of rules. This will not pass. */ -static u32 xfrm_gen_index(u8 type, int dir) +static u32 xfrm_gen_index(struct net *net, int dir) { static u32 idx_generator; @@ -536,7 +520,7 @@ static u32 xfrm_gen_index(u8 type, int dir) idx_generator += 8; if (idx == 0) idx = 8; - list = xfrm_policy_byidx + idx_hash(idx); + list = net->xfrm.policy_byidx + idx_hash(net, idx); found = 0; hlist_for_each_entry(p, entry, list, byidx) { if (p->index == idx) { @@ -566,6 +550,7 @@ static inline int selector_cmp(struct xfrm_selector *s1, struct xfrm_selector *s int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) { + struct net *net = xp_net(policy); struct xfrm_policy *pol; struct xfrm_policy *delpol; struct hlist_head *chain; @@ -573,7 +558,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) struct dst_entry *gc_list; write_lock_bh(&xfrm_policy_lock); - chain = policy_hash_bysel(&policy->selector, policy->family, dir); + chain = policy_hash_bysel(net, &policy->selector, policy->family, dir); delpol = NULL; newpos = NULL; hlist_for_each_entry(pol, entry, chain, bydst) { @@ -600,27 +585,23 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) else hlist_add_head(&policy->bydst, chain); xfrm_pol_hold(policy); - xfrm_policy_count[dir]++; + net->xfrm.policy_count[dir]++; atomic_inc(&flow_cache_genid); - if (delpol) { - hlist_del(&delpol->bydst); - hlist_del(&delpol->byidx); - list_del(&delpol->walk.all); - xfrm_policy_count[dir]--; - } - policy->index = delpol ? delpol->index : xfrm_gen_index(policy->type, dir); - hlist_add_head(&policy->byidx, xfrm_policy_byidx+idx_hash(policy->index)); + if (delpol) + __xfrm_policy_unlink(delpol, dir); + policy->index = delpol ? delpol->index : xfrm_gen_index(net, dir); + hlist_add_head(&policy->byidx, net->xfrm.policy_byidx+idx_hash(net, policy->index)); policy->curlft.add_time = get_seconds(); policy->curlft.use_time = 0; if (!mod_timer(&policy->timer, jiffies + HZ)) xfrm_pol_hold(policy); - list_add(&policy->walk.all, &xfrm_policy_all); + list_add(&policy->walk.all, &net->xfrm.policy_all); write_unlock_bh(&xfrm_policy_lock); if (delpol) xfrm_policy_kill(delpol); - else if (xfrm_bydst_should_resize(dir, NULL)) - schedule_work(&xfrm_hash_work); + else if (xfrm_bydst_should_resize(net, dir, NULL)) + schedule_work(&net->xfrm.policy_hash_work); read_lock_bh(&xfrm_policy_lock); gc_list = NULL; @@ -654,7 +635,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) } EXPORT_SYMBOL(xfrm_policy_insert); -struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, +struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u8 type, int dir, struct xfrm_selector *sel, struct xfrm_sec_ctx *ctx, int delete, int *err) @@ -665,7 +646,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, *err = 0; write_lock_bh(&xfrm_policy_lock); - chain = policy_hash_bysel(sel, sel->family, dir); + chain = policy_hash_bysel(net, sel, sel->family, dir); ret = NULL; hlist_for_each_entry(pol, entry, chain, bydst) { if (pol->type == type && @@ -679,10 +660,7 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, write_unlock_bh(&xfrm_policy_lock); return pol; } - hlist_del(&pol->bydst); - hlist_del(&pol->byidx); - list_del(&pol->walk.all); - xfrm_policy_count[dir]--; + __xfrm_policy_unlink(pol, dir); } ret = pol; break; @@ -698,8 +676,8 @@ struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir, } EXPORT_SYMBOL(xfrm_policy_bysel_ctx); -struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete, - int *err) +struct xfrm_policy *xfrm_policy_byid(struct net *net, u8 type, int dir, u32 id, + int delete, int *err) { struct xfrm_policy *pol, *ret; struct hlist_head *chain; @@ -711,7 +689,7 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete, *err = 0; write_lock_bh(&xfrm_policy_lock); - chain = xfrm_policy_byidx + idx_hash(id); + chain = net->xfrm.policy_byidx + idx_hash(net, id); ret = NULL; hlist_for_each_entry(pol, entry, chain, byidx) { if (pol->type == type && pol->index == id) { @@ -723,10 +701,7 @@ struct xfrm_policy *xfrm_policy_byid(u8 type, int dir, u32 id, int delete, write_unlock_bh(&xfrm_policy_lock); return pol; } - hlist_del(&pol->bydst); - hlist_del(&pol->byidx); - list_del(&pol->walk.all); - xfrm_policy_count[dir]--; + __xfrm_policy_unlink(pol, dir); } ret = pol; break; @@ -744,7 +719,7 @@ EXPORT_SYMBOL(xfrm_policy_byid); #ifdef CONFIG_SECURITY_NETWORK_XFRM static inline int -xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) +xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audit_info) { int dir, err = 0; @@ -754,7 +729,7 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) int i; hlist_for_each_entry(pol, entry, - &xfrm_policy_inexact[dir], bydst) { + &net->xfrm.policy_inexact[dir], bydst) { if (pol->type != type) continue; err = security_xfrm_policy_delete(pol->security); @@ -766,9 +741,9 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) return err; } } - for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { + for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) { hlist_for_each_entry(pol, entry, - xfrm_policy_bydst[dir].table + i, + net->xfrm.policy_bydst[dir].table + i, bydst) { if (pol->type != type) continue; @@ -788,36 +763,33 @@ xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) } #else static inline int -xfrm_policy_flush_secctx_check(u8 type, struct xfrm_audit *audit_info) +xfrm_policy_flush_secctx_check(struct net *net, u8 type, struct xfrm_audit *audit_info) { return 0; } #endif -int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) +int xfrm_policy_flush(struct net *net, u8 type, struct xfrm_audit *audit_info) { int dir, err = 0; write_lock_bh(&xfrm_policy_lock); - err = xfrm_policy_flush_secctx_check(type, audit_info); + err = xfrm_policy_flush_secctx_check(net, type, audit_info); if (err) goto out; for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { struct xfrm_policy *pol; struct hlist_node *entry; - int i, killed; + int i; - killed = 0; again1: hlist_for_each_entry(pol, entry, - &xfrm_policy_inexact[dir], bydst) { + &net->xfrm.policy_inexact[dir], bydst) { if (pol->type != type) continue; - hlist_del(&pol->bydst); - hlist_del(&pol->byidx); - list_del(&pol->walk.all); + __xfrm_policy_unlink(pol, dir); write_unlock_bh(&xfrm_policy_lock); xfrm_audit_policy_delete(pol, 1, audit_info->loginuid, @@ -825,22 +797,19 @@ int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) audit_info->secid); xfrm_policy_kill(pol); - killed++; write_lock_bh(&xfrm_policy_lock); goto again1; } - for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { + for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) { again2: hlist_for_each_entry(pol, entry, - xfrm_policy_bydst[dir].table + i, + net->xfrm.policy_bydst[dir].table + i, bydst) { if (pol->type != type) continue; - hlist_del(&pol->bydst); - hlist_del(&pol->byidx); - list_del(&pol->walk.all); + __xfrm_policy_unlink(pol, dir); write_unlock_bh(&xfrm_policy_lock); xfrm_audit_policy_delete(pol, 1, @@ -848,14 +817,12 @@ int xfrm_policy_flush(u8 type, struct xfrm_audit *audit_info) audit_info->sessionid, audit_info->secid); xfrm_policy_kill(pol); - killed++; write_lock_bh(&xfrm_policy_lock); goto again2; } } - xfrm_policy_count[dir] -= killed; } atomic_inc(&flow_cache_genid); out: @@ -864,7 +831,7 @@ out: } EXPORT_SYMBOL(xfrm_policy_flush); -int xfrm_policy_walk(struct xfrm_policy_walk *walk, +int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, int (*func)(struct xfrm_policy *, int, int, void*), void *data) { @@ -881,10 +848,10 @@ int xfrm_policy_walk(struct xfrm_policy_walk *walk, write_lock_bh(&xfrm_policy_lock); if (list_empty(&walk->walk.all)) - x = list_first_entry(&xfrm_policy_all, struct xfrm_policy_walk_entry, all); + x = list_first_entry(&net->xfrm.policy_all, struct xfrm_policy_walk_entry, all); else x = list_entry(&walk->walk.all, struct xfrm_policy_walk_entry, all); - list_for_each_entry_from(x, &xfrm_policy_all, all) { + list_for_each_entry_from(x, &net->xfrm.policy_all, all) { if (x->dead) continue; pol = container_of(x, struct xfrm_policy, walk); @@ -953,7 +920,8 @@ static int xfrm_policy_match(struct xfrm_policy *pol, struct flowi *fl, return ret; } -static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, +static struct xfrm_policy *xfrm_policy_lookup_bytype(struct net *net, u8 type, + struct flowi *fl, u16 family, u8 dir) { int err; @@ -969,7 +937,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, return NULL; read_lock_bh(&xfrm_policy_lock); - chain = policy_hash_direct(daddr, saddr, family, dir); + chain = policy_hash_direct(net, daddr, saddr, family, dir); ret = NULL; hlist_for_each_entry(pol, entry, chain, bydst) { err = xfrm_policy_match(pol, fl, type, family, dir); @@ -986,7 +954,7 @@ static struct xfrm_policy *xfrm_policy_lookup_bytype(u8 type, struct flowi *fl, break; } } - chain = &xfrm_policy_inexact[dir]; + chain = &net->xfrm.policy_inexact[dir]; hlist_for_each_entry(pol, entry, chain, bydst) { err = xfrm_policy_match(pol, fl, type, family, dir); if (err) { @@ -1009,14 +977,14 @@ fail: return ret; } -static int xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, - void **objp, atomic_t **obj_refp) +static int xfrm_policy_lookup(struct net *net, struct flowi *fl, u16 family, + u8 dir, void **objp, atomic_t **obj_refp) { struct xfrm_policy *pol; int err = 0; #ifdef CONFIG_XFRM_SUB_POLICY - pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_SUB, fl, family, dir); + pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_SUB, fl, family, dir); if (IS_ERR(pol)) { err = PTR_ERR(pol); pol = NULL; @@ -1024,7 +992,7 @@ static int xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir, if (pol || err) goto end; #endif - pol = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, fl, family, dir); + pol = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, fl, family, dir); if (IS_ERR(pol)) { err = PTR_ERR(pol); pol = NULL; @@ -1083,29 +1051,32 @@ static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struc static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) { - struct hlist_head *chain = policy_hash_bysel(&pol->selector, + struct net *net = xp_net(pol); + struct hlist_head *chain = policy_hash_bysel(net, &pol->selector, pol->family, dir); - list_add(&pol->walk.all, &xfrm_policy_all); + list_add(&pol->walk.all, &net->xfrm.policy_all); hlist_add_head(&pol->bydst, chain); - hlist_add_head(&pol->byidx, xfrm_policy_byidx+idx_hash(pol->index)); - xfrm_policy_count[dir]++; + hlist_add_head(&pol->byidx, net->xfrm.policy_byidx+idx_hash(net, pol->index)); + net->xfrm.policy_count[dir]++; xfrm_pol_hold(pol); - if (xfrm_bydst_should_resize(dir, NULL)) - schedule_work(&xfrm_hash_work); + if (xfrm_bydst_should_resize(net, dir, NULL)) + schedule_work(&net->xfrm.policy_hash_work); } static struct xfrm_policy *__xfrm_policy_unlink(struct xfrm_policy *pol, int dir) { + struct net *net = xp_net(pol); + if (hlist_unhashed(&pol->bydst)) return NULL; hlist_del(&pol->bydst); hlist_del(&pol->byidx); list_del(&pol->walk.all); - xfrm_policy_count[dir]--; + net->xfrm.policy_count[dir]--; return pol; } @@ -1127,6 +1098,7 @@ EXPORT_SYMBOL(xfrm_policy_delete); int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) { + struct net *net = xp_net(pol); struct xfrm_policy *old_pol; #ifdef CONFIG_XFRM_SUB_POLICY @@ -1139,7 +1111,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) sk->sk_policy[dir] = pol; if (pol) { pol->curlft.add_time = get_seconds(); - pol->index = xfrm_gen_index(pol->type, XFRM_POLICY_MAX+dir); + pol->index = xfrm_gen_index(net, XFRM_POLICY_MAX+dir); __xfrm_policy_link(pol, XFRM_POLICY_MAX+dir); } if (old_pol) @@ -1154,7 +1126,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) { - struct xfrm_policy *newp = xfrm_policy_alloc(GFP_ATOMIC); + struct xfrm_policy *newp = xfrm_policy_alloc(xp_net(old), GFP_ATOMIC); if (newp) { newp->selector = old->selector; @@ -1194,7 +1166,7 @@ int __xfrm_sk_clone_policy(struct sock *sk) } static int -xfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote, +xfrm_get_saddr(struct net *net, xfrm_address_t *local, xfrm_address_t *remote, unsigned short family) { int err; @@ -1202,7 +1174,7 @@ xfrm_get_saddr(xfrm_address_t *local, xfrm_address_t *remote, if (unlikely(afinfo == NULL)) return -EINVAL; - err = afinfo->get_saddr(local, remote); + err = afinfo->get_saddr(net, local, remote); xfrm_policy_put_afinfo(afinfo); return err; } @@ -1214,6 +1186,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl, struct xfrm_state **xfrm, unsigned short family) { + struct net *net = xp_net(policy); int nx; int i, error; xfrm_address_t *daddr = xfrm_flowi_daddr(fl, family); @@ -1232,7 +1205,7 @@ xfrm_tmpl_resolve_one(struct xfrm_policy *policy, struct flowi *fl, local = &tmpl->saddr; family = tmpl->encap_family; if (xfrm_addr_any(local, family)) { - error = xfrm_get_saddr(&tmp, remote, family); + error = xfrm_get_saddr(net, &tmp, remote, family); if (error) goto fail; local = &tmp; @@ -1546,7 +1519,7 @@ static int stale_bundle(struct dst_entry *dst); * At the moment we eat a raw IP route. Mostly to speed up lookups * on interfaces with disabled IPsec. */ -int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, +int __xfrm_lookup(struct net *net, struct dst_entry **dst_p, struct flowi *fl, struct sock *sk, int flags) { struct xfrm_policy *policy; @@ -1576,7 +1549,7 @@ restart: policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl); err = PTR_ERR(policy); if (IS_ERR(policy)) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); goto dropdst; } } @@ -1584,14 +1557,14 @@ restart: if (!policy) { /* To accelerate a bit... */ if ((dst_orig->flags & DST_NOXFRM) || - !xfrm_policy_count[XFRM_POLICY_OUT]) + !net->xfrm.policy_count[XFRM_POLICY_OUT]) goto nopol; - policy = flow_cache_lookup(fl, dst_orig->ops->family, + policy = flow_cache_lookup(net, fl, dst_orig->ops->family, dir, xfrm_policy_lookup); err = PTR_ERR(policy); if (IS_ERR(policy)) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); goto dropdst; } } @@ -1614,7 +1587,7 @@ restart: default: case XFRM_POLICY_BLOCK: /* Prohibit the flow */ - XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLBLOCK); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK); err = -EPERM; goto error; @@ -1634,7 +1607,7 @@ restart: */ dst = xfrm_find_bundle(fl, policy, family); if (IS_ERR(dst)) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR); err = PTR_ERR(dst); goto error; } @@ -1644,17 +1617,18 @@ restart: #ifdef CONFIG_XFRM_SUB_POLICY if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { - pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, + pols[1] = xfrm_policy_lookup_bytype(net, + XFRM_POLICY_TYPE_MAIN, fl, family, XFRM_POLICY_OUT); if (pols[1]) { if (IS_ERR(pols[1])) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLERROR); err = PTR_ERR(pols[1]); goto error; } if (pols[1]->action == XFRM_POLICY_BLOCK) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLBLOCK); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLBLOCK); err = -EPERM; goto error; } @@ -1681,27 +1655,27 @@ restart: if (unlikely(nx<0)) { err = nx; - if (err == -EAGAIN && sysctl_xfrm_larval_drop) { + if (err == -EAGAIN && net->xfrm.sysctl_larval_drop) { /* EREMOTE tells the caller to generate * a one-shot blackhole route. */ - XFRM_INC_STATS(LINUX_MIB_XFRMOUTNOSTATES); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); xfrm_pol_put(policy); return -EREMOTE; } if (err == -EAGAIN && (flags & XFRM_LOOKUP_WAIT)) { DECLARE_WAITQUEUE(wait, current); - add_wait_queue(&km_waitq, &wait); + add_wait_queue(&net->xfrm.km_waitq, &wait); set_current_state(TASK_INTERRUPTIBLE); schedule(); set_current_state(TASK_RUNNING); - remove_wait_queue(&km_waitq, &wait); + remove_wait_queue(&net->xfrm.km_waitq, &wait); nx = xfrm_tmpl_resolve(pols, npols, fl, xfrm, family); if (nx == -EAGAIN && signal_pending(current)) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTNOSTATES); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); err = -ERESTART; goto error; } @@ -1713,7 +1687,7 @@ restart: err = nx; } if (err < 0) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTNOSTATES); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTNOSTATES); goto error; } } @@ -1726,7 +1700,7 @@ restart: dst = xfrm_bundle_create(policy, xfrm, nx, fl, dst_orig); err = PTR_ERR(dst); if (IS_ERR(dst)) { - XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLEGENERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLEGENERROR); goto error; } @@ -1747,9 +1721,9 @@ restart: dst_free(dst); if (pol_dead) - XFRM_INC_STATS(LINUX_MIB_XFRMOUTPOLDEAD); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTPOLDEAD); else - XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR); err = -EHOSTUNREACH; goto error; } @@ -1761,7 +1735,7 @@ restart: if (unlikely(err)) { write_unlock_bh(&policy->lock); dst_free(dst); - XFRM_INC_STATS(LINUX_MIB_XFRMOUTBUNDLECHECKERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMOUTBUNDLECHECKERROR); goto error; } @@ -1790,10 +1764,10 @@ nopol: } EXPORT_SYMBOL(__xfrm_lookup); -int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, +int xfrm_lookup(struct net *net, struct dst_entry **dst_p, struct flowi *fl, struct sock *sk, int flags) { - int err = __xfrm_lookup(dst_p, fl, sk, flags); + int err = __xfrm_lookup(net, dst_p, fl, sk, flags); if (err == -EREMOTE) { dst_release(*dst_p); @@ -1901,6 +1875,7 @@ static inline int secpath_has_nontransport(struct sec_path *sp, int k, int *idxp int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, unsigned short family) { + struct net *net = dev_net(skb->dev); struct xfrm_policy *pol; struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; int npols = 0; @@ -1916,7 +1891,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, fl_dir = policy_to_flow_dir(dir); if (__xfrm_decode_session(skb, &fl, family, reverse) < 0) { - XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); return 0; } @@ -1929,7 +1904,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, for (i=skb->sp->len-1; i>=0; i--) { struct xfrm_state *x = skb->sp->xvec[i]; if (!xfrm_selector_match(&x->sel, &fl, family)) { - XFRM_INC_STATS(LINUX_MIB_XFRMINSTATEMISMATCH); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH); return 0; } } @@ -1939,24 +1914,24 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, if (sk && sk->sk_policy[dir]) { pol = xfrm_sk_policy_lookup(sk, dir, &fl); if (IS_ERR(pol)) { - XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); return 0; } } if (!pol) - pol = flow_cache_lookup(&fl, family, fl_dir, + pol = flow_cache_lookup(net, &fl, family, fl_dir, xfrm_policy_lookup); if (IS_ERR(pol)) { - XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); return 0; } if (!pol) { if (skb->sp && secpath_has_nontransport(skb->sp, 0, &xerr_idx)) { xfrm_secpath_reject(xerr_idx, skb, &fl); - XFRM_INC_STATS(LINUX_MIB_XFRMINNOPOLS); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOPOLS); return 0; } return 1; @@ -1968,12 +1943,12 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, npols ++; #ifdef CONFIG_XFRM_SUB_POLICY if (pols[0]->type != XFRM_POLICY_TYPE_MAIN) { - pols[1] = xfrm_policy_lookup_bytype(XFRM_POLICY_TYPE_MAIN, + pols[1] = xfrm_policy_lookup_bytype(net, XFRM_POLICY_TYPE_MAIN, &fl, family, XFRM_POLICY_IN); if (pols[1]) { if (IS_ERR(pols[1])) { - XFRM_INC_STATS(LINUX_MIB_XFRMINPOLERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLERROR); return 0; } pols[1]->curlft.use_time = get_seconds(); @@ -1997,11 +1972,11 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, for (pi = 0; pi < npols; pi++) { if (pols[pi] != pol && pols[pi]->action != XFRM_POLICY_ALLOW) { - XFRM_INC_STATS(LINUX_MIB_XFRMINPOLBLOCK); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK); goto reject; } if (ti + pols[pi]->xfrm_nr >= XFRM_MAX_DEPTH) { - XFRM_INC_STATS(LINUX_MIB_XFRMINBUFFERERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR); goto reject_error; } for (i = 0; i < pols[pi]->xfrm_nr; i++) @@ -2025,20 +2000,20 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb, if (k < -1) /* "-2 - errored_index" returned */ xerr_idx = -(2+k); - XFRM_INC_STATS(LINUX_MIB_XFRMINTMPLMISMATCH); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH); goto reject; } } if (secpath_has_nontransport(sp, k, &xerr_idx)) { - XFRM_INC_STATS(LINUX_MIB_XFRMINTMPLMISMATCH); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINTMPLMISMATCH); goto reject; } xfrm_pols_put(pols, npols); return 1; } - XFRM_INC_STATS(LINUX_MIB_XFRMINPOLBLOCK); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINPOLBLOCK); reject: xfrm_secpath_reject(xerr_idx, skb, &fl); @@ -2050,15 +2025,16 @@ EXPORT_SYMBOL(__xfrm_policy_check); int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) { + struct net *net = dev_net(skb->dev); struct flowi fl; if (xfrm_decode_session(skb, &fl, family) < 0) { /* XXX: we should have something like FWDHDRERROR here. */ - XFRM_INC_STATS(LINUX_MIB_XFRMINHDRERROR); + XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR); return 0; } - return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0; + return xfrm_lookup(net, &skb->dst, &fl, NULL, 0) == 0; } EXPORT_SYMBOL(__xfrm_route_forward); @@ -2142,7 +2118,7 @@ static void prune_one_bundle(struct xfrm_policy *pol, int (*func)(struct dst_ent write_unlock(&pol->lock); } -static void xfrm_prune_bundles(int (*func)(struct dst_entry *)) +static void xfrm_prune_bundles(struct net *net, int (*func)(struct dst_entry *)) { struct dst_entry *gc_list = NULL; int dir; @@ -2155,11 +2131,11 @@ static void xfrm_prune_bundles(int (*func)(struct dst_entry *)) int i; hlist_for_each_entry(pol, entry, - &xfrm_policy_inexact[dir], bydst) + &net->xfrm.policy_inexact[dir], bydst) prune_one_bundle(pol, func, &gc_list); - table = xfrm_policy_bydst[dir].table; - for (i = xfrm_policy_bydst[dir].hmask; i >= 0; i--) { + table = net->xfrm.policy_bydst[dir].table; + for (i = net->xfrm.policy_bydst[dir].hmask; i >= 0; i--) { hlist_for_each_entry(pol, entry, table + i, bydst) prune_one_bundle(pol, func, &gc_list); } @@ -2178,14 +2154,14 @@ static int unused_bundle(struct dst_entry *dst) return !atomic_read(&dst->__refcnt); } -static void __xfrm_garbage_collect(void) +static void __xfrm_garbage_collect(struct net *net) { - xfrm_prune_bundles(unused_bundle); + xfrm_prune_bundles(net, unused_bundle); } -static int xfrm_flush_bundles(void) +static int xfrm_flush_bundles(struct net *net) { - xfrm_prune_bundles(stale_bundle); + xfrm_prune_bundles(net, stale_bundle); return 0; } @@ -2371,38 +2347,54 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void { struct net_device *dev = ptr; - if (!net_eq(dev_net(dev), &init_net)) - return NOTIFY_DONE; - switch (event) { case NETDEV_DOWN: - xfrm_flush_bundles(); + xfrm_flush_bundles(dev_net(dev)); } return NOTIFY_DONE; } static struct notifier_block xfrm_dev_notifier = { - xfrm_dev_event, - NULL, - 0 + .notifier_call = xfrm_dev_event, }; #ifdef CONFIG_XFRM_STATISTICS -static int __init xfrm_statistics_init(void) +static int __net_init xfrm_statistics_init(struct net *net) { - if (snmp_mib_init((void **)xfrm_statistics, + int rv; + + if (snmp_mib_init((void **)net->mib.xfrm_statistics, sizeof(struct linux_xfrm_mib)) < 0) return -ENOMEM; + rv = xfrm_proc_init(net); + if (rv < 0) + snmp_mib_free((void **)net->mib.xfrm_statistics); + return rv; +} + +static void xfrm_statistics_fini(struct net *net) +{ + xfrm_proc_fini(net); + snmp_mib_free((void **)net->mib.xfrm_statistics); +} +#else +static int __net_init xfrm_statistics_init(struct net *net) +{ return 0; } + +static void xfrm_statistics_fini(struct net *net) +{ +} #endif -static void __init xfrm_policy_init(void) +static int __net_init xfrm_policy_init(struct net *net) { unsigned int hmask, sz; int dir; - xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", + if (net_eq(net, &init_net)) + xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", sizeof(struct xfrm_dst), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); @@ -2410,39 +2402,124 @@ static void __init xfrm_policy_init(void) hmask = 8 - 1; sz = (hmask+1) * sizeof(struct hlist_head); - xfrm_policy_byidx = xfrm_hash_alloc(sz); - xfrm_idx_hmask = hmask; - if (!xfrm_policy_byidx) - panic("XFRM: failed to allocate byidx hash\n"); + net->xfrm.policy_byidx = xfrm_hash_alloc(sz); + if (!net->xfrm.policy_byidx) + goto out_byidx; + net->xfrm.policy_idx_hmask = hmask; for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { struct xfrm_policy_hash *htab; - INIT_HLIST_HEAD(&xfrm_policy_inexact[dir]); + net->xfrm.policy_count[dir] = 0; + INIT_HLIST_HEAD(&net->xfrm.policy_inexact[dir]); - htab = &xfrm_policy_bydst[dir]; + htab = &net->xfrm.policy_bydst[dir]; htab->table = xfrm_hash_alloc(sz); - htab->hmask = hmask; if (!htab->table) - panic("XFRM: failed to allocate bydst hash\n"); + goto out_bydst; + htab->hmask = hmask; } - INIT_LIST_HEAD(&xfrm_policy_all); - INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task); - register_netdevice_notifier(&xfrm_dev_notifier); + INIT_LIST_HEAD(&net->xfrm.policy_all); + INIT_WORK(&net->xfrm.policy_hash_work, xfrm_hash_resize); + if (net_eq(net, &init_net)) + register_netdevice_notifier(&xfrm_dev_notifier); + return 0; + +out_bydst: + for (dir--; dir >= 0; dir--) { + struct xfrm_policy_hash *htab; + + htab = &net->xfrm.policy_bydst[dir]; + xfrm_hash_free(htab->table, sz); + } + xfrm_hash_free(net->xfrm.policy_byidx, sz); +out_byidx: + return -ENOMEM; } -void __init xfrm_init(void) +static void xfrm_policy_fini(struct net *net) { -#ifdef CONFIG_XFRM_STATISTICS - xfrm_statistics_init(); + struct xfrm_audit audit_info; + unsigned int sz; + int dir; + + flush_work(&net->xfrm.policy_hash_work); +#ifdef CONFIG_XFRM_SUB_POLICY + audit_info.loginuid = -1; + audit_info.sessionid = -1; + audit_info.secid = 0; + xfrm_policy_flush(net, XFRM_POLICY_TYPE_SUB, &audit_info); #endif - xfrm_state_init(); - xfrm_policy_init(); + audit_info.loginuid = -1; + audit_info.sessionid = -1; + audit_info.secid = 0; + xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); + flush_work(&xfrm_policy_gc_work); + + WARN_ON(!list_empty(&net->xfrm.policy_all)); + + for (dir = 0; dir < XFRM_POLICY_MAX * 2; dir++) { + struct xfrm_policy_hash *htab; + + WARN_ON(!hlist_empty(&net->xfrm.policy_inexact[dir])); + + htab = &net->xfrm.policy_bydst[dir]; + sz = (htab->hmask + 1); + WARN_ON(!hlist_empty(htab->table)); + xfrm_hash_free(htab->table, sz); + } + + sz = (net->xfrm.policy_idx_hmask + 1) * sizeof(struct hlist_head); + WARN_ON(!hlist_empty(net->xfrm.policy_byidx)); + xfrm_hash_free(net->xfrm.policy_byidx, sz); +} + +static int __net_init xfrm_net_init(struct net *net) +{ + int rv; + + rv = xfrm_statistics_init(net); + if (rv < 0) + goto out_statistics; + rv = xfrm_state_init(net); + if (rv < 0) + goto out_state; + rv = xfrm_policy_init(net); + if (rv < 0) + goto out_policy; + rv = xfrm_sysctl_init(net); + if (rv < 0) + goto out_sysctl; + return 0; + +out_sysctl: + xfrm_policy_fini(net); +out_policy: + xfrm_state_fini(net); +out_state: + xfrm_statistics_fini(net); +out_statistics: + return rv; +} + +static void __net_exit xfrm_net_exit(struct net *net) +{ + xfrm_sysctl_fini(net); + xfrm_policy_fini(net); + xfrm_state_fini(net); + xfrm_statistics_fini(net); +} + +static struct pernet_operations __net_initdata xfrm_net_ops = { + .init = xfrm_net_init, + .exit = xfrm_net_exit, +}; + +void __init xfrm_init(void) +{ + register_pernet_subsys(&xfrm_net_ops); xfrm_input_init(); -#ifdef CONFIG_XFRM_STATISTICS - xfrm_proc_init(); -#endif } #ifdef CONFIG_AUDITSYSCALL @@ -2458,25 +2535,21 @@ static void xfrm_audit_common_policyinfo(struct xfrm_policy *xp, switch(sel->family) { case AF_INET: - audit_log_format(audit_buf, " src=" NIPQUAD_FMT, - NIPQUAD(sel->saddr.a4)); + audit_log_format(audit_buf, " src=%pI4", &sel->saddr.a4); if (sel->prefixlen_s != 32) audit_log_format(audit_buf, " src_prefixlen=%d", sel->prefixlen_s); - audit_log_format(audit_buf, " dst=" NIPQUAD_FMT, - NIPQUAD(sel->daddr.a4)); + audit_log_format(audit_buf, " dst=%pI4", &sel->daddr.a4); if (sel->prefixlen_d != 32) audit_log_format(audit_buf, " dst_prefixlen=%d", sel->prefixlen_d); break; case AF_INET6: - audit_log_format(audit_buf, " src=" NIP6_FMT, - NIP6(*(struct in6_addr *)sel->saddr.a6)); + audit_log_format(audit_buf, " src=%pI6", sel->saddr.a6); if (sel->prefixlen_s != 128) audit_log_format(audit_buf, " src_prefixlen=%d", sel->prefixlen_s); - audit_log_format(audit_buf, " dst=" NIP6_FMT, - NIP6(*(struct in6_addr *)sel->daddr.a6)); + audit_log_format(audit_buf, " dst=%pI6", sel->daddr.a6); if (sel->prefixlen_d != 128) audit_log_format(audit_buf, " dst_prefixlen=%d", sel->prefixlen_d); @@ -2546,7 +2619,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(struct xfrm_selector *sel, u32 priority = ~0U; read_lock_bh(&xfrm_policy_lock); - chain = policy_hash_direct(&sel->daddr, &sel->saddr, sel->family, dir); + chain = policy_hash_direct(&init_net, &sel->daddr, &sel->saddr, sel->family, dir); hlist_for_each_entry(pol, entry, chain, bydst) { if (xfrm_migrate_selector_match(sel, &pol->selector) && pol->type == type) { @@ -2555,7 +2628,7 @@ static struct xfrm_policy * xfrm_migrate_policy_find(struct xfrm_selector *sel, break; } } - chain = &xfrm_policy_inexact[dir]; + chain = &init_net.xfrm.policy_inexact[dir]; hlist_for_each_entry(pol, entry, chain, bydst) { if (xfrm_migrate_selector_match(sel, &pol->selector) && pol->type == type && diff --git a/net/xfrm/xfrm_proc.c b/net/xfrm/xfrm_proc.c index 2b0db13f0cda681c9482e86a97a51cf6f9f660d4..284eaef1dbf22f49babc1d76f2e35814a874cedc 100644 --- a/net/xfrm/xfrm_proc.c +++ b/net/xfrm/xfrm_proc.c @@ -59,17 +59,18 @@ fold_field(void *mib[], int offt) static int xfrm_statistics_seq_show(struct seq_file *seq, void *v) { + struct net *net = seq->private; int i; for (i=0; xfrm_mib_list[i].name; i++) seq_printf(seq, "%-24s\t%lu\n", xfrm_mib_list[i].name, - fold_field((void **)xfrm_statistics, + fold_field((void **)net->mib.xfrm_statistics, xfrm_mib_list[i].entry)); return 0; } static int xfrm_statistics_seq_open(struct inode *inode, struct file *file) { - return single_open(file, xfrm_statistics_seq_show, NULL); + return single_open_net(inode, file, xfrm_statistics_seq_show); } static struct file_operations xfrm_statistics_seq_fops = { @@ -77,21 +78,18 @@ static struct file_operations xfrm_statistics_seq_fops = { .open = xfrm_statistics_seq_open, .read = seq_read, .llseek = seq_lseek, - .release = single_release, + .release = single_release_net, }; -int __init xfrm_proc_init(void) +int __net_init xfrm_proc_init(struct net *net) { - int rc = 0; - - if (!proc_net_fops_create(&init_net, "xfrm_stat", S_IRUGO, + if (!proc_net_fops_create(net, "xfrm_stat", S_IRUGO, &xfrm_statistics_seq_fops)) - goto stat_fail; - - out: - return rc; + return -ENOMEM; + return 0; +} - stat_fail: - rc = -ENOMEM; - goto out; +void xfrm_proc_fini(struct net *net) +{ + proc_net_remove(net, "xfrm_stat"); } diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 508337f97249d421e524013cdd83c86b6cbbf210..e25ff62ab2a62676e239cef57e9a288973d1ed25 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c @@ -24,17 +24,6 @@ #include "xfrm_hash.h" -struct sock *xfrm_nl; -EXPORT_SYMBOL(xfrm_nl); - -u32 sysctl_xfrm_aevent_etime __read_mostly = XFRM_AE_ETIME; -EXPORT_SYMBOL(sysctl_xfrm_aevent_etime); - -u32 sysctl_xfrm_aevent_rseqth __read_mostly = XFRM_AE_SEQT_SIZE; -EXPORT_SYMBOL(sysctl_xfrm_aevent_rseqth); - -u32 sysctl_xfrm_acq_expires __read_mostly = 30; - /* Each xfrm_state may be linked to two tables: 1. Hash table by (spi,daddr,ah/esp) to find SA by SPI. (input,ctl) @@ -44,19 +33,7 @@ u32 sysctl_xfrm_acq_expires __read_mostly = 30; static DEFINE_SPINLOCK(xfrm_state_lock); -/* Hash table to find appropriate SA towards given target (endpoint - * of tunnel or destination of transport mode) allowed by selector. - * - * 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; -static unsigned int xfrm_state_hmask __read_mostly; static unsigned int xfrm_state_hashmax __read_mostly = 1 * 1024 * 1024; -static unsigned int xfrm_state_num; static unsigned int xfrm_state_genid; static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family); @@ -69,25 +46,27 @@ static void xfrm_audit_state_replay(struct xfrm_state *x, #define xfrm_audit_state_replay(x, s, sq) do { ; } while (0) #endif /* CONFIG_AUDITSYSCALL */ -static inline unsigned int xfrm_dst_hash(xfrm_address_t *daddr, +static inline unsigned int xfrm_dst_hash(struct net *net, + xfrm_address_t *daddr, xfrm_address_t *saddr, u32 reqid, unsigned short family) { - return __xfrm_dst_hash(daddr, saddr, reqid, family, xfrm_state_hmask); + return __xfrm_dst_hash(daddr, saddr, reqid, family, net->xfrm.state_hmask); } -static inline unsigned int xfrm_src_hash(xfrm_address_t *daddr, +static inline unsigned int xfrm_src_hash(struct net *net, + xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family) { - return __xfrm_src_hash(daddr, saddr, family, xfrm_state_hmask); + return __xfrm_src_hash(daddr, saddr, family, net->xfrm.state_hmask); } static inline unsigned int -xfrm_spi_hash(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) +xfrm_spi_hash(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) { - return __xfrm_spi_hash(daddr, spi, proto, family, xfrm_state_hmask); + return __xfrm_spi_hash(daddr, spi, proto, family, net->xfrm.state_hmask); } static void xfrm_hash_transfer(struct hlist_head *list, @@ -121,16 +100,16 @@ static void xfrm_hash_transfer(struct hlist_head *list, } } -static unsigned long xfrm_hash_new_size(void) +static unsigned long xfrm_hash_new_size(unsigned int state_hmask) { - return ((xfrm_state_hmask + 1) << 1) * - sizeof(struct hlist_head); + return ((state_hmask + 1) << 1) * sizeof(struct hlist_head); } static DEFINE_MUTEX(hash_resize_mutex); -static void xfrm_hash_resize(struct work_struct *__unused) +static void xfrm_hash_resize(struct work_struct *work) { + struct net *net = container_of(work, struct net, xfrm.state_hash_work); struct hlist_head *ndst, *nsrc, *nspi, *odst, *osrc, *ospi; unsigned long nsize, osize; unsigned int nhashmask, ohashmask; @@ -138,7 +117,7 @@ static void xfrm_hash_resize(struct work_struct *__unused) mutex_lock(&hash_resize_mutex); - nsize = xfrm_hash_new_size(); + nsize = xfrm_hash_new_size(net->xfrm.state_hmask); ndst = xfrm_hash_alloc(nsize); if (!ndst) goto out_unlock; @@ -157,19 +136,19 @@ static void xfrm_hash_resize(struct work_struct *__unused) spin_lock_bh(&xfrm_state_lock); nhashmask = (nsize / sizeof(struct hlist_head)) - 1U; - for (i = xfrm_state_hmask; i >= 0; i--) - xfrm_hash_transfer(xfrm_state_bydst+i, ndst, nsrc, nspi, + for (i = net->xfrm.state_hmask; i >= 0; i--) + xfrm_hash_transfer(net->xfrm.state_bydst+i, ndst, nsrc, nspi, nhashmask); - odst = xfrm_state_bydst; - osrc = xfrm_state_bysrc; - ospi = xfrm_state_byspi; - ohashmask = xfrm_state_hmask; + odst = net->xfrm.state_bydst; + osrc = net->xfrm.state_bysrc; + ospi = net->xfrm.state_byspi; + ohashmask = net->xfrm.state_hmask; - xfrm_state_bydst = ndst; - xfrm_state_bysrc = nsrc; - xfrm_state_byspi = nspi; - xfrm_state_hmask = nhashmask; + net->xfrm.state_bydst = ndst; + net->xfrm.state_bysrc = nsrc; + net->xfrm.state_byspi = nspi; + net->xfrm.state_hmask = nhashmask; spin_unlock_bh(&xfrm_state_lock); @@ -182,16 +161,9 @@ out_unlock: mutex_unlock(&hash_resize_mutex); } -static DECLARE_WORK(xfrm_hash_work, xfrm_hash_resize); - -DECLARE_WAIT_QUEUE_HEAD(km_waitq); -EXPORT_SYMBOL(km_waitq); - static DEFINE_RWLOCK(xfrm_state_afinfo_lock); static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; -static struct work_struct xfrm_state_gc_work; -static HLIST_HEAD(xfrm_state_gc_list); static DEFINE_SPINLOCK(xfrm_state_gc_lock); int __xfrm_state_delete(struct xfrm_state *x); @@ -401,20 +373,21 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x) kfree(x); } -static void xfrm_state_gc_task(struct work_struct *data) +static void xfrm_state_gc_task(struct work_struct *work) { + struct net *net = container_of(work, struct net, xfrm.state_gc_work); struct xfrm_state *x; struct hlist_node *entry, *tmp; struct hlist_head gc_list; spin_lock_bh(&xfrm_state_gc_lock); - hlist_move_list(&xfrm_state_gc_list, &gc_list); + hlist_move_list(&net->xfrm.state_gc_list, &gc_list); spin_unlock_bh(&xfrm_state_gc_lock); hlist_for_each_entry_safe(x, entry, tmp, &gc_list, gclist) xfrm_state_gc_destroy(x); - wake_up(&km_waitq); + wake_up(&net->xfrm.km_waitq); } static inline unsigned long make_jiffies(long secs) @@ -428,6 +401,7 @@ static inline unsigned long make_jiffies(long secs) static void xfrm_timer_handler(unsigned long data) { struct xfrm_state *x = (struct xfrm_state*)data; + struct net *net = xs_net(x); unsigned long now = get_seconds(); long next = LONG_MAX; int warn = 0; @@ -485,7 +459,7 @@ resched: expired: if (x->km.state == XFRM_STATE_ACQ && x->id.spi == 0) { x->km.state = XFRM_STATE_EXPIRED; - wake_up(&km_waitq); + wake_up(&net->xfrm.km_waitq); next = 2; goto resched; } @@ -504,13 +478,14 @@ out: static void xfrm_replay_timer_handler(unsigned long data); -struct xfrm_state *xfrm_state_alloc(void) +struct xfrm_state *xfrm_state_alloc(struct net *net) { struct xfrm_state *x; x = kzalloc(sizeof(struct xfrm_state), GFP_ATOMIC); if (x) { + write_pnet(&x->xs_net, net); atomic_set(&x->refcnt, 1); atomic_set(&x->tunnel_users, 0); INIT_LIST_HEAD(&x->km.all); @@ -537,17 +512,20 @@ EXPORT_SYMBOL(xfrm_state_alloc); void __xfrm_state_destroy(struct xfrm_state *x) { + struct net *net = xs_net(x); + WARN_ON(x->km.state != XFRM_STATE_DEAD); spin_lock_bh(&xfrm_state_gc_lock); - hlist_add_head(&x->gclist, &xfrm_state_gc_list); + hlist_add_head(&x->gclist, &net->xfrm.state_gc_list); spin_unlock_bh(&xfrm_state_gc_lock); - schedule_work(&xfrm_state_gc_work); + schedule_work(&net->xfrm.state_gc_work); } EXPORT_SYMBOL(__xfrm_state_destroy); int __xfrm_state_delete(struct xfrm_state *x) { + struct net *net = xs_net(x); int err = -ESRCH; if (x->km.state != XFRM_STATE_DEAD) { @@ -558,7 +536,7 @@ int __xfrm_state_delete(struct xfrm_state *x) hlist_del(&x->bysrc); if (x->id.spi) hlist_del(&x->byspi); - xfrm_state_num--; + net->xfrm.state_num--; spin_unlock(&xfrm_state_lock); /* All xfrm_state objects are created by xfrm_state_alloc. @@ -587,15 +565,15 @@ EXPORT_SYMBOL(xfrm_state_delete); #ifdef CONFIG_SECURITY_NETWORK_XFRM static inline int -xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) +xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info) { int i, err = 0; - for (i = 0; i <= xfrm_state_hmask; i++) { + for (i = 0; i <= net->xfrm.state_hmask; i++) { struct hlist_node *entry; struct xfrm_state *x; - hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { + hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) { if (xfrm_id_proto_match(x->id.proto, proto) && (err = security_xfrm_state_delete(x)) != 0) { xfrm_audit_state_delete(x, 0, @@ -611,26 +589,26 @@ xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) } #else static inline int -xfrm_state_flush_secctx_check(u8 proto, struct xfrm_audit *audit_info) +xfrm_state_flush_secctx_check(struct net *net, u8 proto, struct xfrm_audit *audit_info) { return 0; } #endif -int xfrm_state_flush(u8 proto, struct xfrm_audit *audit_info) +int xfrm_state_flush(struct net *net, u8 proto, struct xfrm_audit *audit_info) { int i, err = 0; spin_lock_bh(&xfrm_state_lock); - err = xfrm_state_flush_secctx_check(proto, audit_info); + err = xfrm_state_flush_secctx_check(net, proto, audit_info); if (err) goto out; - for (i = 0; i <= xfrm_state_hmask; i++) { + for (i = 0; i <= net->xfrm.state_hmask; i++) { struct hlist_node *entry; struct xfrm_state *x; restart: - hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { + hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) { if (!xfrm_state_kern(x) && xfrm_id_proto_match(x->id.proto, proto)) { xfrm_state_hold(x); @@ -652,7 +630,7 @@ restart: out: spin_unlock_bh(&xfrm_state_lock); - wake_up(&km_waitq); + wake_up(&net->xfrm.km_waitq); return err; } EXPORT_SYMBOL(xfrm_state_flush); @@ -660,8 +638,8 @@ EXPORT_SYMBOL(xfrm_state_flush); void xfrm_sad_getinfo(struct xfrmk_sadinfo *si) { spin_lock_bh(&xfrm_state_lock); - si->sadcnt = xfrm_state_num; - si->sadhcnt = xfrm_state_hmask; + si->sadcnt = init_net.xfrm.state_num; + si->sadhcnt = init_net.xfrm.state_hmask; si->sadhmcnt = xfrm_state_hashmax; spin_unlock_bh(&xfrm_state_lock); } @@ -681,13 +659,13 @@ xfrm_init_tempsel(struct xfrm_state *x, struct flowi *fl, return 0; } -static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) +static struct xfrm_state *__xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) { - unsigned int h = xfrm_spi_hash(daddr, spi, proto, family); + unsigned int h = xfrm_spi_hash(net, daddr, spi, proto, family); struct xfrm_state *x; struct hlist_node *entry; - hlist_for_each_entry(x, entry, xfrm_state_byspi+h, byspi) { + hlist_for_each_entry(x, entry, net->xfrm.state_byspi+h, byspi) { if (x->props.family != family || x->id.spi != spi || x->id.proto != proto) @@ -713,13 +691,13 @@ static struct xfrm_state *__xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, return NULL; } -static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) +static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) { - unsigned int h = xfrm_src_hash(daddr, saddr, family); + unsigned int h = xfrm_src_hash(net, daddr, saddr, family); struct xfrm_state *x; struct hlist_node *entry; - hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { + hlist_for_each_entry(x, entry, net->xfrm.state_bysrc+h, bysrc) { if (x->props.family != family || x->id.proto != proto) continue; @@ -751,21 +729,23 @@ static struct xfrm_state *__xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm static inline struct xfrm_state * __xfrm_state_locate(struct xfrm_state *x, int use_spi, int family) { + struct net *net = xs_net(x); + if (use_spi) - return __xfrm_state_lookup(&x->id.daddr, x->id.spi, + return __xfrm_state_lookup(net, &x->id.daddr, x->id.spi, x->id.proto, family); else - return __xfrm_state_lookup_byaddr(&x->id.daddr, + return __xfrm_state_lookup_byaddr(net, &x->id.daddr, &x->props.saddr, x->id.proto, family); } -static void xfrm_hash_grow_check(int have_hash_collision) +static void xfrm_hash_grow_check(struct net *net, int have_hash_collision) { if (have_hash_collision && - (xfrm_state_hmask + 1) < xfrm_state_hashmax && - xfrm_state_num > xfrm_state_hmask) - schedule_work(&xfrm_hash_work); + (net->xfrm.state_hmask + 1) < xfrm_state_hashmax && + net->xfrm.state_num > net->xfrm.state_hmask) + schedule_work(&net->xfrm.state_hash_work); } struct xfrm_state * @@ -774,6 +754,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, struct xfrm_policy *pol, int *err, unsigned short family) { + struct net *net = xp_net(pol); unsigned int h; struct hlist_node *entry; struct xfrm_state *x, *x0, *to_put; @@ -784,8 +765,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, to_put = NULL; spin_lock_bh(&xfrm_state_lock); - h = xfrm_dst_hash(daddr, saddr, tmpl->reqid, family); - hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { + h = xfrm_dst_hash(net, daddr, saddr, tmpl->reqid, family); + hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { if (x->props.family == family && x->props.reqid == tmpl->reqid && !(x->props.flags & XFRM_STATE_WILDRECV) && @@ -829,13 +810,13 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, x = best; if (!x && !error && !acquire_in_progress) { if (tmpl->id.spi && - (x0 = __xfrm_state_lookup(daddr, tmpl->id.spi, + (x0 = __xfrm_state_lookup(net, daddr, tmpl->id.spi, tmpl->id.proto, family)) != NULL) { to_put = x0; error = -EEXIST; goto out; } - x = xfrm_state_alloc(); + x = xfrm_state_alloc(net); if (x == NULL) { error = -ENOMEM; goto out; @@ -854,19 +835,19 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr, if (km_query(x, tmpl, pol) == 0) { x->km.state = XFRM_STATE_ACQ; - list_add(&x->km.all, &xfrm_state_all); - hlist_add_head(&x->bydst, xfrm_state_bydst+h); - h = xfrm_src_hash(daddr, saddr, family); - hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); + list_add(&x->km.all, &net->xfrm.state_all); + hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); + h = xfrm_src_hash(net, daddr, saddr, family); + hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h); if (x->id.spi) { - h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, family); - hlist_add_head(&x->byspi, xfrm_state_byspi+h); + h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, family); + hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); } - x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; - x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; + x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; + x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ; add_timer(&x->timer); - xfrm_state_num++; - xfrm_hash_grow_check(x->bydst.next != NULL); + net->xfrm.state_num++; + xfrm_hash_grow_check(net, x->bydst.next != NULL); } else { x->km.state = XFRM_STATE_DEAD; to_put = x; @@ -886,7 +867,8 @@ out: } struct xfrm_state * -xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr, +xfrm_stateonly_find(struct net *net, + xfrm_address_t *daddr, xfrm_address_t *saddr, unsigned short family, u8 mode, u8 proto, u32 reqid) { unsigned int h; @@ -894,8 +876,8 @@ xfrm_stateonly_find(xfrm_address_t *daddr, xfrm_address_t *saddr, struct hlist_node *entry; spin_lock(&xfrm_state_lock); - h = xfrm_dst_hash(daddr, saddr, reqid, family); - hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { + h = xfrm_dst_hash(net, daddr, saddr, reqid, family); + hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { if (x->props.family == family && x->props.reqid == reqid && !(x->props.flags & XFRM_STATE_WILDRECV) && @@ -919,48 +901,50 @@ EXPORT_SYMBOL(xfrm_stateonly_find); static void __xfrm_state_insert(struct xfrm_state *x) { + struct net *net = xs_net(x); unsigned int h; x->genid = ++xfrm_state_genid; - list_add(&x->km.all, &xfrm_state_all); + list_add(&x->km.all, &net->xfrm.state_all); - h = xfrm_dst_hash(&x->id.daddr, &x->props.saddr, + h = xfrm_dst_hash(net, &x->id.daddr, &x->props.saddr, x->props.reqid, x->props.family); - hlist_add_head(&x->bydst, xfrm_state_bydst+h); + hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); - h = xfrm_src_hash(&x->id.daddr, &x->props.saddr, x->props.family); - hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); + h = xfrm_src_hash(net, &x->id.daddr, &x->props.saddr, x->props.family); + hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h); if (x->id.spi) { - h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, + h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); - hlist_add_head(&x->byspi, xfrm_state_byspi+h); + hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); } mod_timer(&x->timer, jiffies + HZ); if (x->replay_maxage) mod_timer(&x->rtimer, jiffies + x->replay_maxage); - wake_up(&km_waitq); + wake_up(&net->xfrm.km_waitq); - xfrm_state_num++; + net->xfrm.state_num++; - xfrm_hash_grow_check(x->bydst.next != NULL); + xfrm_hash_grow_check(net, x->bydst.next != NULL); } /* xfrm_state_lock is held */ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) { + struct net *net = xs_net(xnew); unsigned short family = xnew->props.family; u32 reqid = xnew->props.reqid; struct xfrm_state *x; struct hlist_node *entry; unsigned int h; - h = xfrm_dst_hash(&xnew->id.daddr, &xnew->props.saddr, reqid, family); - hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { + h = xfrm_dst_hash(net, &xnew->id.daddr, &xnew->props.saddr, reqid, family); + hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { if (x->props.family == family && x->props.reqid == reqid && !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && @@ -979,13 +963,13 @@ void xfrm_state_insert(struct xfrm_state *x) EXPORT_SYMBOL(xfrm_state_insert); /* xfrm_state_lock is held */ -static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) +static struct xfrm_state *__find_acq_core(struct net *net, unsigned short family, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create) { - unsigned int h = xfrm_dst_hash(daddr, saddr, reqid, family); + unsigned int h = xfrm_dst_hash(net, daddr, saddr, reqid, family); struct hlist_node *entry; struct xfrm_state *x; - hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { + hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) { if (x->props.reqid != reqid || x->props.mode != mode || x->props.family != family || @@ -1017,7 +1001,7 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re if (!create) return NULL; - x = xfrm_state_alloc(); + x = xfrm_state_alloc(net); if (likely(x)) { switch (family) { case AF_INET: @@ -1048,27 +1032,28 @@ static struct xfrm_state *__find_acq_core(unsigned short family, u8 mode, u32 re x->props.family = family; x->props.mode = mode; x->props.reqid = reqid; - x->lft.hard_add_expires_seconds = sysctl_xfrm_acq_expires; + x->lft.hard_add_expires_seconds = net->xfrm.sysctl_acq_expires; xfrm_state_hold(x); - x->timer.expires = jiffies + sysctl_xfrm_acq_expires*HZ; + x->timer.expires = jiffies + net->xfrm.sysctl_acq_expires*HZ; add_timer(&x->timer); - list_add(&x->km.all, &xfrm_state_all); - hlist_add_head(&x->bydst, xfrm_state_bydst+h); - h = xfrm_src_hash(daddr, saddr, family); - hlist_add_head(&x->bysrc, xfrm_state_bysrc+h); + list_add(&x->km.all, &net->xfrm.state_all); + hlist_add_head(&x->bydst, net->xfrm.state_bydst+h); + h = xfrm_src_hash(net, daddr, saddr, family); + hlist_add_head(&x->bysrc, net->xfrm.state_bysrc+h); - xfrm_state_num++; + net->xfrm.state_num++; - xfrm_hash_grow_check(x->bydst.next != NULL); + xfrm_hash_grow_check(net, x->bydst.next != NULL); } return x; } -static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq); +static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq); int xfrm_state_add(struct xfrm_state *x) { + struct net *net = xs_net(x); struct xfrm_state *x1, *to_put; int family; int err; @@ -1089,7 +1074,7 @@ int xfrm_state_add(struct xfrm_state *x) } if (use_spi && x->km.seq) { - x1 = __xfrm_find_acq_byseq(x->km.seq); + x1 = __xfrm_find_acq_byseq(net, x->km.seq); if (x1 && ((x1->id.proto != x->id.proto) || xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { to_put = x1; @@ -1098,7 +1083,7 @@ int xfrm_state_add(struct xfrm_state *x) } if (use_spi && !x1) - x1 = __find_acq_core(family, x->props.mode, x->props.reqid, + x1 = __find_acq_core(net, family, x->props.mode, x->props.reqid, x->id.proto, &x->id.daddr, &x->props.saddr, 0); @@ -1124,8 +1109,9 @@ EXPORT_SYMBOL(xfrm_state_add); #ifdef CONFIG_XFRM_MIGRATE static struct xfrm_state *xfrm_state_clone(struct xfrm_state *orig, int *errp) { + struct net *net = xs_net(orig); int err = -ENOMEM; - struct xfrm_state *x = xfrm_state_alloc(); + struct xfrm_state *x = xfrm_state_alloc(net); if (!x) goto error; @@ -1206,9 +1192,9 @@ struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) struct hlist_node *entry; if (m->reqid) { - h = xfrm_dst_hash(&m->old_daddr, &m->old_saddr, + h = xfrm_dst_hash(&init_net, &m->old_daddr, &m->old_saddr, m->reqid, m->old_family); - hlist_for_each_entry(x, entry, xfrm_state_bydst+h, bydst) { + hlist_for_each_entry(x, entry, init_net.xfrm.state_bydst+h, bydst) { if (x->props.mode != m->mode || x->id.proto != m->proto) continue; @@ -1223,9 +1209,9 @@ struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) return x; } } else { - h = xfrm_src_hash(&m->old_daddr, &m->old_saddr, + h = xfrm_src_hash(&init_net, &m->old_daddr, &m->old_saddr, m->old_family); - hlist_for_each_entry(x, entry, xfrm_state_bysrc+h, bysrc) { + hlist_for_each_entry(x, entry, init_net.xfrm.state_bysrc+h, bysrc) { if (x->props.mode != m->mode || x->id.proto != m->proto) continue; @@ -1369,40 +1355,41 @@ int xfrm_state_check_expire(struct xfrm_state *x) EXPORT_SYMBOL(xfrm_state_check_expire); struct xfrm_state * -xfrm_state_lookup(xfrm_address_t *daddr, __be32 spi, u8 proto, +xfrm_state_lookup(struct net *net, xfrm_address_t *daddr, __be32 spi, u8 proto, unsigned short family) { struct xfrm_state *x; spin_lock_bh(&xfrm_state_lock); - x = __xfrm_state_lookup(daddr, spi, proto, family); + x = __xfrm_state_lookup(net, daddr, spi, proto, family); spin_unlock_bh(&xfrm_state_lock); return x; } EXPORT_SYMBOL(xfrm_state_lookup); struct xfrm_state * -xfrm_state_lookup_byaddr(xfrm_address_t *daddr, xfrm_address_t *saddr, +xfrm_state_lookup_byaddr(struct net *net, + xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto, unsigned short family) { struct xfrm_state *x; spin_lock_bh(&xfrm_state_lock); - x = __xfrm_state_lookup_byaddr(daddr, saddr, proto, family); + x = __xfrm_state_lookup_byaddr(net, daddr, saddr, proto, family); spin_unlock_bh(&xfrm_state_lock); return x; } EXPORT_SYMBOL(xfrm_state_lookup_byaddr); struct xfrm_state * -xfrm_find_acq(u8 mode, u32 reqid, u8 proto, +xfrm_find_acq(struct net *net, u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create, unsigned short family) { struct xfrm_state *x; spin_lock_bh(&xfrm_state_lock); - x = __find_acq_core(family, mode, reqid, proto, daddr, saddr, create); + x = __find_acq_core(net, family, mode, reqid, proto, daddr, saddr, create); spin_unlock_bh(&xfrm_state_lock); return x; @@ -1449,15 +1436,15 @@ EXPORT_SYMBOL(xfrm_state_sort); /* Silly enough, but I'm lazy to build resolution list */ -static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) +static struct xfrm_state *__xfrm_find_acq_byseq(struct net *net, u32 seq) { int i; - for (i = 0; i <= xfrm_state_hmask; i++) { + for (i = 0; i <= net->xfrm.state_hmask; i++) { struct hlist_node *entry; struct xfrm_state *x; - hlist_for_each_entry(x, entry, xfrm_state_bydst+i, bydst) { + hlist_for_each_entry(x, entry, net->xfrm.state_bydst+i, bydst) { if (x->km.seq == seq && x->km.state == XFRM_STATE_ACQ) { xfrm_state_hold(x); @@ -1468,12 +1455,12 @@ static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq) return NULL; } -struct xfrm_state *xfrm_find_acq_byseq(u32 seq) +struct xfrm_state *xfrm_find_acq_byseq(struct net *net, u32 seq) { struct xfrm_state *x; spin_lock_bh(&xfrm_state_lock); - x = __xfrm_find_acq_byseq(seq); + x = __xfrm_find_acq_byseq(net, seq); spin_unlock_bh(&xfrm_state_lock); return x; } @@ -1494,6 +1481,7 @@ EXPORT_SYMBOL(xfrm_get_acqseq); int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) { + struct net *net = xs_net(x); unsigned int h; struct xfrm_state *x0; int err = -ENOENT; @@ -1511,7 +1499,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) err = -ENOENT; if (minspi == maxspi) { - x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family); + x0 = xfrm_state_lookup(net, &x->id.daddr, minspi, x->id.proto, x->props.family); if (x0) { xfrm_state_put(x0); goto unlock; @@ -1521,7 +1509,7 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) u32 spi = 0; for (h=0; hid.daddr, htonl(spi), x->id.proto, x->props.family); + x0 = xfrm_state_lookup(net, &x->id.daddr, htonl(spi), x->id.proto, x->props.family); if (x0 == NULL) { x->id.spi = htonl(spi); break; @@ -1531,8 +1519,8 @@ int xfrm_alloc_spi(struct xfrm_state *x, u32 low, u32 high) } if (x->id.spi) { spin_lock_bh(&xfrm_state_lock); - h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); - hlist_add_head(&x->byspi, xfrm_state_byspi+h); + h = xfrm_spi_hash(net, &x->id.daddr, x->id.spi, x->id.proto, x->props.family); + hlist_add_head(&x->byspi, net->xfrm.state_byspi+h); spin_unlock_bh(&xfrm_state_lock); err = 0; @@ -1545,7 +1533,7 @@ unlock: } EXPORT_SYMBOL(xfrm_alloc_spi); -int xfrm_state_walk(struct xfrm_state_walk *walk, +int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, int (*func)(struct xfrm_state *, int, void*), void *data) { @@ -1558,10 +1546,10 @@ int xfrm_state_walk(struct xfrm_state_walk *walk, spin_lock_bh(&xfrm_state_lock); if (list_empty(&walk->all)) - x = list_first_entry(&xfrm_state_all, struct xfrm_state_walk, all); + x = list_first_entry(&net->xfrm.state_all, struct xfrm_state_walk, all); else x = list_entry(&walk->all, struct xfrm_state_walk, all); - list_for_each_entry_from(x, &xfrm_state_all, all) { + list_for_each_entry_from(x, &net->xfrm.state_all, all) { if (x->state == XFRM_STATE_DEAD) continue; state = container_of(x, struct xfrm_state, km); @@ -1660,7 +1648,7 @@ static void xfrm_replay_timer_handler(unsigned long data) spin_lock(&x->lock); if (x->km.state == XFRM_STATE_VALID) { - if (xfrm_aevent_is_on()) + if (xfrm_aevent_is_on(xs_net(x))) xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); else x->xflags |= XFRM_TIME_DEFER; @@ -1716,7 +1704,7 @@ void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq) x->replay.bitmap |= (1U << diff); } - if (xfrm_aevent_is_on()) + if (xfrm_aevent_is_on(xs_net(x))) xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); } @@ -1749,6 +1737,7 @@ EXPORT_SYMBOL(km_state_notify); void km_state_expired(struct xfrm_state *x, int hard, u32 pid) { + struct net *net = xs_net(x); struct km_event c; c.data.hard = hard; @@ -1757,7 +1746,7 @@ void km_state_expired(struct xfrm_state *x, int hard, u32 pid) km_state_notify(x, &c); if (hard) - wake_up(&km_waitq); + wake_up(&net->xfrm.km_waitq); } EXPORT_SYMBOL(km_state_expired); @@ -1800,6 +1789,7 @@ EXPORT_SYMBOL(km_new_mapping); void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) { + struct net *net = xp_net(pol); struct km_event c; c.data.hard = hard; @@ -1808,7 +1798,7 @@ void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid) km_policy_notify(pol, dir, &c); if (hard) - wake_up(&km_waitq); + wake_up(&net->xfrm.km_waitq); } EXPORT_SYMBOL(km_policy_expired); @@ -1835,7 +1825,7 @@ int km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, EXPORT_SYMBOL(km_migrate); #endif -int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) +int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) { int err = -EINVAL; int ret; @@ -1844,7 +1834,7 @@ int km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr) read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) { if (km->report) { - ret = km->report(proto, sel, addr); + ret = km->report(net, proto, sel, addr); if (!ret) err = ret; } @@ -2032,8 +2022,9 @@ int xfrm_init_state(struct xfrm_state *x) x->inner_mode = inner_mode; } else { struct xfrm_mode *inner_mode_iaf; + int iafamily = AF_INET; - inner_mode = xfrm_get_mode(x->props.mode, AF_INET); + inner_mode = xfrm_get_mode(x->props.mode, x->props.family); if (inner_mode == NULL) goto error; @@ -2041,22 +2032,17 @@ int xfrm_init_state(struct xfrm_state *x) xfrm_put_mode(inner_mode); goto error; } + x->inner_mode = inner_mode; - inner_mode_iaf = xfrm_get_mode(x->props.mode, AF_INET6); - if (inner_mode_iaf == NULL) - goto error; - - if (!(inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL)) { - xfrm_put_mode(inner_mode_iaf); - goto error; - } + if (x->props.family == AF_INET) + iafamily = AF_INET6; - if (x->props.family == AF_INET) { - x->inner_mode = inner_mode; - x->inner_mode_iaf = inner_mode_iaf; - } else { - x->inner_mode = inner_mode_iaf; - x->inner_mode_iaf = inner_mode; + inner_mode_iaf = xfrm_get_mode(x->props.mode, iafamily); + if (inner_mode_iaf) { + if (inner_mode_iaf->flags & XFRM_MODE_FLAG_TUNNEL) + x->inner_mode_iaf = inner_mode_iaf; + else + xfrm_put_mode(inner_mode_iaf); } } @@ -2080,20 +2066,61 @@ error: EXPORT_SYMBOL(xfrm_init_state); -void __init xfrm_state_init(void) +int __net_init xfrm_state_init(struct net *net) { unsigned int sz; + INIT_LIST_HEAD(&net->xfrm.state_all); + sz = sizeof(struct hlist_head) * 8; - xfrm_state_bydst = xfrm_hash_alloc(sz); - xfrm_state_bysrc = xfrm_hash_alloc(sz); - xfrm_state_byspi = xfrm_hash_alloc(sz); - if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi) - panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes."); - xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); + net->xfrm.state_bydst = xfrm_hash_alloc(sz); + if (!net->xfrm.state_bydst) + goto out_bydst; + net->xfrm.state_bysrc = xfrm_hash_alloc(sz); + if (!net->xfrm.state_bysrc) + goto out_bysrc; + net->xfrm.state_byspi = xfrm_hash_alloc(sz); + if (!net->xfrm.state_byspi) + goto out_byspi; + net->xfrm.state_hmask = ((sz / sizeof(struct hlist_head)) - 1); + + net->xfrm.state_num = 0; + INIT_WORK(&net->xfrm.state_hash_work, xfrm_hash_resize); + INIT_HLIST_HEAD(&net->xfrm.state_gc_list); + INIT_WORK(&net->xfrm.state_gc_work, xfrm_state_gc_task); + init_waitqueue_head(&net->xfrm.km_waitq); + return 0; + +out_byspi: + xfrm_hash_free(net->xfrm.state_bysrc, sz); +out_bysrc: + xfrm_hash_free(net->xfrm.state_bydst, sz); +out_bydst: + return -ENOMEM; +} + +void xfrm_state_fini(struct net *net) +{ + struct xfrm_audit audit_info; + unsigned int sz; + + flush_work(&net->xfrm.state_hash_work); + audit_info.loginuid = -1; + audit_info.sessionid = -1; + audit_info.secid = 0; + xfrm_state_flush(net, IPSEC_PROTO_ANY, &audit_info); + flush_work(&net->xfrm.state_gc_work); + + WARN_ON(!list_empty(&net->xfrm.state_all)); - INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task); + sz = (net->xfrm.state_hmask + 1) * sizeof(struct hlist_head); + WARN_ON(!hlist_empty(net->xfrm.state_byspi)); + xfrm_hash_free(net->xfrm.state_byspi, sz); + WARN_ON(!hlist_empty(net->xfrm.state_bysrc)); + xfrm_hash_free(net->xfrm.state_bysrc, sz); + WARN_ON(!hlist_empty(net->xfrm.state_bydst)); + xfrm_hash_free(net->xfrm.state_bydst, sz); } #ifdef CONFIG_AUDITSYSCALL @@ -2109,16 +2136,12 @@ static void xfrm_audit_helper_sainfo(struct xfrm_state *x, switch(x->props.family) { case AF_INET: - audit_log_format(audit_buf, - " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT, - NIPQUAD(x->props.saddr.a4), - NIPQUAD(x->id.daddr.a4)); + audit_log_format(audit_buf, " src=%pI4 dst=%pI4", + &x->props.saddr.a4, &x->id.daddr.a4); break; case AF_INET6: - audit_log_format(audit_buf, - " src=" NIP6_FMT " dst=" NIP6_FMT, - NIP6(*(struct in6_addr *)x->props.saddr.a6), - NIP6(*(struct in6_addr *)x->id.daddr.a6)); + audit_log_format(audit_buf, " src=%pI6 dst=%pI6", + x->props.saddr.a6, x->id.daddr.a6); break; } @@ -2134,18 +2157,14 @@ static void xfrm_audit_helper_pktinfo(struct sk_buff *skb, u16 family, switch (family) { case AF_INET: iph4 = ip_hdr(skb); - audit_log_format(audit_buf, - " src=" NIPQUAD_FMT " dst=" NIPQUAD_FMT, - NIPQUAD(iph4->saddr), - NIPQUAD(iph4->daddr)); + audit_log_format(audit_buf, " src=%pI4 dst=%pI4", + &iph4->saddr, &iph4->daddr); break; case AF_INET6: iph6 = ipv6_hdr(skb); audit_log_format(audit_buf, - " src=" NIP6_FMT " dst=" NIP6_FMT - " flowlbl=0x%x%02x%02x", - NIP6(iph6->saddr), - NIP6(iph6->daddr), + " src=%pI6 dst=%pI6 flowlbl=0x%x%02x%02x", + &iph6->saddr,&iph6->daddr, iph6->flow_lbl[0] & 0x0f, iph6->flow_lbl[1], iph6->flow_lbl[2]); diff --git a/net/xfrm/xfrm_sysctl.c b/net/xfrm/xfrm_sysctl.c new file mode 100644 index 0000000000000000000000000000000000000000..2e6ffb66f06f1a2ee7bf935ab216ba9658278fdb --- /dev/null +++ b/net/xfrm/xfrm_sysctl.c @@ -0,0 +1,85 @@ +#include +#include +#include + +static void __xfrm_sysctl_init(struct net *net) +{ + net->xfrm.sysctl_aevent_etime = XFRM_AE_ETIME; + net->xfrm.sysctl_aevent_rseqth = XFRM_AE_SEQT_SIZE; + net->xfrm.sysctl_larval_drop = 1; + net->xfrm.sysctl_acq_expires = 30; +} + +#ifdef CONFIG_SYSCTL +static struct ctl_table xfrm_table[] = { + { + .ctl_name = NET_CORE_AEVENT_ETIME, + .procname = "xfrm_aevent_etime", + .maxlen = sizeof(u32), + .mode = 0644, + .proc_handler = proc_dointvec + }, + { + .ctl_name = NET_CORE_AEVENT_RSEQTH, + .procname = "xfrm_aevent_rseqth", + .maxlen = sizeof(u32), + .mode = 0644, + .proc_handler = proc_dointvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "xfrm_larval_drop", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "xfrm_acq_expires", + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec + }, + {} +}; + +int __net_init xfrm_sysctl_init(struct net *net) +{ + struct ctl_table *table; + + __xfrm_sysctl_init(net); + + table = kmemdup(xfrm_table, sizeof(xfrm_table), GFP_KERNEL); + if (!table) + goto out_kmemdup; + table[0].data = &net->xfrm.sysctl_aevent_etime; + table[1].data = &net->xfrm.sysctl_aevent_rseqth; + table[2].data = &net->xfrm.sysctl_larval_drop; + table[3].data = &net->xfrm.sysctl_acq_expires; + + net->xfrm.sysctl_hdr = register_net_sysctl_table(net, net_core_path, table); + if (!net->xfrm.sysctl_hdr) + goto out_register; + return 0; + +out_register: + kfree(table); +out_kmemdup: + return -ENOMEM; +} + +void xfrm_sysctl_fini(struct net *net) +{ + struct ctl_table *table; + + table = net->xfrm.sysctl_hdr->ctl_table_arg; + unregister_net_sysctl_table(net->xfrm.sysctl_hdr); + kfree(table); +} +#else +int __net_init xfrm_sysctl_init(struct net *net) +{ + __xfrm_sysctl_init(net); + return 0; +} +#endif diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index a278a6f3b9913eedb9d80f8e46e930520704ae3f..b95a2d64eb59c3f86e066acc86fee8e2e7fb61e1 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -316,11 +316,12 @@ static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs) x->replay_maxdiff = nla_get_u32(rt); } -static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, +static struct xfrm_state *xfrm_state_construct(struct net *net, + struct xfrm_usersa_info *p, struct nlattr **attrs, int *errp) { - struct xfrm_state *x = xfrm_state_alloc(); + struct xfrm_state *x = xfrm_state_alloc(net); int err = -ENOMEM; if (!x) @@ -367,9 +368,9 @@ static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, goto error; x->km.seq = p->seq; - x->replay_maxdiff = sysctl_xfrm_aevent_rseqth; + x->replay_maxdiff = net->xfrm.sysctl_aevent_rseqth; /* sysctl_xfrm_aevent_etime is in 100ms units */ - x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M; + x->replay_maxage = (net->xfrm.sysctl_aevent_etime*HZ)/XFRM_AE_ETH_M; x->preplay.bitmap = 0; x->preplay.seq = x->replay.seq+x->replay_maxdiff; x->preplay.oseq = x->replay.oseq +x->replay_maxdiff; @@ -391,6 +392,7 @@ error_no_put: static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct xfrm_usersa_info *p = nlmsg_data(nlh); struct xfrm_state *x; int err; @@ -403,7 +405,7 @@ static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, if (err) return err; - x = xfrm_state_construct(p, attrs, &err); + x = xfrm_state_construct(net, p, attrs, &err); if (!x) return err; @@ -431,7 +433,8 @@ out: return err; } -static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, +static struct xfrm_state *xfrm_user_state_lookup(struct net *net, + struct xfrm_usersa_id *p, struct nlattr **attrs, int *errp) { @@ -440,7 +443,7 @@ static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { err = -ESRCH; - x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); + x = xfrm_state_lookup(net, &p->daddr, p->spi, p->proto, p->family); } else { xfrm_address_t *saddr = NULL; @@ -451,8 +454,8 @@ static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, } err = -ESRCH; - x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto, - p->family); + x = xfrm_state_lookup_byaddr(net, &p->daddr, saddr, + p->proto, p->family); } out: @@ -464,6 +467,7 @@ static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct xfrm_state *x; int err = -ESRCH; struct km_event c; @@ -472,7 +476,7 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, u32 sessionid = NETLINK_CB(skb).sessionid; u32 sid = NETLINK_CB(skb).sid; - x = xfrm_user_state_lookup(p, attrs, &err); + x = xfrm_user_state_lookup(net, p, attrs, &err); if (x == NULL) return err; @@ -615,6 +619,7 @@ static int xfrm_dump_sa_done(struct netlink_callback *cb) static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) { + struct net *net = sock_net(skb->sk); struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; struct xfrm_dump_info info; @@ -631,7 +636,7 @@ static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) xfrm_state_walk_init(walk, 0); } - (void) xfrm_state_walk(walk, dump_one_state, &info); + (void) xfrm_state_walk(net, walk, dump_one_state, &info); return skb->len; } @@ -703,6 +708,7 @@ nla_put_failure: static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct sk_buff *r_skb; u32 *flags = nlmsg_data(nlh); u32 spid = NETLINK_CB(skb).pid; @@ -715,7 +721,7 @@ static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, if (build_spdinfo(r_skb, spid, seq, *flags) < 0) BUG(); - return nlmsg_unicast(xfrm_nl, r_skb, spid); + return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid); } static inline size_t xfrm_sadinfo_msgsize(void) @@ -756,6 +762,7 @@ nla_put_failure: static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct sk_buff *r_skb; u32 *flags = nlmsg_data(nlh); u32 spid = NETLINK_CB(skb).pid; @@ -768,18 +775,19 @@ static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, if (build_sadinfo(r_skb, spid, seq, *flags) < 0) BUG(); - return nlmsg_unicast(xfrm_nl, r_skb, spid); + return nlmsg_unicast(net->xfrm.nlsk, r_skb, spid); } static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct xfrm_usersa_id *p = nlmsg_data(nlh); struct xfrm_state *x; struct sk_buff *resp_skb; int err = -ESRCH; - x = xfrm_user_state_lookup(p, attrs, &err); + x = xfrm_user_state_lookup(net, p, attrs, &err); if (x == NULL) goto out_noput; @@ -787,7 +795,7 @@ static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, if (IS_ERR(resp_skb)) { err = PTR_ERR(resp_skb); } else { - err = nlmsg_unicast(xfrm_nl, resp_skb, NETLINK_CB(skb).pid); + err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).pid); } xfrm_state_put(x); out_noput: @@ -820,6 +828,7 @@ static int verify_userspi_info(struct xfrm_userspi_info *p) static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct xfrm_state *x; struct xfrm_userspi_info *p; struct sk_buff *resp_skb; @@ -837,7 +846,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, x = NULL; if (p->info.seq) { - x = xfrm_find_acq_byseq(p->info.seq); + x = xfrm_find_acq_byseq(net, p->info.seq); if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) { xfrm_state_put(x); x = NULL; @@ -845,7 +854,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, } if (!x) - x = xfrm_find_acq(p->info.mode, p->info.reqid, + x = xfrm_find_acq(net, p->info.mode, p->info.reqid, p->info.id.proto, daddr, &p->info.saddr, 1, family); @@ -863,7 +872,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, goto out; } - err = nlmsg_unicast(xfrm_nl, resp_skb, NETLINK_CB(skb).pid); + err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).pid); out: xfrm_state_put(x); @@ -1078,9 +1087,9 @@ static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_i p->share = XFRM_SHARE_ANY; /* XXX xp->share */ } -static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp) +static struct xfrm_policy *xfrm_policy_construct(struct net *net, struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp) { - struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL); + struct xfrm_policy *xp = xfrm_policy_alloc(net, GFP_KERNEL); int err; if (!xp) { @@ -1110,6 +1119,7 @@ static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct xfrm_userpolicy_info *p = nlmsg_data(nlh); struct xfrm_policy *xp; struct km_event c; @@ -1126,7 +1136,7 @@ static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, if (err) return err; - xp = xfrm_policy_construct(p, attrs, &err); + xp = xfrm_policy_construct(net, p, attrs, &err); if (!xp) return err; @@ -1263,6 +1273,7 @@ static int xfrm_dump_policy_done(struct netlink_callback *cb) static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) { + struct net *net = sock_net(skb->sk); struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; struct xfrm_dump_info info; @@ -1279,7 +1290,7 @@ static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); } - (void) xfrm_policy_walk(walk, dump_one_policy, &info); + (void) xfrm_policy_walk(net, walk, dump_one_policy, &info); return skb->len; } @@ -1311,6 +1322,7 @@ static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct xfrm_policy *xp; struct xfrm_userpolicy_id *p; u8 type = XFRM_POLICY_TYPE_MAIN; @@ -1330,7 +1342,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, return err; if (p->index) - xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err); + xp = xfrm_policy_byid(net, type, p->dir, p->index, delete, &err); else { struct nlattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_sec_ctx *ctx; @@ -1347,7 +1359,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, if (err) return err; } - xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, + xp = xfrm_policy_bysel_ctx(net, type, p->dir, &p->sel, ctx, delete, &err); security_xfrm_policy_free(ctx); } @@ -1361,7 +1373,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, if (IS_ERR(resp_skb)) { err = PTR_ERR(resp_skb); } else { - err = nlmsg_unicast(xfrm_nl, resp_skb, + err = nlmsg_unicast(net->xfrm.nlsk, resp_skb, NETLINK_CB(skb).pid); } } else { @@ -1390,6 +1402,7 @@ out: static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct km_event c; struct xfrm_usersa_flush *p = nlmsg_data(nlh); struct xfrm_audit audit_info; @@ -1398,13 +1411,14 @@ static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, audit_info.loginuid = NETLINK_CB(skb).loginuid; audit_info.sessionid = NETLINK_CB(skb).sessionid; audit_info.secid = NETLINK_CB(skb).sid; - err = xfrm_state_flush(p->proto, &audit_info); + err = xfrm_state_flush(net, p->proto, &audit_info); if (err) return err; c.data.proto = p->proto; c.event = nlh->nlmsg_type; c.seq = nlh->nlmsg_seq; c.pid = nlh->nlmsg_pid; + c.net = net; km_state_notify(NULL, &c); return 0; @@ -1457,6 +1471,7 @@ nla_put_failure: static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct xfrm_state *x; struct sk_buff *r_skb; int err; @@ -1468,7 +1483,7 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, if (r_skb == NULL) return -ENOMEM; - x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family); + x = xfrm_state_lookup(net, &id->daddr, id->spi, id->proto, id->family); if (x == NULL) { kfree_skb(r_skb); return -ESRCH; @@ -1486,7 +1501,7 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, if (build_aevent(r_skb, x, &c) < 0) BUG(); - err = nlmsg_unicast(xfrm_nl, r_skb, NETLINK_CB(skb).pid); + err = nlmsg_unicast(net->xfrm.nlsk, r_skb, NETLINK_CB(skb).pid); spin_unlock_bh(&x->lock); xfrm_state_put(x); return err; @@ -1495,6 +1510,7 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct xfrm_state *x; struct km_event c; int err = - EINVAL; @@ -1509,7 +1525,7 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) return err; - x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); + x = xfrm_state_lookup(net, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); if (x == NULL) return -ESRCH; @@ -1534,6 +1550,7 @@ out: static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct km_event c; u8 type = XFRM_POLICY_TYPE_MAIN; int err; @@ -1546,13 +1563,14 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, audit_info.loginuid = NETLINK_CB(skb).loginuid; audit_info.sessionid = NETLINK_CB(skb).sessionid; audit_info.secid = NETLINK_CB(skb).sid; - err = xfrm_policy_flush(type, &audit_info); + err = xfrm_policy_flush(net, type, &audit_info); if (err) return err; c.data.type = type; c.event = nlh->nlmsg_type; c.seq = nlh->nlmsg_seq; c.pid = nlh->nlmsg_pid; + c.net = net; km_policy_notify(NULL, 0, &c); return 0; } @@ -1560,6 +1578,7 @@ static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct xfrm_policy *xp; struct xfrm_user_polexpire *up = nlmsg_data(nlh); struct xfrm_userpolicy_info *p = &up->pol; @@ -1571,7 +1590,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, return err; if (p->index) - xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err); + xp = xfrm_policy_byid(net, type, p->dir, p->index, 0, &err); else { struct nlattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_sec_ctx *ctx; @@ -1588,7 +1607,7 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, if (err) return err; } - xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, ctx, 0, &err); + xp = xfrm_policy_bysel_ctx(net, type, p->dir, &p->sel, ctx, 0, &err); security_xfrm_policy_free(ctx); } if (xp == NULL) @@ -1623,12 +1642,13 @@ out: static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct xfrm_state *x; int err; struct xfrm_user_expire *ue = nlmsg_data(nlh); struct xfrm_usersa_info *p = &ue->state; - x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family); + x = xfrm_state_lookup(net, &p->id.daddr, p->id.spi, p->id.proto, p->family); err = -ENOENT; if (x == NULL) @@ -1657,31 +1677,27 @@ out: static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, struct nlattr **attrs) { + struct net *net = sock_net(skb->sk); struct xfrm_policy *xp; struct xfrm_user_tmpl *ut; int i; struct nlattr *rt = attrs[XFRMA_TMPL]; struct xfrm_user_acquire *ua = nlmsg_data(nlh); - struct xfrm_state *x = xfrm_state_alloc(); + struct xfrm_state *x = xfrm_state_alloc(net); int err = -ENOMEM; if (!x) - return err; + goto nomem; err = verify_newpolicy_info(&ua->policy); - if (err) { - printk("BAD policy passed\n"); - kfree(x); - return err; - } + if (err) + goto bad_policy; /* build an XP */ - xp = xfrm_policy_construct(&ua->policy, attrs, &err); - if (!xp) { - kfree(x); - return err; - } + xp = xfrm_policy_construct(net, &ua->policy, attrs, &err); + if (!xp) + goto free_state; memcpy(&x->id, &ua->id, sizeof(ua->id)); memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); @@ -1706,6 +1722,13 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, kfree(xp); return 0; + +bad_policy: + printk("BAD policy passed\n"); +free_state: + kfree(x); +nomem: + return err; } #ifdef CONFIG_XFRM_MIGRATE @@ -1869,6 +1892,7 @@ static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_migrate, struct xfrm_kmaddress *k) { + struct net *net = &init_net; struct sk_buff *skb; skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate, !!k), GFP_ATOMIC); @@ -1879,7 +1903,7 @@ static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, if (build_migrate(skb, m, num_migrate, k, sel, dir, type) < 0) BUG(); - return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC); + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC); } #else static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, @@ -1968,6 +1992,7 @@ static struct xfrm_link { static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) { + struct net *net = sock_net(skb->sk); struct nlattr *attrs[XFRMA_MAX+1]; struct xfrm_link *link; int type, err; @@ -1989,7 +2014,7 @@ static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) if (link->dump == NULL) return -EINVAL; - return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done); + return netlink_dump_start(net->xfrm.nlsk, skb, nlh, link->dump, link->done); } err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, @@ -2033,6 +2058,7 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) { + struct net *net = xs_net(x); struct sk_buff *skb; skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC); @@ -2042,11 +2068,12 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) if (build_expire(skb, x, c) < 0) BUG(); - return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); } static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) { + struct net *net = xs_net(x); struct sk_buff *skb; skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC); @@ -2056,11 +2083,12 @@ static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) if (build_aevent(skb, x, c) < 0) BUG(); - return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); } static int xfrm_notify_sa_flush(struct km_event *c) { + struct net *net = c->net; struct xfrm_usersa_flush *p; struct nlmsghdr *nlh; struct sk_buff *skb; @@ -2081,7 +2109,7 @@ static int xfrm_notify_sa_flush(struct km_event *c) nlmsg_end(skb, nlh); - return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); } static inline size_t xfrm_sa_len(struct xfrm_state *x) @@ -2111,6 +2139,7 @@ static inline size_t xfrm_sa_len(struct xfrm_state *x) static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) { + struct net *net = xs_net(x); struct xfrm_usersa_info *p; struct xfrm_usersa_id *id; struct nlmsghdr *nlh; @@ -2155,7 +2184,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) nlmsg_end(skb, nlh); - return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); nla_put_failure: /* Somebody screwed up with xfrm_sa_len! */ @@ -2235,6 +2264,7 @@ nlmsg_failure: static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, struct xfrm_policy *xp, int dir) { + struct net *net = xs_net(x); struct sk_buff *skb; skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC); @@ -2244,7 +2274,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, if (build_acquire(skb, x, xt, xp, dir) < 0) BUG(); - return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC); + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC); } /* User gives us xfrm_user_policy_info followed by an array of 0 @@ -2253,6 +2283,7 @@ static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, u8 *data, int len, int *dir) { + struct net *net = sock_net(sk); struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (p + 1); struct xfrm_policy *xp; @@ -2291,7 +2322,7 @@ static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, if (p->dir > XFRM_POLICY_OUT) return NULL; - xp = xfrm_policy_alloc(GFP_KERNEL); + xp = xfrm_policy_alloc(net, GFP_KERNEL); if (xp == NULL) { *dir = -ENOBUFS; return NULL; @@ -2344,6 +2375,7 @@ nlmsg_failure: static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) { + struct net *net = xp_net(xp); struct sk_buff *skb; skb = nlmsg_new(xfrm_polexpire_msgsize(xp), GFP_ATOMIC); @@ -2353,11 +2385,12 @@ static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_eve if (build_polexpire(skb, xp, dir, c) < 0) BUG(); - return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); } static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) { + struct net *net = xp_net(xp); struct xfrm_userpolicy_info *p; struct xfrm_userpolicy_id *id; struct nlmsghdr *nlh; @@ -2408,7 +2441,7 @@ static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event * nlmsg_end(skb, nlh); - return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); nlmsg_failure: kfree_skb(skb); @@ -2417,6 +2450,7 @@ nlmsg_failure: static int xfrm_notify_policy_flush(struct km_event *c) { + struct net *net = c->net; struct nlmsghdr *nlh; struct sk_buff *skb; @@ -2432,7 +2466,7 @@ static int xfrm_notify_policy_flush(struct km_event *c) nlmsg_end(skb, nlh); - return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); nlmsg_failure: kfree_skb(skb); @@ -2488,8 +2522,8 @@ nla_put_failure: return -EMSGSIZE; } -static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, - xfrm_address_t *addr) +static int xfrm_send_report(struct net *net, u8 proto, + struct xfrm_selector *sel, xfrm_address_t *addr) { struct sk_buff *skb; @@ -2500,7 +2534,59 @@ static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, if (build_report(skb, proto, sel, addr) < 0) BUG(); - return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); +} + +static inline size_t xfrm_mapping_msgsize(void) +{ + return NLMSG_ALIGN(sizeof(struct xfrm_user_mapping)); +} + +static int build_mapping(struct sk_buff *skb, struct xfrm_state *x, + xfrm_address_t *new_saddr, __be16 new_sport) +{ + struct xfrm_user_mapping *um; + struct nlmsghdr *nlh; + + nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MAPPING, sizeof(*um), 0); + if (nlh == NULL) + return -EMSGSIZE; + + um = nlmsg_data(nlh); + + memcpy(&um->id.daddr, &x->id.daddr, sizeof(um->id.daddr)); + um->id.spi = x->id.spi; + um->id.family = x->props.family; + um->id.proto = x->id.proto; + memcpy(&um->new_saddr, new_saddr, sizeof(um->new_saddr)); + memcpy(&um->old_saddr, &x->props.saddr, sizeof(um->old_saddr)); + um->new_sport = new_sport; + um->old_sport = x->encap->encap_sport; + um->reqid = x->props.reqid; + + return nlmsg_end(skb, nlh); +} + +static int xfrm_send_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, + __be16 sport) +{ + struct net *net = xs_net(x); + struct sk_buff *skb; + + if (x->id.proto != IPPROTO_ESP) + return -EINVAL; + + if (!x->encap) + return -EINVAL; + + skb = nlmsg_new(xfrm_mapping_msgsize(), GFP_ATOMIC); + if (skb == NULL) + return -ENOMEM; + + if (build_mapping(skb, x, ipaddr, sport) < 0) + BUG(); + + return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_MAPPING, GFP_ATOMIC); } static struct xfrm_mgr netlink_mgr = { @@ -2511,35 +2597,56 @@ static struct xfrm_mgr netlink_mgr = { .notify_policy = xfrm_send_policy_notify, .report = xfrm_send_report, .migrate = xfrm_send_migrate, + .new_mapping = xfrm_send_mapping, }; -static int __init xfrm_user_init(void) +static int __net_init xfrm_user_net_init(struct net *net) { struct sock *nlsk; - printk(KERN_INFO "Initializing XFRM netlink socket\n"); - - nlsk = netlink_kernel_create(&init_net, NETLINK_XFRM, XFRMNLGRP_MAX, + nlsk = netlink_kernel_create(net, NETLINK_XFRM, XFRMNLGRP_MAX, xfrm_netlink_rcv, NULL, THIS_MODULE); if (nlsk == NULL) return -ENOMEM; - rcu_assign_pointer(xfrm_nl, nlsk); - - xfrm_register_km(&netlink_mgr); - + rcu_assign_pointer(net->xfrm.nlsk, nlsk); return 0; } -static void __exit xfrm_user_exit(void) +static void __net_exit xfrm_user_net_exit(struct net *net) { - struct sock *nlsk = xfrm_nl; + struct sock *nlsk = net->xfrm.nlsk; - xfrm_unregister_km(&netlink_mgr); - rcu_assign_pointer(xfrm_nl, NULL); + rcu_assign_pointer(net->xfrm.nlsk, NULL); synchronize_rcu(); netlink_kernel_release(nlsk); } +static struct pernet_operations xfrm_user_net_ops = { + .init = xfrm_user_net_init, + .exit = xfrm_user_net_exit, +}; + +static int __init xfrm_user_init(void) +{ + int rv; + + printk(KERN_INFO "Initializing XFRM netlink socket\n"); + + rv = register_pernet_subsys(&xfrm_user_net_ops); + if (rv < 0) + return rv; + rv = xfrm_register_km(&netlink_mgr); + if (rv < 0) + unregister_pernet_subsys(&xfrm_user_net_ops); + return rv; +} + +static void __exit xfrm_user_exit(void) +{ + xfrm_unregister_km(&netlink_mgr); + unregister_pernet_subsys(&xfrm_user_net_ops); +} + module_init(xfrm_user_init); module_exit(xfrm_user_exit); MODULE_LICENSE("GPL"); diff --git a/security/selinux/avc.c b/security/selinux/avc.c index cb30c7e350b356c00a8d77dc5532ff20b6e5f62d..d43bd6baeeaa9e1c4526d1fd8a82eaf57c9472c8 100644 --- a/security/selinux/avc.c +++ b/security/selinux/avc.c @@ -495,7 +495,7 @@ static inline void avc_print_ipv6_addr(struct audit_buffer *ab, char *name1, char *name2) { if (!ipv6_addr_any(addr)) - audit_log_format(ab, " %s=" NIP6_FMT, name1, NIP6(*addr)); + audit_log_format(ab, " %s=%pI6", name1, addr); if (port) audit_log_format(ab, " %s=%d", name2, ntohs(port)); } @@ -504,7 +504,7 @@ static inline void avc_print_ipv4_addr(struct audit_buffer *ab, __be32 addr, __be16 port, char *name1, char *name2) { if (addr) - audit_log_format(ab, " %s=" NIPQUAD_FMT, name1, NIPQUAD(addr)); + audit_log_format(ab, " %s=%pI4", name1, &addr); if (port) audit_log_format(ab, " %s=%d", name2, ntohs(port)); } diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 853b58c8b2cb13d48011dc1d069ac32c6538e875..dbeaa783b2a968429a808dfde80dd84cf587228f 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4735,7 +4735,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, * as fast and as clean as possible. */ if (selinux_compat_net || !selinux_policycap_netpeer) return selinux_ip_postroute_compat(skb, ifindex, family); - +#ifdef CONFIG_XFRM /* If skb->dst->xfrm is non-NULL then the packet is undergoing an IPsec * packet transformation so allow the packet to pass without any checks * since we'll have another chance to perform access control checks @@ -4744,7 +4744,7 @@ static unsigned int selinux_ip_postroute(struct sk_buff *skb, int ifindex, * is NULL, in this case go ahead and apply access control. */ if (skb->dst != NULL && skb->dst->xfrm != NULL) return NF_ACCEPT; - +#endif secmark_active = selinux_secmark_enabled(); peerlbl_active = netlbl_enabled() || selinux_xfrm_enabled(); if (!secmark_active && !peerlbl_active)